贪吃蛇AI-能百分百吃满屏幕

       如何保证百分百吃满全屏呢?,假设蛇在一个圆上跑,所有的食物都在圆上刷新,蛇是不会死的,所以,将点阵连成一个圆,当然是个被 叠的失去梦想的圆,且看下图8*8点阵

贪吃蛇极大环路
贪吃蛇极大环路

 

沿着黄线路径顺时针和蓝色逆时针,是不是一定不会死,食物都在环路上刷新,但是这样的环产生的蛇就像智障一样,食物在它身边它也不吃,非要把环跑完,那该如何是好?顺便说一句,奇*奇的点阵是无法形成一个包含所有点的环路的。比如3*3。总会有一个点不在环路上。

 

 

 

 

 

 

环路组合与拆分

极小环路

其中R代表right,D代表down,L为left,U为up,每一个点均指明了蛇头在这一个点的下一个该如何移动。这是极小环路

 

 

纵向组合拆分:

纵向组合拆分

左边为两个不相干的环路,右边组合成了一个大环。自己假装站在上面跑一跑看看。

 

 

 

 

 

横向组合拆分

横向组合拆分

自己跑一跑感受一下,红到绿,为组合,绿到红为拆分。

 

 

 

 

在之前概率性贪吃它的基础上,删去了next_point,添加了以下两个数据结构

bool path_board[16][16];//点是否在环路上
short path[16][16];//每个点上的移动方向,存储L,R,D,U

初始化时,蛇长为2,左上角的极小环路为true,然后根据食物所在目的地,组合环路,每走一步,都重新拆分再组合回路。

组合和拆分的实现

	void set_path_board(COORD x, bool t) {
		path_board[x.X][x.Y] = t;
		path_board[x.X+1][x.Y] = t;
		path_board[x.X][x.Y+1] = t;
		path_board[x.X+1][x.Y+1] = t;
	}//一次性将一个环添加或删除时,修改path_board
	bool matrix_no_point(COORD x) {
		return board[x.X][x.Y] == false &&
			board[x.X + 1][x.Y] == false &&
			board[x.X][x.Y + 1] == false &&
			board[x.X + 1][x.Y + 1] == false;
	}//某一极小环路是否存在蛇的身体,不存在的环路要拆除
	bool path_board_not_all_true(COORD x) {
		return !(path_board[x.X][x.Y] &&path_board[x.X+1][x.Y+1]);
	}//两个极小环路相接的环路是否一个在路径里,一个在路径外,这是可添加路径的判断依据
	void add_path_matrix(COORD x) {
		if (x.X % 2) {
			if (path_board_not_all_true(x)) {
				path[x.X][x.Y] = R;
				path[x.X + 1][x.Y + 1] = L;
				set_path_board({ x.X - 1,x.Y }, true);
				set_path_board({ x.X + 1,x.Y }, true);
			}
		}
		else {
			if (path_board_not_all_true(x)) {
				path[x.X + 1][x.Y] = D;
				path[x.X][x.Y + 1] = U;
				set_path_board({ x.X,x.Y + 1 }, true);
				set_path_board({ x.X,x.Y - 1 }, true);
			}
		}
	}//添加路径
	void check_if_del(COORD x) {
		if (board[x.X][x.Y] == false && board[x.X + 1][x.Y] == false &&
		board[x.X + 1][x.Y + 1] == false && board[x.X][x.Y + 1] == false)
		{
			set_path_board(x, false);
		}
	}//判断是否为可剪除的环路
	void del_path_matrix(COORD x) {
		if (x.X % 2) {
			path[x.X][x.Y] = D;
			path[x.X + 1][x.Y + 1] = U;
			check_if_del({ x.X - 1,x.Y });
			check_if_del({ x.X + 1,x.Y });
		}
		else {
			path[x.X + 1][x.Y] = L;
			path[x.X][x.Y + 1] = R;
			check_if_del({ x.X,x.Y-1 });
			check_if_del({ x.X,x.Y+1 });
		}
	}

环路组合-拆分原则,只有由路径上的极小环与路径外的极小环之间可以组合拆分,已经在路径上的两个极小环之间不可再次组合。

