Refactor lab with Strategy classes
This commit is contained in:
88
ttt_game.py
88
ttt_game.py
@@ -2,47 +2,81 @@ class TTTGame:
|
||||
"Models a tic-tac-toe game."
|
||||
|
||||
def __init__(self, playerX, playerO):
|
||||
self.board = [None] * 9
|
||||
self.turn_index = 0
|
||||
self.state = self.get_initial_state()
|
||||
self.players = {
|
||||
'X': playerX,
|
||||
'O': playerO,
|
||||
}
|
||||
|
||||
def play_move(self, move):
|
||||
"Updates the game's state by recording a move"
|
||||
if not self.is_valid_move(move):
|
||||
raise ValueError(f"Illegal move {move} with board {self.board}.")
|
||||
self.board[move] = self.get_current_player_symbol()
|
||||
self.turn_index += 1
|
||||
def get_initial_state(self):
|
||||
"Returns the game's initial state."
|
||||
return {
|
||||
"board": ['-', '-', '-', '-', '-', '-', '-', '-', '-'],
|
||||
"player": "X",
|
||||
}
|
||||
|
||||
def get_valid_moves(self):
|
||||
def get_next_state(self, state, action):
|
||||
"""Given a state and an action, returns the resulting state.
|
||||
In the resulting state, the current player's symbol has been placed
|
||||
in an empty board space, and it is the opposite player's turn.
|
||||
"""
|
||||
new_board = state["board"]
|
||||
new_board[action] = state["player"]
|
||||
if state["player"] == "O":
|
||||
new_player = "X"
|
||||
else:
|
||||
new_player = "O"
|
||||
return {
|
||||
"board": new_board,
|
||||
"player": new_player,
|
||||
}
|
||||
|
||||
def get_actions(self, state):
|
||||
"Returns a list of the indices of empty spaces"
|
||||
return [index for index in range(9) if self.board[index] is None]
|
||||
return [index for index in range(9) if state["board"][index] == '-']
|
||||
|
||||
def is_over(self):
|
||||
"Checks whether the game is over."
|
||||
return self.board_is_full() or self.check_winner('X') or self.check_winner('O')
|
||||
|
||||
def get_reward(self, state):
|
||||
"""Determines the reward associated with reaching this state.
|
||||
For tic-tac-toe, the two opponents each want a different game outcome. So
|
||||
we set the reward for X winning to 1 and the reward for O winning to -1.
|
||||
All other states (unfinished games and games which ended in a draw) are worth 0.
|
||||
"""
|
||||
if self.check_winner('X'):
|
||||
return 1
|
||||
elif self.check_winner('O'):
|
||||
return -1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_objective(self, state):
|
||||
"""Returns a player's objective, or a function describing what a player wants.
|
||||
This function should choose the best value from a list. In tic tac toe, the players
|
||||
want opposite things, so we set X's objective to the built-in function `max`
|
||||
(which chooses the largest number), and we set O's objective to the built-in function `min`.
|
||||
"""
|
||||
if state["player"] == 'X':
|
||||
return max
|
||||
elif state["player"] == 'O':
|
||||
return min
|
||||
else:
|
||||
raise ValueError(f"Unrecognized player {state['player']}")
|
||||
|
||||
def play_action(self, action):
|
||||
"Plays a move, updating the game's state."
|
||||
self.state = self.get_next_state(self.state, action)
|
||||
|
||||
def is_valid_move(self, move):
|
||||
"Checks whether a move is valid"
|
||||
return move in self.get_valid_moves()
|
||||
|
||||
def get_current_player_symbol(self):
|
||||
"Returns the symbol of the current player"
|
||||
if self.turn_index % 2 == 0:
|
||||
return 'X'
|
||||
else:
|
||||
return 'O'
|
||||
|
||||
def get_current_player(self):
|
||||
"Returns the symbol of the current player and the current player"
|
||||
return self.players[self.get_current_player_symbol()]
|
||||
|
||||
def is_over(self):
|
||||
"Checks whether the game is over."
|
||||
return self.board_is_full() or self.check_winner('X') or self.check_winner('O')
|
||||
|
||||
def board_is_full(self):
|
||||
"Checks whether all the spaces in the board are occupied."
|
||||
for space in self.board:
|
||||
if space == None:
|
||||
for space in self.state["board"]:
|
||||
if space == '-':
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user