Илия обнови решението на 10.04.2013 18:12 (преди над 11 години)
+class TicTacToeBoard:
+ def __init__(self):
+ self.board = [' ' for i in range(9)]
+ self.all_coordinates = [i + str(j) for j in [3, 2, 1]
+ for i in ['A', 'B', 'C']]
+ self.status = 'Game in progress.'
+ self.turn = ''
+
+ def get_index(self, coordinates):
+ return self.all_coordinates.index(coordinates)
+
+ def __getitem__(self, coordinates):
+ return self.board[self.get_index(coordinates)]
+
+ def make_valid_move(move):
+ def valid_move(self, *args):
+ if self.status == 'Game in progress.':
+ self.check_for_invalid_turn(*args)
+ move(self, *args)
+ self.check_for_winning_move(*args)
+ self.check_if_board_is_full()
+ return valid_move
+
+ @make_valid_move
+ def __setitem__(self, coordinates, value):
+ self.board[self.get_index(coordinates)] = value
+ self.turn = value
+
+ def check_for_invalid_turn(self, coordinates, value):
+ if coordinates not in self.all_coordinates:
+ raise InvalidKey(coordinates)
+ if self[coordinates] != ' ':
+ raise InvalidMove(coordinates)
+ if value not in ['X', 'O']:
+ raise InvalidValue(value)
+ if value == self.turn:
+ raise NotYourTurn(value)
+
+ def check_for_winning_move(self, coordinates, value):
+ index = self.get_index(coordinates)
+ current_row = [self[i] for i in self.all_coordinates if (
+ self.get_index(i) - index) % 3 == 0]
+ current_column = [self[i] for i in self.all_coordinates if (
+ self.get_index(i) // 3 == index // 3)]
+ primary_diagonal = [self.board[i] for i in [0, 4, 8]]
+ secondary_diagonal = [self.board[i] for i in [2, 4, 6]]
+ all_possible_winning_lines = [current_row, current_column,
+ primary_diagonal, secondary_diagonal]
+ if set(value) in [set(line) for line in all_possible_winning_lines]:
+ self.status = "{} wins!".format(value)
+
+ def check_if_board_is_full(self):
+ if ' ' not in self.board and self.status == 'Game in progress.':
+ self.status = "Draw!"
+
+ def game_status(self):
+ return self.status
+
+ def __str__(self):
+ lines = ['']
+ for i in [3, 2, 1]:
+ lines.append(str(i) + ' | {} | {} | {} |')
+ lines.append(' A B C \n')
+ return '\n -------------\n'.join(lines).format(*self.board)
+
+
+class InvalidKey(Exception):
+ def __init__(self, coordinates):
+ self.message = 'No tile at coordinates {}'.format(coordinates)
+
+
+class InvalidMove(Exception):
+ def __init__(self, coordinates):
+ self.message = 'The tile at {} is already taken'.format(coordinates)
+
+
+class InvalidValue(Exception):
+ def __init__(self, value):
+ self.message = 'The value {} is not valid\nTry X or O'.format(value)
+
+
+class NotYourTurn(Exception):
+ def __init__(self, value):
+ self.message = 'Player {}, it is not your turn'.format(value)
Декораторът ти @make_valid_move е абсолютно ненужен в случая и само усложнява решението ти. Като цяло ако направиш декоратор който се използва само веднъж, значи нещо бъркаш.
Освен това е по-добре да дефинираш изключенията ти така:
class InvalidValue(Exception):
pass
и да ги извикваш така: raise InvalidValue('The value {} is not valid\nTry X or O'.format(value))
__str__
на Exception
връща първият аргумент подаден на изключението така че няма нужда от message
атрибут.