(Java)使用2维数组的Tic-Tac-Toe游戏

时间:2016-10-09 16:30:12

标签: java arrays

在课堂上,我们的任务是创建一个二维数组并围绕它创建一个井字游戏。除了显示整个棋盘已满并且游戏是平局时,我已经完成了所有工作。我尝试过一些东西,但我没有找到解决方案,我需要一些帮助...这是我的代码:

import java.util.Scanner;

public class TicTacToe {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int row, column;
        char player = 'X';

        //create 2 dimensional array for tic tac toe board
        char[][] board = new char[3][3];
        char ch = '1';
        for (int i = 0; i < 3; i++){
            for (int j = 0; j < 3; j++) {
                board[i][j] = ch++;
            }
        }
        displayBoard(board);
        while(!winner(board) == true){

            //get input for row/column
            System.out.println("Enter a row and column (0, 1, or 2); for player " + player + ":");
            row = in.nextInt();
            column = in.nextInt();

            //occupied
            while (board[row][column] == 'X' || board[row][column] == 'O') {
                System.out.println("This spot is occupied. Please try again");
            }
            //place the X
            board[row][column] = player;
            displayBoard(board);

            if (winner(board)){
                System.out.println("Player " + player + " is the winner!");
            }

            //time to swap players after each go.
            if (player == 'O') {
                player = 'X';

            }
            else {
                player = 'O';
            }
            if (winner(board) == false) {
            System.out.println("The game is a draw. Please try again.");

        }

    }

    private static void displayBoard(char[][] board) {
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                if (j == board[i].length - 1) System.out.print(board[i][j]);
                else System.out.print( board[i][j] + " | ");
            }
            System.out.println();
        }


    }
    //method to determine whether there is an x or an o in the spot
    public static Boolean winner(char[][] board){
        for (int i = 0; i< board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] == 'O' || board[i][j] == 'X') {
                    return false;
                }
            }
        }

        return (board[0][0] == board [0][1] && board[0][0] == board [0][2]) ||
            (board[0][0] == board [1][1] && board[0][0] == board [2][2]) ||
            (board[0][0] == board [1][0] && board[0][0] == board [2][0]) ||
            (board[2][0] == board [2][1] && board[2][0] == board [2][2]) ||
            (board[2][0] == board [1][1] && board[0][0] == board [0][2]) ||
            (board[0][2] == board [1][2] && board[0][2] == board [2][2]) ||
            (board[0][1] == board [1][1] && board[0][1] == board [2][1]) ||
            (board[1][0] == board [1][1] && board[1][0] == board [1][2]);
    }
}

我想要输出说当电路板已满时电路板已满,但我什么都没得到。这是我输出的最后一行,正如您所看到的,我当前的策略不起作用,因为它继续要求输入。 - &GT;

输入行和列(0,1或2);对于玩家X: 2 0 X | O | X O | O | X X | X | Ø 输入行和列(0,1或2);对于球员O:

5 个答案:

答案 0 :(得分:2)

首先关闭:

 while (board[row][column] == 'X' || board[row][column] == 'O') {
            System.out.println("This spot is occupied. Please try again");
        }

这将创建一个无限循环,因为rowcolumn不应该改变,你应该要求新的输入!

另外

