Bootstrap

简易五子棋

  1. 准备工作

1.1材料代码

    static String white = "☆";  //用来表示白棋
    static String black = "★";  //用来表示黑棋
    static String[][] qp = new String[15][15];  //制作棋盘的数组 
    static String[] num = {"⒈", "⒉", "⒊", "⒋", "⒌", "⒍", "⒎", "⒏", "⒐", "⒑", "⒒", "⒓", "⒔", "⒕", "⒖"};
    static String line = "十";   //制作棋盘的材料 

1.2建立主方法main

public staic void main(String[]args){

}
  1. 制作棋盘

制作如下图所示的棋盘。棋盘由数字和十字符号组成。构建两个方法paintqp(绘制棋盘)和printqp(输出棋盘)。其中绘制棋盘主要是利用for循环给二维数组qp对应的下标赋值。输出棋盘主要是用for循环遍历输出二维数组qp。

 public static void paintqp() { //绘制棋盘
        for (int i = 0; i < qp.length - 1; i++) {  //棋盘是15×15式,但最后一列和最后一行都是num数组输出的,所以字符串Line实际是14×14
            for (int j = 0; j < qp[i].length - 1; j++) {  //这里循环条件写j<qp.length也可以,因为两个值是一样的。
                qp[i][j] = line;
            }
            for (int m = 0; m < qp.length; m++) {   //给最后一列赋num数组。
                for (int n = 0; n < qp[m].length; n++) {
                    if (n == qp[m].length - 1) {   //判断是否到最后一列
                        qp[m][n] = num[m];
                    }
                }
            }
            for (int k = 0; k < qp.length; k++) { //给最后一行赋num数组。
                for (int l = 0; l < qp[k].length - 1; l++) {
                    if (k == qp.length - 1) {   //判断是否到最后一行
                        qp[k][l] = num[l];
                    }
                }
            }
        }
    }

    public static void printqp() { //循环遍历输出棋盘
        for (int i = 0; i < qp.length; i++) {
            for (int j = 0; j < qp.length; j++) {
                System.out.print(qp[i][j]);
            }
            System.out.println();
        }
    }
  1. 下棋

五子棋分为黑白两方,一般由黑方先下;因此我们可以定义一个布尔型变量flag,flag为真黑方下子,flag为假白方下子。由于在下棋时一直需要重复这段操作,所以加上一个while(true)无限循环。定义方法为start。

  public static void start() { //下棋
        while (true) {
            if (flag) {
                System.out.println("请黑棋下子");
            } else {
                System.out.println("请白棋下子");
            }
        }
    }
  1. 下棋细节

下棋我们需要用到Scanner类来进行输入,我们定义一个y坐标和一个x坐标来确定棋子的位置。x方向应该向右,y方向向下,坐标原点在棋盘左上方。可以看到y是二维数组里的行数,x是二维数组里的列数。所以输出坐标时注意y和x在数组的位置。

其次要注意我们看到的位置和对应的下标,例如我们看到的是第一行第一列,实际对应的下标是0,0。当下子成功后改变二维数组对应坐标的值并重新输出棋盘。

定义方法为game。

public static void game() {  //下棋的细节
        int y = s.nextInt() - 1;
        int x = s.nextInt() - 1;    //我们看到的第1行第1个,坐标应该是第0行第0个,以此类推;所以输入后要减1
        boolean con = check(x, y); //接受方法check的返回值
        if (con && flag) {          //若都为真,那么应该是黑棋的回合
            qp[y][x] = black;    //坐标相应位置变为黑棋
            printqp();        //下完后更新棋盘
                flag = false;//转到白棋回合
        } else if (con && flag == false) {  //若false为假,con为真,那么应该是白棋的回合
            qp[y][x] = white;        //坐标相应位置变为白棋
            printqp();
                flag = true;//转到黑棋回合
        } else {
            System.out.println("输入错误,请重新输入");  //如果con为假,那就证明输入有错误
        }
    }

下棋时我们需要注意以下两点,第一:棋子不能超过棋盘边界,第二:在有棋子的位置不能重复落子。 定义方法为check

