打造AI贪吃蛇

Posted 肥学

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了打造AI贪吃蛇相关的知识,希望对你有一定的参考价值。

目录标题

演示

自动贪吃蛇

技术栈

bottom 属性规定元素的底部边缘。该属性定义了定位元素下外边距边界与其包含块下边界之间的偏移。

注释:如果 “position” 属性的值为 “static”,那么设置 “bottom” 属性不会产生任何效果。

对于 static 元素,为 auto;对于长度值,则为相应的绝对长度;对于百分比数值,为指定值;否则为 auto。

对于相对定义元素,如果 bottom 和 top 都是 auto,其计算值则都是 0;如果其中之一为auto,则取另一个值的相反数;如果二者都不是 auto,bottom 将取 top 值的相反数。

默认值:	auto
继承性:	no
版本:	CSS2
javascript 语法:	object.style.bottom="50px"

user-select 属性规定是否能选取元素的文本。

在 web 浏览器中,如果您在文本上双击,文本会被选取或高亮显示。此属性用于阻止这种行为。

user-select: auto|none|text|all;
auto	默认。如果浏览器允许,则可以选择文本。
none	防止文本选取。
text	文本可被用户选取。
all	单击选取文本,而不是双击。

源码

样式设置

canvas 
	position: absolute;
	width: 100vh;
	height: 100vh;
	margin: auto;
	top: 0;
	bottom: 0;
	left: 0;
	right: 0;
	user-select: none;
	background: #000;
	cursor: pointer;

构建食物对象

var food = 
		x: 0,
		y: 0,
		// add random food
		add: function add() 
			var emptyNodes = [];
			for (var x = 0; x < map.width; ++x) 
				for (var y = 0; y < map.height; ++y) 
					if (!map.collision(x, y)) emptyNodes.push(
						x: x,
						y: y
					);
				
			
			if (emptyNodes.length) 
				var p = emptyNodes[Math.floor(Math.random() * emptyNodes.length)];
				this.x = p.x;
				this.y = p.y;
			
		
	;

构建贪吃蛇对象

var snake = 
		body: [],
		head: 
			x: 0,
			y: 0
		,
		removeTail: function removeTail() 
			var p = this.body.shift();
			map.setSnake(p.x, p.y, 0);
		,
		addHead: function addHead(x, y) 
			this.head.x = x;
			this.head.y = y;
			this.body.push(
				x: x,
				y: y
			);
			map.setSnake(x, y, 1);
		,
		move: function move(dir) 
			var next = map.getNext(this.head.x, this.head.y, dir);
			this.addHead(next.x, next.y);
			if (next.x === food.x && next.y === food.y) 
				food.add();
			 else this.removeTail();
		,

		// snake IA
		nextDirection: function nextDirection() 
			var x = this.head.x;
			var y = this.head.y;
			var pathNumber = map.tour(x, y);
			var distanceToFood = map.distance(pathNumber, map.tour(food.x, food.y));
			var distanceToTail = map.distance(pathNumber, map.tour(snake.body[0].x, snake.body[0].y));
			var cuttingAmountAvailable = distanceToTail - 4;
			var numEmptySquaresOnBoard = map.size - snake.body.length - 1;
			if (distanceToFood < distanceToTail) cuttingAmountAvailable -= 1;
			var cuttingAmountDesired = distanceToFood;
			if (cuttingAmountDesired < cuttingAmountAvailable) cuttingAmountAvailable = cuttingAmountDesired;
			if (cuttingAmountAvailable < 0) cuttingAmountAvailable = 0;
			var canGoRight = !map.collision(x + 1, y);
			var canGoLeft = !map.collision(x - 1, y);
			var canGoDown = !map.collision(x, y + 1);
			var canGoUp = !map.collision(x, y - 1);
			var bestDir = -1;
			var bestDist = -1;
			var dist = 0;
			if (canGoRight) 
				dist = map.distance(pathNumber, map.tour(x + 1, y));
				if (dist <= cuttingAmountAvailable && dist > bestDist) 
					bestDir = map.Right;
					bestDist = dist;
				
			
			if (canGoLeft) 
				dist = map.distance(pathNumber, map.tour(x - 1, y));
				if (dist <= cuttingAmountAvailable && dist > bestDist) 
					bestDir = map.Left;
					bestDist = dist;
				
			
			if (canGoDown) 
				dist = map.distance(pathNumber, map.tour(x, y + 1));
				if (dist <= cuttingAmountAvailable && dist > bestDist) 
					bestDir = map.Down;
					bestDist = dist;
				
			
			if (canGoUp) 
				dist = map.distance(pathNumber, map.tour(x, y - 1));
				if (dist <= cuttingAmountAvailable && dist > bestDist) 
					bestDir = map.Up;
					bestDist = dist;
				
			
			if (bestDist >= 0) return bestDir;
			if (canGoUp) return map.Up;
			if (canGoLeft) return map.Left;
			if (canGoDown) return map.Down;
			if (canGoRight) return map.Right;
			return map.Right;
		
	;

