阵列编程 - 检查Tic Tac Toe游戏中的获胜者,获得n个玩家的nxn棋盘

时间:2013-12-05 12:20:51

标签: java arrays debugging

我正在为nxn板上的n个玩家制作一个tic tac toe游戏,但获胜条件是连续3个。我到目前为止解决这个问题的方法是:当一个移动时,程序将检查以下方块是否连续3个。

(x-1,y+1) (x,y+1) (x+1,y+1)

 (x-1,y)   (x,y)   (x+1,y)

(x-1,y-1) (x,y-1) (x+1,y-1)

它将检查顶部(x-1,y + 1)(x,y + 1)(x + 1,y + 1)底部(x-1,y-1)(x,y-1) (X + 1,Y-1)  边(x + 1,y + 1)(x + 1,y)(x + 1,y-1),(x-1,y + 1)(x-1,y)(x-1,y- 1),对角线和穿过中间(x,y)的对角线。

到目前为止,我的代码是:

   public int checkWinning() {
     for(int a = 1; a < size-1; a++){
        for(int b = 1; b < size-1; b++){
            if (board[a][b] == board[a+1][b] && board[a][b] == board[a-1][b]){
                return board[a][b];
            }else if(board[a][b] == board[a][b+1] && board[a][b] == board[a][b-1]){
                return board[a][b];
            }else if(board[a][b] == board[a+1][b-1] && board[a][b] == board[a-1][b+1]){
                return board[a][b];
            }else if(board[a][b] == board[a+1][b+1] && board[a][b] == board[a-1][b-1]){
                return board[a][b];
            }
        }
    }
    for(int d = 1; d < size-1; d++){
        if (board[0][d] == board[0][d-1] && board[0][d] == board[0][d+1]){
            return board[0][d];
        } else if (board[size-1][d] == board[size-1][d-1] && board[size-1][d] == board[size-1][d+1]){
            return board[size-1][d];
        }
    }

    for(int c = 1; c < size-1; c++){
        if (board[c][0] == board[c-1][0] && board[c][0] == board[c+1][0]){
            return board[c][0];
        }else if(board[c][size-1] == board[c-1][size-1] && board[c][size-1] == board[c+1][size-1]){
            return board[c][size-1];
            }
        }   
    return 0;
}

第一部分是我通过中间和对角线检查的部分。第二部分我检查顶部的底部和顶部和第三部分检查两侧。

当它返回0表示还没有赢家。

@override
public void checkResult() {
    int winner = this.board.checkWinning();
    if (winner > 0) {
        this.ui.showResult("Player "+winner+" wins!");
    }
    if (this.board.checkFull()) {
        this.ui.showResult("This is a DRAW!");
    }
}

Board [x] [y] - &gt;表示板的二维数组,坐标从左上角(0,0)到右下角(大小-1,大小-1)计数,板[x] [y] == 0表示位置自由( x,y),board [x] [y] == i for i&gt; 0代表玩家我在(x,y)上移动,只是你知道它。

我的问题是,当我将电路板扩展到大于3x3的大小时,程序会以某种方式自行覆盖它,或者每次都不会检查每个方面的顶部和底部,而且我看起来似乎不太原因。

3 个答案:

答案 0 :(得分:3)

编辑:

在应用程序中播放了几分钟...有趣的结果

java -jar tic-tac-toe.jar 5 20

It was a cats game!!

|1|1|5|5|1|3|5|3|1|5|2|5|1|1|2|
|2|3|2|3|1|5|3|5|3|2|3|1|5|2|2|
|5|4|5|4|1|5|5|4|2|1|4|5|4|2|2|
|3|2|1|5|5|5|2|4|5|3|4|1|2|4|2|
|3|4|1|2|5|4|1|1|4|5|1|3|3|4|1|
|1|5|4|4|3|2|5|1|3|5|1|3|5|3|4|
|2|5|1|4|3|3|3|5|3|1|1|4|3|4|4|
|1|4|5|1|1|5|4|5|2|4|1|1|5|4|3|
|1|3|2|1|4|2|4|3|3|4|5|2|4|3|3|
|5|1|1|3|3|4|4|4|2|2|1|4|3|2|5|
|2|2|3|1|5|5|4|1|3|5|3|2|3|3|2|
|2|4|2|4|4|1|3|1|1|3|1|2|1|2|2|
|2|5|5|1|4|3|4|5|5|4|5|3|3|5|2| 
|4|5|2|1|5|3|2|1|3|2|2|2|2|4|4|
|4|1|1|4|5|4|5|4|2|2|3|3|2|2|3|

