活动地址:优快云21天学习挑战赛
题目描述
贪吃蛇是一个经典游戏,蛇的身体由若干方格连接而成,身体随蛇头移动。蛇头触碰到食物时,蛇的长度会增加一格。蛇头和身体的任一方格或者游戏版图边界碰撞时,游戏结束。
下面让我们来完成贪吃蛇游戏的模拟。给定一个N*M的数组arr,代表N*M组成的版图,贪吃蛇每次移动一个方格。若arr[i][i]==‘H’,表示该方格为贪吃蛇的起始位置;若arr[i][j]为’F’,表示该方格为食物,若arr[i][j]为’E’,表示该方格为空格。
贪吃蛇初始长度为1,初始移动方向为向左。为给定一系列贪吃蛇的移动操作,返回操作后蛇的长度,如果在操作执行完之前已经游戏结束,返回游戏结束时蛇的长度。
注意:
- H表示蛇头,F表示食物,数字为身体各节的编号,从1开始;
- 蛇头和食物重叠,在蛇尾添加一节,表示蛇的生长;
- 蛇头越过边界或者与自身碰撞都会使游戏结束
输入、输出描述
输入描述
第一行为空格间隔的字母,代表贪吃蛇的移动操作。字母取值为[U|D|L|R|G],其中U、D、L、R分别表示贪吃蛇上、下、左、右转向,转向时贪吃蛇不移动,G表示贪吃蛇按照当前的方向移动一格。第二行是空格为分隔的两个数,指定N和M,为数组的行和列数。余下N行每行是空格分隔的M个字母。字母取值为H、F和E,H表示贪吃蛇的起始位置,F表示食物,E表示该方格为空,H只有一个,而F和E会有多个。
输出描述
输出一个数字,为蛇的长度。
示例
输入
D G G
3 3
F F F
F F H
E F E
输出
1
说明
贪吃蛇一开始就向下转向并且移动两步,此时蛇头已经越过边界,游戏结束,故长度为1。
思考
可以用二维数组表示整个移动的区域,然后在其中赋值就可以实现贪吃蛇了。其中需要注意当确定贪吃蛇移动时,需要从蛇尾开始移动,并将原始位置设置为空。
代码实现
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String[] action = scanner.nextLine().split(" ");
String[] size = scanner.nextLine().split(" ");
int n = Integer.parseInt(size[0]);
int m = Integer.parseInt(size[1]);
//记录蛇头
int x = 0,y = 0;
//区域字符记录
String[][] arr = new String[n][m];
for (int i=0;i<n;i++) {
String[] line = scanner.nextLine().split(" ");
for (int j=0;j<m;j++) {
arr[i][j] = line[j];
if (arr[i][j].equals("H")) {
x = i;
y = j;
}
}
}
//记录贪吃蛇方向
String direction = "L";
//记录贪吃蛇长度
int len = 1;
//循环遍历操作符
for (int i=0;i<action.length;i++) {
//某方向前进
if (action[i].equals("G")) {
//前进记录
if ("L".equals(direction)) {
y--;
} else if ("R".equals(direction)) {
y++;
} else if ("U".equals(direction)) {
x--;
} else if ("D".equals(direction)) {
x++;
}
//移动
int move = move(arr, x, y, len);
//移动失败,游戏结束
if (move == -1) {
break;
}else {
//长度变长
len = move;
}
}else{
//更改贪吃蛇方向
direction = action[i];
}
}
System.out.println(len);
}
//移动 x,y表示蛇头移动后的位置,len表示贪吃蛇长度
public static int move(String[][] arr,int x,int y,int len) {
//判断是否越界或者撞到自己
if (x<0 || x>=arr.length ||
y<0 || y>=arr[0].length ||
!arr[x][y].equals("[F|E]")) {
return -1;
}
//记录是否需要蛇尾置空
boolean flag = true;
//迟到食物,长度加一,不需要蛇尾置空
if (arr[x][y].equals("F")) {
len ++;
flag = false;
}
//记录原来蛇尾位置
int[] tail;
if (len==1) tail = findIndex(arr, "H");
else tail = findIndex(arr, String.valueOf(len - 1));
//蛇身向前移动
int[] index;
for (int i=len;i>0;i--) {
if (i > 1) {
index = findIndex(arr, String.valueOf(i - 1));
}else {
index = findIndex(arr, "H");
}
arr[index[0]][index[1]] = String.valueOf(i);
}
//设置蛇头位置
arr[x][y] = "H";
//置空蛇尾
if (flag) {
arr[tail[0]][tail[1]] = "E";
}
return len;
}
//寻找字符的位置
public static int[] findIndex(String[][] arr,String word) {
//记录字符位置
int[] index = new int[2];
//全域寻找字符
for (int i=0;i<arr.length;i++) {
for (int j=0;j<arr[0].length;j++) {
if (arr[i][j].equals(word)) {
index[0] = i;
index[j] = j;
return index;
}
}
}
index[0] = -1;
index[1] = -1;
return index;
}
}
总结
博主原文 中使用了队列记录了贪吃蛇身体的各个位置,可以很方便的得到蛇身体的各个位置记录,我这里使用了循环找蛇身体的位置,增加了处理的时间复杂度,两相比较来说,这里加一点存储空间来换寻找的时间是更合适的。
21天的学习结束了,通过算法题训练了我的数据结构知识运用能力,感谢平台的活动。