JSFiddle - React, Tailwind, and code Playground
HTML
<canvas id='canvas' width='400' height='400'></canvas>
CSS
canvas {border:1px solid;}
JavaScript
var context = canvas.getContext('2d');
context.fillStyle="Khaki";
context.fillRect(0, 0, canvas.width, canvas.height);
var snake=[-1, 0, 18, 10, 19, 10];
var food=[17, 10];
var side=[-1, 0];
context.fillStyle="DarkOliveGreen";
context.fillRect(340, 200, 60, 20);
// периодически запускаем функцию
var snake_crawl=setInterval(crawl, 50);
// мозг змеи
function ai() {
var dx=food[0]-snake[2];
var dy=food[1]-snake[3];
// считаем оптимальный маршрут
if (dx!=0) {
if (dx>0) side=[1, 0];
else side=[-1, 0];
} else {
if (dy>0) side=[0, 1];
if (dy<0) side=[0, -1];
}
// поворачиваем наугад на препятствиях
if (coll()) {
side=[0, 1];
if (coll()) {
side=[-1, 0];
if (coll()) {
side=[0, -1];
if (coll()) side=[1, 0];
}
}
}
}
// поиск препятствий
function coll() {
var x=snake[2]+side[0];
var y=snake[3]+side[1];
if (x<0 || x>19 || y<0 || y>19) return true;
for (var i=4; i<snake.length; i+=2) {
if (snake[i]==x && snake[i+1]==y) return true;
}
return false;
}
// функция считает кадр
function crawl() {
ai();
snake[0]=side[0];
snake[1]=side[1];
snake.splice(2, 0, snake[0]+snake[2], snake[1]+snake[3]);
// если ест стену, то конец игры
if (snake[2]<0 || snake[2]>19 || snake[3]<0 || snake[3]>19) {
clearInterval(snake_crawl);
}
// проверяем на самоедство
for (var i=4; i<snake.length; i+=2) {
if(snake[i]==snake[2] && snake[i+1]==snake[3]) {
clearInterval(snake_crawl);
}
}
// удаляем кончик хвостика
context.fillStyle="Khaki";
context.fillRect(20*snake[snake.length-2], 20*snake[snake.length-1], 20, 20);
// рисуем голову
context.fillStyle="DarkOliveGreen";
context.fillRect(20*snake[2], 20*snake[3], 20, 20);
// проверяем на еду
if(food[0]==snake[2] && food[1]==snake[3]) {
out: while (true) { // делаем новую еду
var x=Math.round(19*Math.random());
var y=Math.round(19*Math.random());
for (var i=2; i<snake.length; i+=2) {
...