diff --git a/49_Hockey/python/README.md b/49_Hockey/python/README.md index 781945ec..2d8807aa 100644 --- a/49_Hockey/python/README.md +++ b/49_Hockey/python/README.md @@ -1,3 +1,27 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Python](https://www.python.org/about/) + + +## Porting Notes + +Variables: + +* C: Do you want instructions? +* A$(7): Team name + player names (6 players) +* B$(7): Team name + player names (6 players) +* T6: Minutes per game +* R: REFEREE + +Functions: + +* REM: A line comment +* `INT(2*RND(X))+1`: X is constantly 1. That means that this expression is simpler expressed as `randint(1,2)` + +--- + +Looking at the JS implementation: + +* as[7] / bs[7]: The team name +* ha[8] : Score of team B +* ha[9] : Score of team A diff --git a/49_Hockey/python/hockey.py b/49_Hockey/python/hockey.py new file mode 100644 index 00000000..f1876619 --- /dev/null +++ b/49_Hockey/python/hockey.py @@ -0,0 +1,566 @@ +""" +HOCKEY + +A simulation of an ice hockey game. + +The original author is Robert Puopolo; +modifications by Steve North of Creative Computing. + +Ported to Python by Martin Thoma in 2022 +""" + +from dataclasses import dataclass, field +from random import randint +from typing import List, Tuple + +NB_PLAYERS = 6 + + +@dataclass +class Team: + # TODO: It would be better to use a Player-class (name, goals, assits) + # and have the attributes directly at each player. This would avoid + # dealing with indices that much + # + # I'm also rather certain that I messed up somewhere with the indices + # - instead of using those, one could use actual player positions: + # LEFT WING, CENTER, RIGHT WING + # LEFT DEFENSE, RIGHT DEFENSE, GOALKEEPER + name: str + players: List[str] # 6 players + shots_on_net: int = 0 + goals: List[int] = field(default_factory=lambda: [0 for _ in range(NB_PLAYERS)]) + assists: List[int] = field(default_factory=lambda: [0 for _ in range(NB_PLAYERS)]) + score: int = 0 + + def show_lineup(self) -> None: + print(" " * 10 + f"{self.name} STARTING LINEUP") + for player in self.players: + print(player) + + +def ask_binary(prompt: str, error_msg: str) -> bool: + while True: + answer = input(prompt).lower() + if answer in ["y", "yes"]: + return True + if answer in ["n", "no"]: + return False + print(error_msg) + + +def get_team_names() -> Tuple[str, str]: + while True: + answer = input("ENTER THE TWO TEAMS: ") + if answer.count(",") == 1: + return answer.split(",") # type: ignore + print("separated by a single comma") + + +def get_pass() -> int: + while True: + answer = input("PASS? ") + try: + passes = int(answer) + if passes >= 0 and passes <= 3: + return passes + except ValueError: + print("ENTER A NUMBER BETWEEN 0 AND 3") + + +def get_minutes_per_game() -> int: + while True: + answer = input("ENTER THE NUMBER OF MINUTES IN A GAME ") + try: + minutes = int(answer) + if minutes >= 1: + return minutes + except ValueError: + print("ENTER A NUMBER") + + +def get_player_names(prompt: str) -> List[str]: + players = [] + print(prompt) + for i in range(1, 7): + player = input(f"PLAYER {i}: ") + players.append(player) + return players + + +def make_shot( + controlling_team: int, team_a: Team, team_b: Team, player_index: List[int], j: int +) -> Tuple[int, int, int, int]: + while True: + try: + s = int(input("SHOT? ")) + except ValueError: + continue + if s >= 1 and s <= 4: + break + if controlling_team == 1: + print(team_a.players[player_index[j - 1]]) + else: + print(team_b.players[player_index[j - 1]]) + g = player_index[j - 1] + g1 = 0 + g2 = 0 + if s == 1: + print(" LET'S A BOOMER GO FROM THE RED LINE!!\n") # line 400 + z = 10 + elif s == 2: + print(" FLIPS A WRISTSHOT DOWN THE ICE\n") # line 420 + # Probable missing line 430 in original + elif s == 3: + print(" BACKHANDS ONE IN ON THE GOALTENDER\n") + z = 25 + elif s == 4: + print(" SNAPS A LONG FLIP SHOT\n") + # line 460 + z = 17 + return z, g, g1, g2 + + +def print_header() -> None: + print(" " * 33 + "HOCKEY") + print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") + + +def instructions() -> None: + wants_it = ask_binary("WOULD YOU LIKE THE INSTRUCTIONS? ", "ANSWER YES OR NO!!") + if wants_it: + print() + print("THIS IS A SIMULATED HOCKEY GAME.") + print("QUESTION RESPONSE") + print("PASS TYPE IN THE NUMBER OF PASSES YOU WOULD") + print(" LIKE TO MAKE, FROM 0 TO 3.") + print("SHOT TYPE THE NUMBER CORRESPONDING TO THE SHOT") + print(" YOU WANT TO MAKE. ENTER:") + print(" 1 FOR A SLAPSHOT") + print(" 2 FOR A WRISTSHOT") + print(" 3 FOR A BACKHAND") + print(" 4 FOR A SNAP SHOT") + print("AREA TYPE IN THE NUMBER CORRESPONDING TO") + print(" THE AREA YOU ARE AIMING AT. ENTER:") + print(" 1 FOR UPPER LEFT HAND CORNER") + print(" 2 FOR UPPER RIGHT HAND CORNER") + print(" 3 FOR LOWER LEFT HAND CORNER") + print(" 4 FOR LOWER RIGHT HAND CORNER") + print("AT THE START OF THE GAME, YOU WILL BE ASKED FOR THE NAMES") + print("OF YOUR PLAYERS. THEY ARE ENTERED IN THE ORDER: ") + print("LEFT WING, CENTER, RIGHT WING, LEFT DEFENSE,") + print("RIGHT DEFENSE, GOALKEEPER. ANY OTHER INPUT REQUIRED WILL") + print("HAVE EXPLANATORY INSTRUCTIONS.") + + +def team1_action( + pass_value: int, player_index: List[int], team_a: Team, team_b: Team, j: int +) -> Tuple[int, int, int, int]: + if pass_value == 1: + print( + team_a.players[player_index[j - 2]] + + " LEADS " + + team_a.players[player_index[j - 1]] + + " WITH A PERFECT PASS.\n" + ) + print(team_a.players[player_index[j - 1]] + " CUTTING IN!!!\n") + scoring_player = player_index[j - 1] + goal_assistant1 = player_index[j - 2] + goal_assistant2 = 0 + z1 = 3 + elif pass_value == 2: + print( + team_a.players[player_index[j - 2]] + + " GIVES TO A STREAKING " + + team_a.players[player_index[j - 1]] + ) + print( + team_a.players[player_index[j - 3]] + + " COMES DOWN ON " + + team_b.players[4] + + " AND " + + team_b.players[3] + ) + scoring_player = player_index[j - 3] + goal_assistant1 = player_index[j - 1] + goal_assistant2 = player_index[j - 2] + z1 = 2 + elif pass_value == 3: + print("OH MY GOD!! A ' 4 ON 2 ' SITUATION\n") + print( + team_a.players[player_index[j - 3]] + + " LEADS " + + team_a.players[player_index[j - 2]] + + "\n" + ) + print(team_a.players[player_index[j - 2]] + " IS WHEELING THROUGH CENTER.\n") + print( + team_a.players[player_index[j - 2]] + + " GIVES AND GOEST WITH " + + team_a.players[player_index[j - 1]] + ) + print("PRETTY PASSING!\n") + print( + team_a.players[player_index[j - 1]] + + " DROPS IT TO " + + team_a.players[player_index[j - 4]] + ) + scoring_player = player_index[j - 4] + goal_assistant1 = player_index[j - 1] + goal_assistant2 = player_index[j - 2] + z1 = 1 + return scoring_player, goal_assistant1, goal_assistant2, z1 + + +def team2_action( + pass_value: int, player_index: List[int], team_a: Team, team_b: Team, j: int +) -> Tuple[int, int, int, int]: + if pass_value == 1: + print( + team_b.players[player_index[j - 1]] + + " HITS " + + team_b.players[player_index[j - 2]] + + " FLYING DOWN THE LEFT SIDE\n" + ) + scoring_player = player_index[j - 2] + goal_assistant1 = player_index[j - 1] + goal_assistant2 = 0 + z1 = 3 + elif pass_value == 2: + print("IT'S A ' 3 ON 2 '!\n") + print( + "ONLY " + team_a.players[3] + " AND " + team_a.players[4] + " ARE BACK.\n" + ) + print( + team_b.players[player_index[j - 2]] + + " GIVES OFF TO " + + team_b.players[player_index[j - 1]] + ) + print( + team_b.players[player_index[j - 1]] + + " DROPS TO " + + team_b.players[player_index[j - 3]] + ) + scoring_player = player_index[j - 3] + goal_assistant1 = player_index[j - 1] + goal_assistant2 = player_index[j - 2] + z1 = 2 + elif pass_value == 3: + print(" A '3 ON 2 ' WITH A ' TRAILER '!\n") + print( + team_b.players[player_index[j - 4]] + + " GIVES TO " + + team_b.players[player_index[j - 2]] + + " WHO SHUFFLES IT OFF TO\n" + ) + print( + team_b.players[player_index[j - 1]] + " WHO FIRES A WING TO WING PASS TO \n" + ) + print(team_b.players[player_index[j - 3]] + " AS HE CUTS IN ALONE!!\n") + scoring_player = player_index[j - 3] + goal_assistant1 = player_index[j - 1] + goal_assistant2 = player_index[j - 2] + z1 = 1 + return scoring_player, goal_assistant1, goal_assistant2, z1 + + +def final_message(team_a: Team, team_b: Team, player_index: List[int]) -> None: + # Bells chime + print("THAT'S THE SIREN\n") + print("\n") + print(" " * 15 + "FINAL SCORE:\n") + if team_b.score <= team_a.score: + print(f"{team_a.name}: {team_a.score}\t{team_b.name}: {team_b.score}\n") + else: + print(f"{team_b.name}: {team_b.score}\t{team_a.name}\t:{team_a.score}\n") + print("\n") + print(" " * 10 + "SCORING SUMMARY\n") + print("\n") + print(" " * 25 + team_a.name + "\n") + print("\tNAME\tGOALS\tASSISTS\n") + print("\t----\t-----\t-------\n") + for i in range(1, 6): + print(f"\t{team_a.players[i]}\t{team_a.goals[i]}\t{team_a.assists[i]}\n") + print("\n") + print(" " * 25 + team_b.name + "\n") + print("\tNAME\tGOALS\tASSISTS\n") + print("\t----\t-----\t-------\n") + for t in range(1, 6): + print(f"\t{team_b.players[t]}\t{team_b.goals[t]}\t{team_b.assists[t]}\n") + print("\n") + print("SHOTS ON NET\n") + print(f"{team_a.name}: {team_a.shots_on_net}\n") + print(team_b.name + f": {team_b.shots_on_net}\n") + + +def main() -> None: + # Intro + print_header() + player_index: List[int] = [0 for _ in range(21)] + print("\n" * 3) + instructions() + + # Gather input + team_name_a, team_name_b = get_team_names() + print() + minutes_per_game = get_minutes_per_game() + print() + players_a = get_player_names(f"WOULD THE {team_name_a} COACH ENTER HIS TEAM") + print() + players_b = get_player_names(f"WOULD THE {team_name_b} COACH DO THE SAME") + team_a = Team(team_name_a, players_a) + team_b = Team(team_name_b, players_b) + print() + referee = input("INPUT THE REFEREE FOR THIS GAME: ") + print() + team_a.show_lineup() + print() + team_b.show_lineup() + print("WE'RE READY FOR TONIGHTS OPENING FACE-OFF.") + print( + f"{referee} WILL DROP THE PUCK BETWEEN " + f"{team_a.players[0]} AND {team_b.players[0]}" + ) + remaining_time = minutes_per_game + + # Play the game + while remaining_time > 0: + cont, remaining_time = simulate_game_round( + team_a, team_b, player_index, remaining_time + ) + remaining_time -= 1 + if cont == "break": + break + + # Outro + final_message(team_a, team_b, player_index) + + +def handle_hit( + controlling_team: int, + team_a: Team, + team_b: Team, + player_index: List[int], + goal_player: int, + goal_assistant1: int, + goal_assistant2: int, + hit_area: int, + z: int, +) -> int: + while True: + player_index[20] = randint(1, 100) + if player_index[20] % z != 0: + break + a2 = randint(1, 100) + if a2 % 4 == 0: + if controlling_team == 1: + print(f"SAVE {team_b.players[5]} -- REBOUND\n") + else: + print(f"SAVE {team_a.players[5]} -- FOLLOW up\n") + continue + else: + hit_area += 1 + if player_index[20] % z != 0: + if controlling_team == 1: + print(f"GOAL {team_a.name}\n") + team_a.score += 1 + else: + print(f"SCORE {team_b.name}\n") + team_b.score += 1 + # Bells in origninal + print("\n") + print("SCORE: ") + if team_b.score <= team_a.score: + print(f"{team_a.name}: {team_a.score}\t{team_b.name}: {team_b.score}\n") + else: + print(f"{team_b.name}: {team_b.score}\t{team_a.name}: {team_a.score}\n") + if controlling_team == 1: + team = team_a + else: + team = team_b + print("GOAL SCORED BY: " + team.players[goal_player] + "\n") + if goal_assistant1 != 0: + if goal_assistant2 != 0: + print( + f" ASSISTED BY: {team.players[goal_assistant1]}" + f" AND {team.players[goal_assistant2]}" + ) + else: + print(f" ASSISTED BY: {team.players[goal_assistant1]}") + team.assists[goal_assistant1] += 1 + team.assists[goal_assistant2] += 1 + else: + print(" UNASSISTED.\n") + team.goals[goal_player] += 1 + + return hit_area + + +def handle_miss( + controlling_team: int, + team_a: Team, + team_b: Team, + remaining_time: int, + goal_player: int, +) -> Tuple[str, int]: + saving_player = randint(1, 7) + if controlling_team == 1: + if saving_player == 1: + print("KICK SAVE AND A BEAUTY BY " + team_b.players[5] + "\n") + print("CLEARED OUT BY " + team_b.players[3] + "\n") + remaining_time -= 1 + return ("continue", remaining_time) + if saving_player == 2: + print("WHAT A SPECTACULAR GLOVE SAVE BY " + team_b.players[5] + "\n") + print("AND " + team_b.players[5] + " GOLFS IT INTO THE CROWD\n") + return ("break", remaining_time) + if saving_player == 3: + print("SKATE SAVE ON A LOW STEAMER BY " + team_b.players[5] + "\n") + remaining_time -= 1 + return ("continue", remaining_time) + if saving_player == 4: + print(f"PAD SAVE BY {team_b.players[5]} OFF THE STICK\n") + print( + f"OF {team_a.players[goal_player]} AND " + f"{team_b.players[5]} COVERS UP\n" + ) + return ("break", remaining_time) + if saving_player == 5: + print(f"WHISTLES ONE OVER THE HEAD OF {team_b.players[5]}\n") + remaining_time -= 1 + return ("continue", remaining_time) + if saving_player == 6: + print(f"{team_b.players[5]} MAKES A FACE SAVE!! AND HE IS HURT\n") + print(f"THE DEFENSEMAN {team_b.players[5]} COVERS UP FOR HIM\n") + return ("break", remaining_time) + else: + if saving_player == 1: + print(f"STICK SAVE BY {team_a.players[5]}\n") + print(f"AND CLEARED OUT BY {team_a.players[3]}\n") + remaining_time -= 1 + return ("continue", remaining_time) + if saving_player == 2: + print( + "OH MY GOD!! " + f"{team_b.players[goal_player]} RATTLES ONE OFF THE POST\n" + ) + print( + f"TO THE RIGHT OF {team_a.players[5]} AND " + f"{team_a.players[5]} COVERS " + ) + print("ON THE LOOSE PUCK!\n") + return ("break", remaining_time) + if saving_player == 3: + print("SKATE SAVE BY " + team_a.players[5] + "\n") + print(team_a.players[5] + " WHACKS THE LOOSE PUCK INTO THE STANDS\n") + return ("break", remaining_time) + if saving_player == 4: + print( + "STICK SAVE BY " + team_a.players[5] + " AND HE CLEARS IT OUT HIMSELF\n" + ) + remaining_time -= 1 + return ("continue", remaining_time) + if saving_player == 5: + print("KICKED OUT BY " + team_a.players[5] + "\n") + print("AND IT REBOUNDS ALL THE WAY TO CENTER ICE\n") + remaining_time -= 1 + return ("continue", remaining_time) + if saving_player == 6: + print("GLOVE SAVE " + team_a.players[5] + " AND HE HANGS ON\n") + return ("break", remaining_time) + return ("continue", remaining_time) + + +def simulate_game_round( + team_a: Team, team_b: Team, player_index: List[int], remaining_time: int +) -> Tuple[str, int]: + controlling_team = randint(1, 2) + if controlling_team == 1: + print(f"{team_a.name} HAS CONTROL OF THE PUCK.") + else: + print(f"{team_b.name} HAS CONTROL.") + pass_value = get_pass() + for i in range(1, 4): + player_index[i] = 0 + + # Line 310: + while True: + j = 0 + for j in range(1, (pass_value + 2) + 1): + player_index[j] = randint(1, 5) + if player_index[j - 1] == player_index[j - 2] or ( + pass_value + 2 >= 3 + and ( + player_index[j - 1] == player_index[j - 3] + or player_index[j - 2] == player_index[j - 3] + ) + ): + break + if pass_value == 0: # line 350 + z, goal_player, goal_assistant1, goal_assistant2 = make_shot( + controlling_team, team_a, team_b, player_index, j + ) + else: + if controlling_team == 1: + goal_player, goal_assistant1, goal_assistant2, z1 = team1_action( + pass_value, player_index, team_a, team_b, j + ) + else: + goal_player, goal_assistant1, goal_assistant2, z1 = team2_action( + pass_value, player_index, team_a, team_b, j + ) + while True: + shot_type = int(input("SHOT? ")) + if not (shot_type < 1 or shot_type > 4): + break + if controlling_team == 1: + print(team_a.players[goal_player], end="") + else: + print(team_b.players[goal_player], end="") + if shot_type == 1: + print(" LET'S A BIG SLAP SHOT GO!!\n") + z = 4 + z += z1 + if shot_type == 2: + print(" RIPS A WRIST SHOT OFF\n") + z = 2 + z += z1 + if shot_type == 3: + print(" GETS A BACKHAND OFF\n") + z = 3 + z += z1 + if shot_type == 4: + print(" SNAPS OFF A SNAP SHOT\n") + z = 2 + z += z1 + while True: + goal_area = int(input("AREA? ")) + if not (goal_area < 1 or goal_area > 4): + break + if controlling_team == 1: + team_a.shots_on_net += 1 + else: + team_b.shots_on_net += 1 + hit_area = randint(1, 5) + if goal_area == hit_area: + hit_area = handle_hit( + controlling_team, + team_a, + team_b, + player_index, + goal_player, + goal_assistant1, + goal_assistant2, + hit_area, + z, + ) + if goal_area != hit_area: + return handle_miss( + controlling_team, team_a, team_b, remaining_time, goal_player + ) + print("AND WE'RE READY FOR THE FACE-OFF\n") + return ("continue", remaining_time) + + +if __name__ == "__main__": + main()