hooyantsing's Blog

第19次课程

字数统计: 2.1k阅读时长: 11 min
2019/05/25

源辰74班

第19次课程

05.25.2019

**内容    **

OOP

1.[项目]扫雷

Class Point

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Point {
    private int x;
    private int y;
    private int state;
    //状态表示方法:0b 1111 11 1
    //前四位表示雷的数量: 8:1000 7:0111 6:0110...
    //中间两位表示当前位置打开状态: 00没开  01打开 10插旗
    //最后一位表示有无雷: 0没雷 1有雷
    public Point(int x, int y, int state) {
       super();
       this.x = x;
       this.y = y;
       this.state = state;
    }
    public Point() {
       super();
    }
    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 int getState() {
       return state;
    }
    public void setState(int state) {
       this.state = state;
    }
}

Class MineMap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import java.util.Random;
import java.util.Scanner;
public class MineMap {
    private int width;
    private int height;
    private int mineCount;
    //初始化棋盘
    public Point[][] getMineMap(){
       Point[][] map = new  Point[height][width];
       //将Point内的State置为0
       for(int i=0;i<map.length;i++) {
           for(int j=0;j<map[i].length;j++)  {
               map[i][j] = new Point(i,j,0);
           }
       }
       return burnMine(map);
    }
    
    public Point[][] burnMine(Point[][]  points){
       Random r = new Random();
       for(int i=0;i<mineCount;) {//i++要判断可以加雷,才++
           int x = r.nextInt(height);
           int y = r.nextInt(width);
           //判断当前位置  points[x][y].getState() 是否有雷
           //位运算。
            /*
              1000001
             &0000001
             =0000001
            */
           if((points[x][y].getState()&0b1)!=0b1) {
               //无雷
               i++;
               /*
                1000000
               |0000001
               =1000001
               */
               //当前位置
               points[x][y].setState(points[x][y].getState()|0b1);
               //上三个邻居
               if(x-1>=0) {
                  points[x-1][y].setState(points[x-1][y].getState()+0b1000);
                  //左上角
                  if(y-1>=0) {
                      points[x-1][y-1].setState(points[x-1][y-1].getState()+0b1000);
                  }
                  //右上角
                  if(y+1<width) {
                      points[x-1][y+1].setState(points[x-1][y+1].getState()+0b1000);
                  }
               }
               //下三个邻居
               if(x+1<height) {
                  points[x+1][y].setState(points[x+1][y].getState()+0b1000);
                  //左下角
                  if(y-1>=0) {
                      points[x+1][y-1].setState(points[x+1][y-1].getState()+0b1000);
                  }
                  //右下角
                  if(y+1<width) {
                      points[x+1][y+1].setState(points[x+1][y+1].getState()+0b1000);
                  }
               }
               //左邻居
               if(y-1>=0) {
                  points[x][y-1].setState(points[x][y-1].getState()+0b1000);
               }
               //右邻居
               if(y+1<width) {
                  points[x][y+1].setState(points[x][y+1].getState()+0b1000);
               }
               
           }else {
               //有雷
           }
       }
       return points;
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    //开局 默认
    public MineMap() {
       this(10,10,30);
    }
    //自定义难度
    public MineMap(int width, int height,  int mineCount) {
       super();
       this.width = width;
       this.height = height;
       this.mineCount = mineCount;
    }
    /*//选择难度 1简单/2中等/3困难
    public MineMap(int difficulty) {
       switch(difficulty) {
       case 1:
           this.width = 5;
           this.height = 5;
           this.mineCount = 10;
           break;
       case 2:
           this.width = 10;
           this.height = 10;
           this.mineCount = 30;
           break;
       case 3:
           this.width = 15;
           this.height = 15;
           this.mineCount = 50;
           break;
       case 0:
           System.out.println("请输入高,宽,雷数(空格隔开):");
           Scanner sc = new  Scanner(System.in);
           this.height = sc.nextInt();
           this.width = sc.nextInt();
           this.mineCount = sc.nextInt();
           break;
       default:
           System.out.println("请重新选择");
       }
    }*/
    public int getWidth() {
       return width;
    }
    public void setWidth(int width) {
       this.width = width;
    }
    public int getHeight() {
       return height;
    }
    public void setHeight(int height) {
       this.height = height;
    }
    public int getMineCount() {
       return mineCount;
    }
    public void setMineCount(int mineCount)  {
       this.mineCount = mineCount;
    }
}

Class ClearMineGame

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
import java.util.Scanner;
public class ClearMineGame {
    private MineMap map;      //地雷地图
    private int pointCount;       //点数
    private int useTime;      //游戏的时间
    private Point[][] minePoint;//地雷的布局
    private Scanner sc = new  Scanner(System.in);
    
    
    public void start() {
       System.out.println("\t\tClearMineGame");
       int choice = 0;
       do{
           System.out.println("请选择游戏难度:");
           System.out.println("1.普通 2.中等  3.困难 0.自定义");
           choice = sc.nextInt();
           switch(choice) {
           case 1:
               map = new MineMap(5,5,1);
               pointCount = 5*5;
               break;
           case 2:
               map = new MineMap(10,10,30);
               pointCount = 10*10;
               break;
           case 3:
               map = new MineMap(15,15,99);
               pointCount = 15*15;
               break;
           case 0:;
           default:
               System.out.println("没有此选项,请重新选择!");
           }
       }while(choice>3 || choice<1);
       minePoint = map.getMineMap();
       //作弊显示:将0bxxxx 00 x -> 0bxxxx  01 x,改为打开状态
       System.out.println("作弊显示:");
       peek(minePoint);
       System.out.println("=========================================");
       //重新隐藏起来:将0bxxxx 01 x ->  0bxxxx 00 x,改为关闭状态
       for(int i=0;i<minePoint.length;i++)  {
           for(int  j=0;j<minePoint[i].length;j++) {
               minePoint[i][j].setState(minePoint[i][j].getState() & 0b1111001);
           }
       }
       playGame();
    }
    private void playGame() {
       boolean isOver = false;
       int i = 1;
       long start =  System.currentTimeMillis(); //开始时间
       do {
           System.out.println("第"+(i++)+"次操作后的雷场:");
           showMineField(minePoint);
           System.out.println("=========================================");
           System.out.println("请输入x坐标:");
           int x = sc.nextInt();
           sc.nextLine();
           System.out.println("请输入y坐标:");
           int y = sc.nextInt();
           sc.nextLine();
           Point p = minePoint[x-1][y-1];
           
           int choice = 0;
           do {
               System.out.println("请选择操作:(1.打开 2.插旗 3.拔旗)");
               choice = sc.nextInt();
               sc.nextLine();
               switch(choice) {
               case 1:
                  isOver = openPoint(p);
                  break;
               case 2:
                  insertFlag(p);
                  break;
               case 3:
                  delFlag(p);
                  break;
               default:
                  System.out.println("还有这种操作??");   
               }
           }while(choice>3 || choice<1);
       }while(!isOver);
       /*if(isOver==false) {
           System.out.println("游戏结束");
       }else {
           //递归方法     缺点:调用playGame()次数多了可能导致游戏崩溃
            *用do{}while()代替;
           playGame();
       }*/
       long end =  System.currentTimeMillis();
       if(isOver) {
           System.out.println("游戏结束");
           System.out.println("共花费:"+(end-start)/1000/60+"分钟");
       }
       
    }
    
    
    private boolean openPoint(Point p) {
       int state = p.getState();
       //1.是否是雷,是雷则游戏结束
       if((state&0b1)==0b1) {
           System.out.println("点"+p.getX()+","+p.getY()+"是雷,游戏结束");
           peek(minePoint);
           return true;
       }
       //1.当前p不是雷 1)是数字 2)是0,则递归显示周围所有不为雷的位置,到数字停止
       
       openAll(p); //当p不是雷,打开周围的点,并且pointCount--
       if(pointCount==map.getMineCount()) {
           System.out.println("恭喜你,游戏通关");
           return true;
       }
       
       //修复插旗后还可以直接打开的bug
       if((p.getState()&0b110)==0b100) {
           System.out.println("点"+p.getX()+","+p.getY()+"已插旗,请先取消旗子");
           sc.nextLine();
       }
       return false;
    }
    private void openAll(Point p) {
       int state = p.getState();
       //递归终止条件,即不能打开的点
       //(state.0b1)==0b1:雷
       //(state.0b110)==0b100:插旗
       //(state.0b110)==0b10:已打开
       if((state&0b1)==0b1 ||  (state&0b110)==0b100 ||(state&0b110)==0b10)  {
           return;
       }
       int x = p.getX();
       int y = p.getY();
       minePoint[x][y].setState(p.getState()+0b10);
       pointCount--;
       //判断是否为0个雷
       if((state>>3)==0) {
           //当前位为0,则递归来打开
           //判断附近的坐标
           //上邻居
           if(x-1>=0) {
               openAll(minePoint[x-1][y]);
               //判断左上角
               if(y-1>=0) {
                  openAll(minePoint[x-1][y-1]);
               }
               if(y+1<minePoint[0].length) {
                  openAll(minePoint[x-1][y+1]);
               }
           }
           //判断下邻居
           if(x+1<minePoint.length) {
               openAll(minePoint[x+1][y]);
               //判断左上角
               if(y-1>=0) {
                  openAll(minePoint[x+1][y-1]);
               }
               if(y+1<minePoint[0].length) {
                  openAll(minePoint[x+1][y+1]);
               }
           }
           //判断左邻居
           if(y-1>=0) {
               openAll(minePoint[x][y-1]);
           }
           if(y+1<minePoint[0].length) {
               openAll(minePoint[x][y+1]);
           }
       }
       
    }
    private void delFlag(Point p) {
       //1.取出p的state
       int state = p.getState();
       //2.判断是否已经有旗子,没有则不能拔旗
       if((state&0b110)==0b100) {
           //3.有,对应位与00取与操作
           minePoint[p.getX()][p.getY()].setState(p.getState()&0b1111001);
           return;
       }
       System.out.println("点"+p.getX()+","+p.getY()+"没有插旗,不能拔旗");
       sc.nextLine();
    }
    private void insertFlag(Point p) {
       //1.取出p的state
       int state = p.getState();
       //2.判断是否打开,打开了则不能插旗
       if((state&0b110)==0b10) {
           System.out.println("点"+p.getX()+","+p.getY()+"已经打开,不能插旗");
           sc.nextLine();
           return;
       }
       //3.没打开,但已经插旗,也不能插旗
       if((state&0b110)==0b100) {
           System.out.println("点"+p.getX()+","+p.getY()+"已经插旗,不能重复插旗");
           sc.nextLine();
           return;
       }
       //4.可以插旗
       minePoint[p.getX()][p.getY()].setState(p.getState()+0b100);
    
    }
    private void peek(Point[][] minePoint) {
       for(int i=0;i<minePoint.length;i++)  {
           for(int  j=0;j<minePoint[i].length;j++) {
               minePoint[i][j].setState((minePoint[i][j].getState() & 0b1111001) | 0b10);
           }
       }
       showMineField(minePoint);
    }
    
