贪吃蛇 – 100行版本

简介

高一时受学校图形计算器上原装贪吃蛇程序启发而写的C++小游戏

高三时整理压缩至100行

代码

//By Eric Jin 2018     编译后切换至英文  a左d右w上s下       使用了Sleep() _kbhit() _getch() system("cls")等
#include <iostream> 
#include <sstream>
#include <string>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <windows.h>
std::string o(int i)//4左6右8上2下
{
	if (i == 0) return "  ";
	else if (i == 1) return "# ";
	else if (i == 3) return "$ ";
	else return "* ";
}
void drawmap(int h, int l, int maptest[100][100])//绘图
{
	std::stringstream ss;
	for (int i = 1; i <= h; i++)
	{
		for (int j = 1; j <= l; j++) ss << o(maptest[i][j]);
		ss << std::endl;
	}
	std::string out = ss.str();
	system("cls");
	std::cout << out;
}
void findfood(int maptest[100][100], int& foodx, int& foody, int h, int l)//出食物
{
	for (;;)
	{
		srand((int)time(0));
		foodx = rand() % h + 1, foody = rand() % l + 1;
		if (maptest[foodx][foody] == 0) break;
	}
}
int gamein()
{
	int speed, h = 20, l = 30, tail = 6, maptest[100][100], x = h / 2, y = l / 2, tx = h / 2, ty = l / 2 - tail, foodx, foody, dir = 6, tdir = 6, food = 0;
	bool skip = 0;
	std::cout << "Speed (100-slow 50-medium 10-fast):" << std::endl;
	std::cin >> speed;
	Sleep(500);
	system("cls");
	for (int i = 1; i <= h; i++)//设置边界
	{
		for (int j = 1; j <= l; j++)
		{
			maptest[i][j] = 0;
			if (i == 1 || i == h) maptest[i][j] = 1;
		}
		maptest[i][1] = 1, maptest[i][l] = 1;
	}
	for (int i = ty + 1; i <= y; i++) maptest[x][i] = 6;
	findfood(maptest, foodx, foody, h, l);
	maptest[foodx][foody] = 3;
	drawmap(h, l, maptest);
	for (;;)
	{
		maptest[x][y] = dir;
		x = (dir == 2) ? (x + 1) : (dir == 8 ? x - 1 : x), y = (dir == 6) ? (y + 1) : (dir == 4 ? y - 1 : y);
		if (maptest[x][y] == 0 || maptest[x][y] == 3) maptest[x][y] = dir;
		else
		{
			std::cout << std::endl << "You died." << std::endl << "Score: " << food << std::endl << "Speed: " << speed << std::endl;
			std::cout << "0:exit" << std::endl;
			std::cout << "1:new game" << std::endl;
			char in1 = _getch();
			std::cout << std::endl;
			if (in1 == '0') return 0;
			else return gamein();
		}
		if (skip == 0)
			tx = (tdir == 2) ? (tx + 1) : (tdir == 8 ? tx - 1 : tx), ty = (tdir == 6) ? (ty + 1) : (tdir == 4 ? ty - 1 : ty), tdir = maptest[tx][ty];
		else skip = 0;
		maptest[tx][ty] = 0;
		drawmap(h, l, maptest);
		std::cout << "Score: " << food << std::endl << "Speed: " << speed << std::endl;
		Sleep(speed);
		if (_kbhit() != 0)
		{
			int in = _getch();
			if (in == 97 && dir != 4 && dir != 6) dir = 4;
			if (in == 115 && dir != 2 && dir != 8) dir = 2;
			if (in == 119 && dir != 2 && dir != 8) dir = 8;
			if (in == 100 && dir != 4 && dir != 6) dir = 6;
		}
		if (x == foodx && y == foody)
		{
			food++;
			findfood(maptest, foodx, foody, h, l);
			maptest[foodx][foody] = 3;
			skip = 1;
		}
	}
}
int main()
{
	return gamein();
}

图片

五子棋 – 人机对战

简介

高一时第一次接触了C++,心血来潮编了几个诸如推箱子、贪吃蛇、俄罗斯方块的小游戏。

觉得不过瘾,碰巧那会儿班里流行五子棋,便着手于编一个人机对战程序。

碍于编程知识不足,算法只用了判断、循环。借助easyx的图形库,它有了图形界面。

最终版本经调查测试,实力优于初学者,并能与中等水平者相抗衡。