路径生成

	void form_path() {
		COORD head = body.front();
		head.X = head.X & 0xfffe;
		head.Y = head.Y & 0xfffe;
		COORD end = food;
		end.X = end.X & 0xfffe;
		end.Y = end.Y & 0xfffe;
		short dx;
		short dy;
		if (head.X > end.X)dx = -2;
		else dx = 2;
		if (head.Y > end.Y)dy = -2;
		else dy = 2;
		while (head.X != end.X) {
			short x = head.X;
			head.X += dx;
			add_path_matrix({ (x + head.X) / 2, head.Y });
		}
		//printf("\n");
	//	_print();
		while (head.Y != end.Y) {
			short y = head.Y;
			head.Y += dy;
			add_path_matrix({end.X,(head.Y+y)/2});
		}
	}

路径删除

	void del_path() {
		for (short i = 0; i <=14; i += 2) {
			for (short j = 1; j < 14; j += 2) {
				if (matrix_no_point({ i,j - 1 }) || matrix_no_point({ i,j + 1 })) {
					del_path_matrix({ i, j });
				}
				if (matrix_no_point({ j-1,i}) || matrix_no_point({ j+1,i })) {
					del_path_matrix({ j, i });
				}
			}
		}
	}

 

完整源代码


#include <stdio.h>
#include <iostream>
#include <time.h>
#include <windows.h>
#include <stack>
#include <deque>
#define L 0
#define R 1
#define U 2
#define D 3
using namespace std;

void print(COORD p, char c)//在p所在的位置输出CHAR c所指的字符
{
	HANDLE Houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(Houtput, p);
	printf("%c", c);
}
bool operator==(COORD &A, COORD&B)
{
	if (A.X == B.X&&A.Y == B.Y)return true;
	return false;
}
bool operator!=(COORD &A, COORD&B) { return !(A == B); }

class snake {
private:
	COORD food;//食物位置
	deque<COORD>body;
	bool board[16][16];
	bool path_board[16][16];
	short path[16][16] = {
	{R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,D},
	{U,L,L,L,L,L,L,L,L,L,L,L,L,L,L,D},
	{R,R,R,R,R,R,R,R,R,R,R,R,R,D,U,D},
	{U,D,L,L,L,L,L,L,L,L,L,L,L,D,U,D},
	{U,D,R,R,R,R,R,R,R,R,R,D,U,D,U,D},
	{U,D,U,D,L,L,L,L,L,L,L,D,U,D,U,D},
	{U,D,U,D,R,R,R,R,R,D,U,D,U,D,U,D},
	{U,D,U,D,U,D,L,L,L,D,U,D,U,D,U,D},
	{U,D,U,D,U,D,R,R,U,D,U,D,U,D,U,D},
	{U,D,U,D,U,D,U,L,L,L,U,D,U,D,U,D},
	{U,D,U,D,U,R,R,R,R,R,U,D,U,D,U,D},
	{U,D,U,D,U,L,L,L,L,L,L,L,U,D,U,D},
	{U,D,U,R,R,R,R,R,R,R,R,R,U,D,U,D},
	{U,D,U,L,L,L,L,L,L,L,L,L,L,L,U,D},
	{U,R,R,R,R,R,R,R,R,R,R,R,R,R,U,D},
	{U,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L},
	};
public:
	snake() {
		init_board(board);
		body.push_back({ 1,0 });
		body.push_back({ 0,0 });
		print(body[0], '*');
		print(body[1], '*');
		board[0][0] = true;
		board[1][0] = true;
		init_board(path_board);
		init_path();
		set_path_board({ 0,0 }, true);
		create_food();
		
	}
	void init_board(bool tmp[16][16]) {
		for (int i = 0; i < 16; i++) {
			for (int j = 0; j < 16; j++)tmp[i][j] = false;//点阵全初始为false
		}
	}
	bool is_not_all_true(bool tmp[16][16]) {
		for (int i = 0; i < 16; i++) {
			for (int j = 0; j < 16; j++) { if (tmp[i][j] == false)return true; }
		}return false;
	}/*
	void _print() {
		for (int y = 0; y < 16; y++) {
			for (int x = 0; x < 16; x++)
				switch (path[x][y]) {
				case L:printf("L "); break;
				case R:printf("R "); break;
				case D:printf("D "); break;
				case U:printf("U "); break;
				default:break;
				}printf("\n");
		}
	}*/
	bool is_valid_point(COORD tmp) { return !((tmp.X & 0xfff0) || (tmp.Y & 0xfff0)); }