public static boolean check(int x, int y) { //判断是否可以下棋
        if (y < 0 || y > qp.length - 1 || x < 0 || x > qp.length - 1) {  //输入的坐标是否超出边界
            return false;
        }
        if (!qp[y][x].equals(line)) {   //输入的坐标是否已经有棋子
            return false;
        } else {
            return true;
        }
    }
  1. 判断输赢

当每次一方下完棋后都需要判断输赢。 五子棋胜利条件即相同颜色任意方向相连数量至少5个。

我们可以写四个方法用来判断执棋方是否已经胜利。其中水平左右方主要是x坐标的移动,垂直上下方主要是y坐标的移动。左右斜x,y坐标都要移动。再定义一个方法win将四个方法综合起来判断最终结果。

 public static boolean win(int x,int y, String color) {//判断胜利
        boolean one = standard(x,y,color);
        boolean two = vertical(x,y,color);
        boolean three = lincline(x,y,color);
        boolean four = rlincline(x,y,color);
        if(one||two||three||four){
            return true;
        }
        return false;
    }

    public static boolean standard(int x, int y, String color) {  //判断水平是否胜利
        int spsum = 1;
        for (int lx = x - 1; lx >= 0; lx--) { //判断左水平是否胜利
            if (qp[y][lx].equals(color)) {
                spsum++;  //相同颜色相连则计数加1,其余类似
            } else {
                break;  //如果没有相同颜色相连直接终止左水平,其余类似
            }
            if (spsum >= 5) {
                return true;   //左水平数量至少五个则胜利,其余类似
            }
        }
        for (int rx = x + 1; rx < qp.length; rx++) {  //判断右水平是否胜利
            if (qp[y][rx].equals(color)) {
                spsum++;
            } else {
                break;
            }
            if (spsum >= 5) {
                return true;
            }
        }
        return false;  //没有胜利,其余类似
    }
    public static boolean vertical(int x, int y, String color){  //判断垂直是否胜利
        int czsum=1;
        for (int uy = y - 1; uy >= 0; uy--) {  //判断上方是否胜利
            if (qp[uy][x].equals(color)) {
                czsum++;
            }
            else{
                break;
            }
            if (czsum >= 5) {
                return true;
            }
        }
        for (int dy = y + 1; dy < qp.length; dy++) {  //判断下方是否胜利
            if (qp[dy][x].equals(color)) {
                czsum++;
            }
            else{
                break;
            }
            if (czsum >= 5) {
                return true;
            }
        }
        return false;
    }
    public static boolean lincline(int x,int y,String color){   //判断左斜是否胜利
        int lqxsum=1;
        for(int lxux=x-1,lxuy=y-1;lxux>=0&&lxuy>=0;lxux--,lxuy--){  //判断左斜上方是否胜利
            if (qp[lxuy][lxux].equals(color)) {
                lqxsum++;
            }
            else{
                break;
            }
            if (lqxsum >= 5) {
                return true;
            }
        }
        for(int lxdx=x+1,lxdy=y+1;lxdx<qp.length&&lxdy<qp.length;lxdx++,lxdy++){  //判断左斜下方是否胜利
            if (qp[lxdy][lxdx].equals(color)) {
                lqxsum++;
            }
            else{
                break;
            }
            if (lqxsum >= 5) {
                return true;
            }
        }
        return false;
    }
    public static boolean rlincline(int x,int y,String color){  //判断右斜是否胜利
        int rqxsum=1;
        for(int rxux=x+1,rxuy=y-1;rxux<qp.length&&rxuy>=0;rxux++,rxuy--){   //判断右斜上方是否胜利
            if (qp[rxuy][rxux].equals(color)) {
                rqxsum++;
            }
            else{
                break;
            }
            if (rqxsum >= 5) {
                return true;
            }
        }
        for(int rxdx=x-1,rxdy=y+1;rxdx>=0&&rxdy<qp.length;rxdx--,rxdy++){  //判断右斜下方是否胜利
            if (qp[rxdy][rxdx].equals(color)) {
                rqxsum++;
            }
            else{
                break;
            }
            if (rqxsum >= 5) {
                return true;
            }
        }
        return false;
    }
}
  1. 问题汇总

6.1判断输赢

