Java系列——五子棋的实现

Java之面向对象编程

五子棋(控制台版)是「面向对象编程」中经典的小项目,下面我将提供一种解决视角,仅供参考。

题目描述:

编程实现控制台版并支持两人对战的五子棋游戏。

(1)绘制棋盘 - 写一个成员方法实现

(2)提示黑方和白方分别下棋并重新绘制棋盘 - 写一个成员方法实现。

(3)每当一方下棋后判断是否获胜 - 写一个成员方法实现。

(4)提示: 采用二维数组来模拟并描述棋盘,棋盘如下:
Java系列——五子棋的实现_第1张图片
注意点:

  • 五子棋棋盘有且只有一张:单例模式实现
  • 绘制棋盘函数:按行打印二维数组,双层for循环实现
  • 判断落子是否合理:落子是否超出界限,落子是否已存在
  • 胜利与否的判断:四个方向的判断
  • 每个方向的判断方法:9个字符的数组中是否存在5个连续的与当前棋子一样的字符

Gobang类:

import java.util.Scanner;

public class Gobang {
     
    // 初始化成员变量,落子区域:16*16
    // 用单例模式实现有且只有一个棋盘
    private char[][] chessboard = new char[17][17];
    private static Gobang gb = new Gobang();

    // 私有化无参构造方法: 绘制棋盘且提示黑子先手
    private Gobang() {
     
        for(int i = 0; i < 17; i++) {
     
            for(int j = 0; j < 17; j++) {
     
                if (0 == i && 0 == j) {
     
                    chessboard[i][j] = (char)32;
                } else if (0 == i && j <= 10) {
      //控制第一行的情况
                    chessboard[i][j] = (char)(j - 1 + 48);
                } else if (0 == i && j <= 16) {
     
                    chessboard[i][j] = (char)(j - 11 + 97);
                } else if (0 == j && i <= 10) {
      // 控制第一列的情况
                    chessboard[i][j] = (char)(i - 1 + 48) ;
                } else if (0 == j && i <= 16) {
     
                    chessboard[i][j] = (char)(i - 11 + 97);
                } else {
     
                    chessboard[i][j] = (char)43;
                }
            }
        }
        drawChessboard(true);
    }