(反正我被他阴了好多次,不知是该笑还是该哭(▼皿▼#) )

基本思路

敌方每下一子,就在一个计数的矩阵里自己那格的四周(横竖撇捺四个方向,正负各延伸四格)加上个数值。这个加上的数值随与敌方所下子的距离而变。

不妨命名一个点的累积值为,下子使周围改变的效果为

己方下的子同理,但所给的是反向的(即所增加的值为负值)。

用四个矩阵分别记录来自四个方向的和相应积累的,互不干扰。

最终己方落子的判断依据来源于所有方向的绝对值的总和,取绝对值的总和最大的点落子。

算法原理很简单,说白了就是赋值再取极值的贪心算法,但至于怎么赋值还是有点讲究的。

初始版本里采用了1-1-1-1赋值法(就是那个加上的值不随与上一落子的距离而变),并且没有加入四方向绝对值相加的机制,导致算法的最终行为很玄学

它居然自动解锁了八卦阵技能,在连活三都不会防的情况下。(⊙_⊙)

升级版本采用了4-3-2-1赋值法,并延续到了最终版本。至此,它学会了如何防双三、三四等局面。

最终版本里又加入了遇四就堵的功能,但已经丧失了初始版本“两仪生四象,四象生八卦”的睿智。

废话讲完了,下面是代码

代码

#pragma comment(lib, "kernel32")
#pragma comment(lib, "user32")
#pragma comment(lib, "gdi32")
#pragma comment(lib, "winspool")
#pragma comment(lib, "comdlg32")
#pragma comment(lib, "advapi32")
#pragma comment(lib, "shell32")
#pragma comment(lib, "ole32")
#pragma comment(lib, "oleaut32")
#pragma comment(lib, "uuid")
#pragma comment(lib, "odbc32")
#pragma comment(lib, "odbccp32")
#include <graphics.h>
#include <conio.h>
#include <math.h>
#include <stdlib.h>

int plotform(int x)
{
	return 25 * (x - 1) + 15;
}

int storgeform(int x)
{
	return (x - 15) / 25 + 1;
}

class whom
{
public:
	int value;//1 or -1
	COLORREF color;//BLACK or WHITE
};

void changeplayer(whom& whom)
{
	whom.value = whom.value*(-1);
	if (whom.value == 1)
		whom.color = BLACK;
	else
		whom.color = WHITE;
}

void drawmap(int map[][20])
{
	int xwidth = 480, ywidth = 480;
	initgraph(xwidth, ywidth);
	setbkcolor(YELLOW);
	cleardevice();
	setlinecolor(LIGHTGRAY);
	for (int i = 15; i <= ywidth - 15; i = i + 25)
		line(15, i, xwidth - 15, i);
	for (int j = 15; j <= xwidth - 15; j = j + 25)
		line(j, 15, j, xwidth - 15);
	setfillcolor(LIGHTGRAY);
	for (int i = 4; i <= 16; i = i + 6)//both i & j are storgeform
	{
		for (int j = 4; j <= 16; j = j + 6)
		{
			solidcircle(plotform(i), plotform(j), 5);
		}
	}
}

void human(int& x, int& y, int&xq, int& yq, whom& whom, int map[][20])//both x & y are storgeform 
{
	MOUSEMSG a;
	do
	{
		do
		{
			a = GetMouseMsg();
		} while (a.mkLButton == 1);
		do
		{
			a = GetMouseMsg();
		} while (a.mkLButton == 0);
		xq = x;
		yq = y;
		x = round(((double)a.x - 15) / 25) + 1;
		y = round(((double)a.y - 15) / 25) + 1;
		/*if (getpixel(plotform(x),plotform(y)) == LIGHTGRAY)
			break;*/
		if (map[x][y] == 0)
			break;
	} while (1);
}

void record(int x, int y, whom whom, int map[][20], int maprecord[][20][20])//for robot
{
	for (int i = 1; i <= 4; i++)
	{
		int dx, dy;
		switch (i)
		{
		case 1:dx = 1, dy = 0; break;
		case 2:dx = 0, dy = 1; break;
		case 3:dx = 1, dy = -1; break;
		case 4:dx = 1, dy = 1; break;
		}
		for (int j = -4; j <= 4; j++)
		{
			if (1 <= x + dx * j&&x + dx * j <= 19 && 1 <= y + dy * j&&y + dy * j <= 19 && map[x + dx * j][y + dy * j] == 0)
			{
				maprecord[i][x + dx * j][y + dy * j] = maprecord[i][x + dx * j][y + dy * j] + whom.value*abs(5 - abs(j));
			}
		}
	}
}

void chong4(int x, int y,whom whom, int map[][20],int coordinate[3])//map[x][y]==whom.value
{
	for (int i = 1; i <= 4; i++)
	{
		int dx, dy;
		switch (i)
		{
		case 1:dx = 1, dy = 0; break;
		case 2:dx = 0, dy = 1; break;
		case 3:dx = 1, dy = -1; break;
		case 4:dx = 1, dy = 1; break;
		}
		int m = 0, n = 0, skip = 0;
		coordinate[0] = 0;
		coordinate[1] = -1;
		coordinate[2] = -1;
		for (int j = 1;; j++)
		{
			if (x + j * dx < 1 || x + j * dx>19 || y + j * dy < 1 || y + j * dy>19)
				break;
			if (map[x + j * dx][y + j * dy] == whom.value)
			{
				m = m + 1;
				if (skip > 0)
					skip++;
			}
			else if (skip == 0 && map[x + j * dx][y + j * dy] == 0)
			{
				skip = 1;
				coordinate[1] = x + j * dx;
				coordinate[2] = y + j * dy;
			}
			else if (skip > 1)
			{
				coordinate[0] = 1;
				break;
			}
			else
				break;
		}
		if (coordinate[0] == 1)
			skip = 1;
		else
			skip = 0;
		for (int j = -1;; j--)
		{
			if (x + j * dx < 1 || x + j * dx>19 || y + j * dy < 1 || y + j * dy>19)
				break;
			if (map[x + j * dx][y + j * dy] == whom.value)
			{
				n = n + 1;
				if (skip > 0)
					skip++;
			}
			else if (skip == 0 && map[x + j * dx][y + j * dy] == 0)
			{
				skip = 1;
				coordinate[1] = x + j * dx;
				coordinate[2] = y + j * dy;
			}
			else if (skip > 1)
			{
				coordinate[0] = 1;
				break;
			}
			else
				break;
		}
		if (m + n >= 3&&coordinate[1]!=-1)
		{
			coordinate[0] = 2;
			settextcolor(whom.value == 1 ? RED : BLUE);//used for debug
			outtextxy(plotform(coordinate[1]), plotform(coordinate[2]), 'x');
			return;
		}
	}
}

void robot(int& x, int& y, int& xq, int& yq, whom& whom, int map[][20], int maprecord[][20][20])//both x & y are storgeform 
{
	int max = -1;
	changeplayer(whom);
	record(x, y, whom, map, maprecord);
	changeplayer(whom);

	int coordinate[3];
	chong4(xq, yq, whom, map, coordinate);
	if (coordinate[0] == 2)
	{
		xq = x;
		yq = y;
		x = coordinate[1];
		y = coordinate[2];
		record(x, y, whom, map, maprecord);
		return;
	}
	changeplayer(whom);
	chong4(x, y, whom, map, coordinate);
	if (coordinate[0] == 2)
	{
		xq = x;
		yq = y;
		x = coordinate[1];
		y = coordinate[2];
		changeplayer(whom);
		record(x, y, whom, map, maprecord);
		return;
	}
	changeplayer(whom);

	for (int i = 1; i <= 19; i++)
	{
		for (int j = 1; j <= 19; j++)
		{
			if (map[i][j] == 0)
			{
				int potential[5];
				for (int p = 1; p <= 4; p++)
				{
					potential[p] = maprecord[p][i][j];
					if (abs(potential[p]) >= 5)
						potential[p] = potential[p] * 2;
					if (abs(potential[p]) >= 18)
						potential[p] = potential[p] * 2;
				}
				int all = abs(potential[1]) + abs(potential[2]) + abs(potential[3]) + abs(potential[4]);
				if (all > max)
				{
					max = all;
					xq = x;
					yq = y;
					x = i;
					y = j;
				}
				if (all == max && rand()%100 <= 60)
				{
					max = all;
					xq = x;
					yq = y;
					x = i;
					y = j;
				}
			}
		}
	}
	record(x, y, whom, map, maprecord);
}

void drawpiece(int x, int y, whom& whom, int map[][20])//both x & y are storgeform 
{
	setfillcolor(whom.color);
	solidcircle(plotform(x), plotform(y), 10);
	map[x][y] = whom.value;
	changeplayer(whom);
}

int main()
{
	int map[20][20] = { 0 };
	int maprecord[5][20][20] = { 0 };
	whom whom;
	whom.color = BLACK;
	whom.value = 1;
	int x, y, xq, yq;
	drawmap(map);
	do
	{
		if (whom.value == 1)
			human(x, y,xq,yq, whom, map);
		else
			robot(x, y, xq, yq, whom, map, maprecord);
		drawpiece(x, y, whom, map);
	} while (1);
	_getch();
	closegraph();
}

图片