From 3fd1d6b0af88b84d295a14205709315de5369a8b Mon Sep 17 00:00:00 2001 From: Toby Donaldson Date: Sun, 2 Jan 2022 22:57:42 -0800 Subject: [PATCH] added evenwins.py --- 35_Even_Wins/python/evenwins.py | 206 ++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 35_Even_Wins/python/evenwins.py diff --git a/35_Even_Wins/python/evenwins.py b/35_Even_Wins/python/evenwins.py new file mode 100644 index 00000000..fba20024 --- /dev/null +++ b/35_Even_Wins/python/evenwins.py @@ -0,0 +1,206 @@ +# evenwins.py + +# +# This version of evenwins.bas based on game decscription and does *not* +# follow the source. The computer chooses marbles at random. +# +# For simplicity, global variables are used to store the game state. +# A good exercise would be to replace this with a class. +# +# The code is not short, but hopefully it is easy for beginners to understand +# and modify. +# +# Infinite loops of the style "while True:" are used to simplify some of the +# code. The "continue" keyword is used in a few places to jump back to the top +# of the loop. The "return" keyword is also used to break out of functions. +# This is generally considered poor style, but in this case it simplifies the +# code and makes it easier to read (at least in my opinion). A good exercise +# would be to remove these infinite loops, and uses of continue, to follow a +# more structured style. +# + +import random + +# global variables +marbles_in_middle = -1 +human_marbles = -1 +computer_marbles = -1 +whose_turn = '' + +# Only called during development for serious errors that are due to mistakes +# in the program. Should never be called during a regular game. +def serious_error(msg): + print('serious_error: ' + msg) + exit(1) + +def welcome_screen(): + print('Welcome to Even Wins!') + print('Based on evenwins.bas from Creative Computing') + print() + print('Even Wins is a two-person game. You start with') + print('27 marbles in the middle of the table.') + print() + print('Players alternate taking marbles from the middle.') + print('A player can take 1 to 4 marbles on their turn, and') + print('turns cannot be skipped. The game ends when there are') + print('no marbles left, and the winner is the one with an even') + print('number of marbles.') + print() + +def marbles_str(n): + if n == 1: return '1 marble' + return f'{n} marbles' + +def choose_first_player(): + global whose_turn + while True: + ans = input('Do you want to play first? (y/n) --> ') + if ans == 'y': + whose_turn = 'human' + return + elif ans == 'n': + whose_turn = 'computer' + return + else: + print() + print('Please enter "y" if you want to play first,') + print('or "n" if you want to play second.') + print() + +def next_player(): + global whose_turn + if whose_turn == 'human': + whose_turn = 'computer' + elif whose_turn == 'computer': + whose_turn = 'human' + else: + serious_error(f'play_game: unknown player {whose_turn}') + +# Converts a string s to an int, if possible. +def to_int(s): + try: + n = int(s) + return True, n + except: + return False, 0 + +def print_board(): + global marbles_in_middle + global human_marbles + global computer_marbles + print() + print(f' marbles in the middle: {marbles_in_middle} ' + marbles_in_middle*'*') + print(f' # marbles you have: {human_marbles}') + print(f'# marbles computer has: {computer_marbles}') + print() + +def human_turn(): + global marbles_in_middle + global human_marbles + + # get number in range 1 to min(4, marbles_in_middle) + max_choice = min(4, marbles_in_middle) + print("It's your turn!") + while True: + s = input(f'Marbles to take? (1 - {max_choice}) --> ') + ok, n = to_int(s) + if not ok: + print() + print(f' Please enter a whole number from 1 to {max_choice}') + print() + continue + if n < 1: + print() + print(' You must take at least 1 marble!') + print() + continue + if n > max_choice: + print() + print(f' You can take at most {marbles_str(max_choice)}') + print() + continue + print() + print(f'Okay, taking {marbles_str(n)} ...') + marbles_in_middle -= n + human_marbles += n + return + +def game_over(): + global marbles_in_middle + global human_marbles + global computer_marbles + print() + print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!') + print('!! All the marbles are taken: Game Over!') + print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!') + print() + print_board() + if human_marbles % 2 == 0: + print('You are the winner! Congratulations!') + else: + print('The computer wins: all hail mighty silicon!') + print('') + +def computer_turn(): + global marbles_in_middle + global computer_marbles + + print("It's the computer's turn ...") + max_choice = min(4, marbles_in_middle) + + # choose at random + n = random.randint(1, max_choice) + print(f'Computer takes {marbles_str(n)} ...') + marbles_in_middle -= n + computer_marbles += n + +def play_game(): + global marbles_in_middle + global human_marbles + global computer_marbles + + # initialize the game state + marbles_in_middle = 27 + human_marbles = 0 + computer_marbles = 0 + print_board() + + while True: + if marbles_in_middle == 0: + game_over() + return + elif whose_turn == 'human': + human_turn() + print_board() + next_player() + elif whose_turn == 'computer': + computer_turn() + print_board() + next_player() + else: + serious_error(f'play_game: unknown player {whose_turn}') + +def main(): + global whose_turn + + welcome_screen() + + while True: + choose_first_player() + play_game() + + # ask if the user if they want to play again + print() + again = input('Would you like to play again? (y/n) --> ') + if again == 'y': + print() + print("Ok, let's play again ...") + print() + else: + print() + print('Ok, thanks for playing ... goodbye!') + print() + return + +if __name__ == '__main__': + main()