Optimisation, formatting changes
This commit is contained in:
parent
ab01fa2878
commit
3e2e69f1c3
13 changed files with 403 additions and 97 deletions
|
@ -1,3 +0,0 @@
|
||||||
# Deadlock and Optimizations
|
|
||||||
|
|
||||||
Explain your optimizations if applicable
|
|
140
report.md
Normal file
140
report.md
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
# Deadlock and Optimizations
|
||||||
|
|
||||||
|
## Deadlock detections
|
||||||
|
### Simple corner deadlock detection
|
||||||
|
The simple corner deadlock that was already implemented aims to prevent a box
|
||||||
|
from being pushed into a corner. If it is pushed into a corner, it is
|
||||||
|
inaccessible and immovable, thus rendering that state unsolvable.
|
||||||
|
|
||||||
|
### Freeze deadlock detection
|
||||||
|
Described
|
||||||
|
[here](http://sokobano.de/wiki/index.php?title=Deadlocks#Freeze_deadlocks),
|
||||||
|
freeze detection is about preventing two boxes from being adjacent against a
|
||||||
|
wall when there is no goal in that location. This deadlock detection was chosen
|
||||||
|
as there are many scenarios (such as in test_maps/test_map2 and
|
||||||
|
test_maps/test_map3) where there are multiple boxes and a complex map layout.
|
||||||
|
This deadlock detection saves a small amount time and reduces the number of
|
||||||
|
nodes that are expanded.
|
||||||
|
|
||||||
|
The code for this detection is contained in `utils.c`, from lines 321 - 480.
|
||||||
|
The function `freeze_deadlock()` is used to check if there is a box adjacent to
|
||||||
|
the player, and if there is, then the function `adjacent_box_check()` is called
|
||||||
|
to check for the freeze deadlock scenario.
|
||||||
|
|
||||||
|
## Optimisation results
|
||||||
|
These results show the impact of implementing the freeze deadlock detection.
|
||||||
|
|
||||||
|
Hardware used:
|
||||||
|
- CPU: AMD Ryzen 4800U
|
||||||
|
- GPU: AMD Radeon RX Vega 8
|
||||||
|
- Memory: 16GB
|
||||||
|
|
||||||
|
### Summary of optimisation
|
||||||
|
The following table summarises some of the key statistics prior to implementing
|
||||||
|
freeze deadlock detection, and after implementing freeze deadlock detection.
|
||||||
|
|
||||||
|
Test: test_map1
|
||||||
|
|
||||||
|
| Statistic | Before implementation | After implementation | % improvement |
|
||||||
|
|----------------|-----------------------|----------------------|---------------|
|
||||||
|
| Expanded nodes | 13 | 13 | 0.00 |
|
||||||
|
| Time (s) | 0.050106 | 0.047723 | 4.76 |
|
||||||
|
|
||||||
|
|
||||||
|
Test: test_map2
|
||||||
|
|
||||||
|
| Statistic | Before implementation | After implementation | % improvement |
|
||||||
|
|----------------|-----------------------|----------------------|---------------|
|
||||||
|
| Expanded nodes | 978745 | 944140 | 3.54 |
|
||||||
|
| Time | 3.456764 | 3.227685 | 6.63 |
|
||||||
|
|
||||||
|
Test: test_map3
|
||||||
|
|
||||||
|
| Statistic | Before implementation | After implementation | % improvement |
|
||||||
|
|----------------|-----------------------|----------------------|---------------|
|
||||||
|
| Expanded nodes | 230041 | 215253 | 6.43 |
|
||||||
|
| Time | 1.828733 | 1.680901 | 8.08 |
|
||||||
|
|
||||||
|
### Full output (before optimisation)
|
||||||
|
```
|
||||||
|
$ ./sokoban -s test_maps/test_map1
|
||||||
|
|
||||||
|
SOLUTION:
|
||||||
|
rrRRRR
|
||||||
|
|
||||||
|
STATS:
|
||||||
|
Expanded nodes: 13
|
||||||
|
Generated nodes: 48
|
||||||
|
Duplicated nodes: 8
|
||||||
|
Solution Length: 6
|
||||||
|
Expanded/seconds: 259
|
||||||
|
Time (seconds): 0.050106
|
||||||
|
|
||||||
|
$ ./sokoban -s test_maps/test_map2
|
||||||
|
|
||||||
|
SOLUTION:
|
||||||
|
rrrrrrdrdLLLLLLLLullluRRRRRRRururRRRRRRRRRR
|
||||||
|
|
||||||
|
STATS:
|
||||||
|
Expanded nodes: 978745
|
||||||
|
Generated nodes: 3914976
|
||||||
|
Duplicated nodes: 2288345
|
||||||
|
Solution Length: 43
|
||||||
|
Expanded/seconds: 283139
|
||||||
|
Time (seconds): 3.456764
|
||||||
|
|
||||||
|
$ ./sokoban -s test_maps/test_map3
|
||||||
|
|
||||||
|
SOLUTION:
|
||||||
|
drdrdrdrrruuuuuulllllddrdrdrDulululldRdRdrdRRllululuurdrdrDululldRuuluurrrrrdddddrddlUUUUUUruLLLLLulDDdrdddrdRRlluluurdrDulldruluulldRuuurrrrrdddddrddlUUUUUUruLLLLLulDDdrdrdddRRlluurDldRuulululldRdRluuuurrrrrdddddrddlUUUUUUruLLLLLulDDdrdrdrddRluulululldRdRluuuurrrrrdddddrddlUUUUUUruLLLLLulDD
|
||||||
|
|
||||||
|
STATS:
|
||||||
|
Expanded nodes: 230041
|
||||||
|
Generated nodes: 920160
|
||||||
|
Duplicated nodes: 331571
|
||||||
|
Solution Length: 292
|
||||||
|
Expanded/seconds: 125792
|
||||||
|
Time (seconds): 1.828733
|
||||||
|
```
|
||||||
|
|
||||||
|
### Full output (after optimisation)
|
||||||
|
```
|
||||||
|
$ ./sokoban -s test_maps/test_map1
|
||||||
|
|
||||||
|
SOLUTION:
|
||||||
|
rrRRRR
|
||||||
|
|
||||||
|
STATS:
|
||||||
|
Expanded nodes: 13
|
||||||
|
Generated nodes: 48
|
||||||
|
Duplicated nodes: 8
|
||||||
|
Solution Length: 6
|
||||||
|
Expanded/seconds: 272
|
||||||
|
Time (seconds): 0.047723
|
||||||
|
|
||||||
|
$ ./sokoban -s test_maps/test_map2
|
||||||
|
|
||||||
|
SOLUTION:
|
||||||
|
rrrrrrdrdLLLLLLLLullluRRRRRRRurruRRRRRRRRRR
|
||||||
|
|
||||||
|
STATS:
|
||||||
|
Expanded nodes: 944140
|
||||||
|
Generated nodes: 3776556
|
||||||
|
Duplicated nodes: 2199712
|
||||||
|
Solution Length: 43
|
||||||
|
Expanded/seconds: 292513
|
||||||
|
Time (seconds): 3.227685
|
||||||
|
|
||||||
|
$ ./sokoban -s test_maps/test_map3
|
||||||
|
|
||||||
|
SOLUTION:
|
||||||
|
drdrdrdrrruuuuuulllllddrdrdrDulululldRdRdrdRRllululuurdrdrDululldRuuluurrrrrdddddrddlUUUUUUruLLLLLulDDdrdddrdRRlluluurdrDulldruululldRuuurrrrrdddddrddlUUUUUUruLLLLLulDDdrdrdddRRlluurDldRluuululldRdRluuuurrrrrdddddrddlUUUUUUruLLLLLulDDdrdrdrddRluulululldRdRluuuurrrrrdddddrddlUUUUUUruLLLLLulDD
|
||||||
|
|
||||||
|
STATS:
|
||||||
|
Expanded nodes: 215253
|
||||||
|
Generated nodes: 861008
|
||||||
|
Duplicated nodes: 309654
|
||||||
|
Solution Length: 292
|
||||||
|
Expanded/seconds: 128058
|
||||||
|
Time (seconds): 1.680901
|
||||||
|
```
|
BIN
sokoban
BIN
sokoban
Binary file not shown.
|
@ -1 +0,0 @@
|
||||||
rrRlllllL
|
|
59
src/ai/ai.c
59
src/ai/ai.c
|
@ -13,37 +13,37 @@
|
||||||
*/
|
*/
|
||||||
char *save_solution(node_t *solution_node) {
|
char *save_solution(node_t *solution_node) {
|
||||||
node_t *n = solution_node;
|
node_t *n = solution_node;
|
||||||
char *solution_string = malloc(sizeof(char) * solution_node->depth+1);
|
char *solution_string = malloc(sizeof(char) * solution_node->depth + 1);
|
||||||
solution_string[n->depth] = '\0';
|
solution_string[n->depth] = '\0';
|
||||||
|
|
||||||
while (n->parent != NULL) {
|
while (n->parent != NULL) {
|
||||||
switch (n->move) {
|
switch (n->move) {
|
||||||
case up:
|
case up:
|
||||||
if (n->parent->state.map[n->state.player_y][n->state.player_x] == '$')
|
if (n->parent->state.map[n->state.player_y][n->state.player_x] == '$')
|
||||||
solution_string[n->depth-1] = 'U';
|
solution_string[n->depth - 1] = 'U';
|
||||||
else
|
else
|
||||||
solution_string[n->depth-1] = 'u';
|
solution_string[n->depth - 1] = 'u';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case down:
|
case down:
|
||||||
if (n->parent->state.map[n->state.player_y][n->state.player_x] == '$')
|
if (n->parent->state.map[n->state.player_y][n->state.player_x] == '$')
|
||||||
solution_string[n->depth-1] = 'D';
|
solution_string[n->depth - 1] = 'D';
|
||||||
else
|
else
|
||||||
solution_string[n->depth-1] = 'd';
|
solution_string[n->depth - 1] = 'd';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case left:
|
case left:
|
||||||
if (n->parent->state.map[n->state.player_y][n->state.player_x] == '$')
|
if (n->parent->state.map[n->state.player_y][n->state.player_x] == '$')
|
||||||
solution_string[n->depth-1] = 'L';
|
solution_string[n->depth - 1] = 'L';
|
||||||
else
|
else
|
||||||
solution_string[n->depth-1] = 'l';
|
solution_string[n->depth - 1] = 'l';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case right:
|
case right:
|
||||||
if (n->parent->state.map[n->state.player_y][n->state.player_x] == '$')
|
if (n->parent->state.map[n->state.player_y][n->state.player_x] == '$')
|
||||||
solution_string[n->depth-1] = 'R';
|
solution_string[n->depth - 1] = 'R';
|
||||||
else
|
else
|
||||||
solution_string[n->depth-1] = 'r';
|
solution_string[n->depth - 1] = 'r';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ void copy_state(sokoban_t *init_data, state_t *dst, state_t *src) {
|
||||||
* Create the initial node
|
* Create the initial node
|
||||||
*/
|
*/
|
||||||
node_t *create_init_node(sokoban_t *init_data) {
|
node_t *create_init_node(sokoban_t *init_data) {
|
||||||
node_t *new_n = (node_t *) malloc(sizeof(node_t));
|
node_t *new_n = malloc(sizeof(node_t));
|
||||||
|
|
||||||
new_n->parent = NULL;
|
new_n->parent = NULL;
|
||||||
new_n->priority = 0;
|
new_n->priority = 0;
|
||||||
|
@ -98,7 +98,7 @@ node_t *create_init_node(sokoban_t *init_data) {
|
||||||
* Create the a node from a parent node
|
* Create the a node from a parent node
|
||||||
*/
|
*/
|
||||||
node_t *create_node(sokoban_t *init_data, node_t *parent) {
|
node_t *create_node(sokoban_t *init_data, node_t *parent) {
|
||||||
node_t *new_n = (node_t *) malloc(sizeof(node_t));
|
node_t *new_n = malloc(sizeof(*new_n));
|
||||||
new_n->parent = parent;
|
new_n->parent = parent;
|
||||||
new_n->depth = parent->depth + 1;
|
new_n->depth = parent->depth + 1;
|
||||||
copy_state(init_data, &(new_n->state), &(parent->state));
|
copy_state(init_data, &(new_n->state), &(parent->state));
|
||||||
|
@ -138,7 +138,7 @@ void update_explore_table(node_t *n, unsigned expanded_nodes) {
|
||||||
sizeof(node_t*) * expanded_nodes_table_size);
|
sizeof(node_t*) * expanded_nodes_table_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
expanded_nodes_table[ expanded_nodes ] = n;
|
expanded_nodes_table[expanded_nodes] = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_memory(unsigned expanded_nodes, int lines) {
|
void free_memory(unsigned expanded_nodes, int lines) {
|
||||||
|
@ -189,7 +189,8 @@ void find_solution(sokoban_t *init_data, bool show_solution) {
|
||||||
// Choose initial capacity of PRIME NUMBER
|
// Choose initial capacity of PRIME NUMBER
|
||||||
// Specify the size of the keys and values you want to store once
|
// Specify the size of the keys and values you want to store once
|
||||||
// The Hash Table only accept a 1D key and value.
|
// The Hash Table only accept a 1D key and value.
|
||||||
ht_setup(&hashTable, sizeof(int8_t) * init_data->num_chars_map, sizeof(int8_t) * init_data->num_chars_map, 16769023);
|
ht_setup(&hashTable, sizeof(int8_t) * init_data->num_chars_map, \
|
||||||
|
sizeof(int8_t) * init_data->num_chars_map, 16769023);
|
||||||
|
|
||||||
// Data structure to create a 1D representation of the map
|
// Data structure to create a 1D representation of the map
|
||||||
// Needed to interact with the hash table
|
// Needed to interact with the hash table
|
||||||
|
@ -200,8 +201,8 @@ void find_solution(sokoban_t *init_data, bool show_solution) {
|
||||||
|
|
||||||
// Initialize expanded nodes table.
|
// Initialize expanded nodes table.
|
||||||
// This table will be used to free your memory once a solution is found
|
// This table will be used to free your memory once a solution is found
|
||||||
expanded_nodes_table = (node_t **) malloc(sizeof(node_t *) * expanded_nodes_table_size);
|
expanded_nodes_table = malloc(sizeof(*expanded_nodes_table) * \
|
||||||
|
expanded_nodes_table_size);
|
||||||
|
|
||||||
// Add the initial node
|
// Add the initial node
|
||||||
node_t *n = create_init_node(init_data);
|
node_t *n = create_init_node(init_data);
|
||||||
|
@ -221,13 +222,17 @@ void find_solution(sokoban_t *init_data, bool show_solution) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (move_t action = left; action <= down; action++) {
|
for (move_t action = left; action <= down; action++) {
|
||||||
node_t *new = malloc(sizeof(*new));
|
node_t *new;
|
||||||
bool player_moved = applyAction(init_data, n, &new, action);
|
bool player_moved = applyAction(init_data, n, &new, action);
|
||||||
generated_nodes += 1;
|
generated_nodes += 1;
|
||||||
if (!player_moved || simple_corner_deadlock(init_data, &(new->state))) {
|
|
||||||
|
if (!player_moved || freeze_deadlock(init_data, &(new->state)) || \
|
||||||
|
simple_corner_deadlock(init_data, &(new->state))) {
|
||||||
|
|
||||||
for (int i = 0; i < init_data->lines; i++) {
|
for (int i = 0; i < init_data->lines; i++) {
|
||||||
free(new->state.map[i]);
|
free(new->state.map[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(new->state.map);
|
free(new->state.map);
|
||||||
free(new);
|
free(new);
|
||||||
continue;
|
continue;
|
||||||
|
@ -256,17 +261,8 @@ void find_solution(sokoban_t *init_data, bool show_solution) {
|
||||||
free_memory(expanded_nodes, init_data->lines);
|
free_memory(expanded_nodes, init_data->lines);
|
||||||
free(flat_map);
|
free(flat_map);
|
||||||
|
|
||||||
// Free initial data
|
|
||||||
for (int i = 0; i < init_data->lines; i++) {
|
|
||||||
free((init_data->map)[i]);
|
|
||||||
free((init_data->map_save)[i]);
|
|
||||||
}
|
|
||||||
free(init_data->map);
|
|
||||||
free(init_data->map_save);
|
|
||||||
free(init_data->buffer);
|
|
||||||
|
|
||||||
// Free priority queue
|
// Free priority queue
|
||||||
for (int i = pq.count; i > 0; i--) {
|
for (int i = 0; i < pq.count; i++) {
|
||||||
for (int j = 0; j < init_data->lines; j++) {
|
for (int j = 0; j < init_data->lines; j++) {
|
||||||
if (pq.heaparr[i]->state.map[j]) {
|
if (pq.heaparr[i]->state.map[j]) {
|
||||||
free(pq.heaparr[i]->state.map[j]);
|
free(pq.heaparr[i]->state.map[j]);
|
||||||
|
@ -326,4 +322,13 @@ void solve(char const *path, bool show_solution) {
|
||||||
sokoban = find_player(sokoban);
|
sokoban = find_player(sokoban);
|
||||||
|
|
||||||
find_solution(&sokoban, show_solution);
|
find_solution(&sokoban, show_solution);
|
||||||
|
|
||||||
|
// Free initial data
|
||||||
|
for (int i = 0; i < sokoban.lines; i++) {
|
||||||
|
free((sokoban.map)[i]);
|
||||||
|
free((sokoban.map_save)[i]);
|
||||||
|
}
|
||||||
|
free(sokoban.map);
|
||||||
|
free(sokoban.map_save);
|
||||||
|
free(sokoban.buffer);
|
||||||
}
|
}
|
||||||
|
|
BIN
src/ai/ai.o
BIN
src/ai/ai.o
Binary file not shown.
279
src/ai/utils.c
279
src/ai/utils.c
|
@ -21,19 +21,19 @@ bool is_goal_loc(int y, int x, sokoban_t *init_data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool push_box_left(sokoban_t *init_data, state_t *state) {
|
bool push_box_left(sokoban_t *init_data, state_t *state) {
|
||||||
if (state->map[state->player_y][state->player_x-2] == '$' || \
|
if (state->map[state->player_y][state->player_x - 2] == '$' || \
|
||||||
state->map[state->player_y][state->player_x-2] == '*') {
|
state->map[state->player_y][state->player_x - 2] == '*') {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else if (state->map[state->player_y][state->player_x-2] == '#') {
|
} else if (state->map[state->player_y][state->player_x - 2] == '#') {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
state->map[state->player_y][state->player_x-1] = '@';
|
state->map[state->player_y][state->player_x - 1] = '@';
|
||||||
|
|
||||||
if (state->map[state->player_y][state->player_x-2] == '.') {
|
if (state->map[state->player_y][state->player_x - 2] == '.') {
|
||||||
state->map[state->player_y][state->player_x-2] = '*';
|
state->map[state->player_y][state->player_x - 2] = '*';
|
||||||
} else {
|
} else {
|
||||||
state->map[state->player_y][state->player_x-2] = '$';
|
state->map[state->player_y][state->player_x - 2] = '$';
|
||||||
}
|
}
|
||||||
|
|
||||||
state->map[state->player_y][state->player_x] = ' ';
|
state->map[state->player_y][state->player_x] = ' ';
|
||||||
|
@ -51,19 +51,19 @@ bool push_box_left(sokoban_t *init_data, state_t *state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool push_box_right(sokoban_t *init_data, state_t *state) {
|
bool push_box_right(sokoban_t *init_data, state_t *state) {
|
||||||
if (state->map[state->player_y][state->player_x+2] == '$' || \
|
if (state->map[state->player_y][state->player_x + 2] == '$' || \
|
||||||
state->map[state->player_y][state->player_x+2] == '*') {
|
state->map[state->player_y][state->player_x + 2] == '*') {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else if (state->map[state->player_y][state->player_x+2] == '#') {
|
} else if (state->map[state->player_y][state->player_x + 2] == '#') {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
state->map[state->player_y][state->player_x+1] = '@';
|
state->map[state->player_y][state->player_x + 1] = '@';
|
||||||
|
|
||||||
if (state->map[state->player_y][state->player_x+2] == '.') {
|
if (state->map[state->player_y][state->player_x + 2] == '.') {
|
||||||
state->map[state->player_y][state->player_x+2] = '*';
|
state->map[state->player_y][state->player_x + 2] = '*';
|
||||||
} else {
|
} else {
|
||||||
state->map[state->player_y][state->player_x+2] = '$';
|
state->map[state->player_y][state->player_x + 2] = '$';
|
||||||
}
|
}
|
||||||
|
|
||||||
state->map[state->player_y][state->player_x] = ' ';
|
state->map[state->player_y][state->player_x] = ' ';
|
||||||
|
@ -81,19 +81,19 @@ bool push_box_right(sokoban_t *init_data, state_t *state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool push_box_up(sokoban_t *init_data, state_t *state) {
|
bool push_box_up(sokoban_t *init_data, state_t *state) {
|
||||||
if (state->map[state->player_y-2][state->player_x] == '$' || \
|
if (state->map[state->player_y - 2][state->player_x] == '$' || \
|
||||||
state->map[state->player_y-2][state->player_x] == '*') {
|
state->map[state->player_y - 2][state->player_x] == '*') {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else if (state->map[state->player_y-2][state->player_x] == '#') {
|
} else if (state->map[state->player_y - 2][state->player_x] == '#') {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
state->map[state->player_y-1][state->player_x] = '@';
|
state->map[state->player_y - 1][state->player_x] = '@';
|
||||||
|
|
||||||
if (state->map[state->player_y-2][state->player_x] == '.') {
|
if (state->map[state->player_y - 2][state->player_x] == '.') {
|
||||||
state->map[state->player_y-2][state->player_x] = '*';
|
state->map[state->player_y - 2][state->player_x] = '*';
|
||||||
} else {
|
} else {
|
||||||
state->map[state->player_y-2][state->player_x] = '$';
|
state->map[state->player_y - 2][state->player_x] = '$';
|
||||||
}
|
}
|
||||||
|
|
||||||
state->map[state->player_y][state->player_x] = ' ';
|
state->map[state->player_y][state->player_x] = ' ';
|
||||||
|
@ -111,19 +111,19 @@ bool push_box_up(sokoban_t *init_data, state_t *state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool push_box_down(sokoban_t *init_data, state_t *state) {
|
bool push_box_down(sokoban_t *init_data, state_t *state) {
|
||||||
if (state->map[state->player_y+2][state->player_x] == '$' || \
|
if (state->map[state->player_y + 2][state->player_x] == '$' || \
|
||||||
state->map[state->player_y+2][state->player_x] == '*') {
|
state->map[state->player_y + 2][state->player_x] == '*') {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else if (state->map[state->player_y+2][state->player_x] == '#') {
|
} else if (state->map[state->player_y + 2][state->player_x] == '#') {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
state->map[state->player_y+1][state->player_x] = '@';
|
state->map[state->player_y + 1][state->player_x] = '@';
|
||||||
|
|
||||||
if (state->map[state->player_y+2][state->player_x] == '.') {
|
if (state->map[state->player_y + 2][state->player_x] == '.') {
|
||||||
state->map[state->player_y+2][state->player_x] = '*';
|
state->map[state->player_y + 2][state->player_x] = '*';
|
||||||
} else {
|
} else {
|
||||||
state->map[state->player_y+2][state->player_x] = '$';
|
state->map[state->player_y + 2][state->player_x] = '$';
|
||||||
}
|
}
|
||||||
|
|
||||||
state->map[state->player_y][state->player_x] = ' ';
|
state->map[state->player_y][state->player_x] = ' ';
|
||||||
|
@ -145,13 +145,13 @@ bool push_box_down(sokoban_t *init_data, state_t *state) {
|
||||||
***************************************/
|
***************************************/
|
||||||
|
|
||||||
bool move_left_player(sokoban_t *init_data, state_t *state) {
|
bool move_left_player(sokoban_t *init_data, state_t *state) {
|
||||||
if (state->map[state->player_y][state->player_x-1] != '#') {
|
if (state->map[state->player_y][state->player_x - 1] != '#') {
|
||||||
if (state->map[state->player_y][state->player_x-1] == '$' || \
|
if (state->map[state->player_y][state->player_x - 1] == '$' || \
|
||||||
state->map[state->player_y][state->player_x-1] == '*') {
|
state->map[state->player_y][state->player_x - 1] == '*') {
|
||||||
|
|
||||||
return push_box_left(init_data, state);
|
return push_box_left(init_data, state);
|
||||||
} else {
|
} else {
|
||||||
state->map[state->player_y][state->player_x-1] = '@';
|
state->map[state->player_y][state->player_x - 1] = '@';
|
||||||
state->map[state->player_y][state->player_x] = ' ';
|
state->map[state->player_y][state->player_x] = ' ';
|
||||||
|
|
||||||
if (is_goal_loc(state->player_y, state->player_x, init_data) && \
|
if (is_goal_loc(state->player_y, state->player_x, init_data) && \
|
||||||
|
@ -170,13 +170,13 @@ bool move_left_player(sokoban_t *init_data, state_t *state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool move_right_player(sokoban_t *init_data, state_t *state) {
|
bool move_right_player(sokoban_t *init_data, state_t *state) {
|
||||||
if (state->map[state->player_y][state->player_x+1] != '#') {
|
if (state->map[state->player_y][state->player_x + 1] != '#') {
|
||||||
if (state->map[state->player_y][state->player_x+1] == '$' || \
|
if (state->map[state->player_y][state->player_x + 1] == '$' || \
|
||||||
state->map[state->player_y][state->player_x+1] == '*') {
|
state->map[state->player_y][state->player_x + 1] == '*') {
|
||||||
|
|
||||||
return push_box_right(init_data, state);
|
return push_box_right(init_data, state);
|
||||||
} else {
|
} else {
|
||||||
state->map[state->player_y][state->player_x+1] = '@';
|
state->map[state->player_y][state->player_x + 1] = '@';
|
||||||
state->map[state->player_y][state->player_x] = ' ';
|
state->map[state->player_y][state->player_x] = ' ';
|
||||||
|
|
||||||
if (is_goal_loc(state->player_y, state->player_x, init_data) && \
|
if (is_goal_loc(state->player_y, state->player_x, init_data) && \
|
||||||
|
@ -195,13 +195,13 @@ bool move_right_player(sokoban_t *init_data, state_t *state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool move_up_player(sokoban_t *init_data, state_t *state) {
|
bool move_up_player(sokoban_t *init_data, state_t *state) {
|
||||||
if (state->map[state->player_y-1][state->player_x] != '#') {
|
if (state->map[state->player_y - 1][state->player_x] != '#') {
|
||||||
if (state->map[state->player_y-1][state->player_x] == '$' || \
|
if (state->map[state->player_y - 1][state->player_x] == '$' || \
|
||||||
state->map[state->player_y-1][state->player_x] == '*') {
|
state->map[state->player_y - 1][state->player_x] == '*') {
|
||||||
|
|
||||||
return push_box_up(init_data, state);
|
return push_box_up(init_data, state);
|
||||||
} else {
|
} else {
|
||||||
state->map[state->player_y-1][state->player_x] = '@';
|
state->map[state->player_y - 1][state->player_x] = '@';
|
||||||
state->map[state->player_y][state->player_x] = ' ';
|
state->map[state->player_y][state->player_x] = ' ';
|
||||||
|
|
||||||
if (is_goal_loc(state->player_y, state->player_x, init_data) && \
|
if (is_goal_loc(state->player_y, state->player_x, init_data) && \
|
||||||
|
@ -220,13 +220,13 @@ bool move_up_player(sokoban_t *init_data, state_t *state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool move_down_player(sokoban_t *init_data, state_t *state) {
|
bool move_down_player(sokoban_t *init_data, state_t *state) {
|
||||||
if (state->map[state->player_y+1][state->player_x] != '#') {
|
if (state->map[state->player_y + 1][state->player_x] != '#') {
|
||||||
if (state->map[state->player_y+1][state->player_x] == '$' || \
|
if (state->map[state->player_y + 1][state->player_x] == '$' || \
|
||||||
state->map[state->player_y+1][state->player_x] == '*') {
|
state->map[state->player_y + 1][state->player_x] == '*') {
|
||||||
|
|
||||||
return push_box_down(init_data, state);
|
return push_box_down(init_data, state);
|
||||||
} else {
|
} else {
|
||||||
state->map[state->player_y+1][state->player_x] = '@';
|
state->map[state->player_y + 1][state->player_x] = '@';
|
||||||
state->map[state->player_y][state->player_x] = ' ';
|
state->map[state->player_y][state->player_x] = ' ';
|
||||||
|
|
||||||
if (is_goal_loc(state->player_y, state->player_x, init_data) && \
|
if (is_goal_loc(state->player_y, state->player_x, init_data) && \
|
||||||
|
@ -279,10 +279,10 @@ bool execute_move_t(sokoban_t *init_data, state_t *state, move_t move) {
|
||||||
|
|
||||||
bool corner_check(int x, int y, sokoban_t *init_data, state_t *state) {
|
bool corner_check(int x, int y, sokoban_t *init_data, state_t *state) {
|
||||||
// Check if corner
|
// Check if corner
|
||||||
if (((state->map[y][x+1] == '#' && state->map[y+1][x] == '#') ||
|
if (((state->map[y][x + 1] == '#' && state->map[y + 1][x] == '#') ||
|
||||||
(state->map[y+1][x] == '#' && state->map[y][x-1] == '#') ||
|
(state->map[y + 1][x] == '#' && state->map[y][x - 1] == '#') ||
|
||||||
(state->map[y][x-1] == '#' && state->map[y-1][x] == '#') ||
|
(state->map[y][x - 1] == '#' && state->map[y - 1][x] == '#') ||
|
||||||
(state->map[y-1][x] == '#' && state->map[y][x+1] == '#')) &&
|
(state->map[y - 1][x] == '#' && state->map[y][x + 1] == '#')) &&
|
||||||
!is_goal_loc(state->player_y, state->player_x, init_data)) {
|
!is_goal_loc(state->player_y, state->player_x, init_data)) {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -300,17 +300,17 @@ bool simple_corner_deadlock(sokoban_t *init_data, state_t *state) {
|
||||||
deadlock = corner_check(x, y, init_data, state);
|
deadlock = corner_check(x, y, init_data, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->map[state->player_y-1][state->player_x] == '$') {
|
if (state->map[state->player_y - 1][state->player_x] == '$') {
|
||||||
y = state->player_y - 1;
|
y = state->player_y - 1;
|
||||||
deadlock = corner_check(x, y, init_data, state);
|
deadlock = corner_check(x, y, init_data, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->map[state->player_y][state->player_x+1] == '$') {
|
if (state->map[state->player_y][state->player_x + 1] == '$') {
|
||||||
x = state->player_x + 1;
|
x = state->player_x + 1;
|
||||||
deadlock = corner_check(x, y, init_data, state);
|
deadlock = corner_check(x, y, init_data, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->map[state->player_y][state->player_x-1] == '$') {
|
if (state->map[state->player_y][state->player_x - 1] == '$') {
|
||||||
x = state->player_x - 1;
|
x = state->player_x - 1;
|
||||||
deadlock = corner_check(x, y, init_data, state);
|
deadlock = corner_check(x, y, init_data, state);
|
||||||
}
|
}
|
||||||
|
@ -318,6 +318,167 @@ bool simple_corner_deadlock(sokoban_t *init_data, state_t *state) {
|
||||||
return deadlock;
|
return deadlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool adjacent_box_check(int x, int y, sokoban_t *init_data, state_t *state) {
|
||||||
|
/* The outside if statement for each example checks to see if the indices
|
||||||
|
* are within the map to prevent out-of-bounds errors.
|
||||||
|
* The inside if statement then checks if the current state matches the
|
||||||
|
* example.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Example 1:
|
||||||
|
* # # # # #
|
||||||
|
* # $
|
||||||
|
* # $
|
||||||
|
* # @
|
||||||
|
* #
|
||||||
|
*/
|
||||||
|
if ((y - 2 >= 0) && (x < (int) strlen((state->map)[y - 2])) && \
|
||||||
|
(x - 1 < (int) strlen((state->map)[y - 1]))) {
|
||||||
|
if (state->map[y - 1][x - 1] == '$' && state->map[y - 2][x] == '#' && \
|
||||||
|
state->map[y - 2][x - 1] == '#' && \
|
||||||
|
!is_goal_loc(state->player_y, state->player_x, init_data)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Example 2:
|
||||||
|
* # # # # #
|
||||||
|
* # $
|
||||||
|
* # $
|
||||||
|
* # @
|
||||||
|
* #
|
||||||
|
*/
|
||||||
|
if ((y - 2 >= 0) && (x + 1 < (int) strlen((state->map)[y - 2])) && \
|
||||||
|
(x + 1 < (int) strlen((state->map)[y - 1]))) {
|
||||||
|
if (state->map[y - 1][x + 1] == '$' && state->map[y - 2][x] == '#' && \
|
||||||
|
state->map[y - 2][x + 1] == '#' && \
|
||||||
|
!is_goal_loc(state->player_y, state->player_x, init_data)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Example 3:
|
||||||
|
* # # # # #
|
||||||
|
* #
|
||||||
|
* # $
|
||||||
|
* # $ @
|
||||||
|
* #
|
||||||
|
*/
|
||||||
|
if ((y < init_data->lines) && (x - 1 < (int) strlen(state->map[y - 1]))) {
|
||||||
|
if (state->map[y - 1][x - 1] == '$' && state->map[y][x - 2] == '#' && \
|
||||||
|
state->map[y - 1][x - 2] == '#' && \
|
||||||
|
!is_goal_loc(state->player_y, state->player_x, init_data)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Example 4:
|
||||||
|
* # # # # #
|
||||||
|
* #
|
||||||
|
* # $ @
|
||||||
|
* # $
|
||||||
|
* #
|
||||||
|
*/
|
||||||
|
if ((y + 1 < init_data->lines) && (x - 1 < (int) strlen(state->map[y + 1]))) {
|
||||||
|
if (state->map[y + 1][x - 1] == '$' && state->map[y][x - 2] == '#' && \
|
||||||
|
state->map[y + 1][x - 2] == '#' && \
|
||||||
|
!is_goal_loc(state->player_y, state->player_x, init_data)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Example 5:
|
||||||
|
* #
|
||||||
|
* #
|
||||||
|
* $ #
|
||||||
|
* @ $ #
|
||||||
|
* #
|
||||||
|
* # # # # #
|
||||||
|
*/
|
||||||
|
if ((y < init_data->lines) && (x + 2 < (int) strlen(state->map[y - 1])) && \
|
||||||
|
(x + 2 < (int) strlen(state->map[y]))) {
|
||||||
|
if (state->map[y - 1][x + 1] == '$' && state->map[y][x + 2] == '#' && \
|
||||||
|
state->map[y - 1][x + 2] == '#' && \
|
||||||
|
!is_goal_loc(state->player_y, state->player_x, init_data)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Example 6:
|
||||||
|
* #
|
||||||
|
* @ $ #
|
||||||
|
* $ #
|
||||||
|
* #
|
||||||
|
* # # # # #
|
||||||
|
*/
|
||||||
|
if ((y - 1 < init_data->lines) && (x + 2 < (int) strlen(state->map[y - 1])) && \
|
||||||
|
(x + 2 < (int) strlen(state->map[y]))) {
|
||||||
|
if (state->map[y - 1][x + 1] == '$' && state->map[y][x + 2] == '#' && \
|
||||||
|
state->map[y - 1][x + 2] == '#' && \
|
||||||
|
!is_goal_loc(state->player_y, state->player_x, init_data)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Example 7:
|
||||||
|
* #
|
||||||
|
* @ #
|
||||||
|
* $ #
|
||||||
|
* $ #
|
||||||
|
* # # # # #
|
||||||
|
*/
|
||||||
|
if ((y + 2 < init_data->lines) && (x < (int) strlen((state->map)[y + 2])) && \
|
||||||
|
(x - 1 < (int) strlen((state->map)[y + 1]))) {
|
||||||
|
if (state->map[y + 1][x - 1] == '$' && state->map[y + 2][x] == '#' && \
|
||||||
|
state->map[y + 2][x - 1] == '#' && \
|
||||||
|
!is_goal_loc(state->player_y, state->player_x, init_data)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Example 8:
|
||||||
|
* #
|
||||||
|
* @ #
|
||||||
|
* $ #
|
||||||
|
* $ #
|
||||||
|
* # # # # #
|
||||||
|
*/
|
||||||
|
if ((y + 2 < init_data->lines) && (x + 1 < (int) strlen((state->map)[y + 2])) && \
|
||||||
|
(x + 1 < (int) strlen((state->map)[y + 1]))) {
|
||||||
|
if (state->map[y + 1][x + 1] == '$' && state->map[y + 2][x] == '#' && \
|
||||||
|
state->map[y + 2][x + 1] == '#' && \
|
||||||
|
!is_goal_loc(state->player_y, state->player_x, init_data)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool freeze_deadlock(sokoban_t *init_data, state_t *state) {
|
||||||
|
bool deadlock = false;
|
||||||
|
|
||||||
|
int x = state->player_x;
|
||||||
|
int y = state->player_y;
|
||||||
|
|
||||||
|
if (state->map[y - 1][x] == '$') {
|
||||||
|
deadlock = adjacent_box_check(x, y - 1, init_data, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->map[y + 1][x] == '$') {
|
||||||
|
deadlock = adjacent_box_check(x, y + 1, init_data, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->map[y][x - 1] == '$') {
|
||||||
|
deadlock = adjacent_box_check(x - 1, y, init_data, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->map[y][x + 1] == '$') {
|
||||||
|
deadlock = adjacent_box_check(x + 1, y, init_data, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return deadlock;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Function: winning_condition *
|
* Function: winning_condition *
|
||||||
* Parameters: sokoban_t *init_data, state_t *state *
|
* Parameters: sokoban_t *init_data, state_t *state *
|
||||||
|
@ -337,13 +498,13 @@ bool winning_condition(sokoban_t *init_data, state_t *state) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void play_solution(sokoban_t init_data, char *solution) {
|
void play_solution(sokoban_t init_data, char *solution ) {
|
||||||
SCREEN *mainScreen = newterm(TERMINAL_TYPE, stdout, stdin);
|
SCREEN *mainScreen = newterm(TERMINAL_TYPE, stdout, stdin);
|
||||||
set_term(mainScreen);
|
set_term(mainScreen);
|
||||||
int cols = 1;
|
|
||||||
|
|
||||||
for (int i = 0; i < init_data.lines; i++) {
|
int cols = 1;
|
||||||
if (strlen(init_data.map[i]) > (size_t) cols) {
|
for(int i = 0; i < init_data.lines; i++){
|
||||||
|
if(strlen(init_data.map[i]) > (size_t) cols){
|
||||||
cols = strlen(init_data.map[i]);
|
cols = strlen(init_data.map[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,13 +529,13 @@ void play_solution(sokoban_t init_data, char *solution) {
|
||||||
|
|
||||||
int key_pressed = 0;
|
int key_pressed = 0;
|
||||||
|
|
||||||
if (solution[i] == 'u' || solution[i] == 'U') {
|
if(solution[i] == 'u' || solution[i] == 'U') {
|
||||||
key_pressed = KEY_UP;
|
key_pressed = KEY_UP;
|
||||||
} else if (solution[i] == 'd' || solution[i] == 'D') {
|
} else if(solution[i] == 'd' || solution[i] == 'D') {
|
||||||
key_pressed = KEY_DOWN;
|
key_pressed = KEY_DOWN;
|
||||||
} else if (solution[i] == 'l' || solution[i] == 'L') {
|
} else if(solution[i] == 'l' || solution[i] == 'L') {
|
||||||
key_pressed = KEY_LEFT;
|
key_pressed = KEY_LEFT;
|
||||||
} else if (solution[i] == 'r' || solution[i] == 'R') {
|
} else if(solution[i] == 'r' || solution[i] == 'R') {
|
||||||
key_pressed = KEY_RIGHT;
|
key_pressed = KEY_RIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,10 @@ bool execute_move_t(sokoban_t *init_data, state_t *state, move_t move);
|
||||||
|
|
||||||
bool simple_corner_deadlock(sokoban_t *init_data, state_t *state);
|
bool simple_corner_deadlock(sokoban_t *init_data, state_t *state);
|
||||||
|
|
||||||
|
bool adjacent_box_check(int x, int y, sokoban_t *init_data, state_t *state);
|
||||||
|
|
||||||
|
bool freeze_deadlock(sokoban_t *init_data, state_t *state);
|
||||||
|
|
||||||
bool winning_condition(sokoban_t *init_data, state_t *state);
|
bool winning_condition(sokoban_t *init_data, state_t *state);
|
||||||
|
|
||||||
void play_solution(sokoban_t init_data, char* solution);
|
void play_solution(sokoban_t init_data, char* solution);
|
||||||
|
|
BIN
src/ai/utils.o
BIN
src/ai/utils.o
Binary file not shown.
|
@ -33,10 +33,10 @@ void loose_check(sokoban_t sokoban) {
|
||||||
|
|
||||||
void storage_loose_check(int y, int x, sokoban_t sokoban) {
|
void storage_loose_check(int y, int x, sokoban_t sokoban) {
|
||||||
if (sokoban.map[y][x] == '$') {
|
if (sokoban.map[y][x] == '$') {
|
||||||
if (((sokoban.map[y][x+1] == '#' && sokoban.map[y+1][x] == '#') ||
|
if (((sokoban.map[y][x + 1] == '#' && sokoban.map[y + 1][x] == '#') ||
|
||||||
(sokoban.map[y+1][x] == '#' && sokoban.map[y][x-1] == '#') ||
|
(sokoban.map[y + 1][x] == '#' && sokoban.map[y][x - 1] == '#') ||
|
||||||
(sokoban.map[y][x-1] == '#' && sokoban.map[y-1][x] == '#') ||
|
(sokoban.map[y][x - 1] == '#' && sokoban.map[y - 1][x] == '#') ||
|
||||||
(sokoban.map[y-1][x] == '#' && sokoban.map[y][x+1] == '#')) &&
|
(sokoban.map[y - 1][x] == '#' && sokoban.map[y][x + 1] == '#')) &&
|
||||||
!is_goal_cell(y, x, sokoban ) ) {
|
!is_goal_cell(y, x, sokoban ) ) {
|
||||||
|
|
||||||
endwin();
|
endwin();
|
||||||
|
|
Binary file not shown.
|
@ -82,8 +82,8 @@ sokoban_t make_map(char const *path, sokoban_t sokoban) {
|
||||||
for (int i = 0; i < columns; i++) {
|
for (int i = 0; i < columns; i++) {
|
||||||
sokoban.map[j][i] = sokoban.buffer[k];
|
sokoban.map[j][i] = sokoban.buffer[k];
|
||||||
sokoban.map_save[j][i] = sokoban.buffer[k];
|
sokoban.map_save[j][i] = sokoban.buffer[k];
|
||||||
sokoban.map[j][i+1] = '\0';
|
sokoban.map[j][i + 1] = '\0';
|
||||||
sokoban.map_save[j][i+1] = '\0';
|
sokoban.map_save[j][i + 1] = '\0';
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Binary file not shown.
Loading…
Reference in a new issue