构建自动贪吃

var map = 
		// init map
		init: function init(width, height) 
			var _this = this;

			this.width = width;
			this.height = height;
			this.size = width * height;
			this.scale = Math.min(canvasWidth, canvasHeight) / Math.max(this.width, this.height);
			// Hamiltonian Cycle

			// flags
			var _array2D = this.array2D(width, height, true);

			var _array2D2 = _slicedToArray(_array2D, 2);

			this.tour = _array2D2[0];
			this.setTour = _array2D2[1];

			var _array2D3 = this.array2D(width / 2, height / 2);

			var _array2D4 = _slicedToArray(_array2D3, 2);

			this.isVisited = _array2D4[0];
			this.setVisited = _array2D4[1];

			var _array2D5 = this.array2D(width / 2, height / 2);

			var _array2D6 = _slicedToArray(_array2D5, 2);

			this.canGoRight = _array2D6[0];
			this.setGoRight = _array2D6[1];

			var _array2D7 = this.array2D(width / 2, height / 2);

			var _array2D8 = _slicedToArray(_array2D7, 2);

			this.canGoDown = _array2D8[0];
			this.setGoDown = _array2D8[1];

			var _array2D9 = this.array2D(width, height);

			var _array2D10 = _slicedToArray(_array2D9, 2);

			this.isSnake = _array2D10[0];
			this.setSnake = _array2D10[1];

			this.canGoLeft = function (x, y) 
				if (x === 0) return false;
				return _this.canGoRight(x - 1, y);
			;
			this.canGoUp = function (x, y) 
				if (y === 0) return false;
				return _this.canGoDown(x, y - 1);
			;
		,

		// directions
		Left: 1,
		Up: 2,
		Right: 3,
		Down: 4,
		// flat 2D array
		array2D: function array2D(width, height, protect) 
			var data = new Uint16Array(width * height);
			return [function (x, y) 
				return data[x + width * y];
			, protect ? function (x, y, value) 
				var i = x + width * y;
				if (!data[i]) data[i] = value;
			 : function (x, y, value) 
				data[x + width * y] = value;
			];
		,

		// test snake collision
		collision: function collision(x, y) 
			if (x < 0 || x >= this.width) return true;
			if (y < 0 || y >= this.height) return true;
			return this.isSnake(x, y) !== 0;
		,

		// path distance
		distance: function distance(a, b) 
			if (a < b) return b - a - 1;else return b - a - 1 + this.size;
		,

		// Hamiltonian Cycle
		generate_r: function generate_r(fromx, fromy, x, y) 
			if (x < 0 || y < 0 || x >= this.width / 2 || y >= this.height / 2) return;
			if (this.isVisited(x, y)) return;
			this.setVisited(x, y, 1);
			if (fromx !== -1) 
				if (fromx < x) this.setGoRight(fromx, fromy, 1);else if (fromx > x) this.setGoRight(x, y, 1);else if (fromy < y) this.setGoDown(fromx, fromy, 1);else if (fromy > y) this.setGoDown(x, y, 1);
			
			for (var i = 0; i < 2; i++) 
				var r = Math.floor(Math.random() * 4);
				switch (r) 
					case 0:
						this.generate_r(x, y, x - 1, y);
						break;
					case 1:
						this.generate_r(x, y, x + 1, y);
						break;
					case 2:
						this.generate_r(x, y, x, y - 1);
						break;
					case 3:
						this.generate_r(x, y, x, y + 1);
						break;
				
			
			this.generate_r(x, y, x - 1, y);
			this.generate_r(x, y, x + 1, y);
			this.generate_r(x, y, x, y + 1);
			this.generate_r(x, y, x, y - 1);
		,

		// find next direction in cycle
		findNextDir: function findNextDir(x, y, dir) 
			if (dir === this.Right) 
				if (this.canGoUp(x, y)) return this.Up;
				if (this.canGoRight(x, y)) return this.Right;
				if (this.canGoDown(x, y)) return this.Down;
				return this.Left;
			 else if (dir === this.Down) 
				if (this.canGoRight(x, y)) return this.Right;
				if (this.canGoDown(x, y)) return this.Down;
				if (this.canGoLeft(x, y)) return this.Left;
				return this.Up;
			 else if (dir === this.Left) 
				if (this.canGoDown(x, y)) return this.Down;
				if (this.canGoLeft(x, y)) return this.Left;
				if (this.canGoUp(x, y)) return this.Up;
				return this.Right;
			 else if (dir === 让AI学会玩贪吃蛇

10分钟教你用python打造贪吃蛇超详细教程

python游戏开发:打造最经典的贪吃蛇游戏

贪吃蛇AI

Python制作AI贪吃蛇

如何用Python写一个贪吃蛇AI