"""CSC108/CSCA08: Fall 2022 -- Assignment 1: Mystery Message Game This code is provided solely for the personal and private use of students taking the CSC108/CSCA08 course at the University of Toronto. Copying for purposes other than this use is expressly prohibited. All forms of distribution of this code, whether as given or with any changes, are expressly prohibited. All of the files in this directory and all subdirectories are: Copyright (c) 2022 Mario Badr, Jennifer Campbell, Tom Fairgrieve, Diane Horton, Michael Liut, Jacqueline Smith, Anya Tafliovich and Michelle Craig. """ from constants import (CONSONANT_POINTS, VOWEL_COST, CONSONANT_BONUS, PLAYER_ONE, PLAYER_TWO, CONSONANT, VOWEL, SOLVE, QUIT, HUMAN, HUMAN_HUMAN, HUMAN_COMPUTER, EASY, HARD, ALL_CONSONANTS, ALL_VOWELS, PRIORITY_CONSONANTS, HIDDEN) # We provide this function as an example. def is_win(view: str, message: str) -> bool: """Return True if and only if message and view are a winning combination. That is, if and only if message and view are the same. >>> is_win('banana', 'banana') True >>> is_win('a^^le', 'apple') False >>> is_win('app', 'apple') False """ return message == view # We provide this function as an example of using a function as a helper. def is_game_over(view: str, message: str, move: str) -> bool: """Return True if and only if message and view are a winning combination or move is QUIT. >>> is_game_over('a^^le', 'apple', 'V') False >>> is_game_over('a^^le', 'apple', 'Q') True >>> is_game_over('apple', 'apple', 'S') True """ return move == QUIT or is_win(view, message) # We provide the header and docstring of this function as an example # of where and how to use constants in the docstring. def is_human(current_player: str, game_type: str) -> bool: """Return True if and only if current_player represents a human in a game of type game_type. current_player is PLAYER_ONE or PLAYER_TWO. game_type is HUMAN, HUMAN_HUMAN, or HUMAN_COMPUTER. In a HUMAN game or a HUMAN_HUMAN game, a player is always human. In a HUMAN_COMPUTER game, PLAYER_ONE is human and PLAYER_TWO is computer. >>> is_human('Player One', 'P1') True >>> is_human('Player One', 'PVP') True >>> is_human('Player Two', 'PVP') True >>> is_human('Player One', 'PVE') True >>> is_human('Player Two', 'PVE') False """ not_human = current_player == PLAYER_TWO and game_type == HUMAN_COMPUTER return not not_human def half_revealed(view: str) -> bool: """Return True if and only if at least half of the alphabetic characters in view are revealed. >>> half_revealed('') True >>> half_revealed('x') True >>> half_revealed('^') False >>> half_revealed('a^,^c!') True >>> half_revealed('a^b^^e ^c^d^^d') False """ num_hidden = view.count(HIDDEN) num_alphabetic = 0 for char in view: if char.isalpha(): num_alphabetic += 1 return num_alphabetic >= num_hidden def is_one_player_game(game_type: str) -> bool: """Return True if and only if game_type represents a one-player game. game_type is HUMAN, HUMAN_HUMAN, or HUMAN_COMPUTER. In a HUMAN game, there is only one player. >>> is_one_player_game(HUMAN) True >>> is_one_player_game(HUMAN_COMPUTER) False >>> is_one_player_game(HUMAN_HUMAN) False """ return game_type == HUMAN def current_player_score(player_one_score: int, player_two_score: int, current_player: str) -> int: """Return score of current_player, current_player is PLAYER_ONE or\ PLAYER_TWO >>> current_player_score( 5, 6, PLAYER_ONE) 5 >>> current_player_score( 5, 6, PLAYER_TWO) 6 """ if current_player == PLAYER_ONE: return player_one_score else: return player_two_score def is_bonus_letter(view: str, letter: str, message: str) -> bool: """Return True if and only if letter is a bonus letter, that is, it is a \ hidden consonant in view. ALL_CONSONANTS is a string of all consonants in the alphabet. >>> is_bonus_letter('a^^le', 'p', 'apple') True >>> is_bonus_letter('b^n^n^', 'a', 'banana') False >>> is_bonus_letter('bi^^er', 'b', 'bitter') False """ is_hidden = letter in message and letter not in view is_consonant = letter in ALL_CONSONANTS return is_hidden and is_consonant def get_updated_char_view(view: str, message: str, character_index: int, guess: str) -> str: """Return a single character string of an updated view of a character at \ character_index of message. If the guess is correct, updated view is the revealed character, otherwise,\ return the unchanged character from the view before the function was called. >>> get_updated_char_view('a^^le', 'apple', 1, 'p') 'p' >>> get_updated_char_view('b^tter', 'bitter', 1, 'u') '^' """ if guess == message[character_index]: updated_view = message[character_index] return updated_view else: updated_view = view[character_index] return updated_view def calculate_score(player_score: int, num_occurrences: int, move: str) -> int: """Return an updated score player_score calculated according to number of \ occurrences num_occurrences of moves, which are either CONSONANT or VOWEL. >>> calculate_score(10, 2, VOWEL) 9 >>> calculate_score(8, 4, CONSONANT) 12 """ if move == CONSONANT: player_score = player_score + num_occurrences * CONSONANT_POINTS return player_score else: player_score = player_score - VOWEL_COST return player_score\ def next_player(current_player: str, num_occurrences: int, game_type: str) -> str: """Return the player current_player who will play in the next turn,\ current_player can be either PLAYER_ONE or PLAYER_TWO. >>> next_player(PLAYER_ONE, 3, HUMAN_HUMAN) 'Player One' >>> next_player(PLAYER_TWO, 0, HUMAN_COMPUTER) 'Player One' >>> next_player(PLAYER_ONE, 0, HUMAN) 'Player One' >>> next_player(PLAYER_ONE, 0, HUMAN_HUMAN) 'Player Two' >>> next_player(PLAYER_ONE, 0, HUMAN_COMPUTER) 'Player Two' """ if game_type == HUMAN: return current_player elif game_type != HUMAN and num_occurrences >= 1: return current_player else: if current_player == PLAYER_ONE: return PLAYER_TWO else: return PLAYER_ONE def is_fully_hidden(view: str, character_index: int, message: str) -> bool: """Return True if and only if the character at character_index of message\ is not revealed anywhere in view. >>> is_fully_hidden('a^e^', 1 , 'axed') True >>> is_fully_hidden('^ana^a', 4 , 'banana') False """ result = message[character_index] in view return not result def computer_chooses_solve(view: str, difficulty: str, consonants_left: str) -> bool: """Return True if and only if computer decides to solve the mystery. This\ happens when: a) Difficulty is HARD and at least half of the letters have been revealed or \there are no more consonants to guess b) Difficulty is EASY and there are no more consonants to choose from >>> computer_chooses_solve("l^t's g^t it st^rt^d", HARD, '') True >>> computer_chooses_solve('c^n c^n', HARD, 'bdgh') False >>> computer_chooses_solve('^anana', EASY, '') True >>> computer_chooses_solve('a^b^^e ^c^d^^d', HARD, 'fghjk') False >>> computer_chooses_solve('app^e', EASY, 'bcdgh') False """ view_sorted = sorted(view) consonants_left_sorted = sorted(consonants_left) comparable_string_1 = ''.join(list(dict.fromkeys( view_sorted + consonants_left_sorted))) comparable_string_2 = ''.join(filter(str.isalnum, comparable_string_1)) no_more_consonants_guessable = comparable_string_2 in ALL_CONSONANTS if difficulty == HARD: return half_revealed(view) or no_more_consonants_guessable elif difficulty == EASY: return len(consonants_left) == 0 else: return False def erase(string_of_letters: str, character_index: int) -> str: """Return new string of letters, where letter at character_index in \ string_of_letters is removed, if character_index is between 0 and last \ character in string_of_letters. Otherwise, return string_of_letters\ unchanged. >>> erase('abcdefg', 2) 'abdefg' >>> erase('banana', 0) 'banana' >>> erase('apple', 4) "apple" """ if 0 < character_index < len(string_of_letters) - 1: new_string = string_of_letters[0: character_index] + \ string_of_letters[character_index + 1: len(string_of_letters)] return new_string else: return string_of_letters