    private void showMineField(Point[][]  minePoints) {
       int rows = minePoints.length;
       int cols = minePoints[0].length;
       
       for(int i=0;i<=cols;i++) {
           if(i==0) {
               System.out.print("  \t");
           }else {
               System.out.print(i+"  ");
           }
       }
       System.out.println();
       for(int i=0;i<rows;i++) {
           System.out.print(i+1+"\t");
           for(int j=0;j<cols;j++) {
               //没有打开,且没有雷00x
               if((minePoints[i][j].getState() &  0b110)==0b0) {
                  System.out.print("N  ");
               }else  if((minePoints[i][j].getState() &  0b110)==0b100){
                  //是否要插旗10x
                  System.out.print("F  ");
               }else {//01x
                  if((minePoints[i][j].getState() &  0b01)==0b1) {
                      //打开且是雷011
                      System.out.print("M   ");
                  }else {
                      //打开不是雷010
                      System.out.print((minePoint[i][j].getState()>>3)+"  ");
                  }
               }
           }
           System.out.println();
       }
    }
}

Main Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Test {
    public static void main(String[] args) {
       /*MineMap m = new MineMap();
       Point[][] map = m.getMineMap();
       Point[][] map = new  MineMap(10,10,100).getMineMap();
       for(int i=0;i<map.length;i++) {
           for(int j=0;j<map[i].length;j++)  {
               System.out.print(map[i][j].getState()+"\t");
           }
           System.out.println();
       }*/
       
       new ClearMineGame().start();
    }
}
CATALOG