Решение на Морски шах от Георги Ангелов

Обратно към всички решения

Към профила на Георги Ангелов

Резултати

  • 6 точки от тестове
  • 2 бонус точки
  • 8 точки общо
  • 8 успешни тест(а)
  • 0 неуспешни тест(а)

Код

class TicTacToeBoard:
BOARD_FORMAT = '\n -------------\n' +\
'3 | {A3} | {B3} | {C3} |\n' +\
' -------------\n' +\
'2 | {A2} | {B2} | {C2} |\n' +\
' -------------\n' +\
'1 | {A1} | {B1} | {C1} |\n' +\
' -------------\n' +\
' A B C \n'
__WIN_LINES = (
((1, 1), (1, 0)),
((1, 1), (0, 1)),
((1, 1), (1, 1)),
((3, 1), (-1, 1)),
((3, 1), (0, 1)),
((3, 3), (-1, 0)),
((2, 1), (0, 1)),
((3, 2), (-1, 0)),
)
def __init__(self):
self.__game_board = {(row, column): ' '
for row in [1, 2, 3]
for column in [1, 2, 3]}
self._next_turn = None
self._winner = None
def __check_line(self, start_index, delta):
"""Check if the line is complete
and return the player to whom it belongs, else return None.
"""
position = start_index
player = None
while 1 <= position[0] <= 3 and 1 <= position[1] <= 3:
if player is not None and self.__game_board[position] != player:
return None
player = self.__game_board[position]
position = position[0] + delta[0], position[1] + delta[1]
return player if player is not ' ' else None
def __check_win(self):
"""Check if any player won the game and return X, O or None."""
for win_line in self.__WIN_LINES:
check_result = self.__check_line(*win_line)
if check_result is not None:
return check_result
return None
def __all_filled(self):
"""Check if all the fields have been filled."""
return all(field != ' ' for field in self.__game_board.values())
def game_status(self):
if self._winner is not None:
return "{} wins!".format(self._winner)
if self.__all_filled():
return "Draw!"
return "Game in progress."
@staticmethod
def _parse_index(index):
"""Return tuple of positions (row, column) in numbers from 1 to 3."""
if len(index) != 2:
raise InvalidKey("The length of the key must be 2 symbols")
column = ord(index[0]) - ord('A') + 1
row = int(index[1])
if not 1 <= column <= 3 or not 1 <= row <= 3:
raise InvalidKey("The first symbol should be A, B or C, and the "
"second one should be 1, 2 or 3.")
return (row, column)
def __getitem__(self, index):
"""Return board data at `index`.
`index` should be one letter A, B or C, followed by 1, 2 or 3.
Raises InvalidKey if the format isn't valid.
"""
index_tuple = TicTacToeBoard._parse_index(index)
return self.__game_board[index_tuple]
def __setitem__(self, index, value):
if value not in ('X', 'O'):
raise InvalidValue("The only allowed values are X and O")
if self._next_turn is not None and self._next_turn != value:
raise NotYourTurn("The {} player should play this turn"
.format(self._next_turn))
index_tuple = TicTacToeBoard._parse_index(index)
if self.__game_board[index_tuple] != ' ':
raise InvalidMove("The field {} is already set.".format(index))
self.__game_board[index_tuple] = value
self._next_turn = 'X' if value == 'O' else 'O'
self._winner = self.__check_win()
def __str__(self):
board_data = {chr(column + ord('A') - 1) + str(row): value
for (row, column), value in self.__game_board.items()}
return self.BOARD_FORMAT.format(**board_data)
class InvalidKey(Exception):
pass
class InvalidMove(Exception):
pass
class InvalidValue(Exception):
pass
class NotYourTurn(Exception):
pass

Лог от изпълнението

........
----------------------------------------------------------------------
Ran 8 tests in 0.008s

OK

История (2 версии и 3 коментара)

Георги обнови решението на 10.04.2013 23:40 (преди около 11 години)

