阵列编程-在一个有n名玩家的nxn板的Tic-Tac-Toe游戏中检查获胜者



我正在为nxn板上的n个玩家制作一个井字游戏,但获胜条件是连续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)(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]->表示棋盘的二维数组,坐标从左上角(0,0)到右下角(size-1,size-1)计数,Board[x][y=0表示在位置(x,y)自由,Board[x][y]==i表示i>0表示玩家i在(x,y)上移动,所以你知道。

我的问题是,当我将电路板扩展到大于3x3的尺寸时,程序会以某种方式自行覆盖它,或者a每次都不会检查上下两侧的所有东西,我似乎不太明白为什么。

编辑:

使用该应用程序玩了几分钟。。。有趣的结果

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();
        }
    }
}

我必须修改我的答案。如果你想让三个排成一行,而不管你的电路板大小,你的循环代码可能就足够了,但你总是在检查字段的值是否相同,但永远不会在空字段和非空字段之间产生差异。

因此,"空"也可以获胜,这将有效地隐藏玩家可能的胜利。换句话说,即使字段大小为3,代码也不能正常工作。你测试得不够。

如果我将板初始化为

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

您的代码返回0,因为第二行包含三个零。我假设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)。如果其中任何一个跑长是三,那么这就是一个获胜的动作。

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;
}

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

最新更新