diff --git a/17_Bullfight/python/Bullfight.py b/17_Bullfight/python/Bullfight.py deleted file mode 100644 index b25d35f0..00000000 --- a/17_Bullfight/python/Bullfight.py +++ /dev/null @@ -1,257 +0,0 @@ -import math -import random -from typing import Dict, Union - - -def print_n_whitespaces(n: int) -> None: - print(" " * n, end="") - - -def print_n_newlines(n: int) -> None: - for _ in range(n): - print() - - -def subroutine_1610(A, AS, BS, LS) -> float: - B = 3 / A * random.random() - if B < 0.37: - C = 0.5 - elif B < 0.5: - C = 0.4 - elif B < 0.63: - C = 0.3 - elif B < 0.87: - C = 0.2 - else: - C = 0.1 - T = math.floor(10 * C + 0.2) - print(f"THE {AS}{BS} DID A {LS[T]} JOB.") - if T >= 4: - if T == 5: - # 1800 & 1810 are unreachable, so it's not presented here - K = random.randint(1, 2) - if K == 1: - print(f"ONE OF THE {AS}{BS} WAS KILLED.") - elif K == 2: - print(f"NO {AS}{BS} WERE KILLED.") - else: - if AS != "TOREAD": - K = random.randint(1, 2) - print(f"{K} OF THE HORSES OF THE {AS}{BS} KILLED.") - K = random.randint(1, 2) - print(f"{K} OF THE {AS}{BS} KILLED.") - print() - return C - - -def FNC(L: float, D: Dict[int, float], A: int) -> float: - Q = ( - 4.5 + L / 6 - (D[1] + D[2]) * 2.5 + 4 * D[4] + 2 * D[5] - (D[3] ** 2) / 120 - A - ) * random.random() - return Q - - -def print_header() -> None: - print_n_whitespaces(34) - print("BULL") - print_n_whitespaces(15) - print("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - print_n_newlines(2) - - -def print_instructions() -> None: - print("HELLO, ALL YOU BLOODLOVERS AND AFICIONADOS.") - print("HERE IS YOUR BIG CHANCE TO KILL A BULL.") - print() - print("ON EACH PASS OF THE BULL, YOU MAY TRY") - print("0 - VERONICA (DANGEROUS INSIDE MOVE OF THE CAPE)") - print("1 - LESS DANGEROUS OUTSIDE MOVE OF THE CAPE") - print("2 - ORDINARY SWIRL OF THE CAPE.") - print() - print("INSTEAD OF THE ABOVE, YOU MAY TRY TO KILL THE BULL") - print("ON ANY TURN: 4 (OVER THE HORNS), 5 (IN THE CHEST).") - print("BUT IF I WERE YOU,") - print("I WOULDN'T TRY IT BEFORE THE SEVENTH PASS.") - print() - print("THE CROWD WILL DETERMINE WHAT AWARD YOU DESERVE") - print("(POSTHUMOUSLY IF NECESSARY).") - print("THE BRAVER YOU ARE, THE BETTER THE AWARD YOU RECEIVE.") - print() - print("THE BETTER THE JOB THE PICADORES AND TOREADORES DO,") - print("THE BETTER YOUR CHANCES ARE.") - - -def print_intro() -> None: - print_header() - Z = input("DO YOU WANT INSTRUCTIONS? ") - if Z != "NO": - print_instructions() - print_n_newlines(2) - - -def main() -> None: - print_intro() - L: float = 1 - D: Dict[int, float] = {4: 1, 5: 1} - LS = ["", "SUPERB", "GOOD", "FAIR", "POOR", "AWFUL"] - A = random.randint(1, 5) - print(f"YOU HAVE DRAWN A {LS[A]} BULL.") - if A > 4: - print("YOU'RE LUCKY.") - elif A < 2: - print("GOOD LUCK. YOU'LL NEED IT.") - print() - print() - AS = "PICADO" - BS = "RES" - C = subroutine_1610(A, AS, BS, LS) - D[1] = C - AS = "TOREAD" - BS = "ORES" - subroutine_1610(A, AS, BS, LS) - D[2] = C - print_n_newlines(2) - D[3] = 0 - while True: - D[3] = D[3] + 1 # 660 - print(f"PASS NUMBER {D[3]}") - if D[3] >= 3: - while True: # 1930 - AS = input("HERE COMES THE BULL. TRY FOR A KILL? ") - if AS not in ["YES", "NO"]: - print("INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'.") - else: - break - Z1 = 1 if AS == "YES" else 2 - if Z1 != 1: - print("CAPE MOVE? ", end="") - else: - pass - # goto 1130 - else: - print("THE BULL IS CHARGING AT YOU! YOU ARE THE MATADOR--") - while True: # 1930 - AS = input("DO YOU WANT TO KILL THE BULL? ") - if AS not in ["YES", "NO"]: - print("INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'.") - else: - break - Z1 = 1 if AS == "YES" else 2 - if Z1 != 1: - print("WHAT MOVE DO YOU MAKE WITH THE CAPE? ", end="") - else: - # goto 1130 - pass - gore = 0 - if Z1 != 1: # NO - while True: - E = float(input()) - if E != float(int(abs(E))): - print("DON'T PANIC, YOU IDIOT! PUT DOWN A CORRECT NUMBER") - elif E < 3: - break - if E == 0: - M: Union[int, float] = 3 - elif E == 1: - M = 2 - else: - M = 0.5 - L = L + M - F = (6 - A + M / 10) * random.random() / ((D[1] + D[2] + D[3] / 10) * 5) - if F < 0.51: - continue - gore = 1 - else: # YES - print() - print("IT IS THE MOMENT OF TRUTH.") - print() - H = int(input("HOW DO YOU TRY TO KILL THE BULL? ")) - if H not in [4, 5]: - print("YOU PANICKED. THE BULL GORED YOU.") - gore = 2 - # goto 970 - else: - K = (6 - A) * 10 * random.random() / ((D[1] + D[2]) * 5 * D[3]) - if H == 4: - if K > 0.8: - gore = 1 - else: - if K > 0.2: - gore = 1 - if gore == 0: - print("YOU KILLED THE BULL!") - D[5] = 2 - break - if gore > 0: - if gore == 1: - print("THE BULL HAS GORED YOU!") - death = False - while True: - _ = random.randint(1, 2) # 970 - if _ == 1: - print("YOU ARE DEAD.") - D[4] = 1.5 - # goto 1320 - death = True - break - else: - print("YOU ARE STILL ALIVE.") - print() - print("DO YOU RUN FROM THE RING? ", end="") - while True: # 1930 - AS = input() - if AS not in ["YES", "NO"]: - print("INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'.") - else: - break - Z1 = 1 if AS == "YES" else 2 - if Z1 == 2: - print("YOU ARE BRAVE. STUPID, BUT BRAVE.") - _ = random.randint(1, 2) - if _ == 1: - D[4] = 2 - # goto 660, outter while loop - death = True - break - else: - print("YOU ARE GORED AGAIN!") - # goto 970 - else: - print("COWARD") - D[4] = 0 - # goto 1310, break outter while loop - death = True - break - - if death: - break - - # 1310 - print_n_newlines(3) - if D[4] == 0: - print("THE CROWD BOOS FOR TEN MINUTES. IF YOU EVER DARE TO SHOW") - print("YOUR FACE IN A RING AGAIN, THEY SWEAR THEY WILL KILL YOU--") - print("UNLESS THE BULL DOES FIRST.") - else: - if D[4] == 2: - print("THE CROWD CHEERS WILDLY!") - elif D[5] == 2: - print("THE CROWD CHEERS!") - print() - print("THE CROWD AWARDS YOU") - if FNC(L, D, A) < 2.4: - print("NOTHING AT ALL.") - elif FNC(L, D, A) < 4.9: - print("ONE EAR OF THE BULL.") - elif FNC(L, D, A) < 7.4: - print("BOTH EARS OF THE BULL!") - print("OLE!") - else: - print("OLE! YOU ARE 'MUY HOMBRE'!! OLE! OLE!") - print() - print("ADIOS") - print_n_newlines(3) - - -if __name__ == "__main__": - main() diff --git a/17_Bullfight/python/bullfight.py b/17_Bullfight/python/bullfight.py new file mode 100644 index 00000000..0c85ae1e --- /dev/null +++ b/17_Bullfight/python/bullfight.py @@ -0,0 +1,330 @@ +import math +import random +from typing import Dict, List, Literal, Tuple, Union + + +def print_n_whitespaces(n: int) -> None: + print(" " * n, end="") + + +def print_n_newlines(n: int) -> None: + for _ in range(n): + print() + + +def determine_player_kills( + bull_quality: int, + player_type: Literal["TOREAD", "PICADO"], + plural_form: Literal["ORES", "RES"], + job_qualities: List[str], +) -> float: + bull_performance = 3 / bull_quality * random.random() + if bull_performance < 0.37: + job_quality_factor = 0.5 + elif bull_performance < 0.5: + job_quality_factor = 0.4 + elif bull_performance < 0.63: + job_quality_factor = 0.3 + elif bull_performance < 0.87: + job_quality_factor = 0.2 + else: + job_quality_factor = 0.1 + job_quality = math.floor(10 * job_quality_factor + 0.2) # higher is better + print(f"THE {player_type}{plural_form} DID A {job_qualities[job_quality]} JOB.") + if job_quality >= 4: + if job_quality == 5: + player_was_killed = random.choice([True, False]) + if player_was_killed: + print(f"ONE OF THE {player_type}{plural_form} WAS KILLED.") + elif player_was_killed: + print(f"NO {player_type}{plural_form} WERE KILLED.") + else: + if player_type != "TOREAD": + killed_horses = random.randint(1, 2) + print( + f"{killed_horses} OF THE HORSES OF THE {player_type}{plural_form} KILLED." + ) + killed_players = random.randint(1, 2) + print(f"{killed_players} OF THE {player_type}{plural_form} KILLED.") + print() + return job_quality_factor + + +def calculate_final_score( + move_risk_sum: float, job_quality_by_round: Dict[int, float], bull_quality: int +) -> float: + quality = ( + 4.5 + + move_risk_sum / 6 + - (job_quality_by_round[1] + job_quality_by_round[2]) * 2.5 + + 4 * job_quality_by_round[4] + + 2 * job_quality_by_round[5] + - (job_quality_by_round[3] ** 2) / 120 + - bull_quality + ) * random.random() + if quality < 2.4: + return 0 + elif quality < 4.9: + return 1 + elif quality < 7.4: + return 2 + else: + return 3 + + +def print_header() -> None: + print_n_whitespaces(34) + print("BULL") + print_n_whitespaces(15) + print("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print_n_newlines(2) + + +def print_instructions() -> None: + print("HELLO, ALL YOU BLOODLOVERS AND AFICIONADOS.") + print("HERE IS YOUR BIG CHANCE TO KILL A BULL.") + print() + print("ON EACH PASS OF THE BULL, YOU MAY TRY") + print("0 - VERONICA (DANGEROUS INSIDE MOVE OF THE CAPE)") + print("1 - LESS DANGEROUS OUTSIDE MOVE OF THE CAPE") + print("2 - ORDINARY SWIRL OF THE CAPE.") + print() + print("INSTEAD OF THE ABOVE, YOU MAY TRY TO KILL THE BULL") + print("ON ANY TURN: 4 (OVER THE HORNS), 5 (IN THE CHEST).") + print("BUT IF I WERE YOU,") + print("I WOULDN'T TRY IT BEFORE THE SEVENTH PASS.") + print() + print("THE CROWD WILL DETERMINE WHAT AWARD YOU DESERVE") + print("(POSTHUMOUSLY IF NECESSARY).") + print("THE BRAVER YOU ARE, THE BETTER THE AWARD YOU RECEIVE.") + print() + print("THE BETTER THE JOB THE PICADORES AND TOREADORES DO,") + print("THE BETTER YOUR CHANCES ARE.") + + +def print_intro() -> None: + print_header() + want_instructions = input("DO YOU WANT INSTRUCTIONS? ") + if want_instructions != "NO": + print_instructions() + print_n_newlines(2) + + +def ask_bool(prompt: str) -> bool: + while True: + answer = input(prompt) + if answer == "YES": + return True + elif answer == "NO": + return False + else: + print("INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'.") + + +def ask_int() -> int: + while True: + foo = float(input()) + if foo != float(int(abs(foo))): # we actually want an integer + print("DON'T PANIC, YOU IDIOT! PUT DOWN A CORRECT NUMBER") + elif foo < 3: + break + return int(foo) + + +def did_bull_hit( + bull_quality: int, + cape_move: int, + job_quality_by_round: Dict[int, float], + move_risk_sum: float, +) -> Tuple[bool, float]: + # The bull quality is a grade: The lower the grade, the better the bull + if cape_move == 0: + move_risk: Union[int, float] = 3 + elif cape_move == 1: + move_risk = 2 + else: + move_risk = 0.5 + move_risk_sum += move_risk + bull_strength = 6 - bull_quality + bull_hit_factor = ( # the higher the factor, the more "likely" it hits + (bull_strength + move_risk / 10) + * random.random() + / ( + ( + job_quality_by_round[1] + + job_quality_by_round[2] + + job_quality_by_round[3] / 10 + ) + * 5 + ) + ) + bull_hit = bull_hit_factor >= 0.51 + return bull_hit, move_risk_sum + + +def handle_bullkill_attempt( + kill_method: int, + job_quality_by_round: Dict[int, float], + bull_quality: int, + gore: int, +) -> int: + if kill_method not in [4, 5]: + print("YOU PANICKED. THE BULL GORED YOU.") + gore = 2 + else: + bull_strength = 6 - bull_quality + kill_probability = ( + bull_strength + * 10 + * random.random() + / ( + (job_quality_by_round[1] + job_quality_by_round[2]) + * 5 + * job_quality_by_round[3] + ) + ) + if kill_method == 4: + if kill_probability > 0.8: + gore = 1 + else: + if kill_probability > 0.2: + gore = 1 + if gore == 0: + print("YOU KILLED THE BULL!") + job_quality_by_round[5] = 2 + return gore + return gore + + +def final_message( + job_quality_by_round: Dict[int, float], bull_quality: int, move_risk_sum: float +) -> None: + print_n_newlines(3) + if job_quality_by_round[4] == 0: + print("THE CROWD BOOS FOR TEN MINUTES. IF YOU EVER DARE TO SHOW") + print("YOUR FACE IN A RING AGAIN, THEY SWEAR THEY WILL KILL YOU--") + print("UNLESS THE BULL DOES FIRST.") + else: + if job_quality_by_round[4] == 2: + print("THE CROWD CHEERS WILDLY!") + elif job_quality_by_round[5] == 2: + print("THE CROWD CHEERS!") + print() + print("THE CROWD AWARDS YOU") + score = calculate_final_score(move_risk_sum, job_quality_by_round, bull_quality) + if score == 0: + print("NOTHING AT ALL.") + elif score == 1: + print("ONE EAR OF THE BULL.") + elif score == 2: + print("BOTH EARS OF THE BULL!") + print("OLE!") + else: + print("OLE! YOU ARE 'MUY HOMBRE'!! OLE! OLE!") + print() + print("ADIOS") + print_n_newlines(3) + + +def main() -> None: + print_intro() + move_risk_sum: float = 1 + job_quality_by_round: Dict[int, float] = {4: 1, 5: 1} + job_quality = ["", "SUPERB", "GOOD", "FAIR", "POOR", "AWFUL"] + bull_quality = random.randint( + 1, 5 + ) # the lower the number, the more powerful the bull + print(f"YOU HAVE DRAWN A {job_quality[bull_quality]} BULL.") + if bull_quality > 4: + print("YOU'RE LUCKY.") + elif bull_quality < 2: + print("GOOD LUCK. YOU'LL NEED IT.") + print() + print() + + # Round 1: Run Picadores + player_type: Literal["TOREAD", "PICADO"] = "PICADO" + plural_form: Literal["ORES", "RES"] = "RES" + job_quality_factor = determine_player_kills( + bull_quality, player_type, plural_form, job_quality + ) + job_quality_by_round[1] = job_quality_factor + + # Round 2: Run Toreadores + player_type = "TOREAD" + plural_form = "ORES" + determine_player_kills(bull_quality, player_type, plural_form, job_quality) + job_quality_by_round[2] = job_quality_factor + print_n_newlines(2) + + # Round 3 + job_quality_by_round[3] = 0 + while True: + job_quality_by_round[3] = job_quality_by_round[3] + 1 + print(f"PASS NUMBER {job_quality_by_round[3]}") + if job_quality_by_round[3] >= 3: + run_from_ring = ask_bool("HERE COMES THE BULL. TRY FOR A KILL? ") + if not run_from_ring: + print("CAPE MOVE? ", end="") + else: + print("THE BULL IS CHARGING AT YOU! YOU ARE THE MATADOR--") + run_from_ring = ask_bool("DO YOU WANT TO KILL THE BULL? ") + if not run_from_ring: + print("WHAT MOVE DO YOU MAKE WITH THE CAPE? ", end="") + gore = 0 + if not run_from_ring: + cape_move = ask_int() + bull_hit, move_risk_sum = did_bull_hit( + bull_quality, cape_move, job_quality_by_round, move_risk_sum + ) + if bull_hit: + gore = 1 + else: + continue + else: + print() + print("IT IS THE MOMENT OF TRUTH.") + print() + kill_method = int(input("HOW DO YOU TRY TO KILL THE BULL? ")) + gore = handle_bullkill_attempt( + kill_method, job_quality_by_round, bull_quality, gore + ) + if gore == 0: + break + if gore > 0: + if gore == 1: + print("THE BULL HAS GORED YOU!") + death = False + while True: + if random.randint(1, 2) == 1: + print("YOU ARE DEAD.") + job_quality_by_round[4] = 1.5 + death = True + break + else: + print("YOU ARE STILL ALIVE.") + print() + print("DO YOU RUN FROM THE RING? ", end="") + run_from_ring = ask_bool("DO YOU RUN FROM THE RING? ") + if not run_from_ring: + print("YOU ARE BRAVE. STUPID, BUT BRAVE.") + if random.randint(1, 2) == 1: + job_quality_by_round[4] = 2 + death = True + break + else: + print("YOU ARE GORED AGAIN!") + else: + print("COWARD") + job_quality_by_round[4] = 0 + death = True + break + + if death: + break + + final_message(job_quality_by_round, bull_quality, move_risk_sum) + + +if __name__ == "__main__": + main() diff --git a/17_Bullfight/python/test_bullfight.py b/17_Bullfight/python/test_bullfight.py new file mode 100644 index 00000000..f61c6b65 --- /dev/null +++ b/17_Bullfight/python/test_bullfight.py @@ -0,0 +1,16 @@ +import io + +from _pytest.monkeypatch import MonkeyPatch +from bullfight import main + + +def test_main(monkeypatch: MonkeyPatch) -> None: + instructions = "Y" + kill_bull = "YES" + kill_method = "0" + run_from_ring = "YES" + monkeypatch.setattr( + "sys.stdin", + io.StringIO(f"{instructions}\n{kill_bull}\n{kill_method}\n{run_from_ring}\n"), + ) + main()