+class TicTacToeBoard:
+ BOARD_FORMAT = '\n -------------\n' +\
+ '3 | {A3} | {B3} | {C3} |\n' +\
+ ' -------------\n' +\
+ '2 | {A2} | {B2} | {C2} |\n' +\
+ ' -------------\n' +\
+ '1 | {A1} | {B1} | {C1} |\n' +\
+ ' -------------\n' +\
+ ' A B C \n'
+
+ __WIN_LINES = (
+ ((3, 3), (-1, 0)),
+ ((3, 3), (0, -1)),
+ ((3, 3), (-1, -1)),
+ ((1, 1), (1, 0)),
+ ((1, 1), (0, 1)),
+ ((1, 1), (1, 1)),
+ ((3, 2), (-1, 0)),
+ ((2, 3), (0, -1)),
+ )
+
+ def __init__(self):
+ self.__game_board = {(row, column): ' '
+ for row in [1, 2, 3]
+ for column in [1, 2, 3]}
+ self._next_turn = None
+ self._winner = None
+
+ def __check_line(self, start_index, delta):
+ """Check if the line is complete
+ and return the player to whom it belongs, else return None.
+ """
+
+ position = start_index
+ player = None
+
+ while 1 <= position[0] <= 3 and 1 <= position[1] <= 3:
+ if player is not None and self.__game_board[position] != player:
+ return None
+
+ player = self.__game_board[position]
+ position = position[0] + delta[0], position[1] + delta[1]
+
+ return player if player is not ' ' else None
+
+ def __check_win(self):
+ """Check if any player won the game and return X, O or None."""
+ for win_line in self.__WIN_LINES:
+ check_result = self.__check_line(*win_line)
+ if check_result is not None:
+ return check_result
+
+ return None
+
+ def __all_filled(self):
+ """Checks if all the fields have been filled."""
+ return all(field != ' ' for field in self.__game_board.values())
+
+ def game_status(self):
+ if self._winner is not None:
+ return "{} wins!".format(self._winner)
+
+ if self.__all_filled():
+ return "Draw!"
+
+ return "Game in progress."
+
+ @staticmethod
+ def _parse_index(index):
+ """Return tuple of positions (row, column) in numbers from 1 to 3."""
+
+ if len(index) != 2:
+ raise InvalidKey("The length of the key must be 2 symbols")
+
+ column = ord(index[0]) - ord('A') + 1
+ row = int(index[1])
+
+ if not 1 <= column <= 3 or not 1 <= row <= 3:
+ raise InvalidKey("The first symbol should be A, B or C, and the "
+ "second one should be 1, 2 or 3.")
+
+ return (row, column)
+
+ def __getitem__(self, index):
+ """Return board data at `index`.
+
+ `index` should be one letter A, B or C, followed by 1, 2 or 3.
+ Raises InvalidKey if the format isn't valid.
+ """
+ index_tuple = TicTacToeBoard._parse_index(index)
+
+ return self.__game_board[index_tuple]
+
+ def __setitem__(self, index, value):
+ if value not in ('X', 'O'):
+ raise InvalidValue("The only allowed values are X and O")
+
+ if self._next_turn is not None and self._next_turn != value:
+ raise NotYourTurn("The {} player should play this turn"
+ .format(self._next_turn))
+
+ index_tuple = TicTacToeBoard._parse_index(index)
+
+ if self.__game_board[index_tuple] != ' ':
+ raise InvalidMove("The field {} is already set.".format(index))
+
+ self.__game_board[index_tuple] = value
+ self._next_turn = 'X' if value == 'O' else 'O'
+ self._winner = self.__check_win()
+
+ def __str__(self):
+ board_data = {chr(column + ord('A') - 1) + str(row): value
+ for (row, column), value in self.__game_board.items()}
+ return self.BOARD_FORMAT.format(**board_data)
+
+
+class InvalidKey(Exception):
+ pass
+
+
+class InvalidMove(Exception):
+ pass
+
+
+class InvalidValue(Exception):
+ pass
+
+
+class NotYourTurn(Exception):
+ pass
+
+
+if __name__ == '__main__':
+ board = TicTacToeBoard()
+
+ board['A2'] = 'X'
+ board['A3'] = 'O'
+ print(board)

Поздравления за решението. Далеч не е най-краткото, но най-доброто до тук. Харесва ми, че си:

  • документирал само това, което има нужда от документация
  • именовал нещата като хората
  • сложил __ пред методите, които не са публични
  • усетил кога нямаш нужда от инстанцията и си направил метода статичен
  • изнесъл нещата си в константи

