龟兔赛跑要求:
--普通格,共100格 _ _
龟:每次随机移动1至3格
兔子:每次随机移动1至6格
每20格会随机出现以下功能格各一次(不会在同一格内出现两种或两种以上功能)
功能格:(**和^^可以连续执行,@@和==不能连续执行)
1.**幸运星格:选手可再行动一次
2.@@地雷格:兔子回到上数两个地雷格,龟回到上一地雷格(若后方无地雷格则回到起点)
3.==传送格:兔子到达下一传送格,龟到达下数两个传送格(若前方无传送格则到达终点)
4.||树格:兔子停止三次行动
5.^^下坡格:龟前进10格
注意:
在此程序中会有以下情况发生数组越界问题
1.随机数会越界
2.传送门、地雷会越界
3.幸运星会越界
4.下坡会越界
思考:
首先思考一共需要创建几个类,在思考每个类中有什么
需要的类有:游戏地图类,动物类(里面包括兔子和乌龟共有的方法),兔子类,乌龟类,游戏测试类一共五个类
动物类动物都共有的方法,因此类的方法都需要在子类中重写,所以可以定义为抽象类:
1.兔子和乌龟都能跑
2.兔子和乌龟在地图上都有位置
3.幸运格、地雷格、传送格都是共有的方法,区别则在于具体跳转几个,如果跳转个数大于1则可以多次调用
Map
游戏地图
//Map
import java.util.Arrays;
public class Map {
public String[] getMap(){
//普通格,共100格
String[] map = new String[100];
//每20个格子内含有五个功能格,所以一共有25个功能格
//保存方式为二维数组,每一个一维数组保存一种功能格
int[][] gn = new int[5][5];
//用于获取25个功能格的辅助数组 创建了100个0
int[] index = new int[100];
//向100个格内添加__ 普通格子数组初始化
Arrays.fill(map,"__ ");
//获取功能格,将100等分为5份,每份长度为20
for(int i = 0; i < 5; i++){
//辅助数组初始化,让索引跟数组中的值一致 数组中赋值为0-99
for(int j = 0+i*20; j < 20+i*20; j++){
index[j] = j;
}
//获取随机数
for(int k = 0; k < 5; k++){
int a = (int)(Math.random()*(20-k))+i*20;
int temp = index[a];
index[a] = index[19-k+i*20];
index[19-k+i*20] = temp;
gn[k][i] = temp;
}
}
//给地图设置五种功能格
for(int i = 0; i < 5; i++){
map[gn[0][i]] = "** ";
map[gn[1][i]] = "@@ ";
map[gn[2][i]] = "== ";
map[gn[3][i]] = "|| ";
map[gn[4][i]] = "^^ ";
}
return map;
}
//显示地图
public void showMap(String[] map,Rabbit R,Tortoise T){
//先复制一个新的地图,为了使兔子和乌龟能显示在新地图上,仅用于输出使用,
//每一次完事之后地图会销毁也就是原本的地图不会被改动,保持完好
String[] maps = Arrays.copyOf(map,map.length);
if(R.position == T.position){
maps[R.position] = "遇 ";
}else {
maps[R.position] = "兔 ";
maps[T.position] = "龟 ";
}
for(int i = 0; i < maps.length; i++){
if(i%20 == 0){
System.out.println();
}
System.out.print(maps[i]);
}
System.out.println();
}
}
获取随机数讲解
//获取随机数
for(int k = 0; k < 5; k++){
int a = (int)(Math.random()*(20-k))+i*20;
int temp = index[a];
index[a] = index[19-k+i*20];
index[19-k+i*20] = temp;
gn[k][i] = temp; //图示
}
随机数随机的是一段连续的数组,不论放大多少倍。
假设有10个数,抽每个数的概率是1/10,剩余数被抽中的概率是1/9,因为不放回的抽取,有一个数已经被抽出去了,以此类推。数据不连续也无所谓,因为是纯随机,数据被抽取的概率不变。每次拿出的数据都是1/数据的个数。
将第一次拿到的数据和最后一个数置换,以保证每次拿到的数据不重复。
控制放大倍数,控制结束,只要放大倍数小于数据个数-1,最后一个数就永远取不到
但需要注意的是:
1.随机数取出的数不能是数组的索引值,也就是随机出来的数不能是最终获得的随机数的索引,可以做一个初始化保证随出来的数据和索引值是一样的
2.随机数的索引值和最后要的数没有关系,例如:第一次要第三个数据的数和第二次要第三个数据的数没有关系,可以随便取,因为只是索引值一样但是里边存的数据不一样
3.最终要的数据一定是里面的值而不是索引
假设第一次拿的是索引为2真实数据为3的数,与最后一个数据置换,再将最后一个数据砍掉,则之后再取就永远都取不到3这个真实的数了
第二次在随机每一个数的概率就为1/9,因为最后一个数已经被砍掉了,即使第二次还取到索引为2的数,可以里面的值也已经改变了,然后再将这次拿到的值与剩余数据的最后一个数进行置换,则这次的数在下次也不会取到,而剩余数据被拿去的概率就变为了1/8,以此类推
随机数随机的值是索引,但真正的值是里面存的数据
Animal
动物都共有的方法,因此类的方法都需要在子类中重写,所以可以定义为抽象类
//Animal
//此类中的方法需要全部在子类中重写,所以可以定义为抽象类
public abstract class Animal {
//初始位置为0 当前位置
int position = 0;
//跑的抽象方法,在子类中重写此方法,没有方法体 每次跑的步数
public abstract int run();
//功能格的验证 验证当前是不是功能格 传参过来才能验证
public abstract void function(String[] map,Tortoise T);
//跑需要在地图上跑 计算跑 地图上的移动
public void move(String[] map,Tortoise T){
//位置累加计算
// position = position + run();
//判断走完之后的位置是不是功能格,如果是则执行功能格代码
// function(map,T);
//改
if(position < 99){
position = position + run();
}else {
position = 99;
}
function(map,T);
}
//**幸运星格:选手可再行动一次 再摇一次筛子
public void star(String[] map,Tortoise T){
System.out.println("选手可再行动一次");
move(map,T);
}
//@@地雷格:兔子回到上数两个地雷格
//龟回到上一地雷格(若后方无地雷格则回到起点) 地雷:mine
public void mine(String[] map) {
position--;
while (true) {
if(position <= 0){
position = 0;
break;
}else if (map[position].equals("@@ ")) {
break;
}else {
position--;
}
}
}
//==传送格:兔子到达下一传送格
//龟到达下数两个传送格(若前方无传送格则到达终点)
public void door(String[] map){
position++;
while (true) {
if(position >= 99){
position = 99;
break;
}else if (map[position].equals("== ")) {
break;
}else {
position++;
}
}
}
}
Rabbit
兔子独有的方法
//Rabbit
public class Rabbit extends Animal {
@Override
public int run() {
//放大六倍是0-5 +1是1-6 左闭右开 [0,6) [1,7)
int pace =(int)(Math.random()*6)+1;
System.out.println("兔子走了"+pace+"步");
return pace;
}
@Override
public void function(String[] map,Tortoise T) {
if(position < 99){
if(map[position].equals("** ")){
System.out.println("兔子遇到幸运星了");
star(map,T); //调方法
}else if(map[position].equals("== ")){
System.out.println("兔子遇到传送门了");
door(map);
}else if(map[position].equals("@@ ")){
System.out.println("兔子遇到地雷了");
mine(map);
mine(map);//遇见返回两个 调两次 兔子回到上数两个地雷格
}else if(map[position].equals("|| ")){
System.out.println("兔子遇到了树格,停三次"); //兔子停三次,乌龟走三次
T.move(map, T); //T对象中有一个跑 调的移动
T.move(map, T);
T.move(map, T);
}
}else {
position = 99;
}
}
}
Tortoise
乌龟独有的方法
//Tortoise
public class Tortoise extends Animal{
@Override
public int run() {
int pace =(int)(Math.random()*3)+1;
// System.out.println("乌龟走了"+pace+"步");
while (position < 99) {
if(position >= 99){
position = 99;
break;
}
// int pace = (int)(Math.random() * 3) + 1;
position++;
}
System.out.println("乌龟走了"+pace+"步");
return pace;
}
@Override
public void function(String[] map, Tortoise T) {
if(position < 99){
if(map[position].equals("** ")){
System.out.println("乌龟遇到幸运星了");
star(map,T); //调方法
}else if(map[position].equals("== ")){
System.out.println("乌龟遇到传送门了");
door(map);
door(map);
}else if(map[position].equals("@@ ")){
System.out.println("乌龟遇到地雷了");
mine(map);
}else if(map[position].equals("^^ ")){
System.out.println("乌龟遇到了下坡,前进十格"); //兔子停三次,乌龟走三次
position = position + 10;
function(map, T); //验证是否为功能格
}
}else if(position >= 99){
position = 99;
}
}
}
Game
游戏测试类
//Game
public class Game {
public static void main(String[] args) {
//获取生成的游戏底图
// String[] map = new Map().getMap();
Map map = new Map();
String[] m = map.getMap();
//创建两个对象 游戏角色兔子和乌龟
Rabbit R = new Rabbit();
Tortoise T = new Tortoise();
String maps[]=m;//将map的信息用maps记录下来,后面的地图就在maps的基础上改变
//输出地图
// for(int i = 0; i<m.length; i++){
// if(i%20==0){
// System.out.println();
// }
// System.out.print(m[i]);
// }
// System.out.println();
map.showMap(maps,R,T);
while (R.position < 99 && T.position < 99){ //位置表示索引位置
R.move(maps,T);
T.move(maps,T);
//判断越界问题 如果越界了让其等于99就到终点了
// if(R.position > 99 && T.position > 99){
// R.position = 99;
// T.position = 99;
// }else if(R.position > 99){
// R.position = 99;
// }else if(T.position > 99){
// T.position = 99;
// }
//或者
if(R.position > 99){
R.position = 99;
}
if(T.position > 99){
T.position = 99;
}
map.showMap(maps,R,T);
}
if(R.position >= 99 && T.position >= 99){
System.out.println("平局");
}else if(R.position >= 99){
System.out.println("兔子赢了");
}else {
System.out.println("乌龟赢了");
}
}
}