generated from mwc/lab_tic_tac_toe
Initial commit
This commit is contained in:
61
ttt/game.py
Normal file
61
ttt/game.py
Normal file
@@ -0,0 +1,61 @@
|
||||
class TTTGame:
|
||||
"Models a tic-tac-toe game."
|
||||
|
||||
def get_initial_state(self):
|
||||
"Returns the game's initial state."
|
||||
return {
|
||||
"board": ['-', '-', '-', '-', '-', '-', '-', '-', '-'],
|
||||
"player_x": True,
|
||||
}
|
||||
|
||||
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"].copy()
|
||||
new_board[action] = 'X' if state["player_x"] else 'O'
|
||||
return {
|
||||
"board": new_board,
|
||||
"player_x": not state["player_x"],
|
||||
}
|
||||
|
||||
def get_actions(self, state):
|
||||
"Returns a list of the indices of empty spaces"
|
||||
return [index for index in range(9) if state["board"][index] == '-']
|
||||
|
||||
def is_over(self, state):
|
||||
"Checks whether the game is over."
|
||||
return self.board_is_full(state) or self.check_winner(state, 'X') or self.check_winner(state, '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(state, 'X'):
|
||||
return 1
|
||||
elif self.check_winner(state, '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`.
|
||||
"""
|
||||
return max if state["player_x"] else min
|
||||
|
||||
def board_is_full(self, state):
|
||||
"Checks whether all the spaces in the board are occupied."
|
||||
for space in state["board"]:
|
||||
if space == '-':
|
||||
return False
|
||||
return True
|
||||
|
||||
def check_winner(self, state, symbol):
|
||||
"Checks whether the player with `symbol` has won the game."
|
||||
return False
|
33
ttt/player.py
Normal file
33
ttt/player.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from click import Choice, prompt
|
||||
from strategy.random_strategy import RandomStrategy
|
||||
from ttt.game import TTTGame
|
||||
import random
|
||||
|
||||
class TTTHumanPlayer:
|
||||
"A human tic tac toe player."
|
||||
|
||||
def __init__(self, name):
|
||||
"Sets up the player."
|
||||
self.name = name
|
||||
self.game = TTTGame()
|
||||
|
||||
def choose_action(self, state):
|
||||
"Chooses an action by prompting the player for a choice."
|
||||
actions = self.game.get_actions(state)
|
||||
choices = Choice([str(action) for action in actions])
|
||||
action = int(prompt("> ", type=choices, show_choices=False))
|
||||
return action
|
||||
|
||||
class TTTComputerPlayer:
|
||||
"A computer tic tac toe player"
|
||||
|
||||
def __init__(self, name):
|
||||
"Sets up the player."
|
||||
self.name = name
|
||||
self.strategy = RandomStrategy(TTTGame())
|
||||
|
||||
def choose_action(self, state):
|
||||
"Chooses a random move from the moves available."
|
||||
action = self.strategy.choose_action(state)
|
||||
print(f"{self.name} chooses {action}.")
|
||||
return action
|
75
ttt/view.py
Normal file
75
ttt/view.py
Normal file
@@ -0,0 +1,75 @@
|
||||
from ttt.game import TTTGame
|
||||
import click
|
||||
|
||||
class TTTView:
|
||||
"Handles user interaction with a tic-tac-toe game."
|
||||
greeting = "Welcome to tic-tac-toe"
|
||||
goodbye = "Well, that's a wrap."
|
||||
divider = "---+---+---"
|
||||
x_color = "red"
|
||||
o_color = "blue"
|
||||
option_color = "bright_black"
|
||||
|
||||
def __init__(self, playerX, playerO):
|
||||
self.game = TTTGame()
|
||||
self.players = {
|
||||
"X": playerX,
|
||||
"O": playerO,
|
||||
}
|
||||
|
||||
def greet(self):
|
||||
"Starts a new game by greeting the players."
|
||||
x_name = self.players['X'].name
|
||||
o_name = self.players['O'].name
|
||||
print(self.greeting)
|
||||
print(f"{x_name} will play as X.")
|
||||
print(f"{o_name} will play as O.")
|
||||
|
||||
def get_action(self, state):
|
||||
"Shows the board and asks the current player for their choice of action."
|
||||
self.print_board(state)
|
||||
current_player_symbol = 'X' if state["player_x"] else 'O'
|
||||
player = self.players[current_player_symbol]
|
||||
print(f"{player.name}, it's your move.")
|
||||
return player.choose_action(state)
|
||||
|
||||
def print_board(self, state):
|
||||
"Prints the current board, showing indices of available spaces"
|
||||
print(self.format_row(state, [0, 1, 2]))
|
||||
print(self.divider)
|
||||
print(self.format_row(state, [3, 4, 5]))
|
||||
print(self.divider)
|
||||
print(self.format_row(state, [6, 7, 8]))
|
||||
|
||||
def format_row(self, state, indices):
|
||||
"Returns a string for one row in the board, like ' X | O | X '"
|
||||
spaces = [self.format_value(state, i) for i in indices]
|
||||
return f" {spaces[0]} | {spaces[1]} | {spaces[2]} "
|
||||
|
||||
def format_value(self, state, index):
|
||||
"""Formats the value for a single space on the board.
|
||||
If the game board already has a symbol in that space, formats that value for the Terminal.
|
||||
If the space is empty, instead formats the index of the space.
|
||||
"""
|
||||
if state["board"][index] == 'X':
|
||||
return click.style('X', fg=self.x_color)
|
||||
elif state["board"][index] == 'O':
|
||||
return click.style('O', fg=self.o_color)
|
||||
else:
|
||||
return click.style(index, fg=self.option_color)
|
||||
|
||||
def conclude(self, state):
|
||||
"""Says goodbye.
|
||||
"""
|
||||
self.print_board(state)
|
||||
if self.game.check_winner(state, 'X'):
|
||||
winner = self.players['X']
|
||||
elif self.game.check_winner(state, 'O'):
|
||||
winner = self.players['O']
|
||||
else:
|
||||
winner = None
|
||||
print(self.goodbye)
|
||||
if winner:
|
||||
print(f"Congratulations to {winner.name}.")
|
||||
else:
|
||||
print("Nobody won this game.")
|
Reference in New Issue
Block a user