#!/usr/bin/env python
#
# Tic Tac Toe, taken from:
#
# http://code.activestate.com/recipes/576661-tic-tac-toe/
#
# and heavily modified to be an easter egg of the computer playing against
# itself.

from random import *
from string import *

EMPTY = ' '
PL_1 = 'X'
PL_2 = 'O'

A = 'A'
B = 'B'
C = 'C'

board = [[EMPTY, EMPTY, EMPTY],
         [EMPTY, EMPTY, EMPTY],
         [EMPTY, EMPTY, EMPTY]]

current_player = randint(1, 2)

def square(row, col):
    return (row, col)

def square_row(square):
    return square[0]

def square_col(square):
    return square[1]

def get_square(square):
    ''' Returns the value of the given square. '''
    row_i = square_row(square) - 1
    col_i = ord(square_col(square)) - ord(A)
    return board[row_i][col_i]

def set_square(square, mark):
    ''' Sets the value of the given square. '''
    row_i = square_row(square) - 1
    col_i = ord(square_col(square)) - ord(A)
    board[row_i][col_i] = mark

def get_row(row):
    ''' Returns the given row as a list of three values. '''
    return [get_square((row, A)), get_square((row, B)), get_square((row, C))]

def get_column(col):
    ''' Returns the given column as a list of three values. '''
    return [get_square((1, col)), get_square((2, col)), get_square((3, col))]

def get_diagonal(corner_square):
    ''' Returns the diagonal that includes the given corner square.
    Only (1, A), (1, C), (3, A) and (3, C) are corner squares. '''
    if corner_square == (1, A) or corner_square == (3, C):
        return [get_square((1, A)), get_square((2, B)), get_square((3, C))]
    else:
        return [get_square((1, C)), get_square((2, B)), get_square((3, A))]

def get_mark(player):
    ''' Returns the mark of the given player (1 or 2). '''
    if player == 1:
        return PL_1
    else:
        return PL_2

def all_squares_filled():
    ''' Returns True iff all squares have been filled. '''
    for row in range(1, 4):
        if EMPTY in get_row(row):
            return False
    return True

def player_has_won(player):
    ''' Returns True iff the given player (1 or 2) has won the game. '''

    MARK = get_mark(player)
    win = [MARK, MARK, MARK]

    if get_row(1) == win or get_row(2) == win or get_row(3) == win:
        return True

    if get_column(A) == win or get_column(B) == win or get_column(C) == win:
        return True

    if get_diagonal((1, A)) == win or get_diagonal((1, C)) == win:
        return True

    return False

def draw_board_straight():
    ''' Returns a straight string representation of the board. '''

    A1, A2, A3 = get_square((1, A)), get_square((2, A)), get_square((3, A))
    B1, B2, B3 = get_square((1, B)), get_square((2, B)), get_square((3, B))
    C1, C2, C3 = get_square((1, C)), get_square((2, C)), get_square((3, C))

    lines = []
    lines.append('')
    lines.append('+---+---+---+')
    lines.append('| ' + A1 + ' | ' + B1 + ' | ' + C1 + ' |')
    lines.append('+---+---+---+')
    lines.append('| ' + A2 + ' | ' + B2 + ' | ' + C2 + ' |')
    lines.append('+---+---+---+')
    lines.append('| ' + A3 + ' | ' + B3 + ' | ' + C3 + ' |')
    lines.append('+---+---+---+')
    lines.append('')

    return join(lines, '\n')

def draw_board():
    ''' Returns a string representation of the board in its current state. '''
    return draw_board_straight()

def reset_board():
    for row in (1, 2, 3):
        for col in (A, B, C):
            set_square(square(row, col), EMPTY)

def ttt():

    global current_player

    reset_board()
    current_player = randint(1, 2)

    player1_name = 'Foo'
    player2_name = 'Bar'

    def get_name(player):
        if player == 1:
            return player1_name
        else:
            return player2_name

    result = []

    result.append(
        'Bored now. Quick games of noughts and crosses...')

    while not all_squares_filled():

        choices = ['A1', 'A2', 'A3',
                   'B1', 'B2', 'B3',
                   'C1', 'C2', 'C3']

        choice = choices[randint(0,8)]

        if choice[0] in ['1', '2', '3']:
            row = int(choice[0])
            col = upper(choice[1])
        else:
            row = int(choice[1])
            col = upper(choice[0])

        choice = square(row, col)

        if get_square(choice) != EMPTY:
            continue

        set_square(choice, get_mark(current_player))

        if player_has_won(current_player):
            for record in draw_board().split('\n'):
                result.append(record)

            result.append('%s (%s) wins!' % \
                          (get_name(current_player),
                           get_mark(current_player)))
            break

        if all_squares_filled():
            for record in draw_board().split('\n'):
                result.append(record)

            result.append('Draw...')
            break

        current_player = 3 - current_player

    result.append('')
    result.append('... ah, that\' better!')

    return result

if __name__ == '__main__':

    result = ttt()
    for r in result:
        print r