	void create_food() {
		food.X = rand() % 16;
		food.Y = rand() % 16;
		while (board[food.X][food.Y]) {food.X = rand() % 16;food.Y = rand() % 16;}
		print(food, '*');
		del_path();
		form_path();
	}
	void set_board_true(COORD &X) { board[X.X][X.Y] = true; }
	void set_board_false(COORD &X) { board[X.X][X.Y] = false; }
	void move_to(COORD t) { 
		if (t != food) { 
			print(body.back(), ' '); 
			set_board_false(body.back());
			body.pop_back(); 
			body.push_front(t); set_board_true(t);
			print(t, '*'); 
		}
		else { 
			body.push_front(t); set_board_true(t);
			create_food(); 
		}del_path(); form_path();
	} 
	void move() {
		COORD tmp_point = body.front();
		switch (path[body.front().X][body.front().Y]) {
		case L:tmp_point.X--; move_to(tmp_point); break;
		case R:tmp_point.X++; move_to(tmp_point); break;
		case D:tmp_point.Y++; move_to(tmp_point); break;
		case U:tmp_point.Y--; move_to(tmp_point); break;
		default:break;
		}
		Sleep(30);
	}
	void init_path() {
		for (int i = 0; i < 16; i += 2) {
			for (int j = 0; j < 16; j += 2) {
				path[i][j] = R;
				path[i + 1][j + 1] = L;
				path[i][j + 1] = U;
				path[i + 1][j] = D;
			}
		}
	}
	void set_path_board(COORD x, bool t) {
		path_board[x.X][x.Y] = t;
		path_board[x.X+1][x.Y] = t;
		path_board[x.X][x.Y+1] = t;
		path_board[x.X+1][x.Y+1] = t;
	}
	bool matrix_no_point(COORD x) {
		return board[x.X][x.Y] == false &&
			board[x.X + 1][x.Y] == false &&
			board[x.X][x.Y + 1] == false &&
			board[x.X + 1][x.Y + 1] == false;
	}
	bool path_board_not_all_true(COORD x) {
		return !(path_board[x.X][x.Y] &&path_board[x.X+1][x.Y+1]);
	}
	void add_path_matrix(COORD x) {
		if (x.X % 2) {
			if (path_board_not_all_true(x)) {
				path[x.X][x.Y] = R;
				path[x.X + 1][x.Y + 1] = L;
				set_path_board({ x.X - 1,x.Y }, true);
				set_path_board({ x.X + 1,x.Y }, true);
			}
		}
		else {
			if (path_board_not_all_true(x)) {
				path[x.X + 1][x.Y] = D;
				path[x.X][x.Y + 1] = U;
				set_path_board({ x.X,x.Y + 1 }, true);
				set_path_board({ x.X,x.Y - 1 }, true);
			}
		}
	}
	void check_if_del(COORD x) {
		if (board[x.X][x.Y] == false && board[x.X + 1][x.Y] == false &&
		board[x.X + 1][x.Y + 1] == false && board[x.X][x.Y + 1] == false)
		{
			set_path_board(x, false);
		}
	}
	void del_path_matrix(COORD x) {
		if (x.X % 2) {
			path[x.X][x.Y] = D;
			path[x.X + 1][x.Y + 1] = U;
			check_if_del({ x.X - 1,x.Y });
			check_if_del({ x.X + 1,x.Y });
		}
		else {
			path[x.X + 1][x.Y] = L;
			path[x.X][x.Y + 1] = R;
			check_if_del({ x.X,x.Y-1 });
			check_if_del({ x.X,x.Y+1 });
		}
	}

	void del_path() {
		for (short i = 0; i <=14; i += 2) {
			for (short j = 1; j < 14; j += 2) {
				if (matrix_no_point({ i,j - 1 }) || matrix_no_point({ i,j + 1 })) {
					del_path_matrix({ i, j });
				}
				if (matrix_no_point({ j-1,i}) || matrix_no_point({ j+1,i })) {
					del_path_matrix({ j, i });
				}
			}
		}
	}
	void form_path() {
		COORD head = body.front();
		head.X = head.X & 0xfffe;
		head.Y = head.Y & 0xfffe;
		COORD end = food;
		end.X = end.X & 0xfffe;
		end.Y = end.Y & 0xfffe;
		short dx;
		short dy;
		if (head.X > end.X)dx = -2;
		else dx = 2;
		if (head.Y > end.Y)dy = -2;
		else dy = 2;
		while (head.X != end.X) {
			short x = head.X;
			head.X += dx;
			add_path_matrix({ (x + head.X) / 2, head.Y });
		}
		//printf("\n");
	//	_print();
		while (head.Y != end.Y) {
			short y = head.Y;
			head.Y += dy;
			add_path_matrix({end.X,(head.Y+y)/2});
		}
	}
};		
int main()
{
	srand(time(NULL));
	snake a;
	while (true) {
		a.move(); 
	}
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值