ITPub博客

首页 > 人工智能 > 人工智能 > 贪吃蛇游戏走法最优解探讨

贪吃蛇游戏走法最优解探讨

原创 人工智能 作者:zixinsu 时间:2026-01-13 12:06:55 0 删除 编辑


附件下载
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>经典贪吃蛇</title>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
            min-height: 100vh;
            margin: 0;
            padding: 20px;
        }
        .game-container {
            position: relative;
            margin-top: 20px;
        }
        #game-board {
            border: 3px solid #333;
            border-radius: 5px;
            box-shadow: 0 10px 20px rgba(0,0,0,0.2);
            background-color: #f0f0f0;
        }
        .score-panel {
            display: flex;
            justify-content: space-between;
            width: 400px;
            margin-bottom: 10px;
            font-size: 18px;
            font-weight: bold;
        }
        .controls {
            margin-top: 20px;
            text-align: center;
        }
        button {
            padding: 10px 20px;
            margin: 0 5px;
            background: #4CAF50;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 16px;
            transition: all 0.3s;
        }
        button:hover {
            background: #45a049;
            transform: translateY(-2px);
        }
        .game-over {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(0,0,0,0.8);
            color: white;
            padding: 20px 40px;
            border-radius: 10px;
            text-align: center;
            display: none;
        }
    </style>
</head>
<body>
    <h1>经典贪吃蛇游戏</h1>
    <div>
        <div>得分: <span id="score">0</span></div>
        <div>最高分: <span id="high-score">0</span></div>
<div>用时: <span id="etimes">0 m 0 s</span></div>
    </div>
    <div>
        <canvas id="game-board" width="400" height="400"></canvas>
        <div id="game-over">
            <h2>游戏结束!</h2>
            <p>你的得分: <span id="final-score">0</span></p>
            <button id="restart-btn">重新开始</button>
        </div>
    </div>
    <div>
        <p>使用方向键或WASD控制蛇的移动</p>
        <button id="start-btn">开始游戏</button>
        <button id="pause-btn">暂停游戏</button>
    </div>
    <script>
        const canvas = document.getElementById('game-board');
        const ctx = canvas.getContext('2d');
        const scoreDisplay = document.getElementById('score');
const etimesDisplay = document.getElementById('etimes');
        const highScoreDisplay = document.getElementById('high-score');
        const finalScoreDisplay = document.getElementById('final-score');
        const gameOverDisplay = document.getElementById('game-over');
        const startBtn = document.getElementById('start-btn');
        const pauseBtn = document.getElementById('pause-btn');
        const restartBtn = document.getElementById('restart-btn');
        const gridSize = 20;
        const tileCount = canvas.width / gridSize;
        let score = 0;
        let highScore = localStorage.getItem('snakeHighScore') || 0;
        highScoreDisplay.textContent = highScore;
        let snake = [];
        let food = {};
        let direction = 'right';
        let nextDirection = 'right';
        let gameSpeed = 5;
        let gameLoop;
        let isPaused = false;
        let isRunning = false;
