概述:之前面试的时候被问过怎么实现贪吃蛇,当时只是粗略的给出了用链表实现的大致思路,最近想起来这个问题,就花几个小时思考和实现了主要的框架。
实现思路:
使用二维数组表示贪吃蛇活动界面;使用List表示贪吃蛇的身体,身体(或食物)节点记录二维数组中的下标。
代码实现如下:
节点类:
import java.util.Objects;
public class SnakeNode {
private int row;
private int col;
public SnakeNode(int row, int col) {
this.row = row;
this.col = col;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getCol() {
return col;
}
public void setCol(int col) {
this.col = col;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SnakeNode node = (SnakeNode) o;
return row == node.row &&
col == node.col;
}
@Override
public int hashCode() {
return Objects.hash(row, col);
}
}
整体流程类:
import java.util.*;
public class Snake {
private static final Set<Integer> directions = new HashSet(Arrays.asList(2, 4, 6, 8));
private static volatile int[][] area;
private static volatile int direction = 2;
private static volatile int high = 100;
private static volatile int width = 50;
private static volatile boolean isAlive = true;
private static volatile boolean isNoFood = true;
private static final Random random = new Random();
private static volatile List<SnakeNode> body = new ArrayList<>();
private static Scanner scanner = new Scanner(System.in);
/**
* init area
*
* @param high area high
* @param width area width
*/
private void initArea(int high, int width) {
if (high > 3 && width > 1) {
this.high = high;
this.width = width;
area = new int[high][width];
for (int i = 0; i < 3; i++) {
area[i][0] = 1;
SnakeNode node = new SnakeNode(i, 0);
body.add(node);
}
}
}
/**
* change direction
*/
private void changeDirection() {
while (isAlive) {
int newDirection = scanner.nextInt();
if (directions.contains(newDirection)) {
boolean cannotChange = (direction == 2 && newDirection == 8)
|| (direction == 8 && newDirection == 2)
|| (direction == 4 && newDirection == 6)
|| (direction == 6 && newDirection == 4);
if (!cannotChange) {
direction = newDirection;
}
}
}
}
/**
* snake move
*/
private void move() {
SnakeNode headNode = body.get(body.size() - 1);
int headCol = headNode.getCol();
int headRow = headNode.getRow();
// 计算前进后头部的坐标
switch (direction) {
case 2:
++headRow;
break;
case 4:
--headCol;
break;
case 6:
++headCol;
break;
case 8:
--headRow;
break;
}
// 头部撞墙
if (headCol < 0 || headCol >= width || headRow < 0 || headRow >= high) {
isAlive = false;
return;
}
// 构造前进后的头部节点对象
SnakeNode forwardNode = new SnakeNode(headRow, headCol);
// 吃掉自己身体的情况
if (body.contains(forwardNode)) {
isAlive = false;
return;
}
body.add(new SnakeNode(headRow, headCol));
// 如果头部前进后的节点没有食物,尾部也需要移动
if (area[headRow][headCol] == 0) {
SnakeNode tailNode = body.get(0);
area[tailNode.getRow()][tailNode.getCol()] = 0;
body.remove(0);
} else {
isNoFood = true;
}
area[headRow][headCol] = 1;
}
/**
* redraw area
*/
private void redrawArea() {
System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
System.out.println("\t\t\t\t\t\t\t\t\t\t\t\t\t\t_________________________");
for (int row = 0; row < area.length; row++) {
int[] rowArea = area[row];
System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t|");
for (int col = 0; col < rowArea.length; col++) {
if (area[row][col] == 0) {
System.out.print(" ");
} else {
System.out.print("●");
}
}
System.out.println("|");
}
System.out.println("\t\t\t\t\t\t\t\t\t\t\t\t\t\t_________________________");
System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n");
}
/**
* 随机生成食物
*/
private void genFood() {
// 没有食物时才需要
if (isNoFood) {
int sum = 0;
for (int[] rowData : area) {
for (int num : rowData) {
sum += num;
}
}
// 占满了屏幕
if (sum == width * high) {
isAlive = false;
return;
}
int row = random.nextInt(high);
int col = random.nextInt(width);
while (area[row][col] == 1) {
row = random.nextInt(high);
col = random.nextInt(width);
}
area[row][col] = 1;
isNoFood = false;
}
}
public static void main(String[] args) throws InterruptedException {
Snake snake = new Snake();
snake.initArea(10, 20);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
snake.changeDirection();
}
});
thread.start();
while (isAlive) {
snake.genFood();
snake.move();
snake.redrawArea();
Thread.sleep(1000);
}
System.out.println("game over!!!\nyour score:" + (body.size() - 3));
}
}