#!/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
