ラングトンのアリの描画
Posted feedbacks - C#
C#でビットマップにごりごり描画します。 フレームスキップして速度を稼いでいます。
今回一番はまったのは、Color.FromArgb(255, 0, 0, 0) が Color.Black とイコールではないってこと。ColorはARGB以外の情報を持っているので、ToArgb()で比較するように、とMSDNにある。
see: Color.Equality 演算子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace LangtonsAnt {
class Ant {
Point pos;
int direction;
public int X { get { return pos.X; } }
public int Y { get { return pos.Y; } }
public Ant(int x, int y) {
pos.X = x;
pos.Y = y;
direction = 0;
}
public void Advance(bool IsBlack) {
if (IsBlack) {
direction = (direction + 1) % 4;
} else {
direction = (direction + 3) % 4;
}
switch (direction) {
case 0: pos.Y--; break; //北
case 1: pos.X++; break; //東
case 2: pos.Y++; break; //南
case 3: pos.X--; break; //西
}
}
}
class Form1 : Form {
Bitmap bitmap; //世界=ビットマップ
List<Ant> ants; //アリたち
Timer timer; //タイマー
long step_count; //ステップ数
Color Black = Color.FromArgb(255, 0, 0, 0);
Color White = Color.FromArgb(255, 255, 255, 255);
public Form1() {
//マップの初期化
this.Width = 300; this.Height = 200;
bitmap = new Bitmap(300, 200, Graphics.FromHwnd(this.Handle));
//100,100を中心に黒点を打つ
Random r = new Random();
for (int i = 0 ; i < 100 ; i++) {
int x = r.Next(40) + bitmap.Width / 2 - 20;
int y = r.Next(40) + bitmap.Height / 2 - 20;
bitmap.SetPixel(x, y, Black);
}
//アリの初期化
ants = new List<Ant>();
ants.Add(new Ant(r.Next(20) + bitmap.Width / 2 - 10, r.Next(20) + bitmap.Height / 2 - 10));
ants.Add(new Ant(r.Next(20) + bitmap.Width / 2 - 10, r.Next(20) + bitmap.Height / 2 - 10));
ants.Add(new Ant(r.Next(20) + bitmap.Width / 2 - 10, r.Next(20) + bitmap.Height / 2 - 10));
//タイマー初期化
step_count = 0;
timer = new Timer();
timer.Interval = 300; //300msに1度再描画
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
void timer_Tick(object sender, EventArgs e) {
//高速化のため1描画につき150周回す
for (int step = 0 ; step < 150 ; step++) {
foreach (Ant ant in ants) {
int x = (ant.X + bitmap.Width) % bitmap.Width;
if (x < 0) x += bitmap.Width;
int y = (ant.Y + bitmap.Height) % bitmap.Height;
if (y < 0) y += bitmap.Height;
Color color = bitmap.GetPixel(x, y);
if (color == Black) {
ant.Advance(true);
bitmap.SetPixel(x, y, White);
} else {
ant.Advance(false);
bitmap.SetPixel(x, y, Black);
}
}
}
Refresh();
step_count += 150;
Text = step_count.ToString();
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
e.Graphics.DrawImage(bitmap, ClientRectangle);
}
protected override void OnClosed(EventArgs e) {
timer.Stop(); timer = null;
base.OnClosed(e);
}
}
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
|
アリ1匹につき1スレッドで。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
namespace doukaku276
{
class Program
{
const int ANT_NUM = 10;
const int FIELD_WIDTH = 100;
const int FIELD_HEIGHT = 100;
static Random rnd = new Random();
static void Main(string[] args)
{
new FormMain().ShowDialog();
}
class Ant
{
int x, y;
int direction;//0:↑ 1:→ 2:↓ 3:←
Color color;
public Ant()
{
x = rnd.Next(FIELD_WIDTH);
y = rnd.Next(FIELD_HEIGHT);
direction = rnd.Next(4);
color = Color.FromArgb(rnd.Next(254), rnd.Next(255), rnd.Next(255));
}
public void step(Bitmap bmp)
{
bool b = bmp.GetPixel(x, y).R != 255; // 黒? R=255を白とする
direction = (direction + (b ? 1 : 3)) % 4; // 回転
bmp.SetPixel(x, y, b ? Color.White : color); // 色反転
// 前進
switch (direction)
{
case 0: y--; break;
case 1: x++; break;
case 2: y++; break;
case 3: x--; break;
}
if (x < 0) x += FIELD_WIDTH;
if (x >= FIELD_WIDTH) x -= FIELD_WIDTH;
if (y < 0) y += FIELD_HEIGHT;
if (y >= FIELD_HEIGHT) y -= FIELD_HEIGHT;
}
}
class FormMain : Form
{
Bitmap bmp = new Bitmap(FIELD_WIDTH, FIELD_HEIGHT);
List<Thread> ants = new List<Thread>();
public FormMain()
{
lock (bmp)
{
for (int y = 0; y < FIELD_HEIGHT; y++)
for (int x = 0; x < FIELD_WIDTH; x++)
bmp.SetPixel(x, y, Color.White);
}
this.Size = new Size(FIELD_WIDTH * 3 + 100, FIELD_HEIGHT * 3 + 100);
this.CenterToScreen();
this.DoubleBuffered = true;
}
void update()
{
Ant ant = new Ant();
while (true)
{
lock (bmp)
{
ant.step(bmp);
}
this.Invalidate();
Thread.Sleep(1);
}
}
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
foreach(var t in ants) t.Abort();
}
protected override void OnPaint(PaintEventArgs e)
{
//base.OnPaint(e);
Graphics g = e.Graphics;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
lock (bmp)
{
g.DrawImage(bmp, 30, 30, FIELD_WIDTH * 3, FIELD_HEIGHT * 3);
}
g.DrawString(string.Format("ants:{0}", ants.Count), this.Font, Brushes.Black, 40, FIELD_HEIGHT * 3);
}
protected override void OnClick(EventArgs e)
{
var thread = new Thread(new ThreadStart(update));
thread.Start();
ants.Add(thread);
}
}
}
}
|


Songmu #9331() [ JavaScript ] Rating8/10=0.80
- 黒いマスにアリがいた場合、90°右に方向転換し、そのマスの色を反転させ、1マス前進する。
- 白いマスにアリがいた場合、90°左に方向転換し、そのマスの色を反転させ、1マス前進する。
詳しくはWikipedia等で調べるか、参考ページに拙作のデモがありますのでご覧下さい。
see: JavaScriptでラングトンの蟻
Rating8/10=0.80-0+
[ reply ]