最开始判断输赢里没有加入return false语句,导致一直提示错误

原因在于我没有完全理解 return语句,return最主要的作用在于它在返回值时同时会停止对这段代码的执行,也就是说,当判断为胜利时判断输赢的方法会直接返回true值,根本不会再执行后面的代码。

6.2胜利后执行的操作

问题:胜利后虽然提示胜利,但是下棋仍然在继续,例如黑棋胜利后,仍会让白棋继续出子。

方案:在判断胜利后,重新开始绘制并打印棋盘即重新开始游戏。

6.3白棋胜利后的小问题

问题:黑棋胜利后会显示黑棋胜利,然后重新开始游戏,但是白棋胜利后显示完白棋胜利,因为flag值仍为false,所以重新开始时会让白子重新下棋。 但目的是不论哪方胜利重新开始后都由黑方先下棋。

方案: 在输出后加入flag=true;

  1. 完整代码和结果展示

7.1完整代码

上面只讨论了每个部分应该怎么操作,但具体在什么位置调用什么方法并没有说。这里不做过多详细说明。以下是完整代码

import java.util.Scanner;
public class wzq {
    static String white = "☆";
    static String black = "★";
    static String[][] qp = new String[15][15];
    static String[] num = {"⒈", "⒉", "⒊", "⒋", "⒌", "⒍", "⒎", "⒏", "⒐", "⒑", "⒒", "⒓", "⒔", "⒕", "⒖"};
    static String line = "十";
    static boolean flag = true;
    static Scanner s = new Scanner(System.in);

    public static void main(String[] args) {
        paintqp();
        printqp();
        start();
    }

    public static void paintqp() { //绘制棋盘
        for (int i = 0; i < qp.length - 1; i++) {  //棋盘是15×15式,但最后一列和最后一行都是num数组输出的,所以字符串Line实际是14×14
            for (int j = 0; j < qp[i].length - 1; j++) {  //这里循环条件写j<qp.length也可以,因为两个值是一样的。
                qp[i][j] = line;
            }
            for (int m = 0; m < qp.length; m++) {   //给最后一列赋num数组。
                for (int n = 0; n < qp[m].length; n++) {
                    if (n == qp[m].length - 1) {   //判断是否到最后一列
                        qp[m][n] = num[m];
                    }
                }
            }
            for (int k = 0; k < qp.length; k++) { //给最后一行赋num数组。
                for (int l = 0; l < qp[k].length - 1; l++) {
                    if (k == qp.length - 1) {   //判断是否到最后一行
                        qp[k][l] = num[l];
                    }
                }
            }
        }
    }

    public static void printqp() { //循环遍历输出棋盘
        for (int i = 0; i < qp.length; i++) {
            for (int j = 0; j < qp.length; j++) {
                System.out.print(qp[i][j]);
            }
            System.out.println();
        }
    }

    public static void start() { //下棋
        while (true) {
            if (flag) {
                System.out.println("请黑棋下子");
                game();
            } else {
                System.out.println("请白棋下子");
                game();
            }
        }
    }

    public static void game() {  //下棋的细节
        int y = s.nextInt() - 1;
        int x = s.nextInt() - 1;    //我们看到的第1行第1个,坐标应该是第0行第0个,以此类推;所以输入后要减1
        boolean con = check(x, y); //接受方法check的返回值
        if (con && flag) {          //若都为真,那么应该是黑棋的回合
            qp[y][x] = black;    //坐标相应位置变为黑棋
            printqp();        //下完后更新棋盘
            boolean biswin=win(x,y,black);
            if(biswin){
                System.out.println("黑棋胜");
                paintqp();
                printqp();
                start();
            }
            else {
                flag = false;//没胜利转到白棋回合
            }
        } else if (con && flag == false) {  //若false为假,con为真,那么应该是白棋的回合
            qp[y][x] = white;        //坐标相应位置变为白棋
            printqp();
            boolean wiswin=win(x,y,white);
            if(wiswin){
                System.out.println("白棋胜");
                flag = true; //保证重新开始游戏时仍是黑方先下棋    
                paintqp(); //重新开始游戏
                printqp();
                start();
            }
            else {
                flag = true;//没胜利转到黑棋回合
            }
        } else {
            System.out.println("输入错误,请重新输入");  //如果con为假,那就证明输入有错误
        }
    }