    // 单例模式:从类层级获取棋盘
    public static Gobang getGobang() {
     
        return gb;
    }
    // 绘制棋盘的成员方法
    public void drawChessboard(boolean flag) {
     
        System.out.println("--------------------趣味五子棋游戏-------------------");
        System.out.println("-----------------作者:Vigoroushui------------------");
        for(int i = 0; i < 17; i++){
     
            for(int j = 0; j < 17; j++) {
     
                System.out.print(chessboard[i][j]);
                System.out.print("  ");
            }
            System.out.println();
        }
        if(true == flag) {
     
            System.out.println("--------------------轮到黑方下棋--------------------");
        } else {
     
            System.out.println("--------------------轮到白方下棋--------------------");
        }
    }
    // 判断落子合理性的成员方法
    public String judgeRationality(String n) {
     
        int judge = 0;
        // 判断当前落子是否超出界限 [0,9]&&[a,f]
        for(int i = 1; i < 17; i++) {
     
            if(String.valueOf(chessboard[0][i]).equals(n)) {
     
                judge = 1;
                break;
            }
        }
        // 如果落子越界,给定"outer"标示符
        if(1 != judge) {
     
            return "outer";
        }
        return n;
    }
    // 开始五子棋游戏的成员方法
    public void playChess() {
     
        boolean flag = true; //用于控制黑白两方落子的标示符,true代表黑方落子,false代表白方落子
        Scanner sc = new Scanner(System.in);
        while(true) {
     
            //合理值的判断
            System.out.println("请输入您要落子的行位置和列位置(如: a 4):");
            int cow, column;
            while(true) {
     
                String a = judgeRationality(sc.next());
                String b = judgeRationality(sc.next());
                // 判断落子是否越界
                if ("outer".equals(a) || "outer".equals(b)) {
     
                    System.out.println("您落子落到棋盘外面去了,请重新落子:");
                }else {
     
                    // 将输入的值转为二维数组对应的行列下标
                    cow = (int) a.charAt(0) + 1 - 48;
                    column = (int) b.charAt(0) + 1 - 48;
                    if (cow >= 11) {
     
                        cow = (int) a.charAt(0) + 11 - 97;
                    }
                    if (column >= 11) {
     
                        column = (int) b.charAt(0) + 11 - 97;
                    }
                    //判断落子是否已存在
                    if ('&' == chessboard[cow][column] || '#' == chessboard[cow][column]) {
     
                        System.out.println("您落子的位置已有棋子,请重新落子:");
                    }else {
     
                        break;
                    }
                }
            }
            // 落子
            if(flag) {
     
                chessboard[cow][column] = (char) 38; // 用 & 代表黑方落子
            } else {
     
                chessboard[cow][column] = (char) 35; // 用 # 代表白方落子
            }
            // 判断是否胜利,若胜利,则退出循环
            boolean win = isWin(cow, column);
            if(win && flag){
     
                System.out.println("恭喜黑子获胜!");
                drawChessboard(true);
                break;
            }else if(win && !flag) {
     
                System.out.println("恭喜白子获胜!");
                drawChessboard(false);
                break;
            }
            // 交换对手并重新绘制棋盘
            flag = !flag;
            drawChessboard(flag);
        }
    }
    // 判断是否胜利的成员方法
    public boolean isWin(int cow, int column) {
     
        int highBound = 16;
        int lowBound = 1;
        // 每次落子连成线只可能有4种情况: 横、纵、左斜、右斜
        // 创建4个一维数组分别保存四个方向上9个子
        char[] cowChess = {
     '*', '*', '*', '*', '*', '*', '*', '*', '*'};
        char[] columnChess = {
     '*', '*', '*', '*', '*', '*', '*', '*', '*'};
        char[] leftDiagonal = {
     '*', '*', '*', '*', '*', '*', '*', '*', '*'};
        char[] rightDiagonal = {
     '*', '*', '*', '*', '*', '*', '*', '*', '*'};
        rightDiagonal[4] = leftDiagonal[4] = columnChess[4] = cowChess[4] = chessboard[cow][column];
        // 生成4个方向的成线数组, 例如:横方向 + + + + & & + + +
        for (int i = 1; i <= 4; i++) {
     
            // 生成横方向的成线情况
            if (column - i >= lowBound) {
     
                cowChess[4 - i] = chessboard[cow][column - i];
            }
            if (column + i <= highBound) {
     
                cowChess[4 + i] = chessboard[cow][column + i];
            }
            // 生成纵方向的成线情况
            if (cow - i >= lowBound) {
     
                columnChess[4 - i] = chessboard[cow - i][column];
            }
            if (cow + i <= highBound) {
     
                columnChess[4 + i] = chessboard[cow + i][column];
            }
            // 生成左斜方向上的成线情况
            if (cow - i >= lowBound && column - i >= lowBound) {
     
                leftDiagonal[4 + i] = chessboard[cow - i][column - i];
            }
            if (cow + i <= highBound && column + i <= highBound) {
     
                leftDiagonal[4 - i] = chessboard[cow + i][column + i];
            }
            // 生成右斜方向上的成线情况
            if (cow - i >= lowBound && column + i <= highBound) {
     
                rightDiagonal[4 + i] = chessboard[cow - i][column + i];
            }
            if (column - i >= lowBound && cow + i <= highBound) {
     
                rightDiagonal[4 - i] = chessboard[cow + i][column - i];
            }
        }
        // 判断4个方向是否存在五子连珠的情况
        boolean resCowChess = fiveSons(cowChess, cow, column);
        boolean resColumnChess = fiveSons(columnChess, cow, column);
        boolean resLeftDiagonal = fiveSons(leftDiagonal, cow, column);
        boolean resRightDiagonal = fiveSons(rightDiagonal, cow, column);
        // 若有一个方向上的存在五子连珠的情况,则胜利
        if(resCowChess || resColumnChess || resLeftDiagonal || resRightDiagonal) {
     
            return true;
        }else {
     
            return false;
        }
    }
    // 判断五子连珠的方法,形参为有9个字符的数组(对应四个方向), 当前落子的行和列
    // 该方法只用于isWin()成员方法中,本质是一维数组中找连续相同的字串
    private boolean fiveSons(char[] sons, int cow, int column) {
     
        int count = 1; // 统计连续子的个数
        for(int i = 0; i < 5;) {
     
            if (sons[i] == chessboard[cow][column]) {
     
                for (int j = i + 1; j < 9; j++) {
     
                    if(sons[j] == sons[j - 1]) {
     
                        count += 1;
                        if(5 == count) return true; // 若找到五子连珠的情况,则返回胜利标示符true
                    }else {
     
                        count = 1;
                        i = j;
                        break;
                    }
                }
            }
            i++;
        }
        return false;
    }
}

GobangTest类:

public class GobangTest {
     

    public static void main(String[] args) {
     
       
        Gobang g = Gobang.getGobang();
        g.playChess();
        Gobang g2 = Gobang.getGobang(); // g和g2指向同一个棋盘
    }
}

后记:

本文代码所用的开发环境为IntelliJ IDEA,代码块中每一步均有详细的注释。整个项目涉及到的核心知识点为:单例模式的实现、二维数组的使用、类的使用(构造方法、成员变量、成员方法)

你可能感兴趣的:(Java,java,数据结构,游戏)