这几天在琢磨反射和动态代理,难度有点高,这博客拖了好久才来完成它。虽然在学校学习了Java和一些其他语言,但是高级特性接触得都不多,主要还是面向过程编程,看了这么多书,慢慢的体悟了面向对象的好处,内心十分触动。以后写代码尽量做到功能单一,便于拓展,便于维护,面向对象。
贪吃蛇吃满屏幕的要点在于,要有一条安全的路径,不管发生什么情况,只要安全路径存在,贪食蛇就能坚持走下去,所以第一步我们要找一条一直存在的安全路径:我们很容易想到贪吃蛇是可以绕圈圈的,蛇头跟着蛇尾走,就一直绕圈,不会撞墙或者撞自己的身体,所以只要蛇头和蛇尾吧之间存在一条路径,那不管发生了什么情况蛇都可以调整自己的状态。
小蛇什么时候要走安全路径?一般来说当小蛇自动吃食物的时候,根据我们的算法,它会找到最短的路径去吃食物,然而因为蛇身体是不断增长的,有一些时候他的身体会把食物三面围起来,这时候再走最短路径去吃食物,很显然,蛇身体就会堵住所有的退路,然后就无路可走,我们应该避免这种情况,所以我们应该在蛇走的每一步之前预判断一下,他的下一步安全吗?
完整代码如下,还有一些坑,都是当初设计代码的时候留下的,但是基本功能实现了,给读者做参考,注释比较多,所以不再解释了。
一共有三个类
Food类内容如下:
import java.util.Random;
public class Food {
private int x;
private int y;
private int length ;
private int width ;
private int pace;
public Food(int length, int width,int pace) {
super();
random = new Random();
this.length = length;
this.width = width;
this.pace = pace;
}
private Random random;
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setY() {
this.y = random.nextInt(width/pace)*pace;
}
public void setX() {
this.x = random.nextInt( length/pace)*pace;
}
/*public void setY(int sss) {
this.y = yyy[sss-1];
}
public void setX(int sss) {
this.x = xxx[sss-1];
}*/
}
Snake类内容如下:
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;
class Road {
private int x;
private int y;
private Road father;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Road other = (Road) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public void setFather(Road father) {
this.father = father;
}
public Road() {
super();
// TODO Auto-generated constructor stub
}
public Road(int x, int y, Road father) {
super();
this.x = x;
this.y = y;
this.father = father;
}
public Road getFather() {
return father;
}
}
public class Snake {
private int x;
private int y;
private int length;
private int pace;
private int nextx;
private int nexty;
private int tailx;
private int taily;
//Distance from the target
private int dFromT;
private int len;
private int width;
private String direction;
private ArrayList<Node> snake = new ArrayList<Node>();
public int getDFromT() {
return dFromT;
}
public void setDFromT(int distance) {
this.dFromT = distance;
}
{
dFromT = 0;
nextx = -1;
nexty = -1;
}
public int getTailx() {
return tailx;
}
public void setTailx(int tailx) {
this.tailx = tailx;
}
public int getTaily() {
return taily;
}
public void setTaily(int taily) {
this.taily = taily;
}
public int getNextx() {
return nextx;
}
public void setNextx(int nextx) {
this.nextx = nextx;
}
public int getNexty() {
return nexty;
}
public void setNexty(int nexty) {
this.nexty = nexty;
}
public int getPace() {
return pace;
}
public void setPace(int pace) {
this.pace = pace;
}
public int getLength() {
return length;
}
private class Node {
private int x;
private int y;
public Node(int x, int y) {
super();
length++;
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
public boolean eat(Food fd) {
if (fd.getX() == this.x && fd.getY() == this.y) {
System.out.println("吃东西啦!好开心~");
snake.add(new Node(tailx, taily));
return true;
}
return false;
}
public int show(int i, int j) {
int num = 0;
for (Node node : snake) {
if (node.getX() == i && node.getY() == j) {
// System.out.println("冲突检测");
return num;
}
num++;
}
return -1;
}
public boolean run(Food fd){
if(fd.getX()>this.x){
this.nextx+=this.pace;
this.nexty = this.y;
}else if(fd.getX()<this.x){
this.nextx-=this.pace;
this.nexty = this.y;
}else if(fd.getY()>this.y){
this.nextx = this.x;
this.nexty+=this.pace;
}else if(fd.getY()<this.y){
this.nextx = this.x;
this.nexty-=this.pace;
}else{
return false;
}
return true;
}
public boolean hangOut(int ax,int ay) {
System.out.println("进入闲逛模式,参数是需要远离的点,如果没有办法选择安全路径就会切换到不安全的随机模式");
int[][] map;
map = new int[this.len][this.width];
int aimx = ax;
int aimy = ay;
//标记食物不可以吃,吃食物必须在外面
for (Node node : snake) {
if (node.getX() >= 0 && node.getY() >= 0) {
map[node.getX()][node.getY()] = 1;
}
}
int findx = this.x;
int findy = this.y;
boolean reflag = false;
int biggerManha = 0;
int ManhattanDistance = 0;
int defaultx = -1;
int defaulty = -1;
int space = -1;
int willGo = findx + this.pace;
int biggerStep = -1;
if (willGo < len && map[willGo][findy] != 1) {
// 如果这一步在棋盘范围内,而且不会撞上蛇身
// 计算它和食物的哈曼吨距离
ManhattanDistance = Math.abs(aimx - (willGo)) + Math.abs(aimy - findy);
System.out.println("右移 最大距离:" + biggerManha + " 本次距离:" + ManhattanDistance);
// 如果longdistance记录的哈曼吨距离小于这个点的
if (biggerManha <= ManhattanDistance || defaultx == -1) {
// 记录下这个点的曼哈顿距离还有坐标,这一点就是远离食物的点,我们还要检测它是不是能找到尾巴
if (findShortestRoad(willGo, findy, tailx, taily)) {
if (biggerStep < this.dFromT) {
biggerStep = this.dFromT;
biggerManha = ManhattanDistance;
if (dFromT > space) {
defaultx = willGo;
defaulty = findy;
this.nextx = willGo;
this.nexty