def is_valid_saved_game(saved_game): """ Checks if the saved game is valid. This is an expensive operation because it replays the game. :param saved_game: The saved game (from to_saved_game_format) :return: A boolean that indicates if the game is valid """ # pylint: disable=too-many-return-statements, too-many-nested-blocks, too-many-branches nb_forced_phases = 0 max_nb_forced_phases = 1 if 'DIFFERENT_ADJUDICATION' in saved_game.get('rules', []) else 0 # Validating default fields if 'id' not in saved_game or not saved_game['id']: return False if 'map' not in saved_game: return False map_object = Map(saved_game['map']) if map_object.name != saved_game['map']: return False if 'rules' not in saved_game: return False if 'phases' not in saved_game: return False # Validating each phase nb_messages = 0 nb_phases = len(saved_game['phases']) last_time_sent = -1 for phase_ix in range(nb_phases): current_phase = saved_game['phases'][phase_ix] state = current_phase['state'] phase_orders = current_phase['orders'] previous_phase_name = 'FORMING' if phase_ix == 0 else saved_game['phases'][phase_ix - 1]['name'] next_phase_name = 'COMPLETED' if phase_ix == nb_phases - 1 else saved_game['phases'][phase_ix + 1]['name'] power_names = list(state['units'].keys()) # Validating messages for message in saved_game['phases'][phase_ix]['messages']: nb_messages += 1 if map_object.compare_phases(previous_phase_name, message['phase']) >= 0: return False if map_object.compare_phases(message['phase'], next_phase_name) > 0: return False if message['sender'] not in power_names + ['SYSTEM']: return False if message['recipient'] not in power_names + ['GLOBAL']: return False if message['time_sent'] < last_time_sent: return False last_time_sent = message['time_sent'] # Validating phase if phase_ix < (nb_phases - 1): is_forced_phase = False # Setting game state game = Game(saved_game['id'], map_name=saved_game['map'], rules=['SOLITAIRE'] + saved_game['rules']) game.set_phase_data(GamePhaseData.from_dict(current_phase)) # Determining what phase we should expect from the dataset. next_state = saved_game['phases'][phase_ix + 1]['state'] # Setting orders game.clear_orders() for power_name in phase_orders: game.set_orders(power_name, phase_orders[power_name]) # Validating orders orders = game.get_orders() possible_orders = game.get_all_possible_orders() for power_name in orders: if sorted(orders[power_name]) != sorted(current_phase['orders'][power_name]): return False if 'NO_CHECK' not in game.rules: for order in orders[power_name]: loc = order.split()[1] if order not in possible_orders[loc]: return False # Validating resulting state game.process() # Checking phase name if game.get_current_phase() != next_state['name']: is_forced_phase = True # Checking zobrist hash if game.get_hash() != next_state['zobrist_hash']: is_forced_phase = True # Checking units units = game.get_units() for power_name in units: if sorted(units[power_name]) != sorted(next_state['units'][power_name]): is_forced_phase = True # Checking centers centers = game.get_centers() for power_name in centers: if sorted(centers[power_name]) != sorted(next_state['centers'][power_name]): is_forced_phase = True # Allowing 1 forced phase if DIFFERENT_ADJUDICATION is in rule if is_forced_phase: nb_forced_phases += 1 if nb_forced_phases > max_nb_forced_phases: return False # Making sure NO_PRESS is not set if 'NO_PRESS' in saved_game['rules'] and nb_messages > 0: return False # The data is valid return True
def on_admin_game_phase_update(admin_game, notification=None): """ Admin game notification callback for game phase update. :param admin_game: admin game :param notification: notification :type admin_game: NetworkGame :type notification: diplomacy.communication.notifications.GameProcessed | None """ assert admin_game.is_omniscient_game() expected_data = admin_game.data # type: ExpectedData expected_data.move_forward() print('=' * 80) print('We changed phase for admin game, moving from phase', expected_data.phase_index, 'to phase', (expected_data.phase_index + 1), '/', len(expected_data.phases)) print('=' * 80) # state_history must not be empty. assert len(admin_game.state_history) == expected_data.phase_index, (len( admin_game.state_history), expected_data.phase_index) # Verify previous game state. if admin_game.state_history: expected_state = expected_data.phases[expected_data.phase_index - 1].state expected_engine = Game(initial_state=expected_state) given_state = admin_game.state_history.last_value() given_engine = Game(initial_state=given_state) print('Verifying expected previous phase', expected_engine.get_current_phase()) print('Verifying game processing from previous phase to next phase.') other_expected_engine = Game(initial_state=expected_state) other_expected_engine.process() other_given_engine = Game(initial_state=given_state) other_given_engine.rules.append('SOLITAIRE') other_given_engine.process() assert other_expected_engine.get_current_phase( ) == other_given_engine.get_current_phase(), ( 'Computed expected next phase %s, got computed given next phase %s' % (other_expected_engine.get_current_phase(), other_given_engine.get_current_phase())) assert expected_engine.map_name == given_engine.map_name assert expected_engine.get_current_phase( ) == given_engine.get_current_phase() expected_orders = expected_engine.get_orders() given_orders = given_engine.get_orders() assert len(expected_orders) == len(given_orders), (expected_orders, given_orders) for power_name in given_orders: assert power_name in expected_orders, power_name given_power_orders = list(sorted(given_orders[power_name])) expected_power_orders = list(sorted(expected_orders[power_name])) assert expected_power_orders == given_power_orders, ( 'Power orders for %s\nExpected: %s\nGiven: %s\nAll given: %s\n' % (power_name, expected_power_orders, given_power_orders, given_orders)) expected_units = expected_engine.get_units() given_units = expected_engine.get_units() assert len(expected_units) == len(given_units) for power_name in given_units: assert power_name in expected_units, (power_name, expected_units, given_units) expected_power_units = list(sorted(expected_units[power_name])) given_power_units = list(sorted(given_units[power_name])) assert expected_power_units == given_power_units, ( power_name, expected_power_units, given_power_units, given_units) expected_centers = expected_engine.get_centers() given_centers = given_engine.get_centers() assert len(expected_centers) == len(given_centers), (expected_centers, given_centers) for power_name in given_centers: assert power_name in expected_centers expected_power_centers = list(sorted(expected_centers[power_name])) given_power_centers = list(sorted(given_centers[power_name])) assert expected_power_centers == given_power_centers, ( power_name, expected_power_centers, given_power_centers) assert expected_engine.get_hash() == given_engine.get_hash(), ( expected_engine.get_hash(), given_engine.get_hash()) if expected_data.phase_index >= len(expected_data.phases): assert expected_data.phase_index == len(expected_data.phases) assert admin_game.state_history.last_value( )['name'] == expected_data.phases[-1].name, ( 'Wrong last phase, expected %s, got %s' % (admin_game.state_history.last_value()['name'], expected_data.phases[-1].name)) print('Admin game terminated.')
def test_deepcopy(): """ Tests - deepcopy """ game = Game() game2 = deepcopy(game) assert game != game2 assert game.get_hash() == game2.get_hash()