From 13d5233e5a3ce1a0946bda980ffcac7f0c12980b Mon Sep 17 00:00:00 2001 From: Daniel Piron Date: Sat, 20 Feb 2021 11:58:36 -0500 Subject: [PATCH 1/4] Implement Core Game --- 11 Bombardment/python/bombardment.py | 113 +++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100755 11 Bombardment/python/bombardment.py diff --git a/11 Bombardment/python/bombardment.py b/11 Bombardment/python/bombardment.py new file mode 100755 index 00000000..0552f0d2 --- /dev/null +++ b/11 Bombardment/python/bombardment.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 +import random + +def display_intro(): + print("" * 33 + "BOMBARDMENT") + print("" * 15 + " CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print("\n\n") + print("YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU") + print("HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.") + print("YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.") + print("THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.") + print() + print("THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE") + print("OUTPOSTS OF THE COMPUTER. IT WILL DO THE SAME TO YOU.") + print("THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS") + print("FIRST IS THE WINNER.") + print() + print("GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!") + print() + print("TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.") + print("\n" * 4) + + +def display_field(): + for row in range(5): + initial = row * 5 + 1 + print('\t'.join([str(initial + column) for column in range(5)])) + + print("\n" * 9) + + +def generate_enemy_positions(): + """ Randomly choose 4 'positions' out of a range of 1 to 25 """ + positions = list(range(1, 26, 1)) + random.shuffle(positions) + return set(positions[:4]) + + +def prompt_for_player_positions(): + + while True: + raw_positions = input("WHAT ARE YOUR FOUR POSITIONS? ") + positions = set(int(pos) for pos in raw_positions.split()) + + # Verify user inputs (for example, if the player gives a + # a position for 26, the enemy can never hit it) + if (len(positions) != 4): + print("PLEASE ENTER 4 UNIQUE POSITIONS\n") + continue + elif (any(pos not in range(1, 26, 1) for pos in positions)): + print("ALL POSITIONS MUST RANGE (1-25)\n") + continue + else: + return positions + + +# Messages correspond to outposts remaining (3, 2, 1, 0) +PLAYER_PROGRESS_MESSAGES = ( + "YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN\n" + "MY TRANSISTO&S RECUP%RA*E!", + "THREE DOWN, ONE TO GO.\n\n", + "TWO DOWN, TWO TO GO.\n\n", + "ONE DOWN, THREE TO GO.\n\n" + ) + + +ENEMY_PROGRESS_MESSAGES = ( + "YOU'RE DEAD. YOUR LAST OUTPOST WAS AT {}. HA, HA, HA.\n" + "BETTER LUCK NEXT TIME.", + "YOU HAVE ONLY ONE OUTPOST LEFT.\n\n", + "YOU HAVE ONLY TWO OUTPOSTS LEFT.\n\n", + "YOU HAVE ONLY THREE OUTPOSTS LEFT.\n\n", + ) + + +def play(): + display_intro() + display_field() + + enemy_positions = generate_enemy_positions() + player_positions = prompt_for_player_positions() + + print(enemy_positions) + + while True: + target = int(input("WHERE DO YOU WISH TO FIRE YOUR MISSLE? ")) + + if target in enemy_positions: + print("YOU GOT ONE OF MY OUTPOSTS!") + enemy_positions.remove(target) + + outposts_left = len(enemy_positions) + print(PLAYER_PROGRESS_MESSAGES[outposts_left]) + if outposts_left == 0: + break + else: + print("HA, HA YOU MISSED. MY TURN NOW:\n\n") + + target = random.randint(1, 25) + if target in player_positions: + print("I GOT YOU. IT WON'T BE LONG NOW. POST", target, "WAS HIT.") + player_positions.remove(target) + + outposts_left = len(player_positions) + print(ENEMY_PROGRESS_MESSAGES[len(player_positions)].format(target)) + if outposts_left == 0: + break + else: + print("I MISSED YOU, YOU DIRTY RAT. I PICKED", target, ". YOUR TURN:\n\n") + + +if __name__ == "__main__": + play() From 37d82b6d56f5db0e493418aef1bf925187658112 Mon Sep 17 00:00:00 2001 From: Daniel Piron Date: Sat, 20 Feb 2021 13:00:34 -0500 Subject: [PATCH 2/4] Extract function for prompting user input --- 11 Bombardment/python/bombardment.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/11 Bombardment/python/bombardment.py b/11 Bombardment/python/bombardment.py index 0552f0d2..4320803a 100755 --- a/11 Bombardment/python/bombardment.py +++ b/11 Bombardment/python/bombardment.py @@ -36,24 +36,37 @@ def generate_enemy_positions(): return set(positions[:4]) +def is_valid_position(pos): + return pos in range(1, 26, 1) + + def prompt_for_player_positions(): while True: raw_positions = input("WHAT ARE YOUR FOUR POSITIONS? ") positions = set(int(pos) for pos in raw_positions.split()) - # Verify user inputs (for example, if the player gives a # a position for 26, the enemy can never hit it) if (len(positions) != 4): print("PLEASE ENTER 4 UNIQUE POSITIONS\n") continue - elif (any(pos not in range(1, 26, 1) for pos in positions)): + elif (any(not is_valid_position(pos) for pos in positions)): print("ALL POSITIONS MUST RANGE (1-25)\n") continue else: return positions +def prompt_player_for_target(): + while True: + target = int(input("WHERE DO YOU WISH TO FIRE YOUR MISSLE? ")) + if not is_valid_position(target): + print("POSITIONS MUST RANGE (1-25)\n") + continue + + return target + + # Messages correspond to outposts remaining (3, 2, 1, 0) PLAYER_PROGRESS_MESSAGES = ( "YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN\n" @@ -83,7 +96,7 @@ def play(): print(enemy_positions) while True: - target = int(input("WHERE DO YOU WISH TO FIRE YOUR MISSLE? ")) + target = prompt_player_for_target() if target in enemy_positions: print("YOU GOT ONE OF MY OUTPOSTS!") From ee3c10545f66bda3014299e1a8b95fcb5b8c3ac2 Mon Sep 17 00:00:00 2001 From: Daniel Piron Date: Sat, 20 Feb 2021 13:28:05 -0500 Subject: [PATCH 3/4] Attack portion as partial functions --- 11 Bombardment/python/bombardment.py | 52 ++++++++++++++++------------ 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/11 Bombardment/python/bombardment.py b/11 Bombardment/python/bombardment.py index 4320803a..5bc3765e 100755 --- a/11 Bombardment/python/bombardment.py +++ b/11 Bombardment/python/bombardment.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import random +from functools import partial def display_intro(): print("" * 33 + "BOMBARDMENT") @@ -67,6 +68,18 @@ def prompt_player_for_target(): return target +def attack(target, positions, hit_message, miss_message, progress_messages): + + if target in positions: + print(hit_message.format(target)) + positions.remove(target) + print(progress_messages[len(positions)].format(target)) + + print(miss_message.format(target)) + + return len(positions) == 0 + + # Messages correspond to outposts remaining (3, 2, 1, 0) PLAYER_PROGRESS_MESSAGES = ( "YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN\n" @@ -93,33 +106,28 @@ def play(): enemy_positions = generate_enemy_positions() player_positions = prompt_for_player_positions() - print(enemy_positions) + # Build partial functions only requiring the target as input + player_attacks = partial(attack, + positions=enemy_positions, + hit_message="YOU GOT ONE OF MY OUTPOSTS!", + miss_message="HA, HA YOU MISSED. MY TURN NOW:\n\n", + progress_messages=PLAYER_PROGRESS_MESSAGES) + + enemy_attacks = partial(attack, + positions=player_positions, + hit_message="I GOT YOU. IT WON'T BE LONG NOW. POST {} WAS HIT.", + miss_message="I MISSED YOU, YOU DIRTY RAT. I PICKED {}. YOUR TURN:\n\n", + progress_messages=ENEMY_PROGRESS_MESSAGES) + while True: target = prompt_player_for_target() - - if target in enemy_positions: - print("YOU GOT ONE OF MY OUTPOSTS!") - enemy_positions.remove(target) - - outposts_left = len(enemy_positions) - print(PLAYER_PROGRESS_MESSAGES[outposts_left]) - if outposts_left == 0: - break + if (player_attacks(target)): + break else: - print("HA, HA YOU MISSED. MY TURN NOW:\n\n") - - target = random.randint(1, 25) - if target in player_positions: - print("I GOT YOU. IT WON'T BE LONG NOW. POST", target, "WAS HIT.") - player_positions.remove(target) - - outposts_left = len(player_positions) - print(ENEMY_PROGRESS_MESSAGES[len(player_positions)].format(target)) - if outposts_left == 0: + target = random.randint(1, 25) + if (enemy_attacks(target)): break - else: - print("I MISSED YOU, YOU DIRTY RAT. I PICKED", target, ". YOUR TURN:\n\n") if __name__ == "__main__": From 34346f26260ea6794073b4ace1923e3bd36d8b6b Mon Sep 17 00:00:00 2001 From: Daniel Piron Date: Sat, 20 Feb 2021 13:50:40 -0500 Subject: [PATCH 4/4] Make heavy use of functions and closures for encapsulation and clarity --- 11 Bombardment/python/bombardment.py | 41 ++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/11 Bombardment/python/bombardment.py b/11 Bombardment/python/bombardment.py index 5bc3765e..a16113e7 100755 --- a/11 Bombardment/python/bombardment.py +++ b/11 Bombardment/python/bombardment.py @@ -30,15 +30,19 @@ def display_field(): print("\n" * 9) +def positions_list(): + return list(range(1, 26, 1)) + + def generate_enemy_positions(): """ Randomly choose 4 'positions' out of a range of 1 to 25 """ - positions = list(range(1, 26, 1)) + positions = positions_list() random.shuffle(positions) return set(positions[:4]) def is_valid_position(pos): - return pos in range(1, 26, 1) + return pos in positions_list() def prompt_for_player_positions(): @@ -59,6 +63,7 @@ def prompt_for_player_positions(): def prompt_player_for_target(): + while True: target = int(input("WHERE DO YOU WISH TO FIRE YOUR MISSLE? ")) if not is_valid_position(target): @@ -69,15 +74,31 @@ def prompt_player_for_target(): def attack(target, positions, hit_message, miss_message, progress_messages): + """ Performs attack procedure returning True if we are to continue. """ if target in positions: print(hit_message.format(target)) positions.remove(target) print(progress_messages[len(positions)].format(target)) + else: + print(miss_message.format(target)) - print(miss_message.format(target)) + return len(positions) > 0 - return len(positions) == 0 + +def init_enemy(): + """ Returns a closure analogous to prompt_player_for_target. Will + choose from a unique sequence of positions to avoid picking the + same position twice. """ + + position_sequence = positions_list() + random.shuffle(position_sequence) + position = iter(position_sequence) + + def choose(): + return next(position) + + return choose # Messages correspond to outposts remaining (3, 2, 1, 0) @@ -119,15 +140,11 @@ def play(): miss_message="I MISSED YOU, YOU DIRTY RAT. I PICKED {}. YOUR TURN:\n\n", progress_messages=ENEMY_PROGRESS_MESSAGES) + enemy_position_choice = init_enemy() - while True: - target = prompt_player_for_target() - if (player_attacks(target)): - break - else: - target = random.randint(1, 25) - if (enemy_attacks(target)): - break + # Play as long as both player_attacks and enemy_attacks allow to continue + while player_attacks(prompt_player_for_target()) and enemy_attacks(enemy_position_choice()): + pass if __name__ == "__main__":