mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-25 12:25:10 -08:00
Merge pull request #502 from bernardcooke53/12-bombs-away-python
12. Bombs Away in Python
This commit is contained in:
189
12_Bombs_Away/python/bombs_away.py
Normal file
189
12_Bombs_Away/python/bombs_away.py
Normal file
@@ -0,0 +1,189 @@
|
||||
"""
|
||||
Bombs away
|
||||
|
||||
Ported from BASIC to Python3 by Bernard Cooke (bernardcooke53)
|
||||
Tested with Python 3.8.10, formatted with Black and type checked with mypy.
|
||||
"""
|
||||
import random
|
||||
from typing import Iterable
|
||||
|
||||
|
||||
def _stdin_choice(prompt: str, *, choices: Iterable[str]) -> str:
|
||||
ret = input(prompt)
|
||||
while ret not in choices:
|
||||
print("TRY AGAIN...")
|
||||
ret = input(prompt)
|
||||
return ret
|
||||
|
||||
|
||||
def player_survived() -> None:
|
||||
print("YOU MADE IT THROUGH TREMENDOUS FLAK!!")
|
||||
|
||||
|
||||
def player_death() -> None:
|
||||
print("* * * * BOOM * * * *")
|
||||
print("YOU HAVE BEEN SHOT DOWN.....")
|
||||
print("DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR")
|
||||
print("LAST TRIBUTE...")
|
||||
|
||||
|
||||
def mission_success() -> None:
|
||||
print(f"DIRECT HIT!!!! {int(100 * random.random())} KILLED.")
|
||||
print("MISSION SUCCESSFUL.")
|
||||
|
||||
|
||||
def death_with_chance(p_death: float) -> bool:
|
||||
"""
|
||||
Takes a float between 0 and 1 and returns a boolean
|
||||
if the player has survived (based on random chance)
|
||||
|
||||
Returns True if death, False if survived
|
||||
"""
|
||||
return p_death > random.random()
|
||||
|
||||
|
||||
def commence_non_kamikazi_attack() -> None:
|
||||
while True:
|
||||
try:
|
||||
nmissions = int(input("HOW MANY MISSIONS HAVE YOU FLOWN? "))
|
||||
|
||||
while nmissions >= 160:
|
||||
print("MISSIONS, NOT MILES...")
|
||||
print("150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS")
|
||||
nmissions = int(input("NOW THEN, HOW MANY MISSIONS HAVE YOU FLOWN? "))
|
||||
break
|
||||
except ValueError:
|
||||
# In the BASIC implementation this
|
||||
# wasn't accounted for
|
||||
print("TRY AGAIN...")
|
||||
continue
|
||||
|
||||
if nmissions >= 100:
|
||||
print("THAT'S PUSHING THE ODDS!")
|
||||
|
||||
if nmissions < 25:
|
||||
print("FRESH OUT OF TRAINING, EH?")
|
||||
|
||||
print()
|
||||
return (
|
||||
mission_success() if nmissions >= 160 * random.random() else mission_failure()
|
||||
)
|
||||
|
||||
|
||||
def mission_failure() -> None:
|
||||
weapons_choices = {
|
||||
"1": "GUNS",
|
||||
"2": "MISSILES",
|
||||
"3": "BOTH",
|
||||
}
|
||||
print(f"MISSED TARGET BY {int(2 + 30 * random.random())} MILES!")
|
||||
print("NOW YOU'RE REALLY IN FOR IT !!")
|
||||
print()
|
||||
enemy_weapons = _stdin_choice(
|
||||
prompt="DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)? ",
|
||||
choices=weapons_choices,
|
||||
)
|
||||
|
||||
# If there are no gunners (i.e. weapon choice 2) then
|
||||
# we say that the gunners have 0 accuracy for the purposes
|
||||
# of calculating probability of player death
|
||||
|
||||
enemy_gunner_accuracy = 0.0
|
||||
if enemy_weapons != "2":
|
||||
# If the enemy has guns, how accurate are the gunners?
|
||||
while True:
|
||||
try:
|
||||
enemy_gunner_accuracy = float(
|
||||
input("WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? ")
|
||||
)
|
||||
break
|
||||
except ValueError:
|
||||
# In the BASIC implementation this
|
||||
# wasn't accounted for
|
||||
print("TRY AGAIN...")
|
||||
continue
|
||||
|
||||
if enemy_gunner_accuracy < 10:
|
||||
print("YOU LIE, BUT YOU'LL PAY...")
|
||||
return player_death()
|
||||
|
||||
missile_threat_weighting = 0 if enemy_weapons == "1" else 35
|
||||
|
||||
death = death_with_chance(
|
||||
p_death=(enemy_gunner_accuracy + missile_threat_weighting) / 100
|
||||
)
|
||||
|
||||
return player_survived() if not death else player_death()
|
||||
|
||||
|
||||
def play_italy() -> None:
|
||||
targets_to_messages = {
|
||||
# 1 - ALBANIA, 2 - GREECE, 3 - NORTH AFRICA
|
||||
"1": "SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.",
|
||||
"2": "BE CAREFUL!!!",
|
||||
"3": "YOU'RE GOING FOR THE OIL, EH?",
|
||||
}
|
||||
target = _stdin_choice(
|
||||
prompt="YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)",
|
||||
choices=targets_to_messages,
|
||||
)
|
||||
|
||||
print(targets_to_messages[target])
|
||||
return commence_non_kamikazi_attack()
|
||||
|
||||
|
||||
def play_allies() -> None:
|
||||
aircraft_to_message = {
|
||||
"1": "YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.",
|
||||
"2": "YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.",
|
||||
"3": "YOU'RE CHASING THE BISMARK IN THE NORTH SEA.",
|
||||
"4": "YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.",
|
||||
}
|
||||
aircraft = _stdin_choice(
|
||||
prompt="AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4): ",
|
||||
choices=aircraft_to_message,
|
||||
)
|
||||
|
||||
print(aircraft_to_message[aircraft])
|
||||
return commence_non_kamikazi_attack()
|
||||
|
||||
|
||||
def play_japan() -> None:
|
||||
print("YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.")
|
||||
first_mission = input("YOUR FIRST KAMIKAZE MISSION? (Y OR N): ")
|
||||
if first_mission.lower() == "n":
|
||||
return player_death()
|
||||
return mission_success() if random.random() > 0.65 else player_death()
|
||||
|
||||
|
||||
def play_germany() -> None:
|
||||
targets_to_messages = {
|
||||
# 1 - RUSSIA, 2 - ENGLAND, 3 - FRANCE
|
||||
"1": "YOU'RE NEARING STALINGRAD.",
|
||||
"2": "NEARING LONDON. BE CAREFUL, THEY'VE GOT RADAR.",
|
||||
"3": "NEARING VERSAILLES. DUCK SOUP. THEY'RE NEARLY DEFENSELESS.",
|
||||
}
|
||||
target = _stdin_choice(
|
||||
prompt="A NAZI, EH? OH WELL. ARE YOU GOING FOR RUSSIA(1),\nENGLAND(2), OR FRANCE(3)? ",
|
||||
choices=targets_to_messages,
|
||||
)
|
||||
|
||||
print(targets_to_messages[target])
|
||||
|
||||
return commence_non_kamikazi_attack()
|
||||
|
||||
|
||||
def play_game() -> None:
|
||||
print("YOU ARE A PILOT IN A WORLD WAR II BOMBER.")
|
||||
sides = {"1": play_italy, "2": play_allies, "3": play_japan, "4": play_germany}
|
||||
side = _stdin_choice(
|
||||
prompt="WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4): ", choices=sides
|
||||
)
|
||||
return sides[side]()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
again = True
|
||||
while again:
|
||||
play_game()
|
||||
again = True if input("ANOTHER MISSION? (Y OR N): ").upper() == "Y" else False
|
||||
Reference in New Issue
Block a user