+2

Не съм 100% сигурен, но ми се струва, че броиш два път главния диагонал и изпускаш вторичния.

И макар да съм сигурен, че Киро ще ме нахрани: Не мисля, че имаш нужда от двойна подчертавка за частните методи тук.

Георги обнови решението на 15.04.2013 14:07 (преди около 11 години)

class TicTacToeBoard:
BOARD_FORMAT = '\n -------------\n' +\
'3 | {A3} | {B3} | {C3} |\n' +\
' -------------\n' +\
'2 | {A2} | {B2} | {C2} |\n' +\
' -------------\n' +\
'1 | {A1} | {B1} | {C1} |\n' +\
' -------------\n' +\
' A B C \n'
__WIN_LINES = (
- ((3, 3), (-1, 0)),
- ((3, 3), (0, -1)),
- ((3, 3), (-1, -1)),
((1, 1), (1, 0)),
((1, 1), (0, 1)),
((1, 1), (1, 1)),
+ ((3, 1), (-1, 1)),
+ ((3, 1), (0, 1)),
+ ((3, 3), (-1, 0)),
+ ((2, 1), (0, 1)),
((3, 2), (-1, 0)),
- ((2, 3), (0, -1)),
)
def __init__(self):
self.__game_board = {(row, column): ' '
for row in [1, 2, 3]
for column in [1, 2, 3]}
self._next_turn = None
self._winner = None
def __check_line(self, start_index, delta):
"""Check if the line is complete
and return the player to whom it belongs, else return None.
"""
position = start_index
player = None
while 1 <= position[0] <= 3 and 1 <= position[1] <= 3:
if player is not None and self.__game_board[position] != player:
return None
player = self.__game_board[position]
position = position[0] + delta[0], position[1] + delta[1]
return player if player is not ' ' else None
def __check_win(self):
"""Check if any player won the game and return X, O or None."""
for win_line in self.__WIN_LINES:
check_result = self.__check_line(*win_line)
if check_result is not None:
return check_result
return None
def __all_filled(self):
- """Checks if all the fields have been filled."""
+ """Check if all the fields have been filled."""
return all(field != ' ' for field in self.__game_board.values())
def game_status(self):
if self._winner is not None:
return "{} wins!".format(self._winner)
if self.__all_filled():
return "Draw!"
return "Game in progress."
@staticmethod
def _parse_index(index):
"""Return tuple of positions (row, column) in numbers from 1 to 3."""
if len(index) != 2:
raise InvalidKey("The length of the key must be 2 symbols")
column = ord(index[0]) - ord('A') + 1
row = int(index[1])
if not 1 <= column <= 3 or not 1 <= row <= 3:
raise InvalidKey("The first symbol should be A, B or C, and the "
"second one should be 1, 2 or 3.")
return (row, column)
def __getitem__(self, index):
"""Return board data at `index`.
`index` should be one letter A, B or C, followed by 1, 2 or 3.
Raises InvalidKey if the format isn't valid.
"""
index_tuple = TicTacToeBoard._parse_index(index)
return self.__game_board[index_tuple]
def __setitem__(self, index, value):
if value not in ('X', 'O'):
raise InvalidValue("The only allowed values are X and O")
if self._next_turn is not None and self._next_turn != value:
raise NotYourTurn("The {} player should play this turn"
.format(self._next_turn))
index_tuple = TicTacToeBoard._parse_index(index)
if self.__game_board[index_tuple] != ' ':
raise InvalidMove("The field {} is already set.".format(index))
self.__game_board[index_tuple] = value
self._next_turn = 'X' if value == 'O' else 'O'
self._winner = self.__check_win()
def __str__(self):
board_data = {chr(column + ord('A') - 1) + str(row): value
for (row, column), value in self.__game_board.items()}
return self.BOARD_FORMAT.format(**board_data)
class InvalidKey(Exception):
pass
class InvalidMove(Exception):
pass
class InvalidValue(Exception):
pass
class NotYourTurn(Exception):
- pass
-
+ pass
-
-if __name__ == '__main__':
- board = TicTacToeBoard()
-
- board['A2'] = 'X'
- board['A3'] = 'O'
- print(board)