mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-23 07:29:02 -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 collections import namedtuple
|
||||||
from random import randint
|
from random import randint
|
||||||
from typing import Any, Dict
|
from typing import Any, Callable, Dict, List, Literal, Optional, Tuple, TypedDict, Union
|
||||||
|
|
||||||
PAGE_WIDTH = 64
|
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
|
Starts the game loop using given states and data
|
||||||
|
|
||||||
@@ -35,10 +61,7 @@ def main(states, data) -> None:
|
|||||||
data = model(data, action)
|
data = model(data, action)
|
||||||
|
|
||||||
|
|
||||||
Bodypart = namedtuple("Bodypart", ["name", "count", "depends"])
|
def print_start(_: Any) -> str:
|
||||||
|
|
||||||
|
|
||||||
def print_start(_) -> str:
|
|
||||||
"""
|
"""
|
||||||
Prints start message
|
Prints start message
|
||||||
"""
|
"""
|
||||||
@@ -53,7 +76,7 @@ def print_start(_) -> str:
|
|||||||
return input("DO YOU WANT INSTRUCTIONS? ")
|
return input("DO YOU WANT INSTRUCTIONS? ")
|
||||||
|
|
||||||
|
|
||||||
def control_start(cmd):
|
def control_start(cmd: str) -> str:
|
||||||
"""
|
"""
|
||||||
Controls the start state
|
Controls the start state
|
||||||
"""
|
"""
|
||||||
@@ -64,7 +87,7 @@ def control_start(cmd):
|
|||||||
return action
|
return action
|
||||||
|
|
||||||
|
|
||||||
def print_instructions(data) -> str:
|
def print_instructions(data: DataDict) -> str:
|
||||||
"""
|
"""
|
||||||
Prints game instructions
|
Prints game instructions
|
||||||
"""
|
"""
|
||||||
@@ -92,26 +115,25 @@ def print_instructions(data) -> str:
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def goto_game(_):
|
def goto_game(_: Any) -> Literal["game"]:
|
||||||
"""
|
|
||||||
Returns game
|
|
||||||
"""
|
|
||||||
return "game"
|
return "game"
|
||||||
|
|
||||||
|
|
||||||
def update_state(data, action):
|
def update_state(data: DataDict, action: Action) -> DataDict:
|
||||||
"""
|
"""
|
||||||
sets game state to given player value
|
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
|
Updates game data for player turns until one player successfully gets a body part
|
||||||
"""
|
"""
|
||||||
# stores logs of what happened during a particular round
|
# 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":
|
if action == "pictures":
|
||||||
data["state"] = "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
|
# 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
|
# the new part depends on and doesn't have enough of the part already
|
||||||
overMaxParts = part_type.count < part_count + 1
|
overMaxParts = part_type.count < part_count + 1
|
||||||
missingPartDep = (
|
missing_part_dep = (
|
||||||
part_type.depends is not None and parts[part_type.depends] == 0
|
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
|
# adds a new part
|
||||||
part_count += 1
|
part_count += 1
|
||||||
logs.append(("added", new_part_idx, player))
|
logs.append(("added", new_part_idx, player))
|
||||||
part_added = True
|
part_added = True
|
||||||
elif missingPartDep:
|
elif missing_part_dep:
|
||||||
logs.append(("missingDep", new_part_idx, player, part_type.depends))
|
logs.append(("missingDep", new_part_idx, player, part_type.depends))
|
||||||
if overMaxParts:
|
if overMaxParts:
|
||||||
logs.append(("overMax", new_part_idx, player, part_count))
|
logs.append(("overMax", new_part_idx, player, part_count))
|
||||||
@@ -159,7 +181,7 @@ def update_game(data, action):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def get_finished(data):
|
def get_finished(data: DataDict) -> List[str]:
|
||||||
"""
|
"""
|
||||||
Gets players who have finished their bugs
|
Gets players who have finished their bugs
|
||||||
"""
|
"""
|
||||||
@@ -171,7 +193,7 @@ def get_finished(data):
|
|||||||
return finished
|
return finished
|
||||||
|
|
||||||
|
|
||||||
def print_game(data) -> str:
|
def print_game(data: DataDict) -> str:
|
||||||
"""
|
"""
|
||||||
Displays the results of the game turn
|
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"
|
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
|
Displays what the bugs look like for each player
|
||||||
"""
|
"""
|
||||||
@@ -261,7 +283,7 @@ def print_pictures(data) -> None:
|
|||||||
print()
|
print()
|
||||||
|
|
||||||
|
|
||||||
def control_game(cmd):
|
def control_game(cmd: str) -> Literal["pictures", "game"]:
|
||||||
"""
|
"""
|
||||||
returns state based on command
|
returns state based on command
|
||||||
"""
|
"""
|
||||||
@@ -269,10 +291,10 @@ def control_game(cmd):
|
|||||||
action = "pictures"
|
action = "pictures"
|
||||||
else:
|
else:
|
||||||
action = "game"
|
action = "game"
|
||||||
return action
|
return action # type: ignore
|
||||||
|
|
||||||
|
|
||||||
def print_winner(data) -> None:
|
def print_winner(data: DataDict) -> None:
|
||||||
"""
|
"""
|
||||||
Displays the winning message
|
Displays the winning message
|
||||||
"""
|
"""
|
||||||
@@ -281,30 +303,25 @@ def print_winner(data) -> None:
|
|||||||
print("I HOPE YOU ENJOYED THE GAME, PLAY IT AGAIN SOON!!")
|
print("I HOPE YOU ENJOYED THE GAME, PLAY IT AGAIN SOON!!")
|
||||||
|
|
||||||
|
|
||||||
def exit_game(_):
|
def exit_game(_: Any) -> Literal["exit"]:
|
||||||
"""
|
"""Exist the game regardless of input"""
|
||||||
Exists the game regardless of input
|
|
||||||
"""
|
|
||||||
return "exit"
|
return "exit"
|
||||||
|
|
||||||
|
|
||||||
def print_centered(msg, width=PAGE_WIDTH) -> None:
|
def print_centered(msg: str, width: int = PAGE_WIDTH) -> None:
|
||||||
"""
|
"""Print given message centered to given width."""
|
||||||
Prints given message centered to given width
|
|
||||||
"""
|
|
||||||
spaces = " " * ((width - len(msg)) // 2)
|
spaces = " " * ((width - len(msg)) // 2)
|
||||||
print(spaces + msg)
|
print(spaces + msg)
|
||||||
|
|
||||||
|
|
||||||
def print_table(rows) -> None:
|
def print_table(rows: List[Any]) -> None:
|
||||||
for row in rows:
|
for row in rows:
|
||||||
print(*row, sep="\t")
|
print(*row, sep="\t")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
def main() -> None:
|
||||||
|
|
||||||
# The main states in the game
|
# The main states in the game
|
||||||
states = {
|
states: Dict[Action, StateFunctions] = {
|
||||||
# Initial state of the game
|
# Initial state of the game
|
||||||
"start": (print_start, control_start, update_state),
|
"start": (print_start, control_start, update_state),
|
||||||
# displays game instructions
|
# displays game instructions
|
||||||
@@ -317,23 +334,17 @@ if __name__ == "__main__":
|
|||||||
"won": (print_winner, exit_game, update_state),
|
"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
|
# all the data used by the game
|
||||||
data: Dict[str, Any] = {
|
data = DataDict(
|
||||||
"state": "start",
|
state="start",
|
||||||
"partNo": None,
|
partNo=None,
|
||||||
"players": {"YOU": [0] * len(part_types), "I": [0] * len(part_types)},
|
players={"YOU": [0] * len(part_types), "I": [0] * len(part_types)},
|
||||||
"partTypes": part_types,
|
partTypes=part_types,
|
||||||
"finished": [],
|
finished=[],
|
||||||
"logs": [],
|
logs=[],
|
||||||
}
|
)
|
||||||
main(states, data)
|
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