def test_roll_method_updates_game_current_frame(self): game_manager = GameManager() for data in self.roll_current_frame: game_manager.game.current_frame = data['frame'] game_manager.roll(data['roll']) self.assertEqual( game_manager.frames[data['frame']].pin_sets[0].rolls, data['expect'])
def test_has_game_rolls_which_updates_on_roll_or_load(self): game_manager = GameManager() expected = [0, 5, 10] for pins_hit in expected: game_manager.roll(pins_hit) self.assertEqual(game_manager.get_pins_hit_list(), expected) game_manager_two = GameManager(game_manager.game.id) self.assertEqual(game_manager_two.get_pins_hit_list(), expected)
def test_calculate_score_updates_all_frames(self): game_manager = GameManager() for roll in self.frame_score_data['rolls']: game_manager.roll(roll) game_manager.calculate_score() for name, frame in game_manager.frames.items(): self.assertEqual(frame.score, self.frame_score_data['scores'][name - 1])
def test_game_marked_inactive_when_all_frames_complete(self): game_manager = GameManager() for roll in self.frame_score_data['rolls']: game_manager.roll(roll) self.assertFalse(game_manager.game.active) complete_rolls = game_manager.get_pins_hit_list() game_manager.roll(10) extra_rolls = game_manager.get_pins_hit_list() self.assertEqual( complete_rolls, extra_rolls, '\nNo extra rolls should be recorded if a game is not active.')
class GameStyle: """ Controls how to style a Game for template context Instance Variables: - game_manager - GameManager """ def __init__(self, game_id=None): self.game_manager = GameManager(game_id) def roll(self, pins_hit): """ Sends 'pins_hit' through 'GameManager' :param pins_hit: The number of pins struck :type pins_hit: int """ self.game_manager.roll(pins_hit) def get_context(self): """ Obtains a 'Game' context for templates :return: dict context for template :rtype: dict """ context = { 'game_id': self.game_manager.game.id, 'active': self.game_manager.game.active, 'headers': self.get_headers(), 'rolls': self.get_roll_results(), 'scores': self.get_scores() } context.update(self.get_current_frame_data()) return context def get_current_frame(self): """ Helper method to get the current 'Frame' of a 'Game' :return: The current Frame of the Game :rtype: bowling.logic.frame.Frame """ return self.game_manager.frames[self.game_manager.game.current_frame] @staticmethod def get_headers(): """ Obtains header information for templates :return: Dictionary with id as key and display as value :rtype: list[str,int] """ headers = {} for index in range(1, 12): headers[index] = index headers[11] = 'Total Score' return headers def get_roll_results(self): """ Obtains a list of roll results for templates :return: list of results for the Game :rtype: list[str] """ roll_results = [] for name, frame in self.game_manager.frames.items(): frame_results = self.get_frame_result(frame, name) roll_results.extend(frame_results) return roll_results def get_frame_result(self, frame, name): """ Obtains list of roll results by frame :param frame: Frame to extract data from :type frame: bowling.logic.frame.Frame :param name: The name of the Frame :type name: int :return: list of results for the Frame :rtype: list[str] """ frame_results = [] for pin_set in frame.pin_sets: self.get_pin_set_result(frame_results, name, pin_set) self.get_blank_results(frame_results, name, len(frame_results)) return frame_results def get_pin_set_result(self, frame_results, name, pin_set): """ Updates frame_results with data from a 'PinSet' :param frame_results: list to update results to :type frame_results: list :param name: The name of the Frame :type name: int :param pin_set: The PinSet to extract roll results from :type pin_set: bowling.logic.pin_set.PinSet """ status = pin_set.get_status() self.get_strike_results(frame_results, status, name) self.get_spare_results(frame_results, status, pin_set) self.get_normal_results(frame_results, status, pin_set) @staticmethod def get_strike_results(frame_results, status, name): """ Updates frame_results with data if status is 'Strike' :param frame_results: list to update results to :type frame_results: list :param status: The status of a 'PinSet' :type status: str :param name: The name of the Frame :type name: int """ if status == 'Strike': if name != 10: frame_results.append('') frame_results.append('X') def get_spare_results(self, frame_results, status, pin_set): """ Updates frame_results with data if status is 'Spare' :param frame_results: list to update results to :type frame_results: list :param status: The status of a 'PinSet' :type status: str :param pin_set: The PinSet to extract roll results from :type pin_set: bowling.logic.pin_set.PinSet """ if status == 'Spare': roll_1 = self.convert_zero_result(pin_set.rolls[0]) frame_results.extend([roll_1, '/']) @staticmethod def convert_zero_result(roll): """ Converts 0 result to '-' :param roll: number representing number of pins hit :type roll: int :return: roll as str, possible changed to '-' :rtype: str """ return str(roll) if roll != 0 else '-' def get_normal_results(self, frame_results, status, pin_set): """ Updates frame_results with results that don't have special bonuses :param frame_results: list to update results to :type frame_results: list :param status: The status of a 'PinSet' :type status: str :param pin_set: The PinSet to extract roll results from :type pin_set: bowling.logic.pin_set.PinSet """ if status in ['Complete', 'Incomplete']: for roll in pin_set.rolls: frame_results.append(self.convert_zero_result(roll)) @staticmethod def get_blank_results(frame_results, name, count): """ Updates frame_results with empty fields if it does not have enough :param frame_results: list to update results to :type frame_results: list :param name: The name of the Frame :type name: int :param count: The current total of results obtained :type count: int """ required_results = 3 if name == 10 else 2 while count < required_results: frame_results.append('') count += 1 def get_scores(self): """ Obtains list of scores for templates :return: list of scores for each frame :rtype: list[str, int] """ total_score = 0 scores = [] self.game_manager.calculate_score() for frame in self.game_manager.frames.values(): total_score = self.get_frame_score(frame, scores, total_score) total_score = '' if '' in scores else total_score scores.append(total_score) return scores @staticmethod def get_frame_score(frame, scores, total_score): """ Updates total_score with the score of the frame :param frame: Frame to extract data from :type frame: bowling.logic.frame.Frame :param scores: list of scores to update :type scores: list :param total_score: the score to increment :type total_score: int :return: The total score :rtype: int """ score = frame.score if frame.score != 0 else '' if score: total_score += score scores.append(total_score) else: scores.append('') return total_score def get_current_frame_data(self): """ Obtains context for data relevant to the current frame :return: Dictionary containing rolls_remaining, current_frame, available_pins :rtype: dict """ rolls = self.get_current_frame().remaining_rolls rolls = 0 if not self.game_manager.game.active else rolls current_frame_data = { 'rolls_remaining': rolls, 'current_frame': self.game_manager.game.current_frame, 'available_pins': self.get_available_pins() } return current_frame_data def get_available_pins(self): """ Obtains context data of available pins for templates :return: dictionary of 'id' with bool :rtype: dict """ available_range = range( 0, 11 - sum(self.get_current_frame().pin_sets[-1].rolls)) if not self.game_manager.game.active: available_range = [] available_pins = {} for index in range(0, 11): available_pins[index] = index in available_range return available_pins