ラングトンのアリの描画
Posted feedbacks - C++
C++でWTL使いました。GDIで描画、Windowsのタイマーメッセージ (WM_TIMER) を使って回数を進めるようにしています。高速に結果を見たかったので、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 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | #define WINVER 0x0400
#define _WIN32_WINDOWS 0
#define _WIN32_WINNT 0
#define _WIN32_IE 0x0300 // IE3以上を指定しないとWTLがコンパイルエラーを起こす。
#define WIN32_LEAN_AND_MEAN
#define _ATL_NO_AUTOMATIC_NAMESPACE
#define _WTL_NO_AUTOMATIC_NAMESPACE
#include <cassert>
#include <sstream>
#include <tchar.h> // _tWinMain
#include <windows.h>
#include <atlbase.h> // ATL共通ヘッダ
#include <atlwin.h> // CWindowImplほか
#include <atlcrack.h> // MSG_*
#include <atlapp.h> // <atlmisc.h>
#include <atlmisc.h> // CPoint
const int ID_TIMER = 1;
enum Direction {Up, Right, Down, Left};
class MainWindow :
public ATL::CWindowImpl<MainWindow, ATL::CWindow, ATL::CFrameWinTraits>
{
public:
MainWindow() : field(), x(100), y(100), direction(Up), step() {} // このxとyの値が初期位置
// ウィンドウクラス名を登録
DECLARE_WND_CLASS(TEXT("Langton's ant"));
// メッセージマップ
BEGIN_MSG_MAP(MainWindow)
MSG_WM_TIMER(OnTimer)
MSG_WM_PAINT(OnPaint)
MSG_WM_CREATE(OnCreate)
MSG_WM_DESTROY(OnDestroy)
END_MSG_MAP()
private:
void OnTimer(UINT /*idEvent*/)
{
for (int i = 0; i < 16; ++i) // 1度のタイマイベントで複数回進める。
{
NextStep();
++step;
}
std::basic_ostringstream<TCHAR> oss;
oss << TEXT("Langton's ant - step: ") << step;
SetWindowText(oss.str().c_str());
Invalidate(FALSE);
}
static const int TILE_WIDTH = 2, TILE_HEIGHT = 2;
static const int X = 200, Y = 200;
void OnPaint(HDC)
{
WTL::CPaintDC dc(m_hWnd);
for (int i = 0; i < Y; ++i)
{
for (int j = 0; j < X; ++j)
{
dc.FillSolidRect(j * TILE_WIDTH, i * TILE_HEIGHT,
TILE_WIDTH, TILE_HEIGHT,
field[i][j] ? RGB(255, 255, 255)
: RGB(0, 0, 0));
}
}
}
LRESULT OnCreate(CREATESTRUCT const* pcs)
{
RECT rc = {0, 0, TILE_WIDTH * X, TILE_HEIGHT * Y};
AdjustWindowRectEx(&rc, pcs->style, FALSE, pcs->dwExStyle);
SetWindowPos(0, &rc, SWP_NOMOVE | SWP_NOZORDER);
SetTimer(ID_TIMER, 10, 0);
return 0;
}
void OnDestroy()
{
PostQuitMessage(0);
}
void NextStep()
{
if (field[y][x]) // trueが白、falseが黒としている
{
if (direction == Up)
{
direction = Left;
}
else
{
--direction;
}
}
else
{
if (direction == Left)
{
direction = Up;
}
else
{
++direction;
}
}
field[y][x] = !field[y][x];
switch (direction)
{
case Up:
y--;
if (y == -1)
{
y = Y - 1;
}
break;
case Right:
x++;
if (x == X)
{
x = 0;
}
break;
case Down:
y++;
if (y == Y)
{
y = 0;
}
break;
case Left:
x--;
if (x == -1)
{
x = X - 1;
}
break;
default:
assert(0);
}
}
bool field[Y][X];
int y;
int x;
int direction; //Direction(列挙)型では++と--できない(できるようにするのが面倒)。
int step;
};
int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int cmdShow)
{
MainWindow wnd;
wnd.Create(NULL, ATL::CWindow::rcDefault, TEXT("Langton's ant"),
WS_CAPTION | WS_SYSMENU | WS_DLGFRAME | WS_MINIMIZEBOX
| WS_OVERLAPPED | WS_SYSMENU, WS_EX_APPWINDOW);
wnd.ShowWindow(cmdShow);
wnd.UpdateWindow();
WTL::CMessageLoop msgLoop;
return msgLoop.Run();
}
|
OpenGL/GLUTで。
ウィンドウの表示と描画がコードの半分以上orz。
作成はMac OS Xでしています。他の環境の場合には調整してください。
コンパイルは、
g++ -ansi -Wall -framework OpenGL -framework GLUT -framework Foundation -o doukaku276 doukaku276.cpp
終了条件はないので、ESCキーかQキーで終了させてください。
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 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | #include <bitset>
#include <GLUT/glut.h>
class Field
{
public:
virtual ~Field() {}
virtual bool operator () (int x, int y) const = 0;
virtual void set(int x, int y) = 0;
virtual void unset(int x, int y) = 0;
};
template<int Width, int Height>
class ConcreteField : public Field
{
public:
ConcreteField() : bits_() {}
bool operator () (int x, int y) const { return bits_[y * Width + x]; }
void set(int x, int y) { bits_[y * Width + x] = true; }
void unset(int x, int y) { bits_[y * Width + x] = false; }
private:
std::bitset<Width * Height> bits_;
};
class Direction
{
public:
static const int North = 0;
static const int East = 1;
static const int South = 2;
static const int West = 3;
Direction(int dir) : dir_(dir) {}
void set(int dir) { dir_ = dir; }
int get() const { return dir_; }
void turnRight()
{
dir_ += 1;
dir_ %= 4;
}
void turnLeft()
{
dir_ += 3;
dir_ %= 4;
}
private:
int dir_;
};
class Ant
{
public:
Ant(int x, int y, Direction direction) : x_(x), y_(y), direction_(direction) {}
void move(Field& field)
{
if(field(x_, y_))
{
field.unset(x_, y_);
direction_.turnRight();
moveForward();
}
else
{
field.set(x_, y_);
direction_.turnLeft();
moveForward();
}
}
void moveForward()
{
switch(direction_.get())
{
case Direction::North: --y_; break;
case Direction::East: ++x_; break;
case Direction::South: ++y_; break;
case Direction::West: --x_; break;
default: break;
}
}
private:
int x_;
int y_;
Direction direction_;
};
static const int Interval = 0;
static const int Width = 320;
static const int Height = 240;
static ConcreteField<Width, Height> field;
static Ant ant(Width / 2, Height / 2, Direction::North);
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
static const GLdouble black[] = { 0.0, 0.0, 0.0 };
glColor3dv(black);
glBegin(GL_POINTS);
for(int y = 0; y < Height; ++y)
{
for(int x = 0; x < Width; ++x)
{
if(field(x, y))
{
glVertex2f(x, y);
}
}
}
glEnd();
glutSwapBuffers();
}
void resize(int w, int h)
{
glViewport(0, 0, w, h);
glLoadIdentity();
glOrtho(-0.5, w - 0.5, h - 0.5, -0.5, -1.0, 1.0);
}
void key(unsigned char key, int x, int y)
{
switch(key)
{
case 'q':
case 'Q':
case '\033':
std::exit(0);
break;
default:
break;
}
}
void timer(int n)
{
ant.move(field);
display();
glutTimerFunc(Interval, timer, 0);
}
void initWindow(int argc, char* argv[])
{
glutInitWindowPosition(100, 100);
glutInitWindowSize(Width, Height);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutCreateWindow("doukaku#276");
glClearColor(1.0, 1.0, 1.0, 1.0);
}
void initEvent()
{
glutDisplayFunc(display);
glutReshapeFunc(resize);
glutKeyboardFunc(key);
glutTimerFunc(Interval, timer, 0);
}
int main(int argc, char* argv[])
{
initWindow(argc, argv);
initEvent();
glutMainLoop();
return 0;
}
|



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