|
| 1 | +#!/usr/bin/env python |
| 2 | + |
| 3 | +import sys |
| 4 | + |
| 5 | +# Map from max player -> values for winners. If X' is the max player, then |
| 6 | +# a tie with '_' winning is better than 'O' winning but worse than 'X' winning. |
| 7 | +VALUES = {'X': {'O': 0, '_': 1, 'X': 2}, |
| 8 | + 'O': {'X': 0, '_': 1, 'O': 2}} |
| 9 | + |
| 10 | + |
| 11 | +def main(): |
| 12 | + player = raw_input() |
| 13 | + board = [list(raw_input()) for _ in range(3)] |
| 14 | + r, c = minimax(board, player, player)[1] |
| 15 | + print('%s %s' % (r, c)) |
| 16 | + |
| 17 | + |
| 18 | +def minimax(board, curr_player, max_player): |
| 19 | + '''Runs min-max on the board.''' |
| 20 | + if finished(board): |
| 21 | + w = winner(board) |
| 22 | + return VALUES[max_player][w], None |
| 23 | + |
| 24 | + if curr_player == 'X': |
| 25 | + value, next_player = VALUES[max_player]['O'], 'O' |
| 26 | + else: |
| 27 | + value, next_player = VALUES[max_player]['X'], 'X' |
| 28 | + |
| 29 | + move = None |
| 30 | + |
| 31 | + for r, c in options(board): |
| 32 | + board[r][c] = curr_player |
| 33 | + value_ = minimax(board, next_player, max_player)[0] |
| 34 | + board[r][c] = '_' |
| 35 | + if (curr_player == max_player and value_ >= value) or \ |
| 36 | + (curr_player != max_player and value_ <= value): |
| 37 | + value, move = value_, (r, c) |
| 38 | + |
| 39 | + return value, move |
| 40 | + |
| 41 | + |
| 42 | +def options(board): |
| 43 | + '''Returns a generator of available moves.''' |
| 44 | + for r in range(3): |
| 45 | + for c in range(3): |
| 46 | + if board[r][c] == '_': |
| 47 | + yield (r, c) |
| 48 | + |
| 49 | + |
| 50 | +def finished(board): |
| 51 | + '''Returns if the game is finished or not.''' |
| 52 | + if winner(board) != '_': |
| 53 | + return True |
| 54 | + for r in board: |
| 55 | + for x in r: |
| 56 | + if x == '_': |
| 57 | + return False |
| 58 | + return True |
| 59 | + |
| 60 | + |
| 61 | +def winner(board): |
| 62 | + '''Returns the current winner, if one exists.''' |
| 63 | + for i in range(3): |
| 64 | + # Check rows... |
| 65 | + if board[i][0] != '_' and board[i][0] == board[i][1] == board[i][2]: |
| 66 | + return board[i][0] |
| 67 | + # Check cols... |
| 68 | + if board[0][i] != '_' and board[0][i] == board[1][i] == board[2][i]: |
| 69 | + return board[0][i] |
| 70 | + |
| 71 | + # Check diags... |
| 72 | + if board[0][0] != '_' and board[0][0] == board[1][1] == board[2][2]: |
| 73 | + return board[0][0] |
| 74 | + |
| 75 | + if board[2][0] != '_' and board[2][0] == board[1][1] == board[0][2]: |
| 76 | + return board[2][0] |
| 77 | + |
| 78 | + return '_' |
| 79 | + |
| 80 | + |
| 81 | +if __name__ == '__main__': |
| 82 | + main() |
0 commit comments