第六节 案例过程的学习记录

1、双色球练习:

1.1、随机数怎么产生?

random() 方法只能产生 double 类型的 0~1 的随机数。需要进行额外处理。所以这里使用Random类,int nextlnt(int n)可以直接产生int类型,范围是[0,n),从0 开始(包含),不包含n,也需要简单处理。

1.2、产生的随机数是带有重复的,怎么处理?

随机数去重:建立一个布尔数组记录数字状态,出现过则将其状态改为true,并进入循环重新生成,直至没出现过

  1. do {
  2. // 因为是双色球号码包括33,所以这里需要注意,前边是[0,33),左闭右开
  3. number = rand.nextInt(33) + 1;
  4. // 只有 条件为 true 才会循环,而true则表明这个数产生过
  5. } while (bool[number]);
  6. // 产生一个数,就把它的位置上标记为 true
  7. 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. 提示黑方(用 1 表示)和白方(用 2 表示)分别下棋(X,Y 轴位置) 并重新绘制棋盘。
  3. 每当一方下棋后判断是否获胜 。

棋盘如下:
第二章 第6节 综合案例 - 图1
代码如下:

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;
    }
}

运行截图:
第二章 第6节 综合案例 - 图2
学习记录:

二维数组的第一个是行索引,第二个是列索引。

五子棋的练习中,为了让用户输入正确的格式和整数范围,我使用了hasNextInt()方法,和if判断,并使用了一个布尔变量记录是否越界,然后发现,程序出现了问题,经过排查,发现是,我在把越界设置成true之后,没有在下次用户输入了合适的数据后,把它变成false,导致出现奇怪的现象。

还有就是,我在判断是否那个位置有棋子和越界上遇到了问题,我的if先判断了是否由棋子,然后用else if 判断了是否越界,结果就会运行出错,无法正常判断越界,然后我意识到是次序的原因。经过这个练习,我深刻的了解了判断次序的重要性,还有就是意识到了短路与,短路或的好处,当条件较多时,用这个很不错。

而获胜的判断,较为繁琐,但是仔细捋程序就能捋通。

经过这次的清除BUG,我只能说,当遇到问题的时候,仔细一句一句的跟着捋程序,一些问题就迎刃而解了。