def minimax_1(self, current_depth: int, current_state: State) -> State or None: """ Cette fonction contient la logique de l'algorithme minimax pour un seul joueur et retourne le meilleur coup à prendre à partir de l'état courant """ self.rushhour.state = current_state possible_states = self.rushhour.get_possible_moves() current_state.score_heuristic_1(self.visited, self.rushhour.free_pos, self.rushhour.length, self.rushhour.move_on, self.rushhour.horiz) current_score = current_state.score if current_depth is self.search_depth or current_state.success(): return current_state current_state.score = - (sys.maxsize - 1) best_state = None for possible_state in possible_states: possible_state.previous_state = None possible_state.nb_moves -= 1 # because it adds one in get_possible_moves tmp_state = self.minimax_1(current_depth + 1, possible_state) tmp_state.score += current_score if tmp_state is None: continue if current_state.score < tmp_state.score: current_state.score = tmp_state.score best_state = tmp_state return best_state if current_depth is 0 else current_state
def test_print_move(self): rh = RushHour([True], [2], [2], ["rouge"]) s = State([0]) s = s.put_rock((3, 1)) # Roche dans la case 3-1 s = s.move(0, 1) # Voiture rouge vers la droite algo = MiniMaxSearch(rh, s, 1) self.assertEqual(algo.str_move(True, s), 'Voiture rouge vers la droite') self.assertEqual(algo.str_move(False, s), 'Roche dans la case 3-1')
def testPossibleRockMoves(self): s = State([1, 0, 3, 1, 1, 4, 3, 4, 4, 2, 4, 1]) self.rh.state = s sols = self.rh.possible_rock_moves() print(len(sols)) self.assertEqual(7, len(sols)) s1 = s.put_rock((3, 4)) self.rh.state = s1 sols = self.rh.possible_rock_moves() print(len(sols)) self.assertEqual(3, len(sols))
def test_blocking_heuristics(self): heuristics = Heuristics(RushHour(*rush_hour_data_1)) nb = heuristics.blocking(State(state_data_1)) self.assertEqual(2, nb) # heuristics = Heuristics(RushHour(*rush_hour_data_2)) # nb = heuristics.blocking(State(state_data_2)) # self.assertEqual(2, nb) heuristics = Heuristics(RushHour(*rush_hour_data_3)) nb = heuristics.blocking(State(state_data_3)) self.assertEqual(3, nb)
def execute_minimax_single_player(self): rush_hour: RushHour = RushHour(*self.rush_hour_data) rush_hour.state = State(self.state_data) algo = MiniMaxSearch(rush_hour, rush_hour.state, 1) algo.rushhour.update_free_pos() algo.solve_single_player(verbose=False) print(rush_hour.state.nb_moves)
def test_solve_expectimax(self): """ best outcome = 9 moves """ rush_hour = RushHour(*rush_hour_data_1) rush_hour.state = State(state_data_1) algo = ExpectimaxSearch(rush_hour, rush_hour.state, 3) nb_moves = self.execute_algo_single_player(algo) print(nb_moves) self.assertEqual(9, nb_moves)
def execute_pruning(self, test_name): rush_hour: RushHour = RushHour(*self.rush_hour_data) rush_hour.state = State(self.state_data) algo = MiniMaxSearch(rush_hour, rush_hour.state, 3) algo.rushhour.update_free_pos() start = time() algo.solve_pruning(verbose=False) duration = (time() - start) * 1000 self.table_maker.append_row([test_name, f'{duration:.2f}']) print(rush_hour.state.nb_moves)
def test_hash_function(self): s0 = State([random.randint(1, 10) for i in range(12)]) s1 = State([random.randint(1, 10) for i in range(12)]) s2 = State([random.randint(1, 10) for i in range(12)]) s0_copy = copy(s0) s1_copy = copy(s1) s2_copy = copy(s2) self.assertEqual(hash(s0), hash(s0_copy)) self.assertEqual(hash(s1), hash(s1_copy)) self.assertEqual(hash(s2), hash(s2_copy)) self.assertNotEqual(hash(s0), hash(s1)) self.assertNotEqual(hash(s0), hash(s2)) self.assertNotEqual(hash(s1), hash(s0)) self.assertNotEqual(hash(s1), hash(s2)) self.assertNotEqual(hash(s2), hash(s0)) self.assertNotEqual(hash(s2), hash(s1))
def test_state_order_sanity(self): """ validate state history make sense """ rush_hour = RushHour(*rush_hour_data_1) rush_hour.state = State(state_data_1) algo = ExpectimaxSearch(rush_hour, rush_hour.state, 3) try: self.execute_algo_single_player(algo) except Exception: pass state_history = algo.state_history for i, in range(len(state_history) - 1): pair = (state_history[i], state_history[i + 1]) self.assertTrue(TestRushHour.states_are_consecutives(pair[0], pair[1]))
def test_print_pretty(self): rh = RushHour(*rush_hour_data_1) state = State(state_data_1) rh.print_pretty_grid_and_update_free_pos(state)
def testRocks(self): s0 = State([1, 0, 3, 1, 1, 4, 3, 4, 4, 2, 4, 1]) s1 = s0.put_rock((4, 4)) s2 = s1.put_rock((3, 2)) print("État initial") self.rh.state = s0 self.rh.print_pretty_grid_and_update_free_pos(s0) print(self.rh.free_pos) print('\n') grid_reference = np.array( [['-', '-', 'v', 'j', 'j', 'j'], ['o', '-', 'v', 'v', 'b', 'b'], ['o', 'r', 'r', 'v', '-', '-'], ['-', 'r', '-', 'v', 'v', 'v'], ['v', 'r', 'n', 'n', '-', 'b'], ['v', 'b', 'b', 'b', '-', 'b']], dtype='|S1' ) free_pos_reference = np.array( [[True, True, False, False, False, False], [False, True, False, False, False, False], [False, False, False, False, True, True], [True, False, True, False, False, False], [False, False, False, False, True, False], [False, False, False, False, True, False]], dtype='bool' ) np.testing.assert_array_equal(self.rh.get_formatted_grid_and_update_free_pos(s0), grid_reference) np.testing.assert_array_equal(self.rh.free_pos, free_pos_reference) print("Roche 4-4") self.rh.state = s1 self.rh.update_free_pos() print(self.rh.free_pos) print('\n') grid_reference = np.array( [[b'-', b'-', b'v', b'j', b'j', b'j'], [b'o', b'-', b'v', b'v', b'b', b'b'], [b'o', b'r', b'r', b'v', b'-', b'-'], [b'-', b'r', b'-', b'v', b'v', b'v'], [b'v', b'r', b'n', b'n', b'x', b'b'], [b'v', b'b', b'b', b'b', b'-', b'b']], dtype='|S1' ) free_pos_reference = np.array( [[True, True, False, False, False, False], [False, True, False, False, False, False], [False, False, False, False, True, True], [True, False, True, False, False, False], [False, False, False, False, False, False], [False, False, False, False, True, False]], dtype='bool' ) np.testing.assert_array_equal(self.rh.get_formatted_grid_and_update_free_pos(s1), grid_reference) np.testing.assert_array_equal(self.rh.free_pos, free_pos_reference) print("Roche 3-2") self.rh.state = s2 print(self.rh.free_pos) print('\n') grid_reference = np.array( [[b'-', b'-', b'v', b'j', b'j', b'j'], [b'o', b'-', b'v', b'v', b'b', b'b'], [b'o', b'r', b'r', b'v', b'-', b'-'], [b'-', b'r', b'x', b'v', b'v', b'v'], [b'v', b'r', b'n', b'n', b'-', b'b'], [b'v', b'b', b'b', b'b', b'-', b'b']], dtype='|S1' ) free_pos_reference = np.array( [[True, True, False, False, False, False], [False, True, False, False, False, False], [False, False, False, False, True, True], [True, False, False, False, False, False], [False, False, False, False, True, False], # Todo: Demander au chargé multiple rock à (4,4) [False, False, False, False, True, False]], dtype='bool' ) np.testing.assert_array_equal(self.rh.get_formatted_grid_and_update_free_pos(s2), grid_reference) np.testing.assert_array_equal(self.rh.free_pos, free_pos_reference)