个人作品

合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下

兰顿蚂蚁(by that boy)

受到生命游戏启发,想到了这个兰顿蚂蚁,都是零玩家游戏。

在平面上的正方形格被填上黑色或白色。在其中一格正方形有一只“蚂蚁”,它的头部朝向上下左右其中一方。
若蚂蚁在白格,右转90度,将该格改为黑格,向前移一步;
若蚂蚁在黑格,左转90度,将该格改为白格,向前移一步。

以上就是兰顿蚂蚁的简单规则描述。更详细的请参考维基百科。

执行效果如下:

完整的源代码如下:

/******************************
 * 兰顿蚂蚁
 * 编译环境:VC++ 2017
 * 作者:that boy,2018/12/19
 * 最后修改:2018/12/21
 ******************************/

#include <EasyX.h>
#include <string>
#include <conio.h>


namespace LangtonAnt
{
	// 方向
	struct Direct
	{
		int dx;
		int dy;
		Direct&TurnLeft();
		Direct&TurnRight();
	};

	Direct	LEFT{ -1,0 },
			RIGHT{ 1,0 },
			UP{ 0,-1 },
			DOWN{ 0,1 };

	IMAGE	BlockMap;		// 地图图像
	int		BlockSize;		// 方块大小
	bool*	Map = nullptr;	// 地图(逻辑)
	// 地图大小(逻辑)
	int		MapWidth;
	int		MapHeight;
	// 当前方向
	Direct	CurrentDirect;
	// 当前位置
	int		CurrentX;
	int		CurrentY;
	// 是否超出边界(开始有规律)
	bool	OutMap = false;

	void Init(int, int, int, int, int, Direct = UP);	// 初始化
	const IMAGE& Update();								// 更新逻辑图像
	void Quit();										// 结束,回收内存
}


// 主函数
int main()
{
	LangtonAnt::Init(10, 80, 60, 40, 30);	// 设置方块大小 10,地图大小 80*60,起点(40,30)

	initgraph(800, 600);

	// 设置字体
	setbkcolor(WHITE);
	settextcolor(BLACK);
	settextstyle(20, 0, L"Arial");

	BeginBatchDraw();

	for (long int step = 0; !LangtonAnt::OutMap; ++step)
	{
		putimage(0, 0, &LangtonAnt::Update());
		outtextxy(0, 0, (std::to_wstring(step) + L" steps").c_str());
		FlushBatchDraw();
		Sleep(1);
	}
	LangtonAnt::Quit();

	// 居中显示结束语
	outtextxy(400 - textwidth(L"Langton's Ant is running in a loop.") / 2, 300 - textheight('L') / 2, L"Langton's Ant is running in a loop.");

	EndBatchDraw();
	_getch();
	closegraph();

	return 0;
}


// 初始化兰顿蚂蚁
void LangtonAnt::Init(int Blocksize, int MapW, int MapH, int StartX, int StartY, Direct StartDirect)
{
	// 设置数据
	MapWidth = MapW;
	MapHeight = MapH;
	CurrentX = StartX;
	CurrentY = StartY;
	CurrentDirect = StartDirect;
	OutMap = false;

	if (Map != nullptr)
		delete[]Map;

	Map = new bool[MapWidth*MapHeight]();

	BlockSize = Blocksize;
	BlockMap.Resize(MapWidth*BlockSize, MapHeight*BlockSize);

	// 填充地图图像
	SetWorkingImage(&BlockMap);
	setbkcolor(WHITE);
	cleardevice();
	SetWorkingImage();
}


// 更新逻辑和图像
const IMAGE & LangtonAnt::Update()
{
	// 处理边界
	if (CurrentX < 0 || CurrentX >= MapWidth || CurrentY < 0 || CurrentY >= MapHeight)
	{
		OutMap = true;
		return BlockMap;
	}

	if (Map[CurrentX + CurrentY * MapWidth])	// 黑色
	{
		CurrentDirect.TurnLeft();	// 左转
	}
	else
	{
		CurrentDirect.TurnRight();	// 右转
	}

	// 绘制图像
	SetWorkingImage(&BlockMap);

	// 转向
	Map[CurrentX + CurrentY * MapWidth] = !Map[CurrentX + CurrentY * MapWidth];

	// 重绘底部
	setfillcolor(Map[CurrentX + CurrentY * MapWidth] ? BLACK : WHITE);
	solidrectangle(CurrentX*BlockSize, CurrentY*BlockSize, (CurrentX + 1)*BlockSize - 1, (CurrentY + 1)*BlockSize - 1);

	// 移动
	CurrentX += CurrentDirect.dx;
	CurrentY += CurrentDirect.dy;

	// 绘制蚂蚁
	setfillcolor(RED);
	solidcircle(CurrentX*BlockSize + BlockSize / 2, CurrentY*BlockSize + BlockSize / 2, BlockSize / 3);

	SetWorkingImage();
	return BlockMap;
}


// 退出兰顿蚂蚁
void LangtonAnt::Quit()
{
	delete[]Map;
	Map = nullptr;
}


// 左转
LangtonAnt::Direct & LangtonAnt::Direct::TurnLeft()
{
	if (dx < 0 && dy == 0)			// 左
		*this = DOWN;
	else if (dx == 0 && dy < 0)		// 上
		*this = LEFT;
	else if (dx > 0  && dy == 0)	// 右
		*this = UP;
	else if (dx == 0 && dy > 0)		// 下
		*this = RIGHT;
	return *this;
}


// 右转
LangtonAnt::Direct & LangtonAnt::Direct::TurnRight()
{
	if (dx < 0 && dy == 0)			// 左
		*this = UP;
	else if (dx == 0 && dy < 0)		// 上
		*this = RIGHT;
	else if (dx > 0  && dy == 0)	// 右
		*this = DOWN;
	else if (dx == 0 && dy > 0)		// 下
		*this = LEFT;
	return *this;
}

作者:that boy
QQ:512906409
邮箱:zhuguangfeng.thatboy@gmail.com

分享到

添加评论