C# - 需要帮助创建通过画线模拟质数行为的程序
C# - Need help creating program that simulates Prime Number behavior by drawing lines
我挑战自己创建一个程序来试验质数,我已经知道如何去做,但不是编码技能..
我的计划是这样的:
首先我会用 C# 创建一个程序,它会按照一些规则生成直线:
规则 1:所有行的长度相同。
规则 2:所有线都是水平或垂直的(没有对角线)。
规则 3: 每一个新行都从前一行结束的地方开始(这样所有的行都连接在一起)。
现在是棘手的部分:
我想制作一个计数器,每次创建新行时计数器都会增加 1(我假设起始值为 1),每当它达到质数时,行就会更改 'direction' 并且开始'going'到原来方向的左边。
前 10 行看起来像这样:
|
__ |
| | |
|__ __|
注意它如何在第 2、3、5 和 7 行改变方向。
(从里面开始到外面结束)
这将创建一条长扭曲线,看看它形成什么样的图案会很酷。
感谢您的帮助!
我再次希望我有足够的分数来发表评论,但我想确保你提前知道这不会导致一直螺旋。一对素数仅相隔 2 个(n、n+2 均为素数),这将使您的蛇旋转 180 度并越过自身。
如果您同意,请查看 System.Drawing 命名空间,尤其是 Graphics.Drawline 方法。或者查看一些有助于为您提供正确想法的代码。只需将 pictureBox 放入 Windows Form 中,这段代码就会在上面放一行。从那里你可以处理你的笔颜色、比例、找到你的质数等。
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawLine(new Pen(Color.Red), 300, 100, 100, 100);
}
pictureBox1.Image = bmp;
这是一个有趣的项目。感谢我早上的娱乐活动!
我在 this SO thread 中使用了 SLaks 代码来获取小于指定数量的素数列表。
这是一些示例输出:
生成素数后,我遍历列表并将行存储在 GraphicsPath 中。然后使用 Graphics.GetBounds()
方法允许我们在 Panel 的 Paint() 事件中适当地缩放和变换图形,以便可以看到整个绘图:
public partial class Form1 : Form
{
private const int segmentLength = 10;
private GraphicsPath gpPrimes = null;
public Form1()
{
InitializeComponent();
nudLessThanMax.Minimum = 15;
nudLessThanMax.Maximum = 500000;
nudLessThanMax.Value = nudLessThanMax.Minimum;
pnlPrimes.Paint += PnlPrimes_Paint;
pnlPrimes.SizeChanged += PnlPrimes_SizeChanged;
}
private void PnlPrimes_SizeChanged(object sender, EventArgs e)
{
pnlPrimes.Invalidate();
}
private void PnlPrimes_Paint(object sender, PaintEventArgs e)
{
if (gpPrimes != null)
{
RectangleF rectF = gpPrimes.GetBounds();
float max = Math.Max(rectF.Width + (2 * segmentLength), rectF.Height + (2 * segmentLength));
e.Graphics.TranslateTransform(pnlPrimes.Width / 2, pnlPrimes.Height / 2);
e.Graphics.ScaleTransform((float)pnlPrimes.Width / max, (float)pnlPrimes.Height / max);
e.Graphics.TranslateTransform(-(rectF.Left + rectF.Width / 2), -(rectF.Top + rectF.Height / 2));
e.Graphics.DrawPath(Pens.Black, gpPrimes);
}
}
private void btnGraphPrimes_Click(object sender, EventArgs e)
{
btnGraphPrimes.Enabled = false;
backgroundWorker1.RunWorkerAsync((int)this.nudLessThanMax.Value);
}
private List<int> PrimesLessThan(int num) // SLaks:
{
return Enumerable.Range(0, (int)Math.Floor(2.52 * Math.Sqrt(num) / Math.Log(num))).Aggregate(
Enumerable.Range(2, num - 1).ToList(),
(result, index) =>
{
var bp = result[index]; var sqr = bp * bp;
result.RemoveAll(i => i >= sqr && i % bp == 0);
return result;
}
);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int diff;
int num = (int)e.Argument;
Point pt = new Point(0, 0);
Point pt2 = pt;
GraphicsPath gp = new GraphicsPath();
List<int> primes = PrimesLessThan(num);
for(int i = 1; i < primes.Count; i++)
{
diff = primes[i] - primes[i - 1];
switch(i % 4)
{
case 1: // up
pt2 = new Point(pt.X, pt.Y - (segmentLength * diff));
break;
case 2: // left
pt2 = new Point(pt.X - (segmentLength * diff), pt.Y);
break;
case 3: // down
pt2 = new Point(pt.X, pt.Y + (segmentLength * diff));
break;
case 0: // right
pt2 = new Point(pt.X + (segmentLength * diff), pt.Y);
break;
}
gp.AddLine(pt, pt2);
pt = pt2;
}
gpPrimes = gp;
e.Result = primes;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lbPrimes.DataSource = (List<int>)e.Result;
pnlPrimes.Invalidate();
btnGraphPrimes.Enabled = true;
}
}
我挑战自己创建一个程序来试验质数,我已经知道如何去做,但不是编码技能..
我的计划是这样的: 首先我会用 C# 创建一个程序,它会按照一些规则生成直线:
规则 1:所有行的长度相同。
规则 2:所有线都是水平或垂直的(没有对角线)。
规则 3: 每一个新行都从前一行结束的地方开始(这样所有的行都连接在一起)。
现在是棘手的部分:
我想制作一个计数器,每次创建新行时计数器都会增加 1(我假设起始值为 1),每当它达到质数时,行就会更改 'direction' 并且开始'going'到原来方向的左边。
前 10 行看起来像这样:
|
__ |
| | |
|__ __|
注意它如何在第 2、3、5 和 7 行改变方向。
(从里面开始到外面结束)
这将创建一条长扭曲线,看看它形成什么样的图案会很酷。
感谢您的帮助!
我再次希望我有足够的分数来发表评论,但我想确保你提前知道这不会导致一直螺旋。一对素数仅相隔 2 个(n、n+2 均为素数),这将使您的蛇旋转 180 度并越过自身。
如果您同意,请查看 System.Drawing 命名空间,尤其是 Graphics.Drawline 方法。或者查看一些有助于为您提供正确想法的代码。只需将 pictureBox 放入 Windows Form 中,这段代码就会在上面放一行。从那里你可以处理你的笔颜色、比例、找到你的质数等。
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawLine(new Pen(Color.Red), 300, 100, 100, 100);
}
pictureBox1.Image = bmp;
这是一个有趣的项目。感谢我早上的娱乐活动!
我在 this SO thread 中使用了 SLaks 代码来获取小于指定数量的素数列表。
这是一些示例输出:
生成素数后,我遍历列表并将行存储在 GraphicsPath 中。然后使用 Graphics.GetBounds()
方法允许我们在 Panel 的 Paint() 事件中适当地缩放和变换图形,以便可以看到整个绘图:
public partial class Form1 : Form
{
private const int segmentLength = 10;
private GraphicsPath gpPrimes = null;
public Form1()
{
InitializeComponent();
nudLessThanMax.Minimum = 15;
nudLessThanMax.Maximum = 500000;
nudLessThanMax.Value = nudLessThanMax.Minimum;
pnlPrimes.Paint += PnlPrimes_Paint;
pnlPrimes.SizeChanged += PnlPrimes_SizeChanged;
}
private void PnlPrimes_SizeChanged(object sender, EventArgs e)
{
pnlPrimes.Invalidate();
}
private void PnlPrimes_Paint(object sender, PaintEventArgs e)
{
if (gpPrimes != null)
{
RectangleF rectF = gpPrimes.GetBounds();
float max = Math.Max(rectF.Width + (2 * segmentLength), rectF.Height + (2 * segmentLength));
e.Graphics.TranslateTransform(pnlPrimes.Width / 2, pnlPrimes.Height / 2);
e.Graphics.ScaleTransform((float)pnlPrimes.Width / max, (float)pnlPrimes.Height / max);
e.Graphics.TranslateTransform(-(rectF.Left + rectF.Width / 2), -(rectF.Top + rectF.Height / 2));
e.Graphics.DrawPath(Pens.Black, gpPrimes);
}
}
private void btnGraphPrimes_Click(object sender, EventArgs e)
{
btnGraphPrimes.Enabled = false;
backgroundWorker1.RunWorkerAsync((int)this.nudLessThanMax.Value);
}
private List<int> PrimesLessThan(int num) // SLaks:
{
return Enumerable.Range(0, (int)Math.Floor(2.52 * Math.Sqrt(num) / Math.Log(num))).Aggregate(
Enumerable.Range(2, num - 1).ToList(),
(result, index) =>
{
var bp = result[index]; var sqr = bp * bp;
result.RemoveAll(i => i >= sqr && i % bp == 0);
return result;
}
);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int diff;
int num = (int)e.Argument;
Point pt = new Point(0, 0);
Point pt2 = pt;
GraphicsPath gp = new GraphicsPath();
List<int> primes = PrimesLessThan(num);
for(int i = 1; i < primes.Count; i++)
{
diff = primes[i] - primes[i - 1];
switch(i % 4)
{
case 1: // up
pt2 = new Point(pt.X, pt.Y - (segmentLength * diff));
break;
case 2: // left
pt2 = new Point(pt.X - (segmentLength * diff), pt.Y);
break;
case 3: // down
pt2 = new Point(pt.X, pt.Y + (segmentLength * diff));
break;
case 0: // right
pt2 = new Point(pt.X + (segmentLength * diff), pt.Y);
break;
}
gp.AddLine(pt, pt2);
pt = pt2;
}
gpPrimes = gp;
e.Result = primes;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lbPrimes.DataSource = (List<int>)e.Result;
pnlPrimes.Invalidate();
btnGraphPrimes.Enabled = true;
}
}