mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-12 15:50:20 -08:00
331 lines
10 KiB
Python
331 lines
10 KiB
Python
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).lower()
|
|
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()
|