1+ #include " astar.hpp"
2+
3+ vector<AStarSearchNode> astar::generate_successors_astar (const AStarSearchNode& current_astar_node, const int COST_PER_MOVE) {
4+ vector<AStarSearchNode> successors;
5+ const vector<Piece>& current_pieces = current_astar_node.pieces ;
6+ const Board& board_node = current_astar_node.board ;
7+
8+ for (size_t piece_idx = 0 ; piece_idx < current_pieces.size (); ++piece_idx) {
9+ const Piece& piece_to_move = current_pieces[piece_idx];
10+ if (piece_to_move.id == ' K' ) continue ;
11+
12+ for (int direction = -1 ; direction <= 1 ; direction += 2 ) {
13+ for (int steps = 1 ; ; ++steps) {
14+ vector<Piece> next_pieces_state = current_pieces;
15+ Piece& piece_moved_in_state = next_pieces_state[piece_idx]; // ambil referensi ke piece yang akan digerakkan di state baru
16+ bool move_possible = true ;
17+
18+ Coordinates original_coords_of_moving_piece = piece_to_move.coordinates ; // simpan koordinat asli sebelum modifikasi
19+
20+ if (piece_to_move.is_vertical ) {
21+ for (int s = 1 ; s <= steps; ++s) {
22+ int y_check;
23+ if (direction > 0 ) {
24+ y_check = piece_to_move.coordinates .y + piece_to_move.size - 1 + s;
25+ } else {
26+ y_check = piece_to_move.coordinates .y - s;
27+ }
28+ if (!Utils::is_cell_clear (board_node, y_check, piece_to_move.coordinates .x , current_pieces, piece_to_move.id )) {
29+ move_possible = false ;
30+ break ;
31+ }
32+ }
33+ if (move_possible) {
34+ piece_moved_in_state.coordinates .y += (direction * steps);
35+ }
36+ } else {
37+ for (int s = 1 ; s <= steps; ++s) {
38+ int x_check;
39+ if (direction > 0 ) {
40+ x_check = piece_to_move.coordinates .x + piece_to_move.size - 1 + s;
41+ } else {
42+ x_check = piece_to_move.coordinates .x - s;
43+ }
44+ if (!Utils::is_cell_clear (board_node, piece_to_move.coordinates .y , x_check, current_pieces, piece_to_move.id )) {
45+ move_possible = false ;
46+ break ;
47+ }
48+ }
49+ if (move_possible) {
50+ piece_moved_in_state.coordinates .x += (direction * steps);
51+ }
52+ }
53+
54+ if (!move_possible) {
55+ break ;
56+ }
57+
58+ vector<PieceMove> next_path = current_astar_node.path ;
59+ PieceMove current_pm;
60+ current_pm.old_coordinates = original_coords_of_moving_piece; // gunakan koordinat asli
61+ current_pm.new_coordinates = piece_moved_in_state.coordinates ; // koordinat baru setelah bergerak
62+ next_path.push_back (current_pm);
63+
64+ int g_cost_successor = current_astar_node.g_cost + COST_PER_MOVE; // biaya pergerakan umumnya 1
65+ int h_cost_successor = Utils::calculate (board_node, next_pieces_state);
66+
67+ successors.emplace_back (next_pieces_state, board_node, next_path, g_cost_successor, h_cost_successor, piece_to_move.id , original_coords_of_moving_piece);
68+ }
69+ }
70+ }
71+ return successors;
72+ }
73+
74+
75+ Solution astar::search_astar (const Board& initial_board, const vector<Piece>& initial_pieces) {
76+ auto time_start = chrono::high_resolution_clock::now ();
77+ Solution result;
78+ result.is_solved = false ;
79+ result.node = 0 ;
80+
81+ const int COST_PER_MOVE = 1 ; // biaya setiap gerakan adalah 1
82+
83+ priority_queue<AStarSearchNode, vector<AStarSearchNode>, greater<AStarSearchNode>> pq;
84+ set<string> visited_states;
85+
86+ // node awal
87+ int initial_g_cost = 0 ;
88+ int initial_h_cost = Utils::calculate (initial_board, initial_pieces);
89+ AStarSearchNode initial_astar_node (initial_pieces, initial_board, {}, initial_g_cost, initial_h_cost);
90+ pq.push (initial_astar_node);
91+
92+ UtilityFunctions::print (" ASTAR: Initial g_cost: 0, h_cost: " + godot::String::num_int64 (initial_h_cost) + " , f_cost: " + godot::String::num_int64 (initial_astar_node.f_cost ));
93+
94+ while (!pq.empty ()) {
95+ AStarSearchNode current_node = pq.top ();
96+ pq.pop ();
97+ result.node ++;
98+
99+ string current_state_str = current_node.get_state_string ();
100+ if (visited_states.count (current_state_str)) {
101+ continue ;
102+ }
103+ visited_states.insert (current_state_str);
104+
105+ UtilityFunctions::print (" ASTAR: Exploring node. " +
106+ godot::String (" f(n):" ) + godot::String::num_int64 (current_node.f_cost ) +
107+ godot::String (" , g(n):" ) + godot::String::num_int64 (current_node.g_cost ) +
108+ godot::String (" , h(n):" ) + godot::String::num_int64 (current_node.h_cost ) +
109+ " . Path length: " + godot::String::num_int64 (static_cast <int64_t >(current_node.path .size ())));
110+
111+ if (current_node.piece_moved != ' ' ) {
112+ Coordinates new_pos_for_log = {-1 , -1 };
113+ // cari piece yang digerakkan di state saat ini untuk mendapatkan posisi barunya
114+ for (const auto & p_state : current_node.pieces ) {
115+ if (p_state.id == current_node.piece_moved ) {
116+ new_pos_for_log = p_state.coordinates ;
117+ break ;
118+ }
119+ }
120+ UtilityFunctions::print (" Moved piece: " , godot::String::utf8 (¤t_node.piece_moved , 1 ), " from (" , current_node.original_position .x , " ," , current_node.original_position .y , " ) to (" , new_pos_for_log.x , " ," , new_pos_for_log.y , " )" );
121+ }
122+
123+
124+ if (Utils::is_exit (current_node.board , current_node.pieces )) {
125+ result.is_solved = true ;
126+ result.moves = current_node.path ;
127+ UtilityFunctions::print (" ASTAR: Solution Found! Optimal steps (g_cost): " + godot::String::num_int64 (current_node.g_cost ) + " . Total moves: " + godot::String::num_int64 (result.moves .size ()) + " . Nodes visited: " + godot::String::num_int64 (static_cast <int64_t >(result.node )));
128+ break ;
129+ }
130+
131+ vector<AStarSearchNode> successors = generate_successors_astar (current_node, COST_PER_MOVE);
132+
133+ for (const auto & successor_node : successors) {
134+ string next_state_str = successor_node.get_state_string ();
135+ if (!visited_states.count (next_state_str)) {
136+ pq.push (successor_node);
137+ }
138+ }
139+ }
140+
141+ auto time_end = chrono::high_resolution_clock::now ();
142+ result.duration = chrono::duration<double , milli>(time_end - time_start);
143+
144+ if (!result.is_solved ) {
145+ UtilityFunctions::print (" ASTAR: No solution found. Nodes visited: " + godot::String::num_int64 (static_cast <int64_t >(result.node )));
146+ }
147+ return result;
148+ }
0 commit comments