Skip to content

Commit 9d1e268

Browse files
committed
Merge branch 'main' into pr/aibrahim185/4
2 parents 0aebe4f + 0e3cfb5 commit 9d1e268

File tree

7 files changed

+241
-147
lines changed

7 files changed

+241
-147
lines changed

src/main_scene/main_scene.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "main_scene.hpp"
22

33
#include "../search/bfs/bfs.hpp"
4+
#include "../search/ucs/ucs.hpp"
45

56
MainScene::MainScene() {}
67
MainScene::~MainScene() {}
@@ -70,9 +71,8 @@ void MainScene::_process(double delta) {
7071

7172
void MainScene::_on_solve_button_pressed() {
7273
UtilityFunctions::print("Solve button pressed!");
73-
7474
Solution solution;
75-
75+
7676
switch (algo_type) {
7777
case BFS: {
7878
solution = bfs::search_bfs(board, pieces);
@@ -89,9 +89,21 @@ void MainScene::_on_solve_button_pressed() {
8989
is_searching = false;
9090
break;
9191
}
92-
case UCS:
93-
UtilityFunctions::print("UCS selected");
92+
case UCS: {
93+
solution = ucs::search_ucs(board, pieces);
94+
is_searching = true;
95+
96+
if (is_solved = solution.is_solved) {
97+
UtilityFunctions::print("UCS found a solution!");
98+
UtilityFunctions::print("Moves: ", solution.moves.size());
99+
} else {
100+
UtilityFunctions::print("UCS could not find a solution.");
101+
}
102+
UtilityFunctions::print("Time taken: ", solution.duration.count(), " ms");
103+
UtilityFunctions::print("Nodes visited: ", solution.node);
104+
is_searching = false;
94105
break;
106+
}
95107
case ASTAR:
96108
UtilityFunctions::print("A* selected");
97109
break;

src/search/bfs/bfs.cpp

Lines changed: 16 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,25 @@
11
#include "bfs.hpp"
2-
#include <godot_cpp/variant/utility_functions.hpp>
3-
#include <iostream>
4-
using namespace std;
5-
6-
vector<SearchNode> bfs::generate_next_bfs(const Board& initial_board, const SearchNode& current_node) {
7-
vector<SearchNode> successors;
8-
const vector<Piece>& current_pieces = current_node.pieces;
9-
10-
for (size_t piece_idx = 0; piece_idx < current_pieces.size(); ++piece_idx) {
11-
const Piece& piece_to_move = current_pieces[piece_idx];
12-
if (piece_to_move.id == 'K') continue; // jangan gerakin exit
13-
14-
// direction: -1 = kiri/atas, 1 = kanan/bawah
15-
for (int direction = -1; direction <= 1; direction += 2) {
16-
if (direction == 0) continue;
17-
for (int steps = 1; ; ++steps) {
18-
vector<Piece> next_pieces_state = current_pieces;
19-
Piece& piece_moved = next_pieces_state[piece_idx];
20-
21-
Coordinates new_top_left_coordinate = piece_to_move.coordinates;
22-
bool move = true;
23-
24-
if (piece_to_move.is_vertical) {
25-
for (int s = 1; s <= steps; ++s) {
26-
int y;
27-
if (direction > 0) { // bergerak ke bawah
28-
y = piece_to_move.coordinates.y + piece_to_move.size - 1 + s;
29-
}
30-
else { // bergerak ke atas
31-
y = piece_to_move.coordinates.y - s;
32-
}
33-
if (!Utils::is_cell_clear(initial_board, y, piece_to_move.coordinates.x, current_pieces, piece_to_move.id)) {
34-
move = false;
35-
break;
36-
}
37-
}
38-
if (move) {
39-
piece_moved.coordinates.y += (direction * steps);
40-
}
41-
}
42-
else { // bergerak horizontal
43-
for (int s = 1; s <= steps; ++s) {
44-
int x;
45-
if (direction > 0) { // bergerak ke kanan
46-
x = piece_to_move.coordinates.x + piece_to_move.size - 1 + s;
47-
}
48-
else { // bergerak ke kiri
49-
x = piece_to_move.coordinates.x - s;
50-
}
51-
if (!Utils::is_cell_clear(initial_board, piece_to_move.coordinates.y, x, current_pieces, piece_to_move.id)) {
52-
move = false;
53-
break;
54-
}
55-
}
56-
if (move) {
57-
piece_moved.coordinates.x += (direction * steps);
58-
}
59-
}
60-
61-
if (!move) {
62-
break;
63-
}
64-
65-
vector<PieceMove> next_path = current_node.path;
66-
PieceMove current_pm;
67-
current_pm.old_coordinates = piece_to_move.coordinates;
68-
current_pm.new_coordinates = piece_moved.coordinates;
69-
next_path.push_back(current_pm);
70-
71-
int val = Utils::calculate(initial_board, next_pieces_state);
72-
73-
successors.emplace_back(next_pieces_state, initial_board, next_path, val, piece_to_move.id, piece_to_move.coordinates);
74-
}
75-
}
76-
}
77-
return successors;
78-
}
2+
#include "../../utils/utils.hpp"
793

804
Solution bfs::search_bfs(const Board& initial_board, const std::vector<Piece>& initial_pieces) {
81-
auto time_start = chrono::high_resolution_clock::now();
82-
83-
// inisialisasi
84-
Solution result;
85-
result.is_solved = false;
86-
result.node = 0;
87-
88-
priority_queue<SearchNode, vector<SearchNode>, greater<SearchNode>> pq;
89-
set<string> visited;
90-
int initial_h = Utils::calculate(initial_board, initial_pieces);
91-
SearchNode initial_node(initial_pieces, initial_board, {}, initial_h);
92-
pq.push(initial_node);
93-
94-
godot::UtilityFunctions::print("GBFS: Initial heuristic: ", initial_h);
95-
96-
while (!pq.empty()) {
97-
SearchNode current_node = pq.top();
98-
pq.pop();
99-
100-
result.node++;
101-
102-
string current_state_str = Utils::state_to_string(current_node.pieces);
103-
if (visited.count(current_state_str)) {
104-
continue;
105-
}
106-
visited.insert(current_state_str);
107-
108-
godot::UtilityFunctions::print("GBFS: Exploring node. Heuristic: ", current_node.val, ". Path length: ", current_node.path.size());
109-
if (current_node.piece_moved != ' ') {
110-
godot::UtilityFunctions::print("Moved piece: ", String::utf8(&current_node.piece_moved, 1) , " from (", current_node.original_pos_moved_piece.x, ",", current_node.original_pos_moved_piece.y, ") to (", current_node.pieces[0].coordinates.x, ",", current_node.pieces[0].coordinates.y, ")");
111-
}
5+
Utils::SearchParams bfs_params;
6+
bfs_params.algorithm_name = "BFS";
1127

8+
bfs_params.calculate_initial_val = [](const Board& board, const vector<Piece>& pieces) {
9+
return Utils::calculate(board, pieces);
10+
};
11311

114-
if (Utils::is_exit(initial_board, current_node.pieces)) {
115-
result.is_solved = true;
116-
result.moves = current_node.path;
117-
godot::UtilityFunctions::print("GBFS: Solution Found! Moves: ", result.moves.size(), " Nodes visited: ", result.node);
118-
break;
119-
}
12+
bfs_params.successor_val = [](const Board& board_state, const vector<Piece>& next_pieces_state, const SearchNode&) {
13+
return Utils::calculate(board_state, next_pieces_state);
14+
};
12015

121-
vector<SearchNode> next = generate_next_bfs(initial_board, current_node);
122-
for (const auto& next_node : next) {
123-
string next_state_str = Utils::state_to_string(next_node.pieces);
124-
if (!visited.count(next_state_str)) {
125-
pq.push(next_node);
126-
}
127-
}
128-
}
16+
bfs_params.get_node_exploration = [](const SearchNode& node) {
17+
return godot::String("Heuristic: ") + godot::String::num_int64(node.val);
18+
};
12919

130-
auto time_end = chrono::high_resolution_clock::now();
131-
result.duration = chrono::duration<double, milli>(time_end - time_start);
132-
133-
if (!result.is_solved) {
134-
godot::UtilityFunctions::print("GBFS: No solution found. Nodes visited: ", result.node);
135-
}
20+
bfs_params.get_solution_details = [](const SearchNode&, const Solution& sol) {
21+
return godot::String("Moves: ") + godot::String::num_int64(sol.moves.size());
22+
};
13623

137-
return result;
24+
return Utils::search(initial_board, initial_pieces, bfs_params);
13825
}

src/search/bfs/bfs.hpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@
1313
class bfs {
1414
public:
1515
static Solution search_bfs(const Board& initial_board, const std::vector<Piece>& initial_pieces);
16-
17-
private:
18-
static std::vector<SearchNode> generate_next_bfs(const Board& initial_board, const SearchNode& current_node);
1916
};
2017

2118
#endif

src/search/ucs/ucs.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include "ucs.hpp"
2+
#include "../../utils/utils.hpp"
3+
4+
Solution ucs::search_ucs(const Board& initial_board, const std::vector<Piece>& initial_pieces) {
5+
const int COST_PER_MOVE = 1;
6+
7+
Utils::SearchParams ucs_params;
8+
ucs_params.algorithm_name = "UCS";
9+
10+
ucs_params.calculate_initial_val = [](const Board&, const vector<Piece>&) {
11+
return 0;
12+
};
13+
14+
ucs_params.successor_val = [COST_PER_MOVE](const Board&, const vector<Piece>&, const SearchNode& parent_node) {
15+
return parent_node.val + COST_PER_MOVE;
16+
};
17+
18+
ucs_params.get_node_exploration = [](const SearchNode& node) {
19+
return godot::String("Cost: ") + godot::String::num_int64(node.val);
20+
};
21+
22+
ucs_params.get_solution_details = [](const SearchNode& node, const Solution&) {
23+
return godot::String("Optimal steps: ") + godot::String::num_int64(node.val);
24+
};
25+
return Utils::search(initial_board, initial_pieces, ucs_params);
26+
}

src/search/ucs/ucs.hpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef UCS_HPP
2+
#define UCS_HPP
3+
4+
#include <vector>
5+
#include <queue>
6+
#include <string>
7+
#include <set>
8+
#include <algorithm>
9+
#include <chrono>
10+
11+
#include "../../main_scene/main_scene.hpp"
12+
13+
class ucs {
14+
public:
15+
static Solution search_ucs(const Board& initial_board, const std::vector<Piece>& initial_pieces);
16+
};
17+
18+
#endif

0 commit comments

Comments
 (0)