1. 程式人生 > >348. Design Tic-Tac-Toe

348. Design Tic-Tac-Toe

Description

Design a Tic-tac-toe game that is played between two players on a n x n grid.

You may assume the following rules:

A move is guaranteed to be valid and is placed on an empty block. Once a winning condition is reached, no more moves is allowed. A player who succeeds in placing n of their marks in a horizontal, vertical, or diagonal row wins the game. Example: Given n = 3, assume that player 1 is “X” and player 2 is “O” in the board.

TicTacToe toe = new TicTacToe(3);

toe.move(0, 0, 1); -> Returns 0 (no one wins) |X| | | | | | | // Player 1 makes a move at (0, 0). | | | |

toe.move(0, 2, 2); -> Returns 0 (no one wins) |X| |O| | | | | // Player 2 makes a move at (0, 2). | | | |

toe.move(2, 2, 1); -> Returns 0 (no one wins) |X| |O| | | | | // Player 1 makes a move at (2, 2). | | |X|

toe.move(1, 1, 2); -> Returns 0 (no one wins) |X| |O| | |O| | // Player 2 makes a move at (1, 1). | | |X|

toe.move(2, 0, 1); -> Returns 0 (no one wins) |X| |O| | |O| | // Player 1 makes a move at (2, 0). |X| |X|

toe.move(1, 0, 2); -> Returns 0 (no one wins) |X| |O| |O|O| | // Player 2 makes a move at (1, 0). |X| |X|

toe.move(2, 1, 1); -> Returns 1 (player 1 wins) |X| |O| |O|O| | // Player 1 makes a move at (2, 1). |X|X|X| Follow up: Could you do better than O(n2) per move() operation?

Solution

設計一個tic-tac-toe遊戲,初始化一個遊戲,並在每次move之後判斷是否有人獲勝。

Use a two-dimensional array to store game status. After each move, judge is there somebody wined in this game.

Code

class TicTacToe {
    int[][] board;
    /** Initialize your data structure here. */
    public TicTacToe(int n) {
        board = new int[n][n];
    }
    
    /** Player {player} makes a move at ({row}, {col}).
        @param row The row of the board.
        @param col The column of the board.
        @param player The player, can be either 1 or 2.
        @return The current winning condition, can be either:
                0: No one wins.
                1: Player 1 wins.
                2: Player 2 wins. */
    public int move(int row, int col, int player) {
        board[row][col] = player;
        if(win(player)){
            return player;
        }
        return 0;
    }
    
    private boolean win(int player){
        for (int i = 0; i < board.length; i++){
            boolean lined = true;
            for (int j = 0; j < board.length; j++){
                if (board[i][j] != player){
                    lined = false;
                }
            }
            if(lined){
                return true;
            }
        }
        
        for (int i = 0; i < board.length; i++){
            boolean lined = true;
            for (int j = 0; j < board.length; j++){
                if (board[j][i] != player){
                    lined = false;
                }
            }
            if(lined){
                return true;
            }
        }
        
        boolean lined = true;
        for (int i = 0, j = 0; i < board.length;){
            if (board[i][j] != player){
                lined = false;
            }
            i++;
            j++;
        }
        if (lined){
            return true;
        }
        lined = true;
        for (int i = board.length - 1, j = 0; i >= 0;){
            if (board[i][j] != player){
                lined = false;
            }
            i--;
            j++;
        }
        if (lined){
            return true;
        }
        else{
            return false;
        }
    }
}

/**
 * Your TicTacToe object will be instantiated and called as such:
 * TicTacToe obj = new TicTacToe(n);
 * int param_1 = obj.move(row,col,player);
 */

Time Complexity: O(n^2) Space Complexity: O(n^2)

Review

The point is we do not need to maintain a whole board. For each row , col and diagonal, we could assign 1 and -1 to player 1 and player 2. If a row or col is occupied with same player, that is a win. So we could optimized move to O(1) time complexity and O(n) space complexity.

class TicTacToe {

    private int[] rows;
    private int[] cols;
    private int diagonal;
    private int anti;
    /** Initialize your data structure here. */
    public TicTacToe(int n) {
        rows = new int[n];
        cols = new int[n];
    }
    
    /** Player {player} makes a move at ({row}, {col}).
        @param row The row of the board.
        @param col The column of the board.
        @param player The player, can be either 1 or 2.
        @return The current winning condition, can be either:
                0: No one wins.
                1: Player 1 wins.
                2: Player 2 wins. */
    public int move(int row, int col, int player) {
        int move = player == 1 ? 1 : -1;
        int size = rows.length;
        rows[row] += move;
        cols[col] += move;
        if (row == col){
            diagonal += move;
        }
        if ((row + col + 1) == size){
            anti += move;
        }
        
        if (Math.abs(rows[row]) == size || Math.abs(cols[col]) == size || Math.abs(diagonal) == size || Math.abs(anti) == size){
            return player;
        }
        else{
            return 0;
        }
    }
}

/**
 * Your TicTacToe object will be instantiated and called as such:
 * TicTacToe obj = new TicTacToe(n);
 * int param_1 = obj.move(row,col,player);
 */