mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 07:10:42 -08:00
MAINT: Add type annotations / use functions
This commit is contained in:
4
01_Acey_Ducey/python/acey_ducey.py
Normal file → Executable file
4
01_Acey_Ducey/python/acey_ducey.py
Normal file → Executable file
@@ -23,7 +23,7 @@ cards = {
|
||||
}
|
||||
|
||||
|
||||
def play_game():
|
||||
def play_game() -> None:
|
||||
"""Play the game"""
|
||||
cash = 100
|
||||
while cash > 0:
|
||||
@@ -63,7 +63,7 @@ def play_game():
|
||||
print("Sorry, friend, but you blew your wad")
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
"""Main"""
|
||||
keep_playing = True
|
||||
|
||||
|
||||
@@ -11,41 +11,43 @@
|
||||
#
|
||||
######################################################
|
||||
|
||||
from typing import List
|
||||
|
||||
|
||||
class Card:
|
||||
def __init__(self, suit, rank):
|
||||
def __init__(self, suit: str, rank: int):
|
||||
self.suit = suit
|
||||
self.rank = rank
|
||||
|
||||
def __str__(self):
|
||||
r = self.rank
|
||||
if r == 11:
|
||||
def __str__(self) -> str:
|
||||
r = str(self.rank)
|
||||
if r == "11":
|
||||
r = "J"
|
||||
elif r == 12:
|
||||
elif r == "12":
|
||||
r = "Q"
|
||||
elif r == 13:
|
||||
elif r == "13":
|
||||
r = "K"
|
||||
elif r == 14:
|
||||
elif r == "14":
|
||||
r = "A"
|
||||
return f"{r}{self.suit}"
|
||||
|
||||
|
||||
class Deck:
|
||||
def __init__(self):
|
||||
self.cards = []
|
||||
self.cards: List[Card] = []
|
||||
self.build()
|
||||
|
||||
def build(self):
|
||||
def build(self) -> None:
|
||||
for suit in ["\u2665", "\u2666", "\u2663", "\u2660"]:
|
||||
for rank in range(2, 15):
|
||||
self.cards.append(Card(suit, rank))
|
||||
|
||||
def shuffle(self):
|
||||
def shuffle(self) -> None:
|
||||
import random
|
||||
|
||||
random.shuffle(self.cards)
|
||||
|
||||
def deal(self):
|
||||
def deal(self) -> Card:
|
||||
return self.cards.pop()
|
||||
|
||||
|
||||
@@ -58,7 +60,7 @@ class Game:
|
||||
self.money = 100
|
||||
self.not_done = True
|
||||
|
||||
def play(self):
|
||||
def play(self) -> None:
|
||||
while self.not_done:
|
||||
while self.money > 0:
|
||||
card_a = self.card_a
|
||||
@@ -90,9 +92,9 @@ class Game:
|
||||
print("Chicken!")
|
||||
print(f"Your deal should have been: {player_card}")
|
||||
if card_a.rank < player_card.rank < card_b.rank:
|
||||
print(f"You could have won!")
|
||||
print("You could have won!")
|
||||
else:
|
||||
print(f"You would lose, so it was wise of you to chicken out!")
|
||||
print("You would lose, so it was wise of you to chicken out!")
|
||||
|
||||
self.not_done = False
|
||||
break
|
||||
|
||||
@@ -30,13 +30,13 @@ import random
|
||||
# to start with more or less than $100."
|
||||
DEFAULT_BANKROLL = 100
|
||||
|
||||
# functions
|
||||
def deal_card_num():
|
||||
|
||||
def deal_card_num() -> int:
|
||||
"""Get card number"""
|
||||
return random.randint(0, 12)
|
||||
|
||||
|
||||
def get_card_name(number):
|
||||
def get_card_name(number: int) -> str:
|
||||
"""Get card name"""
|
||||
card_names = (
|
||||
" 2",
|
||||
@@ -56,7 +56,7 @@ def get_card_name(number):
|
||||
return card_names[number]
|
||||
|
||||
|
||||
def display_bankroll(bank_roll):
|
||||
def display_bankroll(bank_roll: int) -> None:
|
||||
"""Print current bankroll"""
|
||||
if BANK_ROLL > 0:
|
||||
print("You now have %s dollars\n" % bank_roll)
|
||||
@@ -103,9 +103,9 @@ while KEEP_PLAYING:
|
||||
# Get and handle player bet choice
|
||||
BET_IS_VALID = False
|
||||
while not BET_IS_VALID:
|
||||
curr_bet = input("What is your bet? ")
|
||||
curr_bet_str = input("What is your bet? ")
|
||||
try:
|
||||
curr_bet = int(curr_bet)
|
||||
curr_bet = int(curr_bet_str)
|
||||
except ValueError:
|
||||
# Bad input? Just loop back up and ask again...
|
||||
pass
|
||||
|
||||
@@ -1,54 +1,66 @@
|
||||
import random
|
||||
from typing import List, NamedTuple, Tuple
|
||||
|
||||
# Python translation by Frank Palazzolo - 2/2021
|
||||
|
||||
print(" " * 28 + "AMAZING PROGRAM")
|
||||
print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
||||
print()
|
||||
print()
|
||||
print()
|
||||
|
||||
while True:
|
||||
width, length = input("What are your width and length?").split(",")
|
||||
width = int(width)
|
||||
length = int(length)
|
||||
if width != 1 and length != 1:
|
||||
break
|
||||
print("Meaningless dimensions. Try again.")
|
||||
class Maze(NamedTuple):
|
||||
used: List[List[int]]
|
||||
walls: List[List[int]]
|
||||
enter_col: int
|
||||
width: int
|
||||
length: int
|
||||
|
||||
# Build two 2D arrays
|
||||
#
|
||||
# used:
|
||||
# Initially set to zero, unprocessed cells
|
||||
# Filled in with consecutive non-zero numbers as cells are processed
|
||||
#
|
||||
# walls:
|
||||
# Initially set to zero, (all paths blocked)
|
||||
# Remains 0 if there is no exit down or right
|
||||
# Set to 1 if there is an exit down
|
||||
# Set to 2 if there is an exit right
|
||||
# Set to 3 if there are exits down and right
|
||||
|
||||
used = []
|
||||
walls = []
|
||||
for i in range(length):
|
||||
def main() -> None:
|
||||
welcome_header()
|
||||
width, length = get_maze_dimensions()
|
||||
maze = build_maze(width, length)
|
||||
print_maze(maze)
|
||||
|
||||
|
||||
def welcome_header() -> None:
|
||||
print(" " * 28 + "AMAZING PROGRAM")
|
||||
print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
||||
print()
|
||||
print()
|
||||
print()
|
||||
|
||||
|
||||
def build_maze(width: int, length: int) -> Maze:
|
||||
# Build two 2D arrays
|
||||
#
|
||||
# used:
|
||||
# Initially set to zero, unprocessed cells
|
||||
# Filled in with consecutive non-zero numbers as cells are processed
|
||||
#
|
||||
# walls:
|
||||
# Initially set to zero, (all paths blocked)
|
||||
# Remains 0 if there is no exit down or right
|
||||
# Set to 1 if there is an exit down
|
||||
# Set to 2 if there is an exit right
|
||||
# Set to 3 if there are exits down and right
|
||||
|
||||
used = []
|
||||
walls = []
|
||||
for _ in range(length):
|
||||
used.append([0] * width)
|
||||
walls.append([0] * width)
|
||||
|
||||
# Use direction variables with nice names
|
||||
GO_LEFT, GO_UP, GO_RIGHT, GO_DOWN = [0, 1, 2, 3]
|
||||
# Give Exit directions nice names
|
||||
EXIT_DOWN = 1
|
||||
EXIT_RIGHT = 2
|
||||
# Use direction variables with nice names
|
||||
GO_LEFT, GO_UP, GO_RIGHT, GO_DOWN = [0, 1, 2, 3]
|
||||
# Give Exit directions nice names
|
||||
EXIT_DOWN = 1
|
||||
EXIT_RIGHT = 2
|
||||
|
||||
# Pick a random entrance, mark as used
|
||||
enter_col = random.randint(0, width - 1)
|
||||
row, col = 0, enter_col
|
||||
count = 1
|
||||
used[row][col] = count
|
||||
count = count + 1
|
||||
# Pick a random entrance, mark as used
|
||||
enter_col = random.randint(0, width - 1)
|
||||
row, col = 0, enter_col
|
||||
count = 1
|
||||
used[row][col] = count
|
||||
count = count + 1
|
||||
|
||||
while count != width * length + 1:
|
||||
while count != width * length + 1:
|
||||
# remove possible directions that are blocked or
|
||||
# hit cells that we have already processed
|
||||
possible_dirs = [GO_LEFT, GO_UP, GO_RIGHT, GO_DOWN]
|
||||
@@ -90,29 +102,46 @@ while count != width * length + 1:
|
||||
if used[row][col] != 0:
|
||||
break
|
||||
|
||||
# Add a random exit
|
||||
col = random.randint(0, width - 1)
|
||||
row = length - 1
|
||||
walls[row][col] = walls[row][col] + 1
|
||||
# Add a random exit
|
||||
col = random.randint(0, width - 1)
|
||||
row = length - 1
|
||||
walls[row][col] = walls[row][col] + 1
|
||||
return Maze(used, walls, enter_col, width, length)
|
||||
|
||||
# Print the maze
|
||||
for col in range(width):
|
||||
if col == enter_col:
|
||||
|
||||
def get_maze_dimensions() -> Tuple[int, int]:
|
||||
while True:
|
||||
width_str, length_str = input("What are your width and length?").split(",")
|
||||
width = int(width_str)
|
||||
length = int(length_str)
|
||||
if width > 1 and length > 1:
|
||||
break
|
||||
print("Meaningless dimensions. Try again.")
|
||||
return width, length
|
||||
|
||||
|
||||
def print_maze(maze: Maze) -> None:
|
||||
for col in range(maze.width):
|
||||
if col == maze.enter_col:
|
||||
print(". ", end="")
|
||||
else:
|
||||
print(".--", end="")
|
||||
print(".")
|
||||
for row in range(length):
|
||||
print(".")
|
||||
for row in range(maze.length):
|
||||
print("I", end="")
|
||||
for col in range(width):
|
||||
if walls[row][col] < 2:
|
||||
for col in range(maze.width):
|
||||
if maze.walls[row][col] < 2:
|
||||
print(" I", end="")
|
||||
else:
|
||||
print(" ", end="")
|
||||
print()
|
||||
for col in range(width):
|
||||
if walls[row][col] == 0 or walls[row][col] == 2:
|
||||
for col in range(maze.width):
|
||||
if maze.walls[row][col] == 0 or maze.walls[row][col] == 2:
|
||||
print(":--", end="")
|
||||
else:
|
||||
print(": ", end="")
|
||||
print(".")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -42,20 +42,26 @@
|
||||
#
|
||||
########################################################
|
||||
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class Node:
|
||||
"""
|
||||
Node of the binary tree of questions.
|
||||
"""
|
||||
|
||||
def __init__(self, text, yes_node, no_node):
|
||||
def __init__(
|
||||
self, text: str, yes_node: Optional["Node"], no_node: Optional["Node"]
|
||||
):
|
||||
# the nodes that are leafs have as text the animal's name, otherwise
|
||||
# a yes/no question
|
||||
self.text = text
|
||||
self.yes_node = yes_node
|
||||
self.no_node = no_node
|
||||
|
||||
def update_node(self, new_question, answer_new_ques, new_animal):
|
||||
def update_node(
|
||||
self, new_question: str, answer_new_ques: str, new_animal: str
|
||||
) -> None:
|
||||
# update the leaf with a question
|
||||
old_animal = self.text
|
||||
# we replace the animal with a new question
|
||||
@@ -69,13 +75,13 @@ class Node:
|
||||
self.no_node = Node(new_animal, None, None)
|
||||
|
||||
# the leafs have as children None
|
||||
def is_leaf(self):
|
||||
return self.yes_node == None and self.no_node == None
|
||||
def is_leaf(self) -> bool:
|
||||
return self.yes_node is None and self.no_node is None
|
||||
|
||||
|
||||
def list_known_animals(root_node):
|
||||
def list_known_animals(root_node: Optional[Node]) -> None:
|
||||
# Traversing the tree by recursion until we reach the leafs
|
||||
if root_node == None:
|
||||
if root_node is None:
|
||||
return
|
||||
|
||||
if root_node.is_leaf():
|
||||
@@ -89,11 +95,10 @@ def list_known_animals(root_node):
|
||||
list_known_animals(root_node.no_node)
|
||||
|
||||
|
||||
def parse_input(message, check_list, root_node):
|
||||
# only accepts yes or no inputs and recognizes list operation
|
||||
correct_input = False
|
||||
while not correct_input:
|
||||
try:
|
||||
def parse_input(message: str, check_list: bool, root_node: Optional[Node]) -> str:
|
||||
"""only accepts yes or no inputs and recognizes list operation"""
|
||||
token = ""
|
||||
while token not in ["y", "n"]:
|
||||
inp = input(message)
|
||||
|
||||
if check_list and inp.lower() == "list":
|
||||
@@ -101,51 +106,55 @@ def parse_input(message, check_list, root_node):
|
||||
list_known_animals(root_node)
|
||||
print("\n")
|
||||
|
||||
if len(inp) > 0:
|
||||
token = inp[0].lower()
|
||||
if token == "y" or token == "n":
|
||||
correct_input = True
|
||||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
token = ""
|
||||
|
||||
return token
|
||||
|
||||
|
||||
def avoid_void_input(message):
|
||||
def avoid_void_input(message: str) -> str:
|
||||
answer = ""
|
||||
while answer == "":
|
||||
answer = input(message)
|
||||
return answer
|
||||
|
||||
|
||||
def initial_message():
|
||||
def initial_message() -> None:
|
||||
print(" " * 32 + "Animal")
|
||||
print(" " * 15 + "Creative Computing Morristown, New Jersey\n")
|
||||
print("Play ´Guess the Animal´")
|
||||
print("Think of an animal and the computer will try to guess it.\n")
|
||||
|
||||
|
||||
# Initial tree
|
||||
yes_child = Node("Fish", None, None)
|
||||
no_child = Node("Bird", None, None)
|
||||
root = Node("Does it swim?", yes_child, no_child)
|
||||
def main() -> None:
|
||||
# Initial tree
|
||||
yes_child = Node("Fish", None, None)
|
||||
no_child = Node("Bird", None, None)
|
||||
root = Node("Does it swim?", yes_child, no_child)
|
||||
|
||||
# Main loop of game
|
||||
initial_message()
|
||||
keep_playing = parse_input("Are you thinking of an animal? ", True, root) == "y"
|
||||
while keep_playing:
|
||||
# Main loop of game
|
||||
initial_message()
|
||||
keep_playing = parse_input("Are you thinking of an animal? ", True, root) == "y"
|
||||
while keep_playing:
|
||||
keep_asking = True
|
||||
# Start traversing the tree by the root
|
||||
actual_node = root
|
||||
actual_node: Node = root
|
||||
|
||||
while keep_asking:
|
||||
|
||||
if not actual_node.is_leaf():
|
||||
|
||||
# we have to keep asking i.e. traversing nodes
|
||||
answer = parse_input(actual_node.text, False, None)
|
||||
|
||||
# As this is an inner node, both children are not None
|
||||
if answer == "y":
|
||||
assert actual_node.yes_node is not None
|
||||
actual_node = actual_node.yes_node
|
||||
else:
|
||||
assert actual_node.no_node is not None
|
||||
actual_node = actual_node.no_node
|
||||
else:
|
||||
# we have reached a possible answer
|
||||
@@ -156,9 +165,8 @@ while keep_playing:
|
||||
"The animal you were thinking of was a ? "
|
||||
)
|
||||
new_question = avoid_void_input(
|
||||
"Please type in a question that would distinguish a {} from a {}: ".format(
|
||||
new_animal, actual_node.text
|
||||
)
|
||||
"Please type in a question that would distinguish a "
|
||||
f"{new_animal} from a {actual_node.text}: "
|
||||
)
|
||||
answer_new_question = parse_input(
|
||||
f"for a {new_animal} the answer would be: ", False, None
|
||||
@@ -193,3 +201,6 @@ while keep_playing:
|
||||
# function (Lines 120 to 130, 135, 158, 160, 168, 173)
|
||||
|
||||
########################################################
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user