public static Boolean winner(char[][] board){
    for (int i = 0; i< board.length; i++) {
        for (int j = 0; j < board[0].length; j++) {
            if (board[i][j] == 'O' || board[i][j] == 'X') {
                return false;
            }
        }
    }

一旦你点击“O&#39;或者&#39; X&#39;您将使用false(无赢家)

退出Method

您可能想要检查的是每个地点是否被占用

public static Boolean winner(char[][] board){
   //Boolean which is true until there is a empty spot
   boolean occupied = true;
   //loop and check if there is empty space or if its a draw
    for (int i = 0; i< board.length; i++) {
        for (int j = 0; j < board[0].length; j++) {
            //Check if spot is not 'O' or not 'X' => empty 
            if (board[i][j] != 'O' || board[i][j] != 'X') {
                occupied = false;
            }
        }
    }
    if(occupied)
        return false;
   //Check if someone won
    return (board[0][0] == board [0][1] && board[0][0] == board [0][2]) ||
        (board[0][0] == board [1][1] && board[0][0] == board [2][2]) ||
        (board[0][0] == board [1][0] && board[0][0] == board [2][0]) ||
        (board[2][0] == board [2][1] && board[2][0] == board [2][2]) ||
        (board[2][0] == board [1][1] && board[0][0] == board [0][2]) ||
        (board[0][2] == board [1][2] && board[0][2] == board [2][2]) ||
        (board[0][1] == board [1][1] && board[0][1] == board [2][1]) ||
        (board[1][0] == board [1][1] && board[1][0] == board [1][2]);
}

现在可以检查是否有赢家或其平局

Occupied == true == tie == return false

Winner == return true

但你有三种状态:

  • NotFinished

使用更改后的方法,在获胜之前,您将无法完成游戏。

原因:

 while(!winner(board) == true)

只要没有赢家,这就会让游戏运行起来 (赢家()将是假的,因为一切都被占用或没有赢家)

while(!false==true) => while(true) 

你可以写一个类似于胜利者的方法,但它只检查董事会是否有空位:

public static Boolean hasEmptySpot(char[][] board){
   //loop and check if there is empty space 
    for (int i = 0; i< board.length; i++) {
        for (int j = 0; j < board[0].length; j++) {
            if (board[i][j] != 'O' && board[i][j] != 'X') {
                return true;
            }
        }
    }
    return false;
}

//New code 
while(hasEmptySpot(board) || !winner(board)){
          //Your code for the game here
     ....
    }

当没有空位时,这将结束游戏 完成游戏后,你可以打电话给胜利者(董事会),如果你并列或赢了,它将会回来!

通过创建hasEmptySpot(),您可以将获胜方法更改为

public static Boolean winner(char[][] board){
    return (board[0][0] == board [0][1] && board[0][0] == board [0][2]) ||
        (board[0][0] == board [1][1] && board[0][0] == board [2][2]) ||
        (board[0][0] == board [1][0] && board[0][0] == board [2][0]) ||
        (board[2][0] == board [2][1] && board[2][0] == board [2][2]) ||
        (board[2][0] == board [1][1] && board[0][0] == board [0][2]) ||
        (board[0][2] == board [1][2] && board[0][2] == board [2][2]) ||
        (board[0][1] == board [1][1] && board[0][1] == board [2][1]) ||
        (board[1][0] == board [1][1] && board[1][0] == board [1][2]);
}

为什么呢? 因为你完成了游戏并且你知道只有两种可能的结果Win或Tie。

我希望这对你有所帮助。

修改 我自己有一个逻辑错误!

第一个错误: 你还需要检查游戏运行时是否有赢家忘记了这一点!

while(hasEmptySpot(board) || !winner(board)){
}

现在,当有赢家或没有留下空白点时,这将退出游戏循环

第二个错误: 在hasEmptySpot()

 if (board[i][j] != 'O' && board[i][j] != 'X') {
                return true;

不是

 if (board[i][j] != 'O' || board[i][j] != 'X') {
                return true;

修正了上面的例子。

对不起给我很抱歉!

答案 1 :(得分:1)

执行此操作的最有效方法是保持先前已填充的空间数的运行计数,并在每次占用空间时增加该计数。当计数达到9时,董事会可被视为已满。

如果您熟悉面向对象的编程,我认为如果将2D数组包装在Board类中,您会发现这更容易实现。

示例:

public static class Board {
    private char[][] spaces = new char[3][3];
    private int numMoves = 0;

    public void makeMove(int row, int col, char player) {
        if (spaces[row][col] == 'X' || spaces[row][col] == 'O') {
            System.out.println("This spot is occupied. Please try again");
        } else {
            spaces[row][col] = player;
            numMoves++;
        }
    }

    public boolean isFull() {
        return numMoves == 9;
    }

    public boolean hasWinner() {
        ...
    }

    public void display() {
        ...
    }
}

答案 2 :(得分:0)

您可以尝试合并一种新方法,例如:

public Boolean boardFull()
{
    short count = 0;
    for(short i = 0; i < 3; i++){
        for(short j = 0; j < 3; j++){
            if(board[i][j] == ‘O’ || board[i][j] == ’X’){
                count++;
            } else {
                continue;
            }
        }
    }

    if(count == 9){
        return true;
    } else {
        return false;
    }
}

你可以使用if语句来查看它是否返回true然后打印出来的话。

答案 3 :(得分:0)

解决方案

无效的代码是winner()方法。如果至少有一个单元被占用,它总是返回false。您可以根据Nordiii's answer的最后一部分继续进行。

额外问题

细胞检查循环

检查单元格是否被占用的代码是无限的。您需要使用'if'语句而不是'while'循环:

if(board[row][column] == 'X' || board[row][column] == 'O'){
    System.out.println("This spot is occupied. Please try again");
    continue;
}

你的旧代码卡住了,总是检查1个单元是否被占用,它总是返回true,这使循环保持活动状态并淹没你的控制台。 continue语句将退出其他'while'循环的当前迭代并开始新的迭代,从而要求新的输入。

例外

男人,这是很多未被捕获的例外!如果我搞砸了我的意见,那就去吧!整件事都失败了。只需为输入检查代码添加try块:

try {
    row = in.nextInt();
    column = in.nextInt();

    // Attempt to place player (an ArrayOutOfBoundsException could be thrown)
    if(board[row][column] == 'X' || board[row][column] == 'O'){
        System.out.println("This spot is occupied. Please try again");
        continue;
    }

    board[row][column] = player;
} catch(Exception e){
    System.out.println("I'm sorry, I didn't get that.");
    continue;
}

这会尝试在try语句中执行代码,如果有人输入了错误的内容,则异常会被“捕获”并创建新的迭代。天才!

答案 4 :(得分:0)

虽然已经有一些很好的答案,但我想发布另一个在其逻辑上更通用的解决方案,以确定获胜者。目前,当您为此编写更多通用逻辑时,您已经对一些可能的获胜方案进行了硬编码。

正如其他答案所指出的那样,你需要一种方法来检查电路板中未占用的空间,这将告诉你是否存在平局。我已经在下面的代码中实现了这样一个方法以及更通用的赢家逻辑。

请注意,某些方法是公开的,以便更容易测试,但它们不一定要公开。

import java.util.Scanner;

public class TicTacToe {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int row, column;
        char player = 'X';

        //create 2 dimensional array for tic tac toe board
        char[][] board = new char[3][3];
        char ch = '1';
        for (int i = 0; i < 3; i++){
            for (int j = 0; j < 3; j++) {
                board[i][j] = ch++;
            }
        }
        displayBoard(board);
        while(!winner(board) == true){

            //get input for row/column
            System.out.println("Enter a row and column (0, 1, or 2); for player " + player + ":");
            row = in.nextInt();
            column = in.nextInt();

            //occupied
            while (board[row][column] == 'X' || board[row][column] == 'O') {
                System.out.println("This spot is occupied. Please try again");
            }
            //place the X
            board[row][column] = player;
            displayBoard(board);

            if (winner(board)){
                System.out.println("Player " + player + " is the winner!");
            }

            //time to swap players after each go.
            if (player == 'O') {
                player = 'X';

            }
            else {
                player = 'O';
            }
            if (winner(board) == false && !hasFreeSpace(board)) {
                System.out.println("The game is a draw. Please try again.");
            }
        }

        //Don't forget to close the scanner.
        in.close();

    }

    public static void displayBoard(char[][] board) {
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                if (j == board[i].length - 1) System.out.print(board[i][j]);
                else System.out.print( board[i][j] + " | ");
            }
            System.out.println();
        }
    }

    /**
     * Determines whether the board is completely occupied by X and O characters
     * @param board the board to search through
     * @return true if entire board is populated by X or O, false otherwise.
     */
    public static boolean hasFreeSpace(char[][] board){
        for (int i = 0; i< board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] != 'O' && board[i][j] != 'X') {
                    return true;
                }
            }
        }
        return false;
    }

    //method to determine whether there is a winner
    public static boolean winner(char[][] board){
        return isHorizontalWin(board) || isVerticalWin(board) || isDiagonalWin(board);
    }

    /**
     * Determines if there is a winner by checking each row for consecutive
     * matching tokens.
     * @return true if there is a winner horizontally, false otherwise.
     */
    private static boolean isHorizontalWin(char[][] board) {
        for(int row = 0; row < board.length; row++){
            if(isWin(board[row]))
                return true;
        }
        return false;
    }

    /**
     * Determines whether all of the buttons in the specified array have the 
     * same text and that the text is not empty string.
     * @param lineToProcess an array of buttons representing a line in the grid
     * @return true if all buttons in the array have the same non-empty text, false otherwise.
     */
    private static boolean isWin(char[] lineToProcess) {
        boolean foundWin = true;
        char prevChar = '-';
        for(char character: lineToProcess) {
            if(prevChar == '-')
                prevChar = character;
            if ('O' != character && 'X' != character) {
                foundWin = false;
                break;
            } else if (prevChar != character) {
                foundWin = false;
                break;
            }
        }
        return foundWin;
    }

    /**
     * Determines whether there is a winner by checking column for consecutive
     * matching tokens.
     * @return true if there is a vertical winner, false otherwise.
     */
    private static boolean isVerticalWin(char[][] board) {
        char[] column = null;
      //assuming all rows have same legnth (same number of cols in each row), use first row
        for(int col = 0; col < board[0].length; col++){
            column = new char[board[0].length]; 
            for(int row = 0; row < column.length; row++){
                column[row] = board[row][col];
            }
            if(isWin(column))
                return true;
        }
        return false;
    }

    /**
     * Determines if there is a winner by checking each diagonal for consecutive
     * matching tokens.
     * @return true if a diagonal winner exists, false otherwise.
     */
    private static boolean isDiagonalWin(char[][] board) {

        int row = 0, col = 0;
        int cols = board.length;
        int rows = board[0].length; //assuming all rows are equal length so just use the first one

        //Create a one-dimensional array to represent the diagonal. Use the lesser
        // of the rows or columns to set its size. If the grid is rectangular then
        // a diagonal will always be the size of the lesser of its two dimensions.
        int size = rows < cols ? rows : cols;
        char[] diagonal = new char[size];

        //Since we know the grid is a square we really could just check one of
        // these - either row or col, but I left both in here anyway.
        while (row < rows && col < cols) {
            diagonal[col] = board[row][col];

            row++;
            col++;
        }
        if (isWin(diagonal)) {
            return true;
        }


        row = rows - 1;
        col = 0;
        diagonal = new char[size];
        while (row >=0 && col < cols) {
            diagonal[col] = board[row][col];
            row--;
            col++;
        }
        return isWin(diagonal);

    }
}