import sys, string, re, readline


class Board:
    def __init__(self, width, height):
        self.__matrix = [[False]*width for i in range(height)]

    def is_solved(self):
        for row in self.__matrix:
            for cell in row:
                if not cell:
                    return False
        return True

    def in_bounds(self, row, col):
        return (0 <= row < len(self.__matrix)) and \
               (0 <= col < len(self.__matrix[0]))

    def get_cell(self, row, col):
        return self.__matrix[row][col]

    def get_width(self):
        return len(self.__matrix[0])

    def get_height(self):
        return len(self.__matrix)

    def toggle(self, row, col):
        self.__matrix[row][col] ^= True

    def flip(self, row, col):
        self.toggle(row, col)
        if self.in_bounds(row+1, col):
            self.toggle(row+1, col)
        if self.in_bounds(row-1, col):
            self.toggle(row-1, col)
        if self.in_bounds(row, col+1):
            self.toggle(row, col+1)
        if self.in_bounds(row, col-1):
            self.toggle(row, col-1)


def show_intro():
    print 'Welcome to the flipping game.'
    print 'The goal is to change all cells on the board from X to O.'
    print 'Whenever you select a cell, it and all its surrounding cells'
    print 'will be flipped from X to O or from O to X.'
    print


def draw_board(board):
    cols = board.get_width()
    rows = board.get_height()
    def X_or_O(n):
        if n: return "O"
        else: return "X"
    print '  ' + ''.join(['%4d' % (h+1) for h in range(cols)]) + '\n' + \
          '  +' + '+'.join(['---']*cols) + '+\n' + \
          '\n'.join([string.uppercase[i] + ' | ' + \
              ' | '.join([X_or_O(board.get_cell(i, j)) for j in range(cols)]) \
                  + ' |' for i in range(rows)]) + '\n' + \
          '  +' + '+'.join(['---']*cols) + '+\n'


def get_selection(board):
    selection = None
    while not selection:
        try:
            selection = raw_input('Select a cell: ').strip()
        except EOFError:
            print
            print 'Farewell.'
            sys.exit()
        m = re.match(r'(\w)\W*(\w+)', selection)
        error = "That doesn't name a cell. Cells are named by a letter\n" \
                "(to indicate the row) followed by a number (to indicate\n" \
                "the column)."
        if not m or re.match(r'\d', m.group(1)) \
                or not re.match(r'\d+', m.group(2)):
            print error
            selection = None
        try:
            row = string.uppercase.index(m.group(1).upper())
            if not (0 <= row < board.get_height()):
                raise ValueError
            col = int(m.group(2))-1
            if not (0 <= col < board.get_width()):
                raise ValueError
        except ValueError:
            print error
            selection = None
        selection = row, col
    return selection


def congratulate():
    print 'A winner is you!'


if __name__ == '__main__':
    usage = 'usage: %s <board width> <board height>' % sys.argv[0]
    try:
        width = int(sys.argv[1])
        height = int(sys.argv[2])
    except:
        print usage
        sys.exit(1)
    if height > len(string.uppercase):
        print "That board is too high."
        sys.exit(1)
    board = Board(width, height)
    show_intro()
    while not board.is_solved():
        draw_board(board)
        board.flip(*get_selection(board))
    draw_board(board)
    congratulate()

