Optimisation, formatting changes

This commit is contained in:
Rory Healy 2021-10-22 15:30:16 +11:00
parent ab01fa2878
commit 3e2e69f1c3
13 changed files with 403 additions and 97 deletions

View file

@ -1,3 +0,0 @@
# Deadlock and Optimizations
Explain your optimizations if applicable

140
report.md Normal file
View 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

Binary file not shown.

View file

@ -1 +0,0 @@
rrRlllllL

View file

@ -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);
} }

Binary file not shown.

View file

@ -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,15 +529,15 @@ 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;
} }
init_data = key_check(init_data, key_pressed); init_data = key_check(init_data, key_pressed);
init_data = check_zone_reset(init_data); init_data = check_zone_reset(init_data);

View file

@ -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);

Binary file not shown.

View file

@ -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.

View file

@ -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.