Java 贪吃蛇

题目描述

给定一个 N*M 的二维数组 arr,模拟贪吃蛇游戏。初始时:

arr[i][j] == 'H' 表示蛇头起始位置;
arr[i][j] == 'F' 表示食物;
arr[i][j] == 'E' 表示空格。

蛇每次移动一格,若吃到食物(移动到 F),长度加一;若撞到边界或自身,游戏结束。求最终蛇的长度或判定游戏结束条件。

核心解题思路

数据结构选择‌

使用 ‌队列‌ 或 ‌链表‌ 存储蛇身坐标,队列头部为蛇头,尾部为蛇尾,便于动态增长和移动。
二维数组记录地图状态,实时更新蛇头和食物的位置。

移动逻辑‌

根据移动方向(上、下、左、右)更新蛇头坐标。
每次移动后检查碰撞:
边界碰撞‌:蛇头超出地图范围;
自身碰撞‌:蛇头与队列中其他坐标重复。

食物处理‌

若新蛇头位置为 F,不删除队尾(长度加一),并生成新食物;
否则,删除队尾(保持长度不变)。
 

import java.util.*;

public class SnakeGame {
    private int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 上、下、左、右
    private Deque<int[]> snake = new LinkedList<>();
    private Set<String> body = new HashSet<>(); // 快速判断碰撞
    private char[][] grid;
    private int foodCount = 0;
    private int n, m;

    public int simulateSnake(char[][] arr, String moves) {
        n = arr.length;
        m = arr[0].length;
        grid = arr;
        // 初始化蛇头位置
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (arr[i][j] == 'H') {
                    snake.add(new int[]{i, j});
                    body.add(i + "," + j);
                    break;
                }
            }
        }
        // 处理移动指令
        for (char move : moves.toCharArray()) {
            int[] head = snake.peekFirst();
            int dir = getDir(move);
            int nx = head[0] + dirs[dir][0];
            int ny = head[1] + dirs[dir][1];
            // 边界碰撞检查
            if (nx < 0 || nx >= n || ny < 0 || ny >= m) {
                return -1; // 游戏结束
            }
            // 自身碰撞检查(注意排除尾部)
            String newPos = nx + "," + ny;
            if (body.contains(newPos) && !(nx == snake.peekLast()[0] && ny == snake.peekLast()[1])) {
                return -1;
            }
            // 处理食物或移动
            if (grid[nx][ny] == 'F') {
                foodCount++;
                grid[nx][ny] = 'E'; // 食物被吃掉
            } else {
                int[] tail = snake.pollLast();
                body.remove(tail[0] + "," + tail[1]);
            }
            // 更新蛇头和身体
            snake.addFirst(new int[]{nx, ny});
            body.add(newPos);
        }
        return foodCount + 1; // 初始长度为1
    }

    private int getDir(char c) {
        switch (c) {
            case 'U': return 0;
            case 'D': return 1;
            case 'L': return 2;
            case 'R': return 3;
            default: return -1;
        }
    }
}

代码关键点解析

数据结构‌

Deque 实现队列存储蛇身,支持快速头部插入和尾部删除;
HashSet 存储蛇身坐标字符串,用于 O(1) 时间复杂度的碰撞检测。

移动逻辑‌

遍历移动指令字符串,依次更新蛇头位置;
每次移动后更新队列和 HashSet,动态维护蛇身。

边界与碰撞处理‌

直接通过坐标范围判断边界碰撞;
自身碰撞需排除尾部(尾部即将被删除,不会与新头碰撞)。
注意
时间复杂度‌:使用 HashSet 优化碰撞检测,避免遍历整个队列;
初始长度‌:起始时蛇长度为1(仅包含 H)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值