let dateb = new Date();
let datee = new Date();
//静默执行: YES NO
let silence = 'NO'; 
        function initGame() {
            snake = [
                {x: 5, y: 10},
                {x: 4, y: 10},
                {x: 3, y: 10}
            ];
            direction = 'right';
            nextDirection = 'right';
            score = 0;
            scoreDisplay.textContent = score;
            generateFood();
            isPaused = false;
            isRunning = true;
            gameOverDisplay.style.display = 'none';
        }
        function generateFood() {
            food = {
                x: Math.floor(Math.random() * tileCount),
                y: Math.floor(Math.random() * tileCount)
            };
            // 确保食物不会生成在蛇身上
            for (let segment of snake) {
                if (segment.x === food.x && segment.y === food.y) {
                    return generateFood();
                }
            }
        }
        function drawGame() {
            // 清空画布
            ctx.fillStyle = '#f0f0f0';
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            // 绘制蛇
            for (let i = 0; i < snake.length; i++) {
                ctx.fillStyle = i === 0 ? '#4CAF50' : '#8BC34A';
                ctx.fillRect(snake[i].x * gridSize, snake[i].y * gridSize, gridSize-1, gridSize-1);
            }
            // 绘制食物
            ctx.fillStyle = '#FF5722';
            ctx.fillRect(food.x * gridSize, food.y * gridSize, gridSize-1, gridSize-1);
        }
        function updateGame() {
            if (isPaused) return;
/*
最优策略:
1、在每个时间点,计算头和食物和尾保持通路且路径无交叉的所有路径
2、选择1结果集中的最短路径
3、重新生成食物后 若头和食物和尾之间无通路可走 则继续走第一步的路径 直到满足条件后循环继续1和2步
算法:
1、动态规划 ???
2、手工设计路径
*/
//console.log('direction=',direction,'food.x=',food.x,'food.y=',food.y,'head.x=',snake[0].x,'head.y=',snake[0].y,'snake.length=',snake.length);
if ( direction === 'right' ) {
if ( snake[0].x === tileCount-1) {
nextDirection = 'down';
}
}
else if ( direction === 'left' ) {
if ( snake[0].x === 1 && snake[0].y === tileCount-1 ) {
nextDirection = 'left';
}
else if ( snake[0].x === 0 && snake[0].y === tileCount-1 ) {
nextDirection = 'up';
}
else if ( snake[0].x === 1 ) {
nextDirection = 'down';
}
}
else if ( direction === 'up' ) {
if ( snake[0].x === 0 && snake[0].y === 0 ) {
nextDirection = 'right';
}
}
else if ( direction === 'down' ) {
if ( snake[0].x === tileCount-1 && snake[0].y === tileCount-1 ) {
nextDirection = 'left';
}
else if ( snake[0].x === 1 ) {
//when tail like C  : nextDirection = 'right';
if ( snake[snake.length-1].x === 0 || snake[snake.length-1].y === 0 || snake[snake.length-1].y === tileCount-1 ) {
if ( food.x >= 1 && food.x <= tileCount-1 && food.y >= snake[0].y ) {
if ( food.y === snake[0].y ) {
nextDirection = 'right';
}
else {
if ( food.y % 2 === 1 ) {
if ( food.y === snake[0].y + 1) {
nextDirection = 'right';
}
}
}
}
else {
//nextDirection = 'right';
if ( snake[0].y === tileCount-2 ) {
nextDirection = 'right';
}
else {
if ( snake.length >= 200 ) {
if ( snake[0].y % 2 === 0 ) {
nextDirection = 'right';
}
}
}
}
}
else {
if ( snake.length >= 80 ) {
if ( snake[0].y % 2 === 0 ) {
nextDirection = 'right';
}
}
else {
if ( food.x >= 1 && food.x <= tileCount-1 && food.y >= snake[0].y ) {
if ( food.y === snake[0].y ) {
nextDirection = 'right';
}
else {
if ( food.y % 2 === 1 ) {
if ( food.y === snake[0].y + 1) {
nextDirection = 'right';
}
}
}
}
else {
//nextDirection = 'right';
if ( snake[0].y === tileCount-2 ) {
nextDirection = 'right';
}
}
}
}
}
else if ( snake[0].x === tileCount-1 ) {
////when tail like C : nextDirection = 'left';
if ( snake[snake.length-1].x === 0 || snake[snake.length-1].y === 0 || snake[snake.length-1].y === tileCount-1 ) {
if ( food.x >= 1 && food.x <= tileCount-1 && food.y >= snake[0].y ) {
if ( food.y === snake[0].y ) {
nextDirection = 'left';
}
else {
if ( food.y % 2 === 0 ) {
if ( food.y === snake[0].y + 1) {
nextDirection = 'left';
}
}
}
}
else {
//nextDirection = 'left';
if ( snake[0].y === tileCount-1 ) {
nextDirection = 'left';
}
else {
if ( snake.length >= 200 ) {
if ( snake[0].y % 2 === 1 ) {
nextDirection = 'left';
}
}
}
}
}
else {
if ( snake.length >= 80 ) {
if ( snake[0].y % 2 === 1 ) {
nextDirection = 'left';
}
}
else {
if ( food.x >= 1 && food.x <= tileCount-1 && food.y >= snake[0].y ) {
if ( food.y === snake[0].y ) {
nextDirection = 'left';
}
else {
if ( food.y % 2 === 0 ) {
if ( food.y === snake[0].y + 1) {
nextDirection = 'left';
}
}
}
}
else {
//nextDirection = 'left';
if ( snake[0].y === tileCount-1 ) {
nextDirection = 'left';
}
}
}
}
}
}
if ( direction !== nextDirection ) {
if ( silence === 'NO' ) {
console.log('direction=',direction,'food.x=',food.x,'food.y=',food.y,'head.x=',snake[0].x,'head.y=',snake[0].y,'snake.length=',snake.length);
}
}
            // 更新蛇的方向
            direction = nextDirection;
            // 计算蛇头新位置
            const head = {x: snake[0].x, y: snake[0].y};
            switch (direction) {
                case 'up':
                    head.y--;
                    break;
                case 'down':
                    head.y++;
                    break;
                case 'left':
                    head.x--;
                    break;
                case 'right':
                    head.x++;
                    break;
            }
            // 检查碰撞
            if (
                head.x < 0 || head.x >= tileCount ||
                head.y < 0 || head.y >= tileCount ||
                checkCollision(head)
            ) {
                gameOver();
                return;
            }
            // 移动蛇
            snake.unshift(head);
            // 检查是否吃到食物
            if (head.x === food.x && head.y === food.y) {
                score++;
                scoreDisplay.textContent = score;
// 检查通关
if ( score === 397 ) {
gameOver();
return;
}
                generateFood();
// 输出用时
datee = new Date();
datee.getTime();
let diff = datee - dateb;
//console.log('dateb=',dateb,'datee=',datee,'diff=',diff);
etimesDisplay.textContent = Math.floor((diff/1000) / 60) + ' m ' + Math.floor((diff/1000) % 60) + ' s';
                
                // 随着分数增加加快游戏速度
                if (score % 5 === 0 && gameSpeed > 50) {
                    gameSpeed -= 10;
                    clearInterval(gameLoop);
                    gameLoop = setInterval(gameStep, gameSpeed);
                }
            } else {
                snake.pop();
            }
        }
        function checkCollision(head) {
            for (let i = 0; i < snake.length; i++) {
                if (head.x === snake[i].x && head.y === snake[i].y) {
                    return true;
                }
            }
            return false;
        }
        function gameOver() {
            clearInterval(gameLoop);
            isRunning = false;
            
            if (score > highScore) {
                highScore = score;
                highScoreDisplay.textContent = highScore;
                localStorage.setItem('snakeHighScore', highScore);
            }
            
            finalScoreDisplay.textContent = score;
            gameOverDisplay.style.display = 'block';
        }
        function gameStep() {
            updateGame();
            //drawGame();
if ( silence === 'NO' ) {
drawGame();
}
        }
        function startGame() {
            if (isRunning) return;
dateb = new Date();
dateb.getTime();
            initGame();
            gameLoop = setInterval(gameStep, gameSpeed);
        }
        function togglePause() {
            if (!isRunning) return;
            isPaused = !isPaused;
            pauseBtn.textContent = isPaused ? '继续游戏' : '暂停游戏';
        }
        // 事件监听
        document.addEventListener('keydown', (e) => {
            if (!isRunning) return;
            
            switch (e.key) {
                case 'ArrowUp':
                case 'w':
                case 'W':
                    if (direction !== 'down') nextDirection = 'up';
                    break;
                case 'ArrowDown':
                case 's':
                case 'S':
                    if (direction !== 'up') nextDirection = 'down';
                    break;
                case 'ArrowLeft':
                case 'a':
                case 'A':
                    if (direction !== 'right') nextDirection = 'left';
                    break;
                case 'ArrowRight':
                case 'd':
                case 'D':
                    if (direction !== 'left') nextDirection = 'right';
                    break;
                case ' ':
                    togglePause();
                    break;
            }
        });
        startBtn.addEventListener('click', startGame);
        pauseBtn.addEventListener('click', togglePause);
        restartBtn.addEventListener('click', startGame);
        // 初始绘制
        drawGame();
    </script>
</body>
</html>

snake.html.txt

后缀改成html后执行 最优策略暂时没研究明白,附件用的 if else 法,通关时间3分多

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/28692050/viewspace-3107770/ ,如需转载,请注明出处,否则将追究法律责任。

下一篇: 没有了~
请登录后发表评论 登录
全部评论
最近实现了: 1、SAP报表集成到EXCEL中 2、外部程序对接 RFC、BAPI处理SAP业务 3、BW HANA 模型和数据分析

注册时间:2013-03-19

  • 博文量
    3
  • 访问量
    17474