mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 23:26:40 -08:00
Bug (Python): Refactoring
- Rename files to follow PEP8 convention / make them testable - Add type annotations - Fix Flake8 issues - Variable naming - Add unit test
This commit is contained in:
@@ -1,307 +0,0 @@
|
||||
import random
|
||||
import time
|
||||
|
||||
|
||||
def print_n_whitespaces(n: int) -> None:
|
||||
print(" " * n, end="")
|
||||
|
||||
|
||||
def print_n_newlines(n: int) -> None:
|
||||
for _ in range(n):
|
||||
print()
|
||||
|
||||
|
||||
def print_feelers(n_feelers, is_player: bool = True) -> None:
|
||||
for _ in range(4):
|
||||
print_n_whitespaces(10)
|
||||
for _ in range(n_feelers):
|
||||
print("A " if is_player else "F ", end="")
|
||||
print()
|
||||
|
||||
|
||||
def print_head() -> None:
|
||||
print(" HHHHHHH")
|
||||
print(" H H")
|
||||
print(" H O O H")
|
||||
print(" H H")
|
||||
print(" H V H")
|
||||
print(" HHHHHHH")
|
||||
|
||||
|
||||
def print_neck() -> None:
|
||||
print(" N N")
|
||||
print(" N N")
|
||||
|
||||
|
||||
def print_body(has_tail: bool = False) -> None:
|
||||
print(" BBBBBBBBBBBB")
|
||||
print(" B B")
|
||||
print(" B B")
|
||||
print("TTTTTB B") if has_tail else ""
|
||||
print(" BBBBBBBBBBBB")
|
||||
|
||||
|
||||
def print_legs(n_legs: int) -> None:
|
||||
for _ in range(2):
|
||||
print_n_whitespaces(5)
|
||||
for _ in range(n_legs):
|
||||
print(" L", end="")
|
||||
print()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print_n_whitespaces(34)
|
||||
print("BUG")
|
||||
print_n_whitespaces(15)
|
||||
print("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
||||
print_n_newlines(3)
|
||||
|
||||
print("THE GAME BUG")
|
||||
print("I HOPE YOU ENJOY THIS GAME.")
|
||||
print()
|
||||
want_instructions = input("DO YOU WANT INSTRUCTIONS? ")
|
||||
if want_instructions != "NO":
|
||||
print("THE OBJECT OF BUG IS TO FINISH YOUR BUG BEFORE I FINISH")
|
||||
print("MINE. EACH NUMBER STANDS FOR A PART OF THE BUG BODY.")
|
||||
print("I WILL ROLL THE DIE FOR YOU, TELL YOU WHAT I ROLLED FOR YOU")
|
||||
print("WHAT THE NUMBER STANDS FOR, AND IF YOU CAN GET THE PART.")
|
||||
print("IF YOU CAN GET THE PART I WILL GIVE IT TO YOU.")
|
||||
print("THE SAME WILL HAPPEN ON MY TURN.")
|
||||
print("IF THERE IS A CHANGE IN EITHER BUG I WILL GIVE YOU THE")
|
||||
print("OPTION OF SEEING THE PICTURES OF THE BUGS.")
|
||||
print("THE NUMBERS STAND FOR PARTS AS FOLLOWS:")
|
||||
table = [
|
||||
["NUMBER", "PART", "NUMBER OF PART NEEDED"],
|
||||
["1", "BODY", "1"],
|
||||
["2", "NECK", "1"],
|
||||
["3", "HEAD", "1"],
|
||||
["4", "FEELERS", "2"],
|
||||
["5", "TAIL", "1"],
|
||||
["6", "LEGS", "6"],
|
||||
]
|
||||
for row in table:
|
||||
print(f"{row[0]:<16}{row[1]:<16}{row[2]:<20}")
|
||||
print_n_newlines(2)
|
||||
|
||||
A = 0
|
||||
B = 0
|
||||
H = 0
|
||||
L = 0
|
||||
N = 0
|
||||
P = 0
|
||||
Q = 0
|
||||
R = 0 # NECK
|
||||
S = 0 # FEELERS
|
||||
T = 0
|
||||
U = 0
|
||||
V = 0
|
||||
Y = 0
|
||||
|
||||
while Y <= 0:
|
||||
Z = random.randint(1, 6)
|
||||
print()
|
||||
C = 1
|
||||
print("YOU ROLLED A", Z)
|
||||
if Z == 1:
|
||||
print("1=BODY")
|
||||
if B == 1:
|
||||
print("YOU DO NOT NEED A BODY.")
|
||||
# goto 970
|
||||
else:
|
||||
print("YOU NOW HAVE A BODY.")
|
||||
B = 1
|
||||
C = 0
|
||||
# goto 970
|
||||
elif Z == 2:
|
||||
print("2=NECK")
|
||||
if N == 1:
|
||||
print("YOU DO NOT NEED A NECK.")
|
||||
# goto 970
|
||||
elif B == 0:
|
||||
print("YOU DO NOT HAVE A BODY.")
|
||||
# goto 970
|
||||
else:
|
||||
print("YOU NOW HAVE A NECK.")
|
||||
N = 1
|
||||
C = 0
|
||||
# goto 970
|
||||
elif Z == 3:
|
||||
print("3=HEAD")
|
||||
if N == 0:
|
||||
print("YOU DO NOT HAVE A NECK.")
|
||||
# goto 970
|
||||
elif H == 1:
|
||||
print("YOU HAVE A HEAD.")
|
||||
# goto 970
|
||||
else:
|
||||
print("YOU NEEDED A HEAD.")
|
||||
H = 1
|
||||
C = 0
|
||||
# goto 970
|
||||
elif Z == 4:
|
||||
print("4=FEELERS")
|
||||
if H == 0:
|
||||
print("YOU DO NOT HAVE A HEAD.")
|
||||
# goto 970
|
||||
elif A == 2:
|
||||
print("YOU HAVE TWO FEELERS ALREADY.")
|
||||
# goto 970
|
||||
else:
|
||||
print("I NOW GIVE YOU A FEELER.")
|
||||
A = A + 1
|
||||
C = 0
|
||||
# goto 970
|
||||
elif Z == 5:
|
||||
print("5=TAIL")
|
||||
if B == 0:
|
||||
print("YOU DO NOT HAVE A BODY.")
|
||||
# goto 970
|
||||
elif T == 1:
|
||||
print("YOU ALREADY HAVE A TAIL.")
|
||||
# goto 970
|
||||
else:
|
||||
print("I NOW GIVE YOU A TAIL.")
|
||||
T = T + 1
|
||||
C = 0
|
||||
# goto 970
|
||||
elif Z == 6:
|
||||
print("6=LEG")
|
||||
if L == 6:
|
||||
print("YOU HAVE 6 FEET ALREADY.")
|
||||
# goto 970
|
||||
elif B == 0:
|
||||
print("YOU DO NOT HAVE A BODY.")
|
||||
# goto 970
|
||||
else:
|
||||
L = L + 1
|
||||
C = 0
|
||||
print(f"YOU NOW HAVE {L} LEGS")
|
||||
# goto 970
|
||||
|
||||
# 970
|
||||
X = random.randint(1, 6)
|
||||
print()
|
||||
time.sleep(2)
|
||||
|
||||
print("I ROLLED A", X)
|
||||
if X == 1:
|
||||
print("1=BODY")
|
||||
if P == 1:
|
||||
print("I DO NOT NEED A BODY.")
|
||||
# goto 1630
|
||||
else:
|
||||
print("I NOW HAVE A BODY.")
|
||||
C = 0
|
||||
P = 1
|
||||
# goto 1630
|
||||
elif X == 2:
|
||||
print("2=NECK")
|
||||
if Q == 1:
|
||||
print("I DO NOT NEED A NECK.")
|
||||
# goto 1630
|
||||
elif P == 0:
|
||||
print("I DO NOT HAVE A BODY.")
|
||||
# goto 1630
|
||||
else:
|
||||
print("I NOW HAVE A NECK.")
|
||||
Q = 1
|
||||
C = 0
|
||||
# goto 1630
|
||||
elif X == 3:
|
||||
print("3=HEAD")
|
||||
if Q == 0:
|
||||
print("I DO NOT HAVE A NECK.")
|
||||
# goto 1630
|
||||
elif R == 1:
|
||||
print("I HAVE A HEAD.")
|
||||
# goto 1630
|
||||
else:
|
||||
print("I NEEDED A HEAD.")
|
||||
R = 1
|
||||
C = 0
|
||||
# goto 1630
|
||||
elif X == 4:
|
||||
print("4=FEELERS")
|
||||
if R == 0:
|
||||
print("I DO NOT HAVE A HEAD.")
|
||||
# goto 1630
|
||||
elif S == 2:
|
||||
print("I HAVE TWO FEELERS ALREADY.")
|
||||
# goto 1630
|
||||
else:
|
||||
print("I GET A FEELER.")
|
||||
S = S + 1
|
||||
C = 0
|
||||
# goto 1630
|
||||
elif X == 5:
|
||||
print("5=TAIL")
|
||||
if P == 0:
|
||||
print("I DO NOT HAVE A BODY.")
|
||||
# goto 1630
|
||||
elif U == 1:
|
||||
print("I ALREADY HAVE A TAIL.")
|
||||
# goto 1630
|
||||
else:
|
||||
print("I NOW HAVE A TAIL.")
|
||||
U = 1
|
||||
C = 0
|
||||
# goto 1630
|
||||
elif X == 6:
|
||||
print("6=LEG")
|
||||
if V == 6:
|
||||
print("I HAVE 6 FEET.")
|
||||
# goto 1630
|
||||
elif P == 0:
|
||||
print("I DO NOT HAVE A BODY.")
|
||||
# goto 1630
|
||||
else:
|
||||
V = V + 1
|
||||
C = 0
|
||||
print(f"I NOW HAVE {V} LEGS")
|
||||
# goto 1630
|
||||
|
||||
# 1630
|
||||
if (A == 2) and (T == 1) and (L == 6):
|
||||
print("YOUR BUG IS FINISHED.")
|
||||
Y = Y + 1
|
||||
if (S == 2) and (P == 1) and (V == 6):
|
||||
print("MY BUG IS FINISHED.")
|
||||
Y = Y + 2
|
||||
if C == 1:
|
||||
continue
|
||||
want_pictures = input("DO YOU WANT THE PICTURES? ")
|
||||
if want_pictures != "NO":
|
||||
print("*****YOUR BUG*****")
|
||||
print_n_newlines(2)
|
||||
if A != 0:
|
||||
print_feelers(A, is_player=True)
|
||||
if H != 0:
|
||||
print_head()
|
||||
if N != 0:
|
||||
print_neck()
|
||||
if B != 0:
|
||||
print_body(True) if T == 1 else print_body(False)
|
||||
if L != 0:
|
||||
print_legs(L)
|
||||
print_n_newlines(4)
|
||||
print("*****MY BUG*****")
|
||||
print_n_newlines(3)
|
||||
if S != 0:
|
||||
print_feelers(S, is_player=False)
|
||||
if R == 1:
|
||||
print_head()
|
||||
if Q != 0:
|
||||
print_neck()
|
||||
if P != 0:
|
||||
print_body(True) if U == 1 else print_body(False)
|
||||
if V != 0:
|
||||
print_legs(V)
|
||||
|
||||
if Y != 0:
|
||||
break
|
||||
|
||||
print("I HOPE YOU ENJOYED THE GAME, PLAY IT AGAIN SOON!!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
234
16_Bug/python/bug.py
Normal file
234
16_Bug/python/bug.py
Normal file
@@ -0,0 +1,234 @@
|
||||
import random
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from typing import Literal
|
||||
|
||||
|
||||
@dataclass
|
||||
class State:
|
||||
is_player: bool
|
||||
body: int = 0
|
||||
neck: int = 0
|
||||
head: int = 0
|
||||
feelers: int = 0
|
||||
tail: int = 0
|
||||
legs: int = 0
|
||||
|
||||
def is_finished(self) -> bool:
|
||||
return (
|
||||
self.feelers == 2
|
||||
and self.tail == 1
|
||||
and self.legs == 6
|
||||
and self.head == 1
|
||||
and self.neck == 1
|
||||
)
|
||||
|
||||
def display(self) -> None:
|
||||
if self.feelers != 0:
|
||||
print_feelers(self.feelers, is_player=self.is_player)
|
||||
if self.head != 0:
|
||||
print_head()
|
||||
if self.neck != 0:
|
||||
print_neck()
|
||||
if self.body != 0:
|
||||
print_body(True) if self.tail == 1 else print_body(False)
|
||||
if self.legs != 0:
|
||||
print_legs(self.legs)
|
||||
|
||||
|
||||
def print_n_whitespaces(n: int) -> None:
|
||||
print(" " * n, end="")
|
||||
|
||||
|
||||
def print_n_newlines(n: int) -> None:
|
||||
for _ in range(n):
|
||||
print()
|
||||
|
||||
|
||||
def print_feelers(n_feelers: int, is_player: bool = True) -> None:
|
||||
for _ in range(4):
|
||||
print_n_whitespaces(10)
|
||||
for _ in range(n_feelers):
|
||||
print("A " if is_player else "F ", end="")
|
||||
print()
|
||||
|
||||
|
||||
def print_head() -> None:
|
||||
print(" HHHHHHH")
|
||||
print(" H H")
|
||||
print(" H O O H")
|
||||
print(" H H")
|
||||
print(" H V H")
|
||||
print(" HHHHHHH")
|
||||
|
||||
|
||||
def print_neck() -> None:
|
||||
print(" N N")
|
||||
print(" N N")
|
||||
|
||||
|
||||
def print_body(has_tail: bool = False) -> None:
|
||||
print(" BBBBBBBBBBBB")
|
||||
print(" B B")
|
||||
print(" B B")
|
||||
print("TTTTTB B") if has_tail else ""
|
||||
print(" BBBBBBBBBBBB")
|
||||
|
||||
|
||||
def print_legs(n_legs: int) -> None:
|
||||
for _ in range(2):
|
||||
print_n_whitespaces(5)
|
||||
for _ in range(n_legs):
|
||||
print(" L", end="")
|
||||
print()
|
||||
|
||||
|
||||
def handle_roll(diceroll: Literal[1, 2, 3, 4, 5, 6], state: State) -> bool:
|
||||
who = "YOU" if state.is_player else "I"
|
||||
changed = False
|
||||
|
||||
print(f"{who} ROLLED A", diceroll)
|
||||
if diceroll == 1:
|
||||
print("1=BODY")
|
||||
if state.body:
|
||||
print(f"{who} DO NOT NEED A BODY.")
|
||||
else:
|
||||
print(f"{who} NOW HAVE A BODY.")
|
||||
state.body = 1
|
||||
changed = True
|
||||
elif diceroll == 2:
|
||||
print("2=NECK")
|
||||
if state.neck:
|
||||
print(f"{who} DO NOT NEED A NECK.")
|
||||
elif state.body == 0:
|
||||
print(f"{who} DO NOT HAVE A BODY.")
|
||||
else:
|
||||
print(f"{who} NOW HAVE A NECK.")
|
||||
state.neck = 1
|
||||
changed = True
|
||||
elif diceroll == 3:
|
||||
print("3=HEAD")
|
||||
if state.neck == 0:
|
||||
print(f"{who} DO NOT HAVE A NECK.")
|
||||
elif state.head:
|
||||
print(f"{who} HAVE A HEAD.")
|
||||
else:
|
||||
print(f"{who} NEEDED A HEAD.")
|
||||
state.head = 1
|
||||
changed = True
|
||||
elif diceroll == 4:
|
||||
print("4=FEELERS")
|
||||
if state.head == 0:
|
||||
print(f"{who} DO NOT HAVE A HEAD.")
|
||||
elif state.feelers == 2:
|
||||
print(f"{who} HAVE TWO FEELERS ALREADY.")
|
||||
else:
|
||||
if state.is_player:
|
||||
print("I NOW GIVE YOU A FEELER.")
|
||||
else:
|
||||
print(f"{who} GET A FEELER.")
|
||||
state.feelers += 1
|
||||
changed = True
|
||||
elif diceroll == 5:
|
||||
print("5=TAIL")
|
||||
if state.body == 0:
|
||||
print(f"{who} DO NOT HAVE A BODY.")
|
||||
elif state.tail:
|
||||
print(f"{who} ALREADY HAVE A TAIL.")
|
||||
else:
|
||||
if state.is_player:
|
||||
print("I NOW GIVE YOU A TAIL.")
|
||||
else:
|
||||
print(f"{who} NOW HAVE A TAIL.")
|
||||
state.tail = 1
|
||||
changed = True
|
||||
elif diceroll == 6:
|
||||
print("6=LEG")
|
||||
if state.legs == 6:
|
||||
print(f"{who} HAVE 6 FEET ALREADY.")
|
||||
elif state.body == 0:
|
||||
print(f"{who} DO NOT HAVE A BODY.")
|
||||
else:
|
||||
state.legs += 1
|
||||
changed = True
|
||||
print(f"{who} NOW HAVE {state.legs} LEGS")
|
||||
return changed
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print_n_whitespaces(34)
|
||||
print("BUG")
|
||||
print_n_whitespaces(15)
|
||||
print("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
||||
print_n_newlines(3)
|
||||
|
||||
print("THE GAME BUG")
|
||||
print("I HOPE YOU ENJOY THIS GAME.")
|
||||
print()
|
||||
want_instructions = input("DO YOU WANT INSTRUCTIONS? ")
|
||||
if want_instructions != "NO":
|
||||
print("THE OBJECT OF BUG IS TO FINISH YOUR BUG BEFORE I FINISH")
|
||||
print("MINE. EACH NUMBER STANDS FOR A PART OF THE BUG BODY.")
|
||||
print("I WILL ROLL THE DIE FOR YOU, TELL YOU WHAT I ROLLED FOR YOU")
|
||||
print("WHAT THE NUMBER STANDS FOR, AND IF YOU CAN GET THE PART.")
|
||||
print("IF YOU CAN GET THE PART I WILL GIVE IT TO YOU.")
|
||||
print("THE SAME WILL HAPPEN ON MY TURN.")
|
||||
print("IF THERE IS A CHANGE IN EITHER BUG I WILL GIVE YOU THE")
|
||||
print("OPTION OF SEEING THE PICTURES OF THE BUGS.")
|
||||
print("THE NUMBERS STAND FOR PARTS AS FOLLOWS:")
|
||||
table = [
|
||||
["NUMBER", "PART", "NUMBER OF PART NEEDED"],
|
||||
["1", "BODY", "1"],
|
||||
["2", "NECK", "1"],
|
||||
["3", "HEAD", "1"],
|
||||
["4", "FEELERS", "2"],
|
||||
["5", "TAIL", "1"],
|
||||
["6", "LEGS", "6"],
|
||||
]
|
||||
for row in table:
|
||||
print(f"{row[0]:<16}{row[1]:<16}{row[2]:<20}")
|
||||
print_n_newlines(2)
|
||||
|
||||
player = State(is_player=True)
|
||||
opponent = State(is_player=False)
|
||||
bugs_finished = 0
|
||||
|
||||
while bugs_finished <= 0:
|
||||
diceroll = random.randint(1, 6)
|
||||
print()
|
||||
changed = handle_roll(diceroll, player) # type: ignore
|
||||
|
||||
diceroll = random.randint(1, 6)
|
||||
print()
|
||||
time.sleep(2)
|
||||
|
||||
changed_op = handle_roll(diceroll, opponent) # type: ignore
|
||||
|
||||
changed = changed or changed_op
|
||||
|
||||
if player.is_finished():
|
||||
print("YOUR BUG IS FINISHED.")
|
||||
bugs_finished += 1
|
||||
if opponent.is_finished():
|
||||
print("MY BUG IS FINISHED.")
|
||||
bugs_finished += 1
|
||||
if not changed:
|
||||
continue
|
||||
want_pictures = input("DO YOU WANT THE PICTURES? ")
|
||||
if want_pictures != "NO":
|
||||
print("*****YOUR BUG*****")
|
||||
print_n_newlines(2)
|
||||
player.display()
|
||||
print_n_newlines(4)
|
||||
print("*****MY BUG*****")
|
||||
print_n_newlines(3)
|
||||
opponent.display()
|
||||
|
||||
if bugs_finished != 0:
|
||||
break
|
||||
|
||||
print("I HOPE YOU ENJOYED THE GAME, PLAY IT AGAIN SOON!!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -9,12 +9,38 @@ Ported by Peter Sharp
|
||||
|
||||
from collections import namedtuple
|
||||
from random import randint
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Callable, Dict, List, Literal, Optional, Tuple, TypedDict, Union
|
||||
|
||||
PAGE_WIDTH = 64
|
||||
|
||||
OneParamFunc = Callable[[Any], Any]
|
||||
TwoParamFunc = Callable[[Any, Any], Any]
|
||||
StateFunctions = Tuple[OneParamFunc, OneParamFunc, TwoParamFunc]
|
||||
Action = Literal["instructions", "game", "pictures", "won", "start", "exit"]
|
||||
|
||||
def main(states, data) -> None:
|
||||
Bodypart = namedtuple("Bodypart", ["name", "count", "depends"])
|
||||
|
||||
# body part types used by the game to work out whether a player's body part can be added
|
||||
part_types = (
|
||||
Bodypart(name="BODY", count=1, depends=None),
|
||||
Bodypart(name="NECK", count=1, depends=0),
|
||||
Bodypart(name="HEAD", count=1, depends=1),
|
||||
Bodypart(name="FEELERS", count=2, depends=2),
|
||||
Bodypart(name="TAIL", count=1, depends=0),
|
||||
Bodypart(name="LEGS", count=6, depends=0),
|
||||
)
|
||||
|
||||
|
||||
class DataDict(TypedDict):
|
||||
state: Action
|
||||
partNo: Optional[Any]
|
||||
players: Dict[str, List[int]]
|
||||
partTypes: Tuple[Bodypart, ...]
|
||||
finished: List[Any]
|
||||
logs: List[Any]
|
||||
|
||||
|
||||
def game_loop(states: Dict[Action, StateFunctions], data: DataDict) -> None:
|
||||
"""
|
||||
Starts the game loop using given states and data
|
||||
|
||||
@@ -35,10 +61,7 @@ def main(states, data) -> None:
|
||||
data = model(data, action)
|
||||
|
||||
|
||||
Bodypart = namedtuple("Bodypart", ["name", "count", "depends"])
|
||||
|
||||
|
||||
def print_start(_) -> str:
|
||||
def print_start(_: Any) -> str:
|
||||
"""
|
||||
Prints start message
|
||||
"""
|
||||
@@ -53,7 +76,7 @@ def print_start(_) -> str:
|
||||
return input("DO YOU WANT INSTRUCTIONS? ")
|
||||
|
||||
|
||||
def control_start(cmd):
|
||||
def control_start(cmd: str) -> str:
|
||||
"""
|
||||
Controls the start state
|
||||
"""
|
||||
@@ -64,7 +87,7 @@ def control_start(cmd):
|
||||
return action
|
||||
|
||||
|
||||
def print_instructions(data) -> str:
|
||||
def print_instructions(data: DataDict) -> str:
|
||||
"""
|
||||
Prints game instructions
|
||||
"""
|
||||
@@ -92,26 +115,25 @@ def print_instructions(data) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
def goto_game(_):
|
||||
"""
|
||||
Returns game
|
||||
"""
|
||||
def goto_game(_: Any) -> Literal["game"]:
|
||||
return "game"
|
||||
|
||||
|
||||
def update_state(data, action):
|
||||
def update_state(data: DataDict, action: Action) -> DataDict:
|
||||
"""
|
||||
sets game state to given player value
|
||||
"""
|
||||
return {**data, "state": action}
|
||||
return {**data, "state": action} # type: ignore
|
||||
|
||||
|
||||
def update_game(data, action):
|
||||
def update_game(data: DataDict, action: Action) -> DataDict:
|
||||
"""
|
||||
Updates game data for player turns until one player successfully gets a body part
|
||||
"""
|
||||
# stores logs of what happened during a particular round
|
||||
logs = []
|
||||
Log1 = Tuple[str, int, Any]
|
||||
Log2 = Tuple[str, int, Any, Any]
|
||||
logs: List[Union[Log1, Log2]] = []
|
||||
|
||||
if action == "pictures":
|
||||
data["state"] = "pictures"
|
||||
@@ -133,16 +155,16 @@ def update_game(data, action):
|
||||
# a new part can only be added if the player has the parts
|
||||
# the new part depends on and doesn't have enough of the part already
|
||||
overMaxParts = part_type.count < part_count + 1
|
||||
missingPartDep = (
|
||||
missing_part_dep = (
|
||||
part_type.depends is not None and parts[part_type.depends] == 0
|
||||
)
|
||||
|
||||
if not overMaxParts and not missingPartDep:
|
||||
if not overMaxParts and not missing_part_dep:
|
||||
# adds a new part
|
||||
part_count += 1
|
||||
logs.append(("added", new_part_idx, player))
|
||||
part_added = True
|
||||
elif missingPartDep:
|
||||
elif missing_part_dep:
|
||||
logs.append(("missingDep", new_part_idx, player, part_type.depends))
|
||||
if overMaxParts:
|
||||
logs.append(("overMax", new_part_idx, player, part_count))
|
||||
@@ -159,7 +181,7 @@ def update_game(data, action):
|
||||
return data
|
||||
|
||||
|
||||
def get_finished(data):
|
||||
def get_finished(data: DataDict) -> List[str]:
|
||||
"""
|
||||
Gets players who have finished their bugs
|
||||
"""
|
||||
@@ -171,7 +193,7 @@ def get_finished(data):
|
||||
return finished
|
||||
|
||||
|
||||
def print_game(data) -> str:
|
||||
def print_game(data: DataDict) -> str:
|
||||
"""
|
||||
Displays the results of the game turn
|
||||
"""
|
||||
@@ -222,7 +244,7 @@ def print_game(data) -> str:
|
||||
return input("DO YOU WANT THE PICTURES? ") if len(data["logs"]) else "n"
|
||||
|
||||
|
||||
def print_pictures(data) -> None:
|
||||
def print_pictures(data: DataDict) -> None:
|
||||
"""
|
||||
Displays what the bugs look like for each player
|
||||
"""
|
||||
@@ -261,7 +283,7 @@ def print_pictures(data) -> None:
|
||||
print()
|
||||
|
||||
|
||||
def control_game(cmd):
|
||||
def control_game(cmd: str) -> Literal["pictures", "game"]:
|
||||
"""
|
||||
returns state based on command
|
||||
"""
|
||||
@@ -269,10 +291,10 @@ def control_game(cmd):
|
||||
action = "pictures"
|
||||
else:
|
||||
action = "game"
|
||||
return action
|
||||
return action # type: ignore
|
||||
|
||||
|
||||
def print_winner(data) -> None:
|
||||
def print_winner(data: DataDict) -> None:
|
||||
"""
|
||||
Displays the winning message
|
||||
"""
|
||||
@@ -281,30 +303,25 @@ def print_winner(data) -> None:
|
||||
print("I HOPE YOU ENJOYED THE GAME, PLAY IT AGAIN SOON!!")
|
||||
|
||||
|
||||
def exit_game(_):
|
||||
"""
|
||||
Exists the game regardless of input
|
||||
"""
|
||||
def exit_game(_: Any) -> Literal["exit"]:
|
||||
"""Exist the game regardless of input"""
|
||||
return "exit"
|
||||
|
||||
|
||||
def print_centered(msg, width=PAGE_WIDTH) -> None:
|
||||
"""
|
||||
Prints given message centered to given width
|
||||
"""
|
||||
def print_centered(msg: str, width: int = PAGE_WIDTH) -> None:
|
||||
"""Print given message centered to given width."""
|
||||
spaces = " " * ((width - len(msg)) // 2)
|
||||
print(spaces + msg)
|
||||
|
||||
|
||||
def print_table(rows) -> None:
|
||||
def print_table(rows: List[Any]) -> None:
|
||||
for row in rows:
|
||||
print(*row, sep="\t")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
def main() -> None:
|
||||
# The main states in the game
|
||||
states = {
|
||||
states: Dict[Action, StateFunctions] = {
|
||||
# Initial state of the game
|
||||
"start": (print_start, control_start, update_state),
|
||||
# displays game instructions
|
||||
@@ -317,23 +334,17 @@ if __name__ == "__main__":
|
||||
"won": (print_winner, exit_game, update_state),
|
||||
}
|
||||
|
||||
# body part types used by the game to work out whether a player's body part can be added
|
||||
part_types = (
|
||||
Bodypart(name="BODY", count=1, depends=None),
|
||||
Bodypart(name="NECK", count=1, depends=0),
|
||||
Bodypart(name="HEAD", count=1, depends=1),
|
||||
Bodypart(name="FEELERS", count=2, depends=2),
|
||||
Bodypart(name="TAIL", count=1, depends=0),
|
||||
Bodypart(name="LEGS", count=6, depends=0),
|
||||
)
|
||||
|
||||
# all the data used by the game
|
||||
data: Dict[str, Any] = {
|
||||
"state": "start",
|
||||
"partNo": None,
|
||||
"players": {"YOU": [0] * len(part_types), "I": [0] * len(part_types)},
|
||||
"partTypes": part_types,
|
||||
"finished": [],
|
||||
"logs": [],
|
||||
}
|
||||
main(states, data)
|
||||
data = DataDict(
|
||||
state="start",
|
||||
partNo=None,
|
||||
players={"YOU": [0] * len(part_types), "I": [0] * len(part_types)},
|
||||
partTypes=part_types,
|
||||
finished=[],
|
||||
logs=[],
|
||||
)
|
||||
game_loop(states, data)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
25
16_Bug/python/test_bug.py
Normal file
25
16_Bug/python/test_bug.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import io
|
||||
from typing import Callable
|
||||
|
||||
import pytest
|
||||
from _pytest.monkeypatch import MonkeyPatch
|
||||
|
||||
from bug import main
|
||||
from bug_overengineered import main as overengineered_main
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"main",
|
||||
[main, overengineered_main],
|
||||
)
|
||||
def test_main(monkeypatch: MonkeyPatch, main: Callable[[], None]) -> None:
|
||||
monkeypatch.setattr("time.sleep", lambda n: n)
|
||||
instructions = "Y"
|
||||
pictures = "Y"
|
||||
monkeypatch.setattr(
|
||||
"sys.stdin",
|
||||
io.StringIO(
|
||||
f"{instructions}\n{pictures}\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\n"
|
||||
),
|
||||
)
|
||||
main()
|
||||
Reference in New Issue
Block a user