【问题标题】:Sorting through 2D array for Tic Tac Toe winner对井字游戏获胜者的二维数组进行排序
【发布时间】:2022-01-15 08:15:19
【问题描述】:

我用这种非常令人讨厌的方式在井字游戏中找到获胜者,我只是想知道是否有更简单的方法来做到这一点。 这是我目前使用的方法,正如您所见,它非常多余和重复。任何缩小范围的技巧都会很棒。我在想也许嵌套的 for 循环可能会起作用,但不完全确定如何在其中进行设置。

public static boolean isGameOver(char[][] gameBoard) {

    //Testing for Horizontal Win
    if(gameBoard[0][0] == 'X' && gameBoard[0][2] == 'X' && gameBoard [0][4] == 'X') {
        System.out.println("Player Wins!\n");
        playerScore++;
        return true;
    }
    if(gameBoard[0][0] == 'O' && gameBoard[0][2] == 'O' && gameBoard [0][4] == 'O') {
        System.out.println("CPU Wins!\n");
        cpuScore++;
        return true;
    }
    if(gameBoard[2][0] == 'X' && gameBoard[2][2] == 'X' && gameBoard [2][4] == 'X') {
        System.out.println("Player Wins!\n");
        playerScore++;
        return true;
    }
    if(gameBoard[2][0] == 'O' && gameBoard[2][2] == 'O' && gameBoard [2][4] == 'O') {
        System.out.println("CPU Wins!\n");
        cpuScore++;
        return true;
    }
    if(gameBoard[4][0] == 'X' && gameBoard[4][2] == 'X' && gameBoard [4][4] == 'X') {
        System.out.println("Player Wins!\n");
        playerScore++;
        return true;
    }
    if(gameBoard[4][0] == 'O' && gameBoard[4][2] == 'O' && gameBoard [4][4] == 'O') {
        System.out.println("CPU Wins!\n");
        cpuScore++;
        return true;
    }

    //Testing for Vertical Win
    if(gameBoard[0][0] == 'X' && gameBoard[2][0] == 'X' && gameBoard [4][0] == 'X') {
        System.out.println("Player Wins!\n");
        playerScore++;
        return true;
    }
    if(gameBoard[0][0] == 'O' && gameBoard[2][0] == 'O' && gameBoard [4][0] == 'O') {
        System.out.println("CPU Wins!\n");
        cpuScore++;
        return true;
    }
    if(gameBoard[0][2] == 'X' && gameBoard[2][2] == 'X' && gameBoard [4][2] == 'X') {
        System.out.println("Player Wins!\n");
        playerScore++;
        return true;
    }
    if(gameBoard[0][2] == 'O' && gameBoard[2][2] == 'O' && gameBoard [4][2] == 'O') {
        System.out.println("CPU Wins!\n");
        cpuScore++;
        return true;
    }
    if(gameBoard[0][4] == 'X' && gameBoard[2][4] == 'X' && gameBoard [4][4] == 'X') {
        System.out.println("Player Wins!\n");
        playerScore++;
        return true;
    }
    if(gameBoard[0][4] == 'O' && gameBoard[2][4] == 'O' && gameBoard [4][4] == 'O') {
        System.out.println("CPU Wins!\n");
        cpuScore++;
        return true;
    }

    //Testing for Diagonal Win
    if(gameBoard[0][0] == 'X' && gameBoard[2][2] == 'X' && gameBoard [4][4] == 'X') {
        System.out.println("Player Wins!\n");
        playerScore++;
        return true;
    }
    if(gameBoard[0][0] == 'O' && gameBoard[2][2] == 'O' && gameBoard [4][4] == 'O') {
        System.out.println("CPU Wins!\n");
        cpuScore++;
        return true;
    }
    if(gameBoard[4][0] == 'X' && gameBoard[2][2] == 'X' && gameBoard [0][4] == 'X') {
        System.out.println("Player Wins!\n");
        playerScore++;
        return true;
    }
    if(gameBoard[4][0] == 'O' && gameBoard[2][2] == 'O' && gameBoard [0][4] == 'O') {
        System.out.println("CPU Wins!\n");
        cpuScore++;
        return true;
    }

    //Testing for Tie
    if(gameBoard[0][0] != ' ' && gameBoard[0][2] != ' ' && gameBoard[0][4] != ' ' &&
            gameBoard[2][0] != ' ' && gameBoard[2][2] != ' ' && gameBoard[2][4] != ' ' &&
            gameBoard[4][0] != ' ' && gameBoard[4][2] != ' ' && gameBoard[4][4] != ' ') {
        System.out.println("It's a tie!!!\n");
        numOfTies++;
        return true;
    }
    return false;
}