Played 100 games:
Number wins by Player1: 0
Number wins by Player2: 0
Number wins by Player3: 0
Number wins by Player4: 0
Number wins by Player5: 0
Number of ties: 100

没有滚动浏览所有100场比赛以找到获胜的棋盘,但我认为这很有趣:

java -jar tic-tac-toe.jar 2 10

Player2 won the game!

|1|1|2|1|2|2| |2|1|2|
|2|2|2|2|2|2|2|2|2|2|
|2|1|2|2|2|1|1|1|1|1|
|1|1|1|1|2|1|2|1|1|1|
|2|2| |1|2|1|1|1|1|2|
|2|2|2|1|1|1| |1|2|2|
|2|2|1|2|2|2|2|2|1|1|
| | |2|2|2|2| |1|1|1|
|1|1|2|2|2|1|1|1|1| |
| | |1|1|1|1|1|2|1| |

Played 100 games:
Number wins by Player1: 0
Number wins by Player2: 1
Number of ties: 99

这确实回答了你的问题...但我把它拿了一点......决定实施解决方案。 而不是计算匹配...我只是从最后一个玩家玩的点开始检查,如果行列中的所有标记和诊断与玩家匹配,他就赢了。

package com.clinkworks.example;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TicTacToe {

    private static final String TIE = "TIE";

    private static final Map<String, Integer> gamesToWinsMap = new HashMap<String, Integer>();


    /**
     * accepts input in the following format:
     * 
     * playerCount rowCount columnCount (sets the game with the n players, n columns, and n rows)
     *      - java -jar tic-tac-toe.jar 2 3 3
     * PlayerCount squareSize (defaults to a game with rows and cols the same as squareSize and the player count given)
     *       - java -jar tic-tac-toe.jar 2 3
     * PlayerCount (defaults to a 3 by 3 game)
     *       - java -jar tic-tac-toe.jar 2
     * no input (defaults to a 3 by 3 game with 2 players)
     *       - java -jar tic-tac-toe.jar
     * @param args
     */
    public static void main(String[] args) {

        int playerCount = 2;
        int rows = 3;
        int cols = 3;

        if(args.length == 3){
            playerCount = Integer.valueOf(args[0]);
            rows = Integer.valueOf(args[1]);
            cols = Integer.valueOf(args[2]);
        }

        if(args.length == 2){
            playerCount = Integer.valueOf(args[0]);
            rows = Integer.valueOf(args[1]);
            cols = rows;
        }

            if(args.length == 1){
                    playerCount = Integer.valueOf(args[0]);
            }


        for(int i = 1; i <= playerCount; i++){
            gamesToWinsMap.put("Player" + i, 0);
        }

        //lets play 100 games and see the wins and ties
        playGames(100, playerCount, rows, cols);

        for(int i = 1; i <= playerCount; i++){
            System.out.println("Number wins by Player" + i + ": " + gamesToWinsMap.get("Player" + i));
        }

        System.out.println("Number of ties: " + gamesToWinsMap.get(TIE));
    }

    public static void playGames(int gamesToPlay, int playerCount, int rows, int cols) {
        //play a new game each iteration, in our example, count = 100;
        for (int i = 0; i < gamesToPlay; i++) {
            playGame(playerCount, rows, cols);
        }
    }

    public static void playGame(int playerCount, int rows, int cols) {
        //create a new game board. this initalizes our 2d array and lets the complexity of handling that
        // array be deligated to the board object.


        Board board = new Board(playerCount, rows, cols);

        //we are going to generate a random list of moves. Heres where we are goign to store it
        List<Move> moves = new ArrayList<Move>();

        //we are creating moves for each space on the board.
        for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++) {
                moves.add(new Move(row, col));
            }
        }

        //randomize the move list
        Collections.shuffle(moves);

        //do each move
        for (Move move : moves) {
            board.play(move);

            if(gameOver(board)){
                break;
            }
        }
    }

    public static boolean gameOver(Board board){
        if (board.whoWon() != null) {
            System.out.println(board.whoWon() + " won the game!");
            System.out.println(board);

            Integer winCount = gamesToWinsMap.get(board.whoWon());
            winCount = winCount == null ? 1 : winCount + 1;

            gamesToWinsMap.put(board.whoWon(), winCount);

            return true;

        } else if (board.movesLeft() == 0) {
            System.out.println("It was a cats game!!");
            System.out.println(board);

            Integer tieCount = gamesToWinsMap.get(TIE);
            tieCount = tieCount == null ? 1 : tieCount + 1;
            gamesToWinsMap.put(TIE, tieCount);

            return true;
        }

        return false;
    }

    public static class Move {
        private int row;
        private int column;

        public Move(int row, int column) {
            this.row = row;
            this.column = column;
        }

        public int getRow() {
            return row;
        }

        public int getColumn() {
            return column;
        }

    }

    public static class Board {

        private final int rowSize;
        private final int columnSize;
        private final Integer[][] gameBoard;
        private int playerCount;
        private int currentPlayer;
        private String winningPlayer;

        public Board() {
            gameBoard = new Integer[3][3];
            currentPlayer = 1;
            winningPlayer = null;
            this.rowSize = 3;
            this.columnSize = 3;
            playerCount = 2;
        }


        public Board(int players) {
            gameBoard = new Integer[3][3];
            currentPlayer = 1;
            winningPlayer = null;
            this.rowSize = 3;
            this.columnSize = 3;
            playerCount = players;
        }

        public Board(int rowSize, int columnSize) {
            gameBoard = new Integer[rowSize][columnSize];
            currentPlayer = 1;
            winningPlayer = null;
            playerCount = 2;
            this.rowSize = rowSize;
            this.columnSize = columnSize;
        }            

        public Board(int players, int rowSize, int columnSize) {
            gameBoard = new Integer[rowSize][columnSize];
            currentPlayer = 1;
            winningPlayer = null;
            playerCount = players;
            this.rowSize = rowSize;
            this.columnSize = columnSize;
        }



        /**
        * 
        * @return the amount of empty spaces remaining on the game board, or if theres a winning player, zero.
        */
        public int movesLeft() {

            if(whoWon() != null){
                return 0;
            }

            int moveCount = 0;
            for (int x = 0; x < getRowSize(); x++) {
                for (int y = 0; y < getColumnSize(); y++) {
                    moveCount += getMoveAt(x, y) == null ? 1 : 0;
                }
            }
            return moveCount;
        }

        /**
        * If someone won, this will return the winning player.
        * 
        * @return the winning player
        */
        public String whoWon() {
            return winningPlayer;
        }

        /**
        * This move allows the next player to choose where to place their mark.
        * 
        * @param row
        * @param column
        * @return if the game is over, play will return true, otherwise false.
        */
        public boolean play(Move move) {

            if (!validMove(move)) {
                // always fail early
                throw new IllegalStateException("Player " + getCurrentPlayer() + " cannot play at " + move.getRow() + ", " + move.getColumn() + "\n" + toString());
            }

            doMove(move);

            boolean playerWon = isWinningMove(move);

            if (playerWon) {
                winningPlayer = "Player" + getCurrentPlayer();
                return true;
            }

            shiftPlayer();

            boolean outOfMoves = movesLeft() <= 0;

            return outOfMoves;
        }

        public int getRowSize() {
            return rowSize;
        }

        public int getColumnSize() {
            return columnSize;
        }

        public int getCurrentPlayer() {
            return currentPlayer;
        }

        public Integer getMoveAt(int row, int column) {
            return gameBoard[row][column];
        }

        private void doMove(Move move) {
            gameBoard[move.getRow()][move.getColumn()] = getCurrentPlayer();
        }

        private void shiftPlayer() {
            if(getCurrentPlayer() == getPlayerCount()){
                currentPlayer = 1;
            }else{
                currentPlayer++;
            }
        }

        private int getPlayerCount() {
            return playerCount;
        }


        private boolean validMove(Move move) {
            boolean noMoveAtIndex = false;
            boolean indexesAreOk = move.getRow() >= 0 || move.getRow() < getRowSize();
            indexesAreOk = indexesAreOk && move.getColumn() >= 0 || move.getColumn() < getColumnSize();
            if (indexesAreOk) {
                noMoveAtIndex = getMoveAt(move.getRow(), move.getColumn()) == null;
            }
            return indexesAreOk && noMoveAtIndex;
        }

        private boolean isWinningMove(Move move) {
            // since we check to see if the player won on each move
            // we are safe to simply check the last move
            return winsDown(move) || winsAcross(move) || winsDiagnally(move);
        }

        private boolean winsDown(Move move) {
            boolean matchesColumn = true;

            for (int i = 0; i < getColumnSize(); i++) {
                Integer moveOnCol = getMoveAt(move.getRow(), i);
                if (moveOnCol == null || getCurrentPlayer() != moveOnCol) {
                    matchesColumn = false;
                    break;
                }
            }

            return matchesColumn;
        }

        private boolean winsAcross(Move move) {
            boolean matchesRow = true;
            for (int i = 0; i < getRowSize(); i++) {
                Integer moveOnRow = getMoveAt(i, move.getColumn());
                if (moveOnRow == null || getCurrentPlayer() != moveOnRow) {
                    matchesRow = false;
                    break;
                }
            }
            return matchesRow;
        }

        private boolean winsDiagnally(Move move) {
            // diagnals we only care about x and y being teh same...
            // only perfect squares can have diagnals
            // so we check (0,0)(1,1)(2,2) .. etc
            boolean matchesDiagnal = false;
            if (isOnDiagnal(move.getRow(), move.getColumn())) {
                matchesDiagnal = true;
                for (int i = 0; i < getRowSize(); i++) {
                    Integer moveOnDiagnal = getMoveAt(i, i);
                    if (moveOnDiagnal == null || moveOnDiagnal != getCurrentPlayer()) {
                        matchesDiagnal = false;
                        break;
                    }
                }
            }

            return matchesDiagnal;
        }

        private boolean isOnDiagnal(int x, int y) {
            if (boardIsAMagicSquare()) {
                return x == y;
            } else {
                return false;
            }
        }

        private boolean boardIsAMagicSquare() {
            return getRowSize() == getColumnSize();
        }

        public String toString() {
            StringBuffer stringBuffer = new StringBuffer();
            for(int y = 0; y < getColumnSize(); y++) {
                for(int x = 0; x < getRowSize(); x++) {
                    Integer move = getMoveAt(x, y);
                        String moveToPrint = "";
                    if (move == null) {
                        moveToPrint = " ";
                    } else {
                        moveToPrint = move.toString();
                    }
                    stringBuffer.append("|").append(moveToPrint);
                }
                stringBuffer.append("|\n");
            }
            return stringBuffer.toString();
        }
    }
}

