Initial version of lab
This commit is contained in:
commit
900c4622ad
|
@ -0,0 +1,9 @@
|
|||
(Commit summary. Replace this with a one-line description of this commit.)
|
||||
|
||||
What I changed
|
||||
(Replace this with a description of what you changed in this commit. This should be 1-2 sentences.)
|
||||
|
||||
Why I changed it
|
||||
(Describe why you made these changes. Were you working toward a goal? Did you reorganize your code? This should be 1-2 sentences.)
|
||||
|
||||
Estimate for remaining time to finish assignment: [REPLACE WITH TIME ESTIMATE]
|
|
@ -0,0 +1 @@
|
|||
__pycache__/*
|
|
@ -0,0 +1,14 @@
|
|||
from ttt_game import TTTGame
|
||||
from ttt_view import TTTView
|
||||
from ttt_player import TTTHumanPlayer
|
||||
|
||||
player0 = TTTHumanPlayer("Player 1")
|
||||
player1 = TTTHumanPlayer("Player 2")
|
||||
game = TTTGame(player0, player1)
|
||||
view = TTTView()
|
||||
|
||||
view.greet(game)
|
||||
while not game.is_over():
|
||||
move = view.get_move(game)
|
||||
game.play_move(move)
|
||||
view.conclude(game)
|
|
@ -0,0 +1,33 @@
|
|||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.3"
|
||||
description = "Composable command line interface toolkit"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.4"
|
||||
description = "Cross-platform colored terminal text."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.9"
|
||||
content-hash = "b1fe87cf4a78305c8810dfd14d6b6354185272e19826bd925ee2d6c7d1a8c763"
|
||||
|
||||
[metadata.files]
|
||||
click = [
|
||||
{file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
|
||||
{file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
|
||||
]
|
||||
colorama = [
|
||||
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
|
||||
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
|
||||
]
|
|
@ -0,0 +1,16 @@
|
|||
[tool.poetry]
|
||||
name = "mwc-pedprog-unit02-lab02"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["Chris Proctor <github.com@accounts.chrisproctor.net>"]
|
||||
license = "MIT"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
click = "^8.1.3"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
class TTTGame:
|
||||
"""Models a tic-tac-toe game.
|
||||
"""
|
||||
|
||||
def __init__(self, playerX, playerO):
|
||||
self.board = [None] * 9
|
||||
self.turn_index = 0
|
||||
self.players = {
|
||||
'X': playerX,
|
||||
'O': playerO,
|
||||
}
|
||||
|
||||
def play_move(self, 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_valid_moves(self):
|
||||
"Returns a list of the indices of empty spaces"
|
||||
return [index for index in range(9) if self.board[index] is None]
|
||||
|
||||
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.check_winner('X') or self.check_winner('O')
|
||||
|
||||
def check_winner(self, symbol):
|
||||
"Checks whether the player with `symbol` has won the game."
|
||||
return False
|
|
@ -0,0 +1,35 @@
|
|||
from click import Choice, prompt
|
||||
import random
|
||||
|
||||
class TTTPlayer:
|
||||
"A tic tac toe player."
|
||||
|
||||
def __init__(self, name):
|
||||
"Sets up the player."
|
||||
self.name = name
|
||||
|
||||
def get_symbol(self, game):
|
||||
"Returns this player's symbol in the game."
|
||||
if game.players['X'] == self:
|
||||
return 'X'
|
||||
elif game.players['O'] == self:
|
||||
return 'O'
|
||||
else:
|
||||
raise ValueError(f"Player {self.name} isn't in this game!")
|
||||
|
||||
class TTTHumanPlayer(TTTPlayer):
|
||||
"A human tic tac toe player."
|
||||
|
||||
def choose_move(self, game):
|
||||
"Chooses a move by prompting the player for a choice."
|
||||
choices = Choice([str(i) for i in game.get_valid_moves()])
|
||||
move = prompt("> ", type=choices, show_choices=False)
|
||||
return int(move)
|
||||
|
||||
class TTTComputerPlayer(TTTPlayer):
|
||||
"A computer tic tac toe player"
|
||||
|
||||
def choose_move(self, game):
|
||||
"Chooses a random move from the moves available."
|
||||
return random.choice(game.get_valid_moves())
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
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 greet(self, game):
|
||||
"Starts a new game by greeting the players."
|
||||
print(self.greeting)
|
||||
print(f"{game.players['X']} will play as X.")
|
||||
print(f"{game.players['O']} will play as O.")
|
||||
|
||||
def get_move(self, game):
|
||||
"Shows the board and asks the current player for their choice of move."
|
||||
self.print_board_with_options(game)
|
||||
player = game.get_current_player()
|
||||
print(f"{player.name}, it's your move.")
|
||||
return player.choose_move(game)
|
||||
|
||||
def print_board_with_options(self, game):
|
||||
"Prints the current board, showing indices of available spaces"
|
||||
print(self.format_row(game, [0, 1, 2]))
|
||||
print(self.divider)
|
||||
print(self.format_row(game, [3, 4, 6]))
|
||||
print(self.divider)
|
||||
print(self.format_row(game, [6, 7, 8]))
|
||||
|
||||
def format_row(self, game, indices):
|
||||
"Returns a string for one row in the board, like ' X | O | X '"
|
||||
spaces = [self.format_value(game, i) for i in indices]
|
||||
return f" {spaces[0]} | {spaces[1]} | {spaces[2]} "
|
||||
|
||||
def format_value(self, game, 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 game.board[index] == 'X':
|
||||
return click.style('X', fg=self.x_color)
|
||||
elif game.board[index] == 'O':
|
||||
return click.style('O', fg=self.o_color)
|
||||
else:
|
||||
return click.style(index, fg=self.option_color)
|
||||
|
||||
def conclude(self, game):
|
||||
"""Says goodbye.
|
||||
"""
|
||||
if game.check_winner('X'):
|
||||
winner = game.players['X']
|
||||
elif game.check_winner('X'):
|
||||
winner = game.players['X']
|
||||
else:
|
||||
raise Exception("Tried to conclude a game which wasn't over!")
|
||||
print(self.goodbye)
|
||||
print(f"Congratulations to {winner.name}.")
|
Loading…
Reference in New Issue