【问题讨论】:

    标签: java arrays tic-tac-toe


    【解决方案1】:

    好吧,我有点得意忘形了。但也许你可以使用这里提出的一些想法。我的主要目标是做到这一点,这样每次移动后都不需要检查整个棋盘。这是在程序设计阶段最好考虑的问题类型。

    • 我创建了一个TriGroup 类(它本质上是一个用于保存连续移动的可变字符串。
    • 然后使用地图来保存所有具有共同坐标的分组。
    • 进行移动时,这些分组会附加当前玩家。
    • 并检查该玩家是否获胜。
    • 此程序将使用随机动作自行运行,从而产生胜利或平局。

    有些边境案件可能被忽略了。

    public class TicTacToeCheck {
        int moveCount = 0;
        static int MAX_MOVES = 27;
        class TriGroup {
            public String group = "";
            
            @Override
            public String toString() {
                return group;
            }
        }
        
        TriGroup row1 = new TriGroup();
        TriGroup row2 = new TriGroup();
        TriGroup row3 = new TriGroup();
        TriGroup col1 = new TriGroup();
        TriGroup col2 = new TriGroup();
        TriGroup col3 = new TriGroup();
        TriGroup diag1 = new TriGroup();
        TriGroup diag2 = new TriGroup();
        
        Map<String, List<TriGroup>> commonGroupings = new HashMap<>();
        {
            commonGroupings.put("00", List.of(row1, col1, diag1));
            commonGroupings.put("02", List.of(row1, col2));
            commonGroupings.put("04", List.of(row1, col3));
            
            commonGroupings.put("20", List.of(row2, col1));
            commonGroupings.put("22", List.of(row2, col2, diag1, diag2));
            commonGroupings.put("24", List.of(row2, col3));
            
            commonGroupings.put("40", List.of(row3, col1, diag1));
            commonGroupings.put("42", List.of(row3, col2));
            commonGroupings.put("44", List.of(row3, col3));
        }
        
        public static void main(String[] args) {
            new TicTacToeCheck().start();
        }
        
        public void start() {
            
            char player = 'X';
            Random r = new Random();
            outer: while (moveCount < MAX_MOVES) {
                commonGroupings.entrySet().forEach(System.out::println);
                
                System.out.println();
                int row = r.nextInt(3) * 2;
                int col = r.nextInt(3) * 2;
                System.out.println("Move: " + row + ", " + col);
                player = player == 'X' ? 'O' : 'X';
                char val;
                switch (val = recordMove(row, col, player)) {
                    case 'X' -> {
                        System.out.println("X wins!");
                        break outer;
                    }
                    case 'O' -> {
                        System.out.println("O wins!");
                        break outer;
                    }
                    case 0 -> {
                        System.out.println("Tie!");
                        break outer;
                    }
                    
                    default -> {
                    }
                    
                }
            }
            commonGroupings.entrySet().forEach(System.out::println);
        }
        
        public char recordMove(int row, int col, char c) {
            moveCount++;
            
            for (TriGroup tri : commonGroupings.get(row + "" + col)) {
                if (tri.group.length() > 2) {
                    // just ignore the row/col and try the next
                    continue;
                }
                
                // update group
                tri.group += c;
                if (tri.group.equals(c + "" + c + "" + c)) {
                    return c;
                }
                
            }
            if (moveCount == MAX_MOVES) {
                return 0;
            }
            return '#';
        }
    }
    

    【讨论】:

    • 我真的很喜欢这种方法(你有一个目标,你成功了;而且代码很漂亮)。但是,我认为作为对 OP 问题的回答,这太过分了。简单就是好的,特别是在游泳池的浅水区。
    【解决方案2】:

    此版本使用 2 个辅助的私有方法来减少代码重复性,而不会改变调用 isGameOver 的行为。主要观察结果是,通过O 检查是否获胜或通过X 检查获胜之间几乎没有区别——只有一个字符。这样就变成了checkWins。下一个观察结果是,检查棋盘上相邻的 3 个位置涉及大量重复。如果你给我expect 的字符,从哪里开始,接下来看哪里(dcoldrow),就变成了allEqual

    您的代码跳过了棋盘的不均匀位置;我的代码没有。我觉得将展示(“你如何向用户展示东西”)与模型(“你如何在内部展示东西”)混为一谈是错误的;所以我的代码目前不是你的替代品,但可以通过调整 checkWins 中的值快速修复为这样的替代品(对角线向下将是 0, 0, 2, 2,依此类推)。

    请注意,就效率而言,您的代码可能更快。但我发现这个版本更短、更易读,因此更易于调试和维护。

    private static boolean allEqual(char expected, char[][] b, 
                                    int row, int col, int drow, int dcol) {
        for (int i=0; i<b[0].length; i++) {
            if (b[row][col] != expected) return false;
            row += drow;
            col += dcol;
        }
        return true;
    }
    
    private static boolean checkWins(char playerChar, char[][]b) {
        boolean win = allEqual(playerChar, b, 0, 0, 0, 1)  // 1st row 
                   || allEqual(playerChar, b, 1, 0, 0, 1) 
                   || allEqual(playerChar, b, 2, 0, 0, 1)  // 3rd row
                   || allEqual(playerChar, b, 0, 0, 1, 0)  // 1st col
                   || allEqual(playerChar, b, 0, 1, 1, 0) 
                   || allEqual(playerChar, b, 0, 2, 1, 0)  // 3rd col
                   || allEqual(playerChar, b, 0, 0, 1, 1)  // diagonal down
                   || allEqual(playerChar, b, 2, 0, 1,-1); // diagonal up
        return win;
    }
    
    public static boolean isGameOver(char[][] gameBoard) {
        if (checkWins('X', gameBoard)) {
            System.out.println("Player Wins!\n");
            playerScore ++;
            return true;
        } else if (checkWins('O', gameBoard)) {
            System.out.println("CPU Wins!\n");
            cpuScore ++;
            return true;
        } else {
            return false;
        }
    }
    

    【讨论】:

      【解决方案3】:

      看看这个: https://www.geeksforgeeks.org/tic-tac-toe-game-in-java/

      添加gameBoard[x][y] 的字符串并在switch 语句中检查它们。 如果复合字符串等于XXXOOO,则可以返回获胜者。

      对于您的代码,如下所示:

      for (int a = 0; a < 8; a++) {
                  String line = null;
        
                  switch (a) {
                  case 0:
                      line = gameBoard[0][0] + gameBoard[0][1] + gameBoard[0][2];
                      break;
                  case 1:
                      line = gameBoard[1][0] + gameBoard[1][1] + gameBoard[1][2];
                      break;
                  case 2:
                      line = gameBoard[2][0] + gameBoard[2][1] + gameBoard[2][2];
                      break;
                  case 3:
                      line = gameBoard[0][0] + gameBoard[1][0] + gameBoard[2][0];
                      break;
                  case 4:
                      line = gameBoard[0][1] + gameBoard[1][1] + gameBoard[2][1];
                      break;
                  case 5:
                      line = gameBoard[0][2] + gameBoard[1][2] + gameBoard[2][2];
                      break;
                  case 6:
                      line = gameBoard[0][0] + gameBoard[1][1] + gameBoard[2][2];
                      break;
                  case 7:
                      line = gameBoard[0][2] + gameBoard[1][1] + gameBoard[2][0];
                      break;
                  }
                  //For X winner
                  if (line.equals("XXX")) {
                      return "X";
                  }
                    
                  // For O winner
                  else if (line.equals("OOO")) {
                      return "O";
                  }
              }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-02
        • 1970-01-01
        • 2023-03-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多