帮助橘麻学算法:有效的井字游戏

159 阅读4分钟

794.有效的井字游戏

一、题目描述

给你一个字符串数组board表示井字游戏的棋盘。当且仅当在井字游戏过程中,棋盘有可能达到board所显示的状态时,才返回true。

井字游戏的棋盘是一个3x3数组,有字符 XO组成。字符 表示一个空位。

以下是井字游戏的规则:

  • 玩家轮流将字符放入空位( )中
  • 玩家1总是放字符X,玩家2总是放字符O.
  • XO只允许放置在空位中,不允许对已放有字符的位置进行填充。
  • 当有3个相同(且非空)的字符填充任何行、列或对角线时,游戏结束。
  • 当所有位置非空时,也算为游戏结束。
  • 如果游戏结束,玩家不允许再放置字符。

二、大白话解释

毫不夸张的说,看见这道题的时候我是😳的~

读了不下10遍,才明白这道题到底要干嘛~

咱就是说,出题者何必呢???

好吧,没办法了。

我们先大声朗读一下题目描述,找一些关键信息:

  • 井字游戏有9个位置
  • 井字游戏有两个玩家:玩家1和玩家2
  • 玩家1和玩家2 轮流下棋
  • 玩家1只能在井字棋盘中填入X
  • 玩家2只能在井字棋盘中填入O
  • 玩家1先下棋
  • 只能在棋盘的空位置下棋
  • 游戏结束条件
    • 无玩家赢但棋盘满了
    • 有玩家赢了
  • 游戏结束了就不能再下棋了

分析完关键信息,我们再看一下这道题到底要考什么?

这道题主要是想让你判断字符串数组board是否是合法的井字游戏。其实说白了就是:将board字符串数组组成一个完整的字符串boardStr,该字符串只包含三种类型的字符(XO, )。玩家1和玩家2从boardStr中自己专属的字符放入井字棋盘。最后,判定board字符串数组包含的是三种类型的字符是否符合井字游戏的合法性。

那如何判定是合法的井字游戏呢?我给你大家写一下井字游戏的测试用例哈~

  • 有效井字游戏
    • 无人获胜情况
      • 棋盘满了:玩家1 下棋次数 - 玩家2 下棋次数 = 1
      • 棋盘未满:玩家1 下棋次数 = 玩家2 下棋次数
    • 有人获胜情况
      • 玩家1获胜 且 玩家1下棋次数 - 玩家2下棋次数 = 1
      • 玩家2获胜 且 玩家1下棋次数 = 玩家2下棋次数
  • 无效井字游戏
    • 无人获胜情况
      • 棋盘满了:玩家1下棋次数 - 玩家2下棋次数 != 1
      • 棋盘未满:玩家1下棋次数 != 玩家2下棋次数
    • 有人获胜情况
      • 玩家1获胜 且 玩家1下棋次数 - 玩家2下棋次数 != 1
      • 玩家2获胜 且 玩家1下棋次数 != 玩家2下棋次数
      • 玩家1 和 玩家2 同时获胜

三、算法实现

  • 计算玩家下棋次数
/**
 * 计算玩家下棋次数
 */
private static int calculateChessCount(String[] board,char player){
    String result = new String();
    for (String str : board) {
        result += str;
    }
    int count = 0;
    for (char c : result.toCharArray()) {
        if (c == player){
            count += 1;
        }
    }
    return count;
}
  • 判定玩家是否赢得游戏
/**
 * 判断是否有人获胜
 */
private static boolean informPlayer1WinTheGame(String[] board,char player){
    ```
return isRowWin(board,player) || isColumnWin(board,player) || isDiagonalWin(board,player);

}

  • 判断是否是某一行相同
/**
 * 判断是否是 行相同
 * @return
 */
private static boolean isRowWin(String[] board,char player){
    for (String str : board) {
        if (str.charAt(0) == str.charAt(1) && str.charAt(0) == str.charAt(2) && str.charAt(0) == player){
            return true;
        }
    }
    return false;
}
  • 判断是否是某一列相同
/**
 * 判断是否是 列相同
 * @return
 */
private static boolean isColumnWin(String[] board,char player){
    for (int i = 0; i < board.length; i++) {
        if (board[0].charAt(i) == board[1].charAt(i) && board[0].charAt(i) == board[2].charAt(i) && board[i].charAt(i) == player){
            return true;
        }
    }
    return false;
}
  • 判断是否是对角线相同
/**
 * 判断是否是对角线相同
 * @param board
 * @param player
 * @return
 */
private static boolean isDiagonalWin(String[] board,char player){
    boolean diagonal1Win = board[0].charAt(0) == board[1].charAt(1) && board[0].charAt(0) == board[2].charAt(2) && board[0].charAt(0) == player;
    boolean diagonal2Win = board[0].charAt(2) == board[1].charAt(1) && board[0].charAt(2) == board[2].charAt(0) && board[0].charAt(2) == player;

    return diagonal1Win || diagonal2Win;
}
  • 判断board中的字符串是否是有效井字游戏
private static boolean validTicTacToe(String[] board){
    if (null == board){
        return false;
    }
    //# 玩家1 下棋次数
    int player1Cnt = calculateChessCount(board,'X');
    //# 玩家2 下棋次数
    int player2Cnt = calculateChessCount(board,'O');
    //# 玩家1 获胜
    boolean player1Win = informPlayer1WinTheGame(board,'X');
    //# 玩家2 获胜
    boolean player2Win = informPlayer1WinTheGame(board,'O');


    //# 无人获胜
    if (!player1Win && !player2Win){
        return player1Cnt == player2Cnt || player1Cnt - player2Cnt == 1;
    }
    //# 不存在双方同时获胜
    if (player1Win && player2Win){
        return false;
    }
    //# 如果玩家1 获胜
    if (player1Win){
        return player1Cnt - player2Cnt == 1;
    }
    //# 如果玩家2 获胜
    if (player2Win){
        return player1Cnt == player2Cnt;
    }
    return false;
}

算法题做完了~

感谢观看~

希望能帮到有缘人!