zoukankan      html  css  js  c++  java
  • Java实现简单井字棋

    Java第一次实验,老师让做一个井字棋,电脑随机下棋。

    然后就想能不能聪明一点,可以判断出走哪一步棋;然后只能做到不会输,还是不够聪明,只能呆板地堵住用户,smartRobot的第三个判断逻辑找不到最佳位置,赢得概率比较小;而且我没事干时,想玩玩这个小游戏找找成就感,但每次都会赢了机器人,所以删删改改了四五次,最后才成。

    =======================

    可以选择谁先开始,但startGame里的代码更加冗余了。看着就很乱,但没想到好的办法。

    smartRobot里的代码全部重写了,比原来更聪明一点了:下在四个角的位置时,能优先选择最佳位置;然后没有最佳位置时,再随便找一空的(随便找空四角位置使用for代替了,比原来更简短)。

    然后smartRobot的第一个和第三个判断逻辑,也更聪明一点了。原来判断机器人和判断用户的逻辑,是放在一个for循环里的,但无法找到最佳位置,现在分开了。

    机器人先开始时,才能发挥出来新添加的机器人的“小聪明”;但机器人原来的能力发挥不回来,只有用户先开始时才能发挥出原来的能力。所以各有利弊,无论谁先开始都能适应。如果机器人先开始,并且用户第一步棋不是下在四角的位置,那么用户就必输了。其他的情况一般都是平局了。

    ======================

    想到一个因为可以选择谁先开始而导致 startGame 代码冗余的问题的解决方法,就是使用局部内部类。内部类能访问到方法的局部对象。

    主逻辑 startGame:

    1. 用一个3X3的二维数组,存储棋盘;

    2. 用户输入1~9下棋;

    3. 判断是否合法,不合法则重新输入;

    4. 将1~9转换成二维的坐标 x = (pos-1)/3, y = (pos-1)%3,再令二维数组相应位置为 'O';

    5. 判断用户是否胜利,是则退出;再判断是否平局,是则退出;

    6. 机器人下棋(根据输入等级,调用不同函数);

    7. 打印棋盘显示出用户和机器人下的棋子;

    8. 判断机器人是否胜利,是则退出;再判断是否平局,是则退出;都不是返回第1步。

    isSuccessful 判断成功的逻辑:

    判断所有行、列、对角线是否有连成一条线的,用字符相加的和判断即可

    willBeSuccessful判断是否将要成功:

    这里判断的是是否有行、列有两个相同棋子和一个空白,用字符相加的和判断。

    calculate 计算行列对角线:

    使用枚举类,来判断是计算行,还是计算列,还是计算左右对角线;计算行列时,传入一个1~3的数字表示是哪一行那一列。

    smartRobot 的第一个判断逻辑:

    如果棋子下在箭头指向的那个位置,那么一步棋就可胜利。

    机器人先判断自己是否有这样一个位置,有则下在哪个地方,胜利;

    方法是尝试填入所有空白地方,每填一次,判断一次 isSuccessful;

    如果没有,再判断对方是否有这样一个位置,有则堵住这个地方。

    smartRobot 的第三个判断逻辑:

    如果棋子下在箭头指向的位置,那么再下一步必会胜利,因为下在了那个地方,第三列、第三行都是两个棋子了,无论对方堵哪里,都会失败。

    也是机器人先判断自己是否有这样一个位置,有则下;

    调用 willBeSuccessful 判断是否有这样的位置。

    没有则再判断对方是否有这样的位置,有则堵住。

    smartRobot 的第零个和第二个判断逻辑:

    处理四个角和中心的位置,如果用户下在了中心,那么机器人必须至少有两个棋子下在四角位置才能保证不输。

     

    更改了无数次的代码:

    import java.util.Arrays;
    import java.util.Scanner;
    
    public class Experiment_1 {
        public static void main(String[] args) {
            ThreeChess game = new ThreeChess();
            game.startGame();
    
        }
    }
    
    class ThreeChess{
        private char[][] chessBoard = new char[3][3];
        private int size = 0; //已经下的棋数
        private final int CAPACITY = 9; //总共可下的棋数
    
        ThreeChess(){
            for(char[] line : chessBoard){ //初始化棋盘
                Arrays.fill(line, ' ');
            }
        }
    
        //【游戏开始】
        public void startGame(){
            System.out.println("┌───┬───┬───┐");
            System.out.println("│ 1 │ 2 │ 3 │");
            System.out.println("├───┼───┼───┤");
            System.out.println("│ 4 │ 5 │ 6 │");
            System.out.println("├───┼───┼───┤");
            System.out.println("│ 7 │ 8 │ 9 │");
            System.out.println("└───┴───┴───┘");
            System.out.println("输入 1 ~ 9 表示要下棋的位置");
            System.out.println("O是你的棋子,*是电脑的棋子");
            Scanner in = new Scanner(System.in);
    
            System.out.print("选择谁先开始:
    	1.用户
    	2.机器人
    Input: ");
            int whoFirst = in.nextInt();
            System.out.print("选择机器人智商:
    	1. 999+
    	2. 250
    Input: ");
            int level = in.nextInt();
    
            class Play{ //代码重用
                //方法返回-1表示退出
                int robotPlay(){
                    if(level == 1)
                        smartRobot();
                    else
                        sillyRobot();
    
                    printChessBroad();
                    if(isSuccessful() == -1) {
                        System.out.println("机器人胜 (/ □ \)");
                        return -1;
                    }else if (size == CAPACITY){
                        System.out.println("==游戏平局==");
                        return -1;
                    }
                    return 0;
                }
                int userPlay(){
                    int pos;
                    while(true){
                        System.out.print("下棋位置: ");
                        pos = in.nextInt();
                        if(pos < 1
                                || pos > 9
                                || chessBoard[(pos - 1) / 3][(pos - 1) % 3] != ' '){
                            System.out.println("输入错误,重新输入!");
                            continue;
                        } else {
                            chessBoard[(pos - 1)/3][(pos - 1) % 3] = 'O';
                            size++;
                            break;
                        }
                    }
    
                    if(isSuccessful() == 1){
                        printChessBroad();
                        System.out.println("恭喜,你胜了 ╰(*°▽°*)╯");
                        return -1;
                    } else if(size == CAPACITY){
                        printChessBroad();
                        System.out.println("==游戏平局==");
                        return -1;
                    }
                    return 0;
                }
            }
    
            Play play = new Play();
            if(whoFirst == 2){
                while(true){
                    //1.机器人下棋
                    if(play.robotPlay() == -1)
                        return;
    
                    //2.用户下棋
                    if(play.userPlay() == -1)
                        return;
                }
            } else {
                while(true){
                    //1.用户下棋
                    if(play.userPlay() == -1)
                        return;
    
                    //2.机器人下棋
                    if(play.robotPlay() == -1)
                        return;
                }
            }
        }
    
        //【机器人下棋】
        private void sillyRobot(){ //笨机器人
            int l, c;
            while(true){
                l = (int)(Math.random() * 3);
                c = (int)(Math.random() * 3);
                if(chessBoard[l][c] == ' '){
                    chessBoard[l][c] = '*';
                    break;
                }
            }
            size++;
        }
    
        private int corner = 2;
        private void smartRobot(){ //无法战胜的机器人
            if(chessBoard[1][1] == ' '){ //抢占中心位置
                chessBoard[1][1] = '*';
                size++;
                return;
            }
    
            //1.判断是否可以下一个棋子就胜利(不能放在一起同时判断,否则有可能错误最佳位置)
            for(int i = 0; i < 3; i++){
                for(int j = 0; j < 3; j++){
                    if(chessBoard[i][j] == ' '){ //【1】如果这个位置没有棋子,就尝试下载这个地方,看看是否可以胜;
                        chessBoard[i][j] = '*';
                        if(isSuccessful() == -1){  //【1】如果胜的话,就下在这个地方了,返回即可;
                            size++;
                            return ;
                        }
                        else
                            chessBoard[i][j] = ' ';
                    }
                }
            }
    
            for(int i = 0; i < 3; i++){
                for(int j = 0; j < 3; j++){
                    //【2】逻辑同【1】
                    if(chessBoard[i][j] == ' '){
                        chessBoard[i][j] = 'O'; //【2】否则尝试用户下在这个位置
                        if(isSuccessful() == 1){ //【2】如果用户下在这个位置会胜利,就占领它。
                            chessBoard[i][j] = '*';
                            size++;
                            return ;
                        } else
                            chessBoard[i][j] = ' ';
                    }
                }
            }
    
            //2.如果用户下在了中间的话,就赶紧占两个四角的位置,才能保证不输。优先级要比第一个低。用户没下在中间也可抢占。
            if(corner > 0){
                corner--;
                for(int i = 0; i < 3; i++){ //优先找四边中没有用户棋子的地方下
                    if(i == 1)
                        continue;
                    boolean NoBigO = true;
                    for(int j = 0; j < 3; j++){
                        if(chessBoard[i][j] == 'O')
                            NoBigO = false;
                    }
                    for(int j = 0; j < 3 && NoBigO; j++){
                        if(chessBoard[i][j] == ' '){
                            chessBoard[i][j] = '*';
                            size++;
                            return;
                        }
                    }
                }
    
                for(int i = 0; i < 3; i++){
                    for(int j = 0; j < 3; j++){
                        if(j == 1 || i == 1)
                            continue;
                        if(chessBoard[i][j] == ' '){
                            chessBoard[i][j] = '*';
                            size++;
                            return;
                        }
                    }
                }
            } //end if
    
            //3.判断是否可以下一个棋子,从而再下一步可以胜利(不能放在一起判断)
            for(int i = 0; i < 3; i++){
                for(int j = 0; j < 3; j++){
                    if(chessBoard[i][j] == ' '){
                        chessBoard[i][j] = '*';
                        if(willBeSuccessful(-1)){
                            size++;
                            return;
                        } else
                            chessBoard[i][j] = ' ';
                    }
                }
            }
    
            for(int i = 0; i < 3; i++){
                for(int j = 0; j < 3; j++){
                    if(chessBoard[i][j] == ' '){
                        chessBoard[i][j] = 'O';
                        if (willBeSuccessful(1)) {
                            chessBoard[i][j] = '*';
                            size++;
                            return;
                        } else
                            chessBoard[i][j] = ' ';
                    }
                }
            }
    
            sillyRobot();
        }
    
        //【打印棋盘】
        private void printChessBroad(){
            System.out.println("
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    "); //模拟清屏
            System.out.println("┌───┬───┬───┐");
            System.out.println("│ " + chessBoard[0][0] + " │ " + chessBoard[0][1] + " │ " + chessBoard[0][2] + " │");
            System.out.println("├───┼───┼───┤");
            System.out.println("│ " + chessBoard[1][0] + " │ " + chessBoard[1][1] + " │ " + chessBoard[1][2] + " │");
            System.out.println("├───┼───┼───┤");
            System.out.println("│ " + chessBoard[2][0] + " │ " + chessBoard[2][1] + " │ " + chessBoard[2][2] + " │");
            System.out.println("└───┴───┴───┘");
        }
    
        //【判断成功逻辑】
        private enum Choice{
            LINE,           //行
            COLUMN,         //列
            RIGHT_DIAGONAL, //右对角线
            LEFT_DIAGONAL;  //左对角线
        }
        private int calculate(Choice choice, int i){ //计算行、列、对角线是否连成一条线
            switch (choice){
                case LINE:
                    return chessBoard[i][0] + chessBoard[i][1] + chessBoard[i][2];
                case COLUMN:
                    return chessBoard[0][i] + chessBoard[1][i] + chessBoard[2][i];
                case RIGHT_DIAGONAL:
                    return chessBoard[0][0] + chessBoard[1][1] + chessBoard[2][2];
                case LEFT_DIAGONAL:
                    return chessBoard[0][2] + chessBoard[1][1] + chessBoard[2][0];
            }
            return 0;
        }
        private int isSuccessful(){
            /*
            返回-1系统胜;返回1用户胜;返回0表示继续下棋。
            系统胜:126 == '*' + '*' + '*'
            用户胜:237 == 'O' + 'O' + 'O'
            */
            for(int i = 0; i < 3; i++){
                if(calculate(Choice.LINE, i) == 237 || calculate(Choice.COLUMN, i) == 237)
                    return 1;
                if(calculate(Choice.LINE, i) == 126 || calculate(Choice.COLUMN, i) == 126)
                    return -1;
            }
            if(calculate(Choice.LEFT_DIAGONAL, 0) == 237 || calculate(Choice.RIGHT_DIAGONAL, 0) == 237)
                return 1;
            if(calculate(Choice.LEFT_DIAGONAL, 0) == 126 || calculate(Choice.RIGHT_DIAGONAL, 0) == 126)
                return -1;
            return 0; //继续下棋
        }
    
        private boolean willBeSuccessful(int who){ //who:-1表示判断机器人的,+1表示判断用户的。
            //如果行、列、对角线有2个相同棋子的个数,则将会胜,
            //190 == 2 * 'O' + ' '
            //116 == 2 * '*' + ' '
    
            int n = 0;
            int s = (who == 1) ? 190 : 116; //用户or机器人要计算的值
    
            for(int i = 0; i < 3; i++){
                if(calculate(Choice.LINE, i) == s)
                    n++;
                if(calculate(Choice.COLUMN, i) == s)
                    n++;
            }
            //因为中心一定会被占的,所以就不用判断对角线了
            return n > 1;
        }
    }
    

      

  • 相关阅读:
    从0开始的Python学习013编写一个Python脚本
    Spring Cloud Eureka基本概述
    RocketMQ入门案例
    Quartz使用记录总结
    Spring Boot 1.5升级2.1 主要问题汇总
    Eureka客户端注册多网卡下IP选择问题
    Spring Security之动态配置资源权限
    代码规范问题
    Spring Security + OAuth系统环境搭建(一)
    Java并发编程之AQS
  • 原文地址:https://www.cnblogs.com/yuanyb/p/10595811.html
Copyright © 2011-2022 走看看