    public static boolean check(int x, int y) { //判断是否可以下棋
        if (y < 0 || y > qp.length - 1 || x < 0 || x > qp.length - 1) {  //输入的坐标是否超出边界
            return false;
        }
        if (!qp[y][x].equals(line)) {   //输入的坐标是否已经有棋子
            return false;
        } else {
            return true;
        }
    }

    public static boolean win(int x,int y, String color) {//判断胜利
        boolean one = standard(x,y,color);
        boolean two = vertical(x,y,color);
        boolean three = lincline(x,y,color);
        boolean four = rlincline(x,y,color); //分别接收四个判断方法的返回值
        if(one||two||three||four){
            return true;
        }
        return false;
    }

    public static boolean standard(int x, int y, String color) {  //判断水平是否胜利
        int spsum = 1;
        for (int lx = x - 1; lx >= 0; lx--) { //判断左水平是否胜利
            if (qp[y][lx].equals(color)) {
                spsum++;  //相同颜色相连则计数加1,其余类似
            } else {
                break;  //如果没有相同颜色相连直接终止左水平,其余类似
            }
            if (spsum >= 5) {
                return true;   //左水平数量至少五个则胜利,其余类似
            }
        }
        for (int rx = x + 1; rx < qp.length; rx++) {  //判断右水平是否胜利
            if (qp[y][rx].equals(color)) {
                spsum++;
            } else {
                break;
            }
            if (spsum >= 5) {
                return true;
            }
        }
        return false;  //没有胜利,其余类似
    }
    public static boolean vertical(int x, int y, String color){  //判断垂直是否胜利
        int czsum=1;
        for (int uy = y - 1; uy >= 0; uy--) {  //判断上方是否胜利
            if (qp[uy][x].equals(color)) {
                czsum++;
            }
            else{
                break;
            }
            if (czsum >= 5) {
                return true;
            }
        }
        for (int dy = y + 1; dy < qp.length; dy++) {  //判断下方是否胜利
            if (qp[dy][x].equals(color)) {
                czsum++;
            }
            else{
                break;
            }
            if (czsum >= 5) {
                return true;
            }
        }
        return false;
    }
    public static boolean lincline(int x,int y,String color){   //判断左斜是否胜利
        int lqxsum=1;
        for(int lxux=x-1,lxuy=y-1;lxux>=0&&lxuy>=0;lxux--,lxuy--){  //判断左斜上方是否胜利
            if (qp[lxuy][lxux].equals(color)) {
                lqxsum++;
            }
            else{
                break;
            }
            if (lqxsum >= 5) {
                return true;
            }
        }
        for(int lxdx=x+1,lxdy=y+1;lxdx<qp.length&&lxdy<qp.length;lxdx++,lxdy++){  //判断左斜下方是否胜利
            if (qp[lxdy][lxdx].equals(color)) {
                lqxsum++;
            }
            else{
                break;
            }
            if (lqxsum >= 5) {
                return true;
            }
        }
        return false;
    }
    public static boolean rlincline(int x,int y,String color){  //判断右斜是否胜利
        int rqxsum=1;
        for(int rxux=x+1,rxuy=y-1;rxux<qp.length&&rxuy>=0;rxux++,rxuy--){   //判断右斜上方是否胜利
            if (qp[rxuy][rxux].equals(color)) {
                rqxsum++;
            }
            else{
                break;
            }
            if (rqxsum >= 5) {
                return true;
            }
        }
        for(int rxdx=x-1,rxdy=y+1;rxdx>=0&&rxdy<qp.length;rxdx--,rxdy++){  //判断右斜下方是否胜利
            if (qp[rxdy][rxdx].equals(color)) {
                rqxsum++;
            }
            else{
                break;
            }
            if (rqxsum >= 5) {
                return true;
            }
        }
        return false;
    }
}

7.2结果展示

制作棋盘及双方下棋

双方下棋及白棋胜利后重新开始游戏

检测棋子超出边界

检测重复位置落子

以上为简易五子棋的制作过程。

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;