答案 1 :(得分:0)

我必须修改我的答案。如果你想要连续三个,无论你的电路板大小如何,你的循环代码可能就足够了,但是你总是在检查字段的值是否相同但是从来没有区别和非空字段。

所以“空”也可以获胜,这将有效地隐藏玩家的可能胜利。换句话说,即使字段大小为3,您的代码也无法正常工作。你没有对它进行足够的测试。

如果我将电路板初始化为

int[][] board={
    { 1, 1, 1 },
    { 0, 0, 0 },
    { 0, 0, 0 },
};

您的代码返回0,因为第二行包含三个零。我假设0表示空字段,但“空”的实际值无关紧要。您必须从三行检查中排除空字段。

答案 2 :(得分:0)

你可以通过稍微打破逻辑来简化这个数量。

首先要意识到你只需要检查你刚放置的那个部分的胜利。

现在我们需要一种方法来检查这一举动是否是赢家。

首先,我们需要一个简单的函数来检查一个单元格是否与给定值匹配,如果它在边界内并匹配则返回true。

 private boolean cellMatches(int x, int y, int val) {
    if (x<0||x>boardWidth)
       return false;
    if (y<0||y>boardHeight)
       return false;
    return board[x][y]==val;
 }

现在是一个函数,你给出一个起始位置(x和y)和一个delta(dx,dy),它会在该方向上检查最多两个单元格,返回一行中匹配值的数量。对于两次检查,for循环可能有点过分,但它可以很容易地扩展到更长的行使用。

private int countMatches(int x, int y, int dx, int dy, int val) {
   int count = 0;
   for (int step=1;step<=2;step++) {
     if (cellMatches(x+dx*step, y+dy*step, val) {
       count++;
     } else {
       return count;
     }
   }
   return count;
}

现在我们可以使用前面的方法了。当我们放置一个新作品时,我们可以在每个匹配的方向上计算出来。合计计数是连续的总数。 (即连续两个顶部+ 1个机器人=总运行长度为4)。如果这些运行长度中的任何一个是3,那么这是一个成功的举动。

private boolean makeMove(int x, int y, int val) {
   board[x][y] = val;
   int runlength=countMatches(x,y,0,1,val) + countMatches(x,y,0,-1,val);
   if (runLength >= 2)
      return true;
   int runlength=countMatches(x,y,1,0,val) + countMatches(x,y,-1,0,val);
   if (runLength >= 2)
      return true;
   int runlength=countMatches(x,y,1,1,val) + countMatches(x,y,-1,-1,val);
   if (runLength >= 2)
      return true;
   int runlength=countMatches(x,y,1,-1,val) + countMatches(x,y,-1,1,val);
   if (runLength >= 2)
      return true;
   return false;
}

请注意,因为我们需要计算我们放置的中心部分,所以我们只需要两个或更多的运行长度。