第六节 案例过程的学习记录
1、双色球练习:
1.1、随机数怎么产生?
random() 方法只能产生 double 类型的 0~1 的随机数。需要进行额外处理。所以这里使用Random类,int nextlnt(int n)可以直接产生int类型,范围是[0,n),从0 开始(包含),不包含n,也需要简单处理。
1.2、产生的随机数是带有重复的,怎么处理?
随机数去重:建立一个布尔数组记录数字状态,出现过则将其状态改为true,并进入循环重新生成,直至没出现过
do {
// 因为是双色球号码包括33,所以这里需要注意,前边是[0,33),左闭右开
number = rand.nextInt(33) + 1;
// 只有 条件为 true 才会循环,而true则表明这个数产生过
} while (bool[number]);
// 产生一个数,就把它的位置上标记为 true
bool[number] = true;
异常捕获遇到的问题,try catch 用不好,本来是想解决输入号码为0,或者大于33的问题,但是出现了不好的情况(会继续执行后边代码,然后让我发现了自己程序的问题,就是int默认初始化的数组元素都是0,而当try catch 跳过用户输入的话,会出现用户的输入全是0,而我在拿出蓝色球编号码之后,把原来的变成了0,那就会导致奖品等级的判定很高,后来我把它换成了 -1,不换也没事了,但最好换上,因为后边我用if判断了输入是不是 1- 33,不是就会终止程序),后来使用if语句替换了了。
1.3、用户输入去重
我的做法是和产生随机数的做法一样。
1.4、用户输入其他字符处理
使用hasNextInt()判断输入类型,不是整数,直接停止程序,并提示用户输入正确的格式。
1.5、用户输入的数字不是 1 - 33
使用了if 判断,是否在范围内,不在就停止程序,并提示用户正确输入。
1.6、怎么样停止程序,并不执行后续代码
我的方法是,设置一个boolean类型的变量记录输入状态,一旦用户输入错误的类型,就把该状态变为false,之后的代码,则需要它为true才会运行。对于在多重循环中的还需要给循环起别名,这样直接跳出外层循环。
1.7、改进
我现在的知识不足以支持我改进,我希望的情况是,可以当用户输入错误的时候,提示他重新输入,而不是直接结束程序。目前只在输入数字去重这里做到了,其他字符处理和范围越界,还不会处理。而且我感觉自己的代码过于冗长,希望可以优化。
2、五子棋练习:
规则如下:
- 绘制棋盘
- 提示黑方(用 1 表示)和白方(用 2 表示)分别下棋(X,Y 轴位置) 并重新绘制棋盘。
- 每当一方下棋后判断是否获胜 。
棋盘如下:
代码如下:
import java.util.Scanner;
public class GoBang {
public static void main(String[] args) {
/*
1. 绘制棋盘
2. 提示黑方(用 1 表示)和白方(用 2 表示)分别下棋(X,Y 轴位置)
并重新绘制棋盘。
3. 每当一方下棋后判断是否获胜 。
4. 采用二维数组来模拟棋盘。
chessBoard[0] = new int[]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
0123456789101112131415
0000000000000000
0000000000000000
可以发现,第一个是行索引,第二个是列索引 所以我们用x表示列,y表示行,符合坐标轴的习惯
5、难点主要在于对获胜的判断
*/
// 定义一个方法实时绘制棋盘
// 先定义棋盘,并初始化边界索引
int[][] chessBoard = new int[16][16];
chessBoard[0] = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
for (int i = 0; i < 16; i++) {
chessBoard[i][0] = i;
}
// 初次绘制棋盘
paintChessBoard(chessBoard);
// 下边的代码要重复运行直到出现胜者,因此最好封装成方法
// 然后发现,大部分代码都一样,因此调整,加参数标记黑白
// 提示黑方下棋 黑色棋子用1,白色棋子用2
Scanner input = new Scanner(System.in);
// 初始化x,y坐标
int x, y;
// 定义一个布尔变量记录上一步白方是否落子
boolean white;
// 定义一个布尔变量判断是否越界
boolean outside = false;
// 初始为黑方先下
int marker = 1;
String text;
while (true) {
if (marker == 1) {
text = "黑";
white = false;
} else {
text = "白";
white = true;
}
System.out.println("请" + text + "方落子:");
System.out.println("输入X坐标:");
if (input.hasNextInt()) {
do {
x = input.nextInt();
System.out.println("输入Y坐标:");
y = input.nextInt();
if (x < 1 || y < 1 || x > 15 || y > 15 ) {
System.out.println("那里是边界,不可以落子!请重新输入!");
System.out.println("请" + text + "方落子:");
System.out.println("输入X坐标:");
outside = true;
} else if (chessBoard[y][x] != 0) {
System.out.println("哪里已经有棋子了!请重新输入!");
System.out.println("请" + text + "方落子:");
System.out.println("输入X坐标:");
}else{
outside = false;
}
} while (outside || chessBoard[y][x] != 0 );
// outside = false;
chessBoard[y][x] = marker;
paintChessBoard(chessBoard);
// 判断是否有赢家
if (isWin(chessBoard, x, y, marker)) {
System.out.println(text + "方赢!");
break;
}
// 更改marker
marker = white ? 1 : 2;
} else {
System.out.println("输入了错误的格式,请重新开始游戏!");
break;
}
}
}
public static void paintChessBoard(int[][] chessBoard) {
System.out.println("------------------------------------------------------------------");
System.out.println(" —X ");
System.out.println("|");
System.out.println("Y");
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
System.out.print(chessBoard[i][j] + "\t");
}
System.out.println(" ");
}
System.out.println("------------------------------------------------------------------");
}
public static boolean isWin(int[][] chessBoard, int x, int y, int marker) {
// 判断横向的是否有5个棋子相连,即横坐标是相同的,即chessBoard[y][x]中y值是相同的
// 判断纵向的是否有5个棋子相连,即纵坐标是相同的,即chessBoard[y][x]中x值是相同的
// 判断斜向的是否有5个棋子相连,即纵横坐标是相差1的,即chessBoard[y][x]中x,y各差1
return checkCount(chessBoard, 1, 0, x, y, marker) >= 5
|| checkCount(chessBoard, 0, 1, x, y, marker) >= 5
|| checkCount(chessBoard, 1, 1, x, y, marker) >= 5
|| checkCount(chessBoard, 1, -1, x, y, marker) >= 5;
}
// 判断棋子连接的数量
public static int checkCount(int[][] chessBoard, int xChange, int yChange, int x, int y, int marker) {
int count = 1;
int tempX = xChange;
int tempY = yChange;
// 先向一个方向搜索
// 不能超出边界 而且要注意 y是行,x是列
while (x + xChange >= 1 && x + xChange <= 15 && y + yChange >= 1 && y + yChange <= 15
&& marker == chessBoard[y + yChange][x + xChange]) {
count++;
if (xChange != 0)
xChange++;
if (yChange != 0) {
if (yChange > 0)
yChange++;
else {
yChange--;
}
}
}
// 向另一个方向搜索
xChange = tempX;
yChange = tempY;
while (x - xChange >= 1 && x - xChange <= 15 && y - yChange >= 1 && y - yChange <= 15
&& marker == chessBoard[y - yChange][x - xChange]) {
count++;
if (xChange != 0)
xChange++;
if (yChange != 0) {
if (yChange > 0)
yChange++;
else {
yChange--;
}
}
}
return count;
}
}
运行截图:
学习记录:
二维数组的第一个是行索引,第二个是列索引。
五子棋的练习中,为了让用户输入正确的格式和整数范围,我使用了hasNextInt()方法,和if判断,并使用了一个布尔变量记录是否越界,然后发现,程序出现了问题,经过排查,发现是,我在把越界设置成true之后,没有在下次用户输入了合适的数据后,把它变成false,导致出现奇怪的现象。
还有就是,我在判断是否那个位置有棋子和越界上遇到了问题,我的if先判断了是否由棋子,然后用else if 判断了是否越界,结果就会运行出错,无法正常判断越界,然后我意识到是次序的原因。经过这个练习,我深刻的了解了判断次序的重要性,还有就是意识到了短路与,短路或的好处,当条件较多时,用这个很不错。
而获胜的判断,较为繁琐,但是仔细捋程序就能捋通。
经过这次的清除BUG,我只能说,当遇到问题的时候,仔细一句一句的跟着捋程序,一些问题就迎刃而解了。