Memory leak fixes, formatting changes

This commit is contained in:
Rory Healy 2021-10-21 20:02:57 +11:00
parent cf9d366133
commit ab01fa2878
43 changed files with 787 additions and 597 deletions

View file

@ -6,6 +6,7 @@
*/ */
#include <stdarg.h> #include <stdarg.h>
#ifndef LIBMY_H #ifndef LIBMY_H
#define LIBMY_H #define LIBMY_H
void my_putchar(char c); void my_putchar(char c);

View file

@ -7,43 +7,72 @@
#ifndef BSQ_H #ifndef BSQ_H
#define BSQ_H #define BSQ_H
typedef struct sokoban {
char *buffer; typedef struct sokoban {
char **map; char *buffer;
char **map_save; char **map;
int lines; char **map_save;
int player_x; int lines;
int player_y; int player_x;
char const *base_path; int player_y;
int win; char const *base_path;
int case_number; int win;
int num_chars_map; int case_number;
} sokoban_t; int num_chars_map;
int helper(void); } sokoban_t;
char *read_map(int reading);
char *open_map(char const *path); int helper(void);
sokoban_t make_map(char const *path, sokoban_t sokoban);
int play(char const *path); char *read_map(int reading);
sokoban_t count_lines(sokoban_t sokoban);
int count_columns(sokoban_t sokoban, int position); char *open_map(char const *path);
sokoban_t check_if_player(sokoban_t sokoban, int y, int x);
sokoban_t find_player(sokoban_t sokoban); sokoban_t make_map(char const *path, sokoban_t sokoban);
sokoban_t key_check(sokoban_t sokoban, int key);
sokoban_t move_right(sokoban_t sokoban); int play(char const *path);
sokoban_t move_left(sokoban_t sokoban);
sokoban_t move_up(sokoban_t sokoban); sokoban_t count_lines(sokoban_t sokoban);
sokoban_t move_down(sokoban_t sokoban);
void win_check(sokoban_t sokoban); int count_columns(sokoban_t sokoban, int position);
int count_storage_zone(int y, int x, sokoban_t sokoban);
int count_storage_won(int y, int x, sokoban_t sokoban); sokoban_t check_if_player(sokoban_t sokoban, int y, int x);
sokoban_t check_zone_reset(sokoban_t sokoban);
sokoban_t reset_zone(int y, int x, sokoban_t sokoban); sokoban_t find_player(sokoban_t sokoban);
void loose_check(sokoban_t sokoban);
void storage_loose_check(int y, int x, sokoban_t sokoban); sokoban_t key_check(sokoban_t sokoban, int key);
void map_check(sokoban_t sokoban);
int count_case_number(int y, int x, sokoban_t sokoban); sokoban_t move_right(sokoban_t sokoban);
int count_player(int y, int x, sokoban_t sokoban);
sokoban_t game_management(sokoban_t sokoban); sokoban_t move_left(sokoban_t sokoban);
int check_tile(int y, int x, sokoban_t sokoban);
int is_goal_cell(int y, int x, sokoban_t sokoban); sokoban_t move_up(sokoban_t sokoban);
sokoban_t move_down(sokoban_t sokoban);
void win_check(sokoban_t sokoban);
int count_storage_zone(int y, int x, sokoban_t sokoban);
int count_storage_won(int y, int x, sokoban_t sokoban);
sokoban_t check_zone_reset(sokoban_t sokoban);
sokoban_t reset_zone(int y, int x, sokoban_t sokoban);
void loose_check(sokoban_t sokoban);
void storage_loose_check(int y, int x, sokoban_t sokoban);
void map_check(sokoban_t sokoban);
int count_case_number(int y, int x, sokoban_t sokoban);
int count_player(int y, int x, sokoban_t sokoban);
sokoban_t game_management(sokoban_t sokoban);
int check_tile(int y, int x, sokoban_t sokoban);
int is_goal_cell(int y, int x, sokoban_t sokoban);
#endif #endif

View file

@ -8,7 +8,6 @@
#include "../include/libmy.h" #include "../include/libmy.h"
#include <unistd.h> #include <unistd.h>
void my_putchar(char c) void my_putchar(char c) {
{
write(1, &c, 1); write(1, &c, 1);
} }

Binary file not shown.

View file

@ -7,13 +7,13 @@
#include "../include/libmy.h" #include "../include/libmy.h"
int my_putstr(char const *str) int my_putstr(char const *str) {
{
int i = 0; int i = 0;
while (str[i] != '\0') { while (str[i] != '\0') {
my_putchar(str[i]); my_putchar(str[i]);
i++; i++;
} }
return (0); return (0);
} }

Binary file not shown.

BIN
sokoban

Binary file not shown.

View file

@ -1 +1 @@
drdrdrdrrruuuuuulllllddrdrdrDulululldRdRdrdRRllululuurdrdrDululldRuuluurrrrrdddddrddlUUUUUUruLLLLLulDDdrdddrdRRlluluurdrDulldruluulldRuuurrrrrdddddrddlUUUUUUruLLLLLulDDdrdrdddRRlluurDldRuulululldRdRluuuurrrrrdddddrddlUUUUUUruLLLLLulDDdrdrdrddRluulululldRdRluuuurrrrrdddddrddlUUUUUUruLLLLLulDD rrRlllllL

View file

@ -1,161 +1,166 @@
#include <time.h>
#include <stdlib.h>
#include <limits.h> #include <limits.h>
#include <math.h> #include <math.h>
#include <stdlib.h>
#include <time.h>
#include "ai.h" #include "ai.h"
#include "utils.h"
#include "hashtable.h" #include "hashtable.h"
#include "priority_queue.h" #include "priority_queue.h"
#include "utils.h"
/** /**
* Retrieve solution and return a string containing the squence of moves * Retrieve solution and return a string containing the squence of moves
*/ */
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:
if (n->parent->state.map[n->state.player_y][n->state.player_x] == '$')
solution_string[n->depth-1] = 'R';
else
solution_string[n->depth-1] = 'r';
break;
case right:
if (n->parent->state.map[n->state.player_y][n->state.player_x] == '$')
solution_string[n->depth-1] = 'R';
else
solution_string[n->depth-1] = 'r';
break;
} }
n = n->parent; n = n->parent;
} }
return solution_string; return solution_string;
} }
/** /**
* Copy a src into a dst state * Copy a src into a dst state
*/ */
void copy_state(sokoban_t* init_data, state_t* dst, state_t* src){ void copy_state(sokoban_t *init_data, state_t *dst, state_t *src) {
dst->map = malloc(sizeof(char *) * init_data->lines); dst->map = malloc(sizeof(char *) * init_data->lines);
for ( int i = 0; i < init_data->lines; ++i ){
for (int i = 0; i < init_data->lines; ++i) {
int width = strlen(src->map[i]) + 1; int width = strlen(src->map[i]) + 1;
dst->map[i] = malloc(width); dst->map[i] = malloc(width);
memcpy(dst->map[i], src->map[i], width); memcpy(dst->map[i], src->map[i], width);
} }
dst->player_x = src->player_x; dst->player_x = src->player_x;
dst->player_y = src->player_y; dst->player_y = src->player_y;
} }
/** /**
* 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 = (node_t *) malloc(sizeof(node_t));
new_n->parent = NULL; new_n->parent = NULL;
new_n->priority = 0; new_n->priority = 0;
new_n->depth = 0; new_n->depth = 0;
new_n->num_childs = 0; new_n->num_childs = 0;
new_n->move = -1; new_n->move = -1;
new_n->state.map = malloc(sizeof(char *) * init_data->lines); new_n->state.map = malloc(sizeof(char *) * init_data->lines);
for (int i = 0; i < init_data->lines; ++i)
{ for (int i = 0; i < init_data->lines; ++i) {
int width = strlen(init_data->map[i]) + 1; int width = strlen(init_data->map[i]) + 1;
new_n->state.map[i] = malloc(width); new_n->state.map[i] = malloc(width);
memcpy(new_n->state.map[i], init_data->map[i], width); memcpy(new_n->state.map[i], init_data->map[i], width);
} }
new_n->state.player_x = init_data->player_x; new_n->state.player_x = init_data->player_x;
new_n->state.player_y = init_data->player_y; new_n->state.player_y = init_data->player_y;
return new_n; return new_n;
} }
/** /**
* 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 = (node_t *) malloc(sizeof(node_t));
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));
return new_n; return new_n;
} }
/** /**
* Apply an action to node n, create a new node resulting from * Apply an action to node n, create a new node resulting from
* executing the action, and return if the player moved * executing the action, and return if the player moved
*/ */
bool applyAction(sokoban_t* init_data, node_t* n, node_t** new_node, move_t action ){ bool applyAction(sokoban_t *init_data, node_t *n, node_t **new_node, \
move_t action) {
bool player_moved = false; bool player_moved = false;
*new_node = create_node( init_data, n ); *new_node = create_node(init_data, n);
(*new_node)->move = action; (*new_node)->move = action;
(*new_node)->priority = -(*new_node)->depth; (*new_node)->priority = -(*new_node)->depth;
player_moved = execute_move_t( init_data, &((*new_node)->state), action ); player_moved = execute_move_t(init_data, &((*new_node)->state), action);
return player_moved; return player_moved;
} }
/** /**
* Book keeping variable and function to free memory once the solver finishes * Book keeping variable and function to free memory once the solver finishes
*/ */
node_t** expanded_nodes_table; node_t **expanded_nodes_table;
unsigned expanded_nodes_table_size = 10000000; //10M
void update_explore_table(node_t* n, unsigned expanded_nodes ){
if( expanded_nodes > expanded_nodes_table_size - 1){
expanded_nodes_table_size *= 2;
expanded_nodes_table = realloc( expanded_nodes_table, sizeof(node_t*) * expanded_nodes_table_size );
// 10M
unsigned expanded_nodes_table_size = 10000000;
void update_explore_table(node_t *n, unsigned expanded_nodes) {
if (expanded_nodes > expanded_nodes_table_size - 1) {
expanded_nodes_table_size *= 2;
expanded_nodes_table = realloc(expanded_nodes_table, \
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 ){ void free_memory(unsigned expanded_nodes, int lines) {
for( unsigned i = 0; i < expanded_nodes; i++){ for (unsigned i = 0; i < expanded_nodes; i++) {
for (int j = 0; j < lines; j++) {
free(expanded_nodes_table[i]->state.map[j]);
}
free(expanded_nodes_table[i]->state.map);
free(expanded_nodes_table[i]); free(expanded_nodes_table[i]);
} }
free(expanded_nodes_table); free(expanded_nodes_table);
} }
/** /**
* Given a 2D map, returns a 1D map * Given a 2D map, returns a 1D map
*/ */
void flatten_map( sokoban_t* init_data, char **dst_map, char **src_map){ void flatten_map(sokoban_t *init_data, char **dst_map, char **src_map) {
int current_i = 0; int current_i = 0;
for (int i = 0; i < init_data->lines; ++i) for (int i = 0; i < init_data->lines; ++i) {
{
int width = strlen(src_map[i]); int width = strlen(src_map[i]);
for ( int j = 0; j < width; j++ ){ for (int j = 0; j < width; j++) {
(*dst_map)[current_i] = src_map[i][j]; (*dst_map)[current_i] = src_map[i][j];
current_i++; current_i++;
} }
@ -165,13 +170,12 @@ void flatten_map( sokoban_t* init_data, char **dst_map, char **src_map){
/** /**
* Find a solution by exploring all possible paths * Find a solution by exploring all possible paths
*/ */
void find_solution(sokoban_t* init_data, bool show_solution) void find_solution(sokoban_t *init_data, bool show_solution) {
{
// Keep track of solving time // Keep track of solving time
clock_t start = clock(); clock_t start = clock();
// Solution String containing the sequence of moves // Solution String containing the sequence of moves
char* solution = NULL; char *solution = NULL;
HashTable hashTable; HashTable hashTable;
struct heap pq; struct heap pq;
@ -185,32 +189,27 @@ 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
char* flat_map = calloc( init_data->num_chars_map, sizeof(char)); char *flat_map = calloc(init_data->num_chars_map, sizeof(char));
// Initialize heap // Initialize heap
heap_init(&pq); heap_init(&pq);
// 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 = (node_t **) malloc(sizeof(node_t *) * 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);
// Use the max heap API provided in priority_queue.h // Use the max heap API provided in priority_queue.h
heap_push(&pq,n); heap_push(&pq,n);
/** // Implementation of Algorithm 1
* FILL IN THE GRAPH ALGORITHM
* */
while (pq.count > 0) { while (pq.count > 0) {
n = heap_delete(&pq); n = heap_delete(&pq);
update_explore_table(n, expanded_nodes); update_explore_table(n, expanded_nodes);
@ -226,6 +225,9 @@ void find_solution(sokoban_t* init_data, bool show_solution)
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 || simple_corner_deadlock(init_data, &(new->state))) {
for (int i = 0; i < init_data->lines; i++) {
free(new->state.map[i]);
}
free(new->state.map); free(new->state.map);
free(new); free(new);
continue; continue;
@ -235,6 +237,9 @@ void find_solution(sokoban_t* init_data, bool show_solution)
if (ht_lookup(&hashTable, flat_map) != NULL) { if (ht_lookup(&hashTable, flat_map) != NULL) {
duplicated_nodes += 1; duplicated_nodes += 1;
for (int i = 0; i < init_data->lines; i++) {
free(new->state.map[i]);
}
free(new->state.map); free(new->state.map);
free(new); free(new);
continue; continue;
@ -245,13 +250,13 @@ void find_solution(sokoban_t* init_data, bool show_solution)
} }
} }
//----------------------------
// Free Memory of HashTable, Explored and flatmap // Free Memory of HashTable, Explored and flatmap
ht_clear(&hashTable); ht_clear(&hashTable);
ht_destroy(&hashTable); ht_destroy(&hashTable);
free_memory(expanded_nodes); 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++) { for (int i = 0; i < init_data->lines; i++) {
free((init_data->map)[i]); free((init_data->map)[i]);
free((init_data->map_save)[i]); free((init_data->map_save)[i]);
@ -259,27 +264,38 @@ void find_solution(sokoban_t* init_data, bool show_solution)
free(init_data->map); free(init_data->map);
free(init_data->map_save); free(init_data->map_save);
free(init_data->buffer); free(init_data->buffer);
emptyPQ(&pq);
// free(pq.heaparr);
// printf("%d\n", pq.count);
//---------------------------- // Free priority queue
for (int i = pq.count; i > 0; i--) {
for (int j = 0; j < init_data->lines; j++) {
if (pq.heaparr[i]->state.map[j]) {
free(pq.heaparr[i]->state.map[j]);
}
}
if (pq.heaparr[i]->state.map) {
free(pq.heaparr[i]->state.map);
}
if (pq.heaparr[i]) {
free(pq.heaparr[i]);
}
}
free(pq.heaparr);
// Stop clock // Stop clock
clock_t end = clock(); clock_t end = clock();
double cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC; double cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
// Show solution // Show solution
if( show_solution && solution != NULL ) play_solution( *init_data, solution); if (show_solution && solution != NULL) play_solution(*init_data, solution);
endwin(); endwin();
if( solution != NULL ){ if (solution != NULL) {
printf("\nSOLUTION: \n"); printf("\nSOLUTION: \n");
printf( "%s\n\n", solution); printf("%s\n\n", solution);
FILE *fptr = fopen("solution.txt", "w"); FILE *fptr = fopen("solution.txt", "w");
if (fptr == NULL) if (fptr == NULL) {
{
printf("Could not open file"); printf("Could not open file");
return ; return ;
} }
@ -289,34 +305,25 @@ void find_solution(sokoban_t* init_data, bool show_solution)
free(solution); free(solution);
} }
printf("STATS: \n"); printf("STATS: \n");
printf("\tExpanded nodes: %'d\n\tGenerated nodes: %'d\n\tDuplicated nodes: %'d\n", expanded_nodes, generated_nodes, duplicated_nodes); printf("\tExpanded nodes: %'d\n\tGenerated nodes: %'d\n\t" \
"Duplicated nodes: %'d\n", expanded_nodes, generated_nodes, \
duplicated_nodes);
printf("\tSolution Length: %d\n", solution_size); printf("\tSolution Length: %d\n", solution_size);
printf("\tExpanded/seconds: %d\n", (int)(expanded_nodes/cpu_time_used) ); printf("\tExpanded/seconds: %d\n", (int)(expanded_nodes/cpu_time_used));
printf("\tTime (seconds): %f\n", cpu_time_used ); printf("\tTime (seconds): %f\n", cpu_time_used);
} }
void solve(char const *path, bool show_solution) void solve(char const *path, bool show_solution) {
{ // Load Map
/**
* Load Map
*/
sokoban_t sokoban = make_map(path, sokoban); sokoban_t sokoban = make_map(path, sokoban);
/**
* Count number of boxes and Storage locations
*/
map_check(sokoban);
/**
* Locate player x,y position
*/
sokoban = find_player(sokoban);
sokoban.base_path = path; sokoban.base_path = path;
find_solution(&sokoban, show_solution); // Count number of boxes and Storage locations
map_check(sokoban);
// Locate player x,y position
sokoban = find_player(sokoban);
find_solution(&sokoban, show_solution);
} }

View file

@ -3,6 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include <unistd.h> #include <unistd.h>
#include "node.h" #include "node.h"
#include "priority_queue.h" #include "priority_queue.h"

Binary file not shown.

View file

@ -3,22 +3,20 @@
*/ */
#include <assert.h> #include <assert.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include "hashtable.h" #include "hashtable.h"
int ht_setup(HashTable* table, int ht_setup(HashTable* table, size_t key_size, size_t value_size, \
size_t key_size, size_t capacity) {
size_t value_size,
size_t capacity) {
assert(table != NULL); assert(table != NULL);
if (table == NULL) return HT_ERROR; if (table == NULL) {
return HT_ERROR;
}
if (capacity < HT_MINIMUM_CAPACITY) { if (capacity < HT_MINIMUM_CAPACITY) {
capacity = HT_MINIMUM_CAPACITY; capacity = HT_MINIMUM_CAPACITY;
@ -38,14 +36,19 @@ int ht_setup(HashTable* table,
} }
int ht_copy(HashTable* first, HashTable* second) { int ht_copy(HashTable* first, HashTable* second) {
size_t chain;
HTNode* node;
assert(first != NULL); assert(first != NULL);
assert(ht_is_initialized(second)); assert(ht_is_initialized(second));
if (first == NULL) return HT_ERROR; size_t chain;
if (!ht_is_initialized(second)) return HT_ERROR; HTNode* node;
if (first == NULL) {
return HT_ERROR;
}
if (!ht_is_initialized(second)) {
return HT_ERROR;
}
if (_ht_allocate(first, second->capacity) == HT_ERROR) { if (_ht_allocate(first, second->capacity) == HT_ERROR) {
return HT_ERROR; return HT_ERROR;
@ -59,7 +62,9 @@ int ht_copy(HashTable* first, HashTable* second) {
for (chain = 0; chain < second->capacity; ++chain) { for (chain = 0; chain < second->capacity; ++chain) {
for (node = second->nodes[chain]; node; node = node->next) { for (node = second->nodes[chain]; node; node = node->next) {
if (_ht_push_front(first, chain, node->key, node->value) == HT_ERROR) { if (_ht_push_front(first, chain, node->key, node->value) == \
HT_ERROR) {
return HT_ERROR; return HT_ERROR;
} }
} }
@ -72,8 +77,13 @@ int ht_move(HashTable* first, HashTable* second) {
assert(first != NULL); assert(first != NULL);
assert(ht_is_initialized(second)); assert(ht_is_initialized(second));
if (first == NULL) return HT_ERROR; if (first == NULL) {
if (!ht_is_initialized(second)) return HT_ERROR; return HT_ERROR;
}
if (!ht_is_initialized(second)) {
return HT_ERROR;
}
*first = *second; *first = *second;
second->nodes = NULL; second->nodes = NULL;
@ -85,8 +95,13 @@ int ht_swap(HashTable* first, HashTable* second) {
assert(ht_is_initialized(first)); assert(ht_is_initialized(first));
assert(ht_is_initialized(second)); assert(ht_is_initialized(second));
if (!ht_is_initialized(first)) return HT_ERROR; if (!ht_is_initialized(first)) {
if (!ht_is_initialized(second)) return HT_ERROR; return HT_ERROR;
}
if (!ht_is_initialized(second)) {
return HT_ERROR;
}
_ht_int_swap(&first->key_size, &second->key_size); _ht_int_swap(&first->key_size, &second->key_size);
_ht_int_swap(&first->value_size, &second->value_size); _ht_int_swap(&first->value_size, &second->value_size);
@ -104,7 +119,9 @@ int ht_destroy(HashTable* table) {
size_t chain; size_t chain;
assert(ht_is_initialized(table)); assert(ht_is_initialized(table));
if (!ht_is_initialized(table)) return HT_ERROR; if (!ht_is_initialized(table)) {
return HT_ERROR;
}
for (chain = 0; chain < table->capacity; ++chain) { for (chain = 0; chain < table->capacity; ++chain) {
node = table->nodes[chain]; node = table->nodes[chain];
@ -127,8 +144,13 @@ int ht_insert(HashTable* table, void* key, void* value) {
assert(ht_is_initialized(table)); assert(ht_is_initialized(table));
assert(key != NULL); assert(key != NULL);
if (!ht_is_initialized(table)) return HT_ERROR; if (!ht_is_initialized(table)) {
if (key == NULL) return HT_ERROR; return HT_ERROR;
}
if (key == NULL) {
return HT_ERROR;
}
if (_ht_should_grow(table)) { if (_ht_should_grow(table)) {
_ht_adjust_capacity(table); _ht_adjust_capacity(table);
@ -158,8 +180,13 @@ int ht_contains(HashTable* table, void* key) {
assert(ht_is_initialized(table)); assert(ht_is_initialized(table));
assert(key != NULL); assert(key != NULL);
if (!ht_is_initialized(table)) return HT_ERROR; if (!ht_is_initialized(table)) {
if (key == NULL) return HT_ERROR; return HT_ERROR;
}
if (key == NULL) {
return HT_ERROR;
}
index = _ht_hash(table, key); index = _ht_hash(table, key);
for (node = table->nodes[index]; node; node = node->next) { for (node = table->nodes[index]; node; node = node->next) {
@ -178,8 +205,13 @@ void* ht_lookup(HashTable* table, void* key) {
assert(table != NULL); assert(table != NULL);
assert(key != NULL); assert(key != NULL);
if (table == NULL) return NULL; if (table == NULL) {
if (key == NULL) return NULL; return NULL;
}
if (key == NULL) {
return NULL;
}
index = _ht_hash(table, key); index = _ht_hash(table, key);
for (node = table->nodes[index]; node; node = node->next) { for (node = table->nodes[index]; node; node = node->next) {
@ -198,8 +230,13 @@ const void* ht_const_lookup(const HashTable* table, void* key) {
assert(table != NULL); assert(table != NULL);
assert(key != NULL); assert(key != NULL);
if (table == NULL) return NULL; if (table == NULL) {
if (key == NULL) return NULL; return NULL;
}
if (key == NULL) {
return NULL;
}
index = _ht_hash(table, key); index = _ht_hash(table, key);
for (node = table->nodes[index]; node; node = node->next) { for (node = table->nodes[index]; node; node = node->next) {
@ -219,8 +256,13 @@ int ht_erase(HashTable* table, void* key) {
assert(table != NULL); assert(table != NULL);
assert(key != NULL); assert(key != NULL);
if (table == NULL) return HT_ERROR; if (table == NULL) {
if (key == NULL) return HT_ERROR; return HT_ERROR;
}
if (key == NULL) {
return HT_ERROR;
}
index = _ht_hash(table, key); index = _ht_hash(table, key);
node = table->nodes[index]; node = table->nodes[index];
@ -253,8 +295,13 @@ int ht_clear(HashTable* table) {
assert(table != NULL); assert(table != NULL);
assert(table->nodes != NULL); assert(table->nodes != NULL);
if (table == NULL) return HT_ERROR; if (table == NULL) {
if (table->nodes == NULL) return HT_ERROR; return HT_ERROR;
}
if (table->nodes == NULL) {
return HT_ERROR;
}
ht_destroy(table); ht_destroy(table);
_ht_allocate(table, HT_MINIMUM_CAPACITY); _ht_allocate(table, HT_MINIMUM_CAPACITY);
@ -265,7 +312,11 @@ int ht_clear(HashTable* table) {
int ht_is_empty(HashTable* table) { int ht_is_empty(HashTable* table) {
assert(table != NULL); assert(table != NULL);
if (table == NULL) return HT_ERROR;
if (table == NULL) {
return HT_ERROR;
}
return table->size == 0; return table->size == 0;
} }
@ -278,8 +329,8 @@ int ht_reserve(HashTable* table, size_t minimum_capacity) {
if (!ht_is_initialized(table)) return HT_ERROR; if (!ht_is_initialized(table)) return HT_ERROR;
/* /*
* We expect the "minimum capacity" to be in elements, not in array indices. * We expect the "minimum capacity" to be in elements,
* This encapsulates the design. * not in array indices. This encapsulates the design.
*/ */
if (minimum_capacity > table->threshold) { if (minimum_capacity > table->threshold) {
return _ht_resize(table, minimum_capacity / HT_LOAD_FACTOR); return _ht_resize(table, minimum_capacity / HT_LOAD_FACTOR);
@ -354,9 +405,11 @@ _ht_create_node(HashTable* table, void* key, void* value, HTNode* next) {
if ((node = malloc(sizeof *node)) == NULL) { if ((node = malloc(sizeof *node)) == NULL) {
return NULL; return NULL;
} }
if ((node->key = malloc(table->key_size)) == NULL) { if ((node->key = malloc(table->key_size)) == NULL) {
return NULL; return NULL;
} }
if ((node->value = malloc(table->value_size)) == NULL) { if ((node->value = malloc(table->value_size)) == NULL) {
return NULL; return NULL;
} }
@ -369,7 +422,8 @@ _ht_create_node(HashTable* table, void* key, void* value, HTNode* next) {
} }
int _ht_push_front(HashTable* table, size_t index, void* key, void* value) { int _ht_push_front(HashTable* table, size_t index, void* key, void* value) {
table->nodes[index] = _ht_create_node(table, key, value, table->nodes[index]); table->nodes[index] = \
_ht_create_node(table, key, value, table->nodes[index]);
return table->nodes[index] == NULL ? HT_ERROR : HT_SUCCESS; return table->nodes[index] == NULL ? HT_ERROR : HT_SUCCESS;
} }

View file

@ -13,23 +13,19 @@
#define HT_MINIMUM_CAPACITY 8 #define HT_MINIMUM_CAPACITY 8
#define HT_LOAD_FACTOR 5 #define HT_LOAD_FACTOR 5
#define HT_MINIMUM_THRESHOLD (HT_MINIMUM_CAPACITY) * (HT_LOAD_FACTOR) #define HT_MINIMUM_THRESHOLD (HT_MINIMUM_CAPACITY) * (HT_LOAD_FACTOR)
#define HT_GROWTH_FACTOR 2 #define HT_GROWTH_FACTOR 2
#define HT_SHRINK_THRESHOLD (1 / 4) #define HT_SHRINK_THRESHOLD (1 / 4)
#define HT_ERROR -1 #define HT_ERROR -1
#define HT_SUCCESS 0 #define HT_SUCCESS 0
#define HT_UPDATED 1 #define HT_UPDATED 1
#define HT_INSERTED 0 #define HT_INSERTED 0
#define HT_NOT_FOUND 0 #define HT_NOT_FOUND 0
#define HT_FOUND 01 #define HT_FOUND 01
#define HT_INITIALIZER {0, 0, 0, 0, 0, NULL, NULL, NULL}; #define HT_INITIALIZER {0, 0, 0, 0, 0, NULL, NULL, NULL};
typedef int (*comparison_t)(void*, void*, size_t); typedef int (*comparison_t)(void *, void *, size_t);
typedef size_t (*hash_t)(void*, size_t);
typedef size_t (*hash_t)(void *, size_t);
/****************** STRUCTURES ******************/ /****************** STRUCTURES ******************/
@ -58,13 +54,13 @@ typedef struct HashTable {
/****************** INTERFACE ******************/ /****************** INTERFACE ******************/
/* Setup */ /* Setup */
int ht_setup(HashTable* table, int ht_setup(HashTable* table, size_t key_size, size_t value_size, \
size_t key_size, size_t capacity);
size_t value_size,
size_t capacity);
int ht_copy(HashTable* first, HashTable* second); int ht_copy(HashTable* first, HashTable* second);
int ht_move(HashTable* first, HashTable* second); int ht_move(HashTable* first, HashTable* second);
int ht_swap(HashTable* first, HashTable* second); int ht_swap(HashTable* first, HashTable* second);
/* Destructor */ /* Destructor */
@ -73,16 +69,20 @@ int ht_destroy(HashTable* table);
int ht_insert(HashTable* table, void* key, void* value); int ht_insert(HashTable* table, void* key, void* value);
int ht_contains(HashTable* table, void* key); int ht_contains(HashTable* table, void* key);
void* ht_lookup(HashTable* table, void* key);
const void* ht_const_lookup(const HashTable* table, void* key); void *ht_lookup(HashTable* table, void* key);
const void *ht_const_lookup(const HashTable* table, void* key);
#define HT_LOOKUP_AS(type, table_pointer, key_pointer) \ #define HT_LOOKUP_AS(type, table_pointer, key_pointer) \
(*(type*)ht_lookup((table_pointer), (key_pointer))) (*(type*)ht_lookup((table_pointer), (key_pointer)))
int ht_erase(HashTable* table, void* key); int ht_erase(HashTable* table, void* key);
int ht_clear(HashTable* table); int ht_clear(HashTable* table);
int ht_is_empty(HashTable* table); int ht_is_empty(HashTable* table);
bool ht_is_initialized(HashTable* table); bool ht_is_initialized(HashTable* table);
int ht_reserve(HashTable* table, size_t minimum_capacity); int ht_reserve(HashTable* table, size_t minimum_capacity);
@ -90,24 +90,34 @@ int ht_reserve(HashTable* table, size_t minimum_capacity);
/****************** PRIVATE ******************/ /****************** PRIVATE ******************/
void _ht_int_swap(size_t* first, size_t* second); void _ht_int_swap(size_t* first, size_t* second);
void _ht_pointer_swap(void** first, void** second); void _ht_pointer_swap(void** first, void** second);
size_t _ht_default_hash(void* key, size_t key_size); size_t _ht_default_hash(void* key, size_t key_size);
int _ht_default_compare(void* first_key, void* second_key, size_t key_size); int _ht_default_compare(void* first_key, void* second_key, size_t key_size);
size_t _ht_hash(const HashTable* table, void* key); size_t _ht_hash(const HashTable* table, void* key);
bool _ht_equal(const HashTable* table, void* first_key, void* second_key); bool _ht_equal(const HashTable* table, void* first_key, void* second_key);
bool _ht_should_grow(HashTable* table); bool _ht_should_grow(HashTable* table);
bool _ht_should_shrink(HashTable* table); bool _ht_should_shrink(HashTable* table);
HTNode* _ht_create_node(HashTable* table, void* key, void* value, HTNode* next); HTNode *_ht_create_node(HashTable* table, void* key, void* value, \
HTNode* next);
int _ht_push_front(HashTable* table, size_t index, void* key, void* value); int _ht_push_front(HashTable* table, size_t index, void* key, void* value);
void _ht_destroy_node(HTNode* node); void _ht_destroy_node(HTNode* node);
int _ht_adjust_capacity(HashTable* table); int _ht_adjust_capacity(HashTable* table);
int _ht_allocate(HashTable* table, size_t capacity); int _ht_allocate(HashTable* table, size_t capacity);
int _ht_resize(HashTable* table, size_t new_capacity); int _ht_resize(HashTable* table, size_t new_capacity);
void _ht_rehash(HashTable* table, HTNode** old, size_t old_capacity); void _ht_rehash(HashTable* table, HTNode** old, size_t old_capacity);
#endif /* HASHTABLE_H */ #endif

Binary file not shown.

View file

@ -3,21 +3,16 @@
#include "utils.h" #include "utils.h"
/** /**
* Data structure containing the node information * Data structure containing the node information
*/ */
struct node_s{ typedef struct node_s {
int priority; int priority;
int depth; int depth;
int num_childs; int num_childs;
move_t move; move_t move;
state_t state; state_t state;
struct node_s* parent; struct node_s* parent;
}; } node_t;
typedef struct node_s node_t;
#endif #endif

View file

@ -2,109 +2,115 @@
int *heap, size, count; int *heap, size, count;
void heap_init(struct heap* h) void heap_init(struct heap *h) {
{
h->count = 0; h->count = 0;
h->size = initial_size; h->size = initial_size;
h->heaparr = (node_t **) malloc(sizeof(node_t*) * initial_size); h->heaparr = (node_t **) malloc(sizeof(node_t*) * initial_size);
for(int i = 0; i < initial_size; i++)
h->heaparr[i]=NULL;
if(!h->heaparr) { for (int i = 0; i < initial_size; i++) {
h->heaparr[i] = NULL;
}
if (!h->heaparr) {
printf("Error allocatinga memory...\n"); printf("Error allocatinga memory...\n");
exit(-1); exit(-1);
} }
} }
void max_heapify(node_t** data, int loc, int count) { void max_heapify(node_t **data, int loc, int count) {
int left, right, largest; int left, right, largest;
node_t* temp; node_t *temp;
left = 2*(loc) + 1; left = 2 * (loc) + 1;
right = left + 1; right = left + 1;
largest = loc; largest = loc;
if (left <= count && data[left]->priority > data[largest]->priority) { if (left <= count && data[left]->priority > data[largest]->priority) {
largest = left; largest = left;
} }
if (right <= count && data[right]->priority > data[largest]->priority) { if (right <= count && data[right]->priority > data[largest]->priority) {
largest = right; largest = right;
} }
if(largest != loc) { if (largest != loc) {
temp = data[loc]; temp = data[loc];
data[loc] = data[largest]; data[loc] = data[largest];
data[largest] = temp; data[largest] = temp;
max_heapify(data, largest, count); max_heapify(data, largest, count);
} }
} }
void heap_push(struct heap* h, node_t* value) void heap_push(struct heap *h, node_t *value) {
{
int index, parent; int index, parent;
// Resize the heap if it is too small to hold all the data // Resize the heap if it is too small to hold all the data
if (h->count == h->size) if (h->count == h->size) {
{
h->size += 1; h->size += 1;
h->heaparr = realloc(h->heaparr, sizeof(node_t) * h->size); h->heaparr = realloc(h->heaparr, sizeof(node_t) * h->size);
if (!h->heaparr) exit(-1); // Exit if the memory allocation fails
// Exit if the memory allocation fails
if (!h->heaparr) {
exit(-1);
}
} }
index = h->count++; // First insert at last of array // First insert at last of array
index = h->count++;
// Find out where to put the element and put it // Find out where to put the element and put it
for(;index; index = parent) for (; index; index = parent) {
{
parent = (index - 1) / 2; parent = (index - 1) / 2;
if (h->heaparr[parent]->priority >= value->priority) break;
if (h->heaparr[parent]->priority >= value->priority) {
break;
}
h->heaparr[index] = h->heaparr[parent]; h->heaparr[index] = h->heaparr[parent];
} }
h->heaparr[index] = value; h->heaparr[index] = value;
} }
void heap_display(struct heap* h, sokoban_t* init_data) { void heap_display(struct heap *h, sokoban_t *init_data) {
int i; for (int i = 0; i < h->count; ++i) {
for(i=0; i<h->count; ++i) { node_t *n = h->heaparr[i];
node_t* n = h->heaparr[i];
printf("priority = %d\n", n->priority);
for (int j = 0; i < init_data->lines; j++) {
mvprintw(i, 0, n->state.map[j]);
}
printf("priority = %d", n->priority);
printf("\n");
for (int i = 0; i < init_data->lines; i++)
mvprintw(i, 0, n->state.map[i]);
move(n->state.player_y, n->state.player_x); move(n->state.player_y, n->state.player_x);
} }
} }
node_t* heap_delete(struct heap* h) node_t *heap_delete(struct heap *h) {
{ node_t *removed;
node_t* removed; node_t *temp = h->heaparr[--h->count];
node_t* temp = h->heaparr[--h->count];
if ((h->count <= (h->size + 2)) && (h->size > initial_size)) {
if ((h->count <= (h->size + 2)) && (h->size > initial_size))
{
h->size -= 1; h->size -= 1;
h->heaparr = realloc(h->heaparr, sizeof(node_t) * h->size); h->heaparr = realloc(h->heaparr, sizeof(node_t) * h->size);
if (!h->heaparr) exit(-1); // Exit if the memory allocation fails
// Exit if the memory allocation fails
if (!h->heaparr) exit(-1);
} }
removed = h->heaparr[0]; removed = h->heaparr[0];
h->heaparr[0] = temp; h->heaparr[0] = temp;
if(temp == removed) h->heaparr[0] = NULL; if (temp == removed) {
max_heapify(h->heaparr, 0, h->count); h->heaparr[0] = NULL;
}
max_heapify(h->heaparr, 0, h->count);
return removed; return removed;
} }
void emptyPQ(struct heap* pq) { void emptyPQ(struct heap *pq) {
while(pq->count != 0) { while(pq->count != 0) {
node_t* n = heap_delete(pq); node_t *n = heap_delete(pq);
for (int i = size; i >= 0; i--) {
free(n->state.map[i]);
}
free(n->state.map);
free(n); free(n);
} }
} }

View file

@ -2,20 +2,19 @@
#define __PQ__ #define __PQ__
/** /**
* NIR: Adapted from https://gist.github.com/aatishnn/8265656#file-binarymaxheap-c * Adapted from https://gist.github.com/aatishnn/8265656#file-binarymaxheap-c
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <curses.h> #include <curses.h>
#include "node.h" #include "node.h"
#include "../../include/sokoban.h" #include "../../include/sokoban.h"
/** /**
* size is the allocated size, count is the number of elements in the queue * size is the allocated size, count is the number of elements in the queue
*/ */
struct heap { struct heap {
int size; int size;
int count; int count;
@ -24,16 +23,16 @@ struct heap {
#define initial_size 4 #define initial_size 4
void heap_init(struct heap* h); void heap_init(struct heap *h);
void max_heapify(node_t** data, int loc, int count); void max_heapify(node_t **data, int loc, int count);
void heap_push(struct heap* h, node_t* value); void heap_push(struct heap *h, node_t *value);
void heap_display(struct heap *h, sokoban_t *init_data); void heap_display(struct heap *h, sokoban_t *init_data);
node_t* heap_delete(struct heap* h); node_t* heap_delete(struct heap *h);
void emptyPQ(struct heap* pq); void emptyPQ(struct heap *pq);
#endif #endif

Binary file not shown.

View file

@ -1,256 +1,316 @@
#include <curses.h> #include <curses.h>
#include <string.h>
#include "utils.h" #include "utils.h"
/*********
* MACROS *
*********/
#define TERMINAL_TYPE (strcmp(getenv("TERM"), "xterm") == 0 ? "rxvt" : \
getenv("TERM"))
/************************************** /**************************************
* Box movement given a state state * * Box movement given a state state *
***************************************/ ***************************************/
bool is_goal_loc(int y, int x, sokoban_t* init_data) bool is_goal_loc(int y, int x, sokoban_t *init_data) {
{ return (init_data->map_save[y][x] == '.') || \
return (init_data->map_save[y][x] == '.') || (init_data->map_save[y][x] == '+') || (init_data->map_save[y][x] == '*'); (init_data->map_save[y][x] == '+') || \
(init_data->map_save[y][x] == '*');
} }
bool push_box_left(sokoban_t *init_data, state_t *state) {
if (state->map[state->player_y][state->player_x-2] == '$' || \
state->map[state->player_y][state->player_x-2] == '*') {
bool push_box_left(sokoban_t* init_data,state_t* state)
{
if (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] = ' ';
if (is_goal_loc( state->player_y, state->player_x, init_data) && state->map[state->player_y][state->player_x] == ' ') {
if (is_goal_loc(state->player_y, state->player_x, init_data) && \
state->map[state->player_y][state->player_x] == ' ') {
state->map[state->player_y][state->player_x] = '.'; state->map[state->player_y][state->player_x] = '.';
} }
state->player_x--; state->player_x--;
} }
return true; return true;
} }
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] = ' ';
if (is_goal_loc( state->player_y, state->player_x, init_data) && 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) && \
state->map[state->player_y][state->player_x] == ' ') {
state->map[state->player_y][state->player_x] = '.';
} }
state->player_x++; state->player_x++;
} }
return true; return true;
} }
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] = ' ';
if (is_goal_loc( state->player_y, state->player_x, init_data) && 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) && \
state->map[state->player_y][state->player_x] == ' ') {
state->map[state->player_y][state->player_x] = '.';
} }
state->player_y--; state->player_y--;
} }
return true; return true;
} }
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] = ' ';
if (is_goal_loc( state->player_y, state->player_x, init_data) && 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) && \
state->map[state->player_y][state->player_x] == ' ') {
state->map[state->player_y][state->player_x] = '.';
} }
state->player_y++; state->player_y++;
} }
return true; return true;
} }
/************************************** /**************************************
* Player Moves given a state state * * Player Moves given a state 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] == '$' || 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] == '*') {
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) && state->map[state->player_y][state->player_x] == ' ') {
if (is_goal_loc(state->player_y, state->player_x, init_data) && \
state->map[state->player_y][state->player_x] == ' ') {
state->map[state->player_y][state->player_x] = '.'; state->map[state->player_y][state->player_x] = '.';
} }
state->player_x--; state->player_x--;
return true; return true;
} }
} }
return false; return false;
} }
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] == '$' || 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] == '*') {
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) && state->map[state->player_y][state->player_x] == ' ') {
if (is_goal_loc(state->player_y, state->player_x, init_data) && \
state->map[state->player_y][state->player_x] == ' ') {
state->map[state->player_y][state->player_x] = '.'; state->map[state->player_y][state->player_x] = '.';
} }
state->player_x++; state->player_x++;
return true; return true;
} }
} }
return false; return false;
} }
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] == '$' || 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] == '*') {
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) && state->map[state->player_y][state->player_x] == ' ') {
if (is_goal_loc(state->player_y, state->player_x, init_data) && \
state->map[state->player_y][state->player_x] == ' ') {
state->map[state->player_y][state->player_x] = '.'; state->map[state->player_y][state->player_x] = '.';
} }
state->player_y--; state->player_y--;
return true; return true;
} }
} }
return false; return false;
} }
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] == '$' || 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] == '*') {
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) && state->map[state->player_y][state->player_x] == ' ') {
if (is_goal_loc(state->player_y, state->player_x, init_data) && \
state->map[state->player_y][state->player_x] == ' ') {
state->map[state->player_y][state->player_x] = '.'; state->map[state->player_y][state->player_x] = '.';
} }
state->player_y++; state->player_y++;
return true; return true;
} }
} }
return false; return false;
} }
bool execute_move_t(sokoban_t *init_data, state_t *state, move_t move) {
bool execute_move_t(sokoban_t* init_data, state_t* state, move_t move) {
bool player_moved = false; bool player_moved = false;
//Determine which button is pushed // Determine which button is pushed
switch (move) { switch (move) {
case up: case up:
player_moved = move_up_player(init_data, state); player_moved = move_up_player(init_data, state);
break; break;
case down: case down:
player_moved = move_down_player(init_data, state); player_moved = move_down_player(init_data, state);
break; break;
case left: case left:
player_moved = move_left_player(init_data, state); player_moved = move_left_player(init_data, state);
break; break;
case right:
player_moved = move_right_player(init_data, state);
break;
case right:
player_moved = move_right_player(init_data, state);
break;
} }
return player_moved; return player_moved;
} }
/***************************************************************************** /*****************************************************************************
* Function: simple_corner_deadlock * * Function: simple_corner_deadlock *
* Parameters: sokoban_t* init_data, state_t* state * * Parameters: sokoban_t *init_data, state_t *state *
* Returns: bool * * Returns: bool *
* Description: Check if box has been pusehd into a loc in a corner wall * * Description: Check if box has been pusehd into a loc in a corner wall *
* and loc != destination * * and loc != destination *
*****************************************************************************/ *****************************************************************************/
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;
} }
return false; return false;
} }
bool simple_corner_deadlock(sokoban_t* init_data, state_t* state) bool simple_corner_deadlock(sokoban_t *init_data, state_t *state) {
{
bool deadlock = false; bool deadlock = false;
int x = state->player_x; int x = state->player_x;
int y = state->player_y; int y = state->player_y;
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-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);
} }
@ -258,46 +318,36 @@ bool simple_corner_deadlock(sokoban_t* init_data, state_t* state)
return deadlock; return deadlock;
} }
/***************************************************************************** /*****************************************************************************
* Function: winning_condition * * Function: winning_condition *
* Parameters: sokoban_t* init_data, state_t* state * * Parameters: sokoban_t *init_data, state_t *state *
* Returns: bool * * Returns: bool *
* Description: Check if all boxes are in a destination * * Description: Check if all boxes are in a destination *
*****************************************************************************/ *****************************************************************************/
bool winning_condition(sokoban_t *init_data, state_t *state) {
bool winning_condition(sokoban_t* init_data, state_t* state)
{
for (int y = 0; y < init_data->lines; y++) { for (int y = 0; y < init_data->lines; y++) {
for (int x = 0; init_data->map_save[y][x] != '\0'; x++) { for (int x = 0; init_data->map_save[y][x] != '\0'; x++) {
if (state->map[y][x] == '$') if (state->map[y][x] == '$') {
return false; return false;
} }
}
} }
return true; return true;
} }
/********* void play_solution(sokoban_t init_data, char *solution) {
* MACROS *
*********/
#include <string.h>
#define TERMINAL_TYPE (strcmp(getenv("TERM"), "xterm") == 0 ? "rxvt" : \
getenv("TERM"))
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; int cols = 1;
for(int i = 0; i < init_data.lines; i++){
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]);
} }
} }
WINDOW *mainWindow = newwin(init_data.lines, cols, 0, 0); WINDOW *mainWindow = newwin(init_data.lines, cols, 0, 0);
cbreak(); cbreak();
@ -310,24 +360,29 @@ void play_solution( sokoban_t init_data, char* solution ){
wnoutrefresh(mainWindow); wnoutrefresh(mainWindow);
doupdate(); doupdate();
refresh(); refresh();
for (int i = 0; i < init_data.lines; i++)
for (int i = 0; i < init_data.lines; i++) {
mvprintw(i, 0, init_data.map[i]); mvprintw(i, 0, init_data.map[i]);
}
move(init_data.player_y, init_data.player_x); move(init_data.player_y, init_data.player_x);
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);
usleep(500000); usleep(500000);
} }
touchwin(mainWindow); touchwin(mainWindow);
wnoutrefresh(mainWindow); wnoutrefresh(mainWindow);
doupdate(); doupdate();
@ -335,12 +390,12 @@ void play_solution( sokoban_t init_data, char* solution ){
usleep(1500000); usleep(1500000);
} }
void print_map(sokoban_t* init_data, state_t* state ){ void print_map(sokoban_t *init_data, state_t *state) {
initscr(); initscr();
cbreak(); cbreak();
noecho(); noecho();
clear(); clear();
for (int i = 0; i < init_data->lines; i++){ for (int i = 0; i < init_data->lines; i++) {
mvprintw(i, 0, state->map[i]); mvprintw(i, 0, state->map[i]);
move(state->player_y, state->player_x); move(state->player_y, state->player_x);
} }

View file

@ -1,15 +1,16 @@
#ifndef __UTILS__ #ifndef __UTILS__
#define __UTILS__ #define __UTILS__
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <termios.h> #include <termios.h>
#include <stdbool.h>
#include <stdint.h>
#include <time.h> #include <time.h>
#include <signal.h> #include <unistd.h>
#include "../../include/sokoban.h" #include "../../include/sokoban.h"
#define SIZE 4 #define SIZE 4
@ -19,14 +20,11 @@
* Data structure containing the information about the game state * Data structure containing the information about the game state
* representing the state of the game. * representing the state of the game.
*/ */
struct state_s{ typedef struct state_s{
char **map; char **map;
int player_x; int player_x;
int player_y; int player_y;
}; } state_t;
typedef struct state_s state_t;
/** /**
* Move type * Move type
@ -38,15 +36,18 @@ typedef enum moves{
down=3 down=3
} move_t; } move_t;
/** /**
* Helper functions * Helper functions
*/ */
bool execute_move_t(sokoban_t *init_data, state_t *state, move_t move); 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 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);
void print_map(sokoban_t *init_data, state_t *state); void print_map(sokoban_t *init_data, state_t *state);
#endif #endif

Binary file not shown.

View file

@ -5,30 +5,32 @@
** Function for finding the player on the map ** Function for finding the player on the map
*/ */
#include <ncurses.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
#include <ncurses.h>
#include <stdlib.h>
#include <unistd.h>
#include "../include/libmy.h" #include "../include/libmy.h"
#include "../include/sokoban.h" #include "../include/sokoban.h"
sokoban_t find_player(sokoban_t sokoban) sokoban_t find_player(sokoban_t sokoban) {
{
sokoban.player_x = 0; sokoban.player_x = 0;
sokoban.player_y = 0; sokoban.player_y = 0;
for (int i = 0; i < sokoban.lines; i++) { for (int i = 0; i < sokoban.lines; i++) {
for (int j = 0; sokoban.map[i][j] != '\0'; j++) { for (int j = 0; sokoban.map[i][j] != '\0'; j++) {
sokoban = check_if_player(sokoban, i, j); sokoban = check_if_player(sokoban, i, j);
} }
} }
return (sokoban); return (sokoban);
} }
sokoban_t check_if_player(sokoban_t sokoban, int y, int x) sokoban_t check_if_player(sokoban_t sokoban, int y, int x) {
{
if (sokoban.map[y][x] == '@') { if (sokoban.map[y][x] == '@') {
sokoban.player_x = x; sokoban.player_x = x;
sokoban.player_y = y; sokoban.player_y = y;
} }
return (sokoban); return (sokoban);
} }

Binary file not shown.

View file

@ -2,14 +2,14 @@
** EPITECH PROJECT, 2017 ** EPITECH PROJECT, 2017
** PSU_my_sokoban_2017 ** PSU_my_sokoban_2017
** File description: ** File description:
** Main function for the my_sokoban ** Function for printing CLI usage
*/ */
#include <unistd.h> #include <unistd.h>
#include "../include/libmy.h" #include "../include/libmy.h"
int helper(void) int helper(void) {
{
my_putstr("USAGE\n"); my_putstr("USAGE\n");
my_putstr(" ./sokoban <-s> map <play_solution>\n\n"); my_putstr(" ./sokoban <-s> map <play_solution>\n\n");
my_putstr("DESCRIPTION\n"); my_putstr("DESCRIPTION\n");

Binary file not shown.

View file

@ -5,25 +5,34 @@
** Function that manage key press for sokoban ** Function that manage key press for sokoban
*/ */
#include <ncurses.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
#include <ncurses.h>
#include <stdlib.h>
#include <unistd.h>
#include "../include/libmy.h" #include "../include/libmy.h"
#include "../include/sokoban.h" #include "../include/sokoban.h"
sokoban_t key_check(sokoban_t sokoban, int key) sokoban_t key_check(sokoban_t sokoban, int key) {
{
if (key == KEY_LEFT) { if (key == KEY_LEFT) {
sokoban = move_left(sokoban); sokoban = move_left(sokoban);
} }
if (key == KEY_RIGHT)
if (key == KEY_RIGHT) {
sokoban = move_right(sokoban); sokoban = move_right(sokoban);
if (key == KEY_UP) }
if (key == KEY_UP) {
sokoban = move_up(sokoban); sokoban = move_up(sokoban);
if (key == KEY_DOWN) }
if (key == KEY_DOWN) {
sokoban = move_down(sokoban); sokoban = move_down(sokoban);
if (key == ' ') }
if (key == ' ') {
play(sokoban.base_path); play(sokoban.base_path);
}
return (sokoban); return (sokoban);
} }

Binary file not shown.

View file

@ -5,37 +5,42 @@
** Functions used to check if the game is loosed ** Functions used to check if the game is loosed
*/ */
#include <ncurses.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
#include <ncurses.h>
#include <stdlib.h>
#include <unistd.h>
#include "../include/libmy.h" #include "../include/libmy.h"
#include "../include/sokoban.h" #include "../include/sokoban.h"
void loose_check(sokoban_t sokoban) void loose_check(sokoban_t sokoban) {
{ if (sokoban.map[sokoban.player_y + 1][sokoban.player_x] == '$') {
if( sokoban.map[sokoban.player_y+1][sokoban.player_x] == '$') storage_loose_check(sokoban.player_y + 1, sokoban.player_x, sokoban);
storage_loose_check(sokoban.player_y+1, sokoban.player_x, sokoban); }
if( sokoban.map[sokoban.player_y-1][sokoban.player_x] == '$')
storage_loose_check(sokoban.player_y-1, sokoban.player_x, sokoban);
if( sokoban.map[sokoban.player_y][sokoban.player_x+1] == '$')
storage_loose_check(sokoban.player_y, sokoban.player_x+1, sokoban);
if( sokoban.map[sokoban.player_y][sokoban.player_x-1] == '$')
storage_loose_check(sokoban.player_y, sokoban.player_x-1, sokoban);
if (sokoban.map[sokoban.player_y - 1][sokoban.player_x] == '$') {
storage_loose_check(sokoban.player_y - 1, sokoban.player_x, sokoban);
}
if (sokoban.map[sokoban.player_y][sokoban.player_x + 1] == '$') {
storage_loose_check(sokoban.player_y, sokoban.player_x + 1, sokoban);
}
if (sokoban.map[sokoban.player_y][sokoban.player_x - 1] == '$') {
storage_loose_check(sokoban.player_y, sokoban.player_x - 1, 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();
exit (1); exit (1);
} }
} }
} }

Binary file not shown.

View file

@ -5,29 +5,32 @@
** Main function for the my_sokoban ** Main function for the my_sokoban
*/ */
#include <ncurses.h>
#include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <ncurses.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include "../include/libmy.h" #include "../include/libmy.h"
#include "../include/sokoban.h" #include "../include/sokoban.h"
#include "ai/ai.h" #include "ai/ai.h"
int main(int argc, char const **argv) int main(int argc, char const **argv) {
{ if (argc < 2 || argc > 4) {
if (argc < 2 || argc > 4)
return (84); return (84);
if (argv[1][0] == '-' && argv[1][1] == 'h') }
if (argv[1][0] == '-' && argv[1][1] == 'h') {
return(helper()); return(helper());
else if (argv[1][0] == '-' && argv[1][1] == 's'){ } else if (argv[1][0] == '-' && argv[1][1] == 's') {
bool show_solution = false; bool show_solution = false;
if (argc > 3 && strcmp(argv[3], "play_solution") == 0) if (argc > 3 && strcmp(argv[3], "play_solution") == 0) {
show_solution = true; show_solution = true;
}
solve(argv[2], show_solution); solve(argv[2], show_solution);
return 0; return 0;
} } else if (argv[1][0] != '-') {
else if (argv[1][0] != '-')
return(play(argv[1])); return(play(argv[1]));
}
return (84); return (84);
} }

Binary file not shown.

View file

@ -5,56 +5,53 @@
** Function used to check if a map is valid or not ** Function used to check if a map is valid or not
*/ */
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include "../include/libmy.h" #include "../include/libmy.h"
#include "../include/sokoban.h" #include "../include/sokoban.h"
void map_check(sokoban_t sokoban) void map_check(sokoban_t sokoban) {
{
int player = 0; int player = 0;
for (int i = 0; i < sokoban.lines; i++) { for (int i = 0; i < sokoban.lines; i++) {
for (int j = 0; sokoban.map_save[i][j] != '\0'; j++) { for (int j = 0; sokoban.map_save[i][j] != '\0'; j++) {
check_tile(i, j, sokoban); check_tile(i, j, sokoban);
player += count_player(i, j, sokoban); player += count_player(i, j, sokoban);
} }
} }
} }
int check_tile(int y, int x, sokoban_t sokoban) int check_tile(int y, int x, sokoban_t sokoban) {
{ if (sokoban.map_save[y][x] != '@' && sokoban.map_save[y][x] != '$' && \
if (sokoban.map_save[y][x] != '@' && sokoban.map_save[y][x] != '$' sokoban.map_save[y][x] != '#' && sokoban.map_save[y][x] != ' ' && \
&& sokoban.map_save[y][x] != '#' && sokoban.map_save[y][x] != ' ' sokoban.map_save[y][x] != '\n' && sokoban.map_save[y][x] != '.' && \
&& sokoban.map_save[y][x] != '\n' && sokoban.map_save[y][x] != '.' sokoban.map_save[y][x] != '+' && sokoban.map_save[y][x] != '*') {
&& sokoban.map_save[y][x] != '+' && sokoban.map_save[y][x] != '*')
{
write(2, "Unknown read character in map\n", 26); write(2, "Unknown read character in map\n", 26);
exit(84); exit(84);
} }
return (0); return (0);
} }
int count_case_number(int y, int x, sokoban_t sokoban) int count_case_number(int y, int x, sokoban_t sokoban) {
{
int i = 0; int i = 0;
if (sokoban.map_save[y][x] == '$') { if (sokoban.map_save[y][x] == '$') {
i++; i++;
} }
return (i); return (i);
} }
int count_player(int y, int x, sokoban_t sokoban) int count_player(int y, int x, sokoban_t sokoban) {
{
int i = 0; int i = 0;
if (sokoban.map_save[y][x] == '@') { if (sokoban.map_save[y][x] == '@') {
i++; i++;
} }
return (i); return (i);
} }

Binary file not shown.

View file

@ -5,15 +5,15 @@
** Main function for the my_sokoban ** Main function for the my_sokoban
*/ */
#include <ncurses.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
#include <ncurses.h>
#include <stdlib.h>
#include <unistd.h>
#include "../include/libmy.h" #include "../include/libmy.h"
#include "../include/sokoban.h" #include "../include/sokoban.h"
char *open_map(char const *path) char *open_map(char const *path) {
{
int reading; int reading;
char *buffer; char *buffer;
@ -22,58 +22,63 @@ char *open_map(char const *path)
write(2, "No such file or directory\n", 26); write(2, "No such file or directory\n", 26);
exit (84); exit (84);
} }
buffer = read_map(reading); buffer = read_map(reading);
close(reading); close(reading);
return (buffer); return (buffer);
} }
char *read_map(int reading) char *read_map(int reading) {
{
char *buffer = malloc(sizeof(char) * 10000); char *buffer = malloc(sizeof(char) * 10000);
int size = 32; int size = 32;
size = read(reading, buffer, 10000); size = read(reading, buffer, 10000);
if (size == -1) if (size == -1) {
exit(84); exit(84);
}
buffer[size] = '\0'; buffer[size] = '\0';
return (buffer); return (buffer);
} }
int count_columns(sokoban_t sokoban, int position) int count_columns(sokoban_t sokoban, int position) {
{
int columns = 0; int columns = 0;
for (; sokoban.buffer[position] != '\n'; position++) { for (; sokoban.buffer[position] != '\n'; position++) {
columns++; columns++;
} }
return (columns); return (columns);
} }
sokoban_t count_lines(sokoban_t sokoban) sokoban_t count_lines(sokoban_t sokoban) {
{
sokoban.lines = 0; sokoban.lines = 0;
for (int i = 0; sokoban.buffer[i] != '\0'; i++) { for (int i = 0; sokoban.buffer[i] != '\0'; i++) {
if (sokoban.buffer[i] == '\n' || sokoban.buffer[i] == '\0') if (sokoban.buffer[i] == '\n' || sokoban.buffer[i] == '\0') {
sokoban.lines++; sokoban.lines += 1;
}
} }
return (sokoban); return (sokoban);
} }
sokoban_t make_map(char const *path, sokoban_t sokoban) sokoban_t make_map(char const *path, sokoban_t sokoban) {
{
sokoban.buffer = open_map(path);
sokoban = count_lines(sokoban);
int k = 0; int k = 0;
int columns = 0; int columns = 0;
sokoban.buffer = open_map(path);
sokoban = count_lines(sokoban);
sokoban.num_chars_map = 0; sokoban.num_chars_map = 0;
sokoban.map = malloc(sizeof(char *) * sokoban.lines); sokoban.map = malloc(sizeof(char *) * sokoban.lines);
sokoban.map_save = malloc(sizeof (char *) * sokoban.lines); sokoban.map_save = malloc(sizeof (char *) * sokoban.lines);
for (int j = 0; j < sokoban.lines; j++) { for (int j = 0; j < sokoban.lines; j++) {
columns = count_columns(sokoban, k); columns = count_columns(sokoban, k);
sokoban.num_chars_map += columns; sokoban.num_chars_map += columns;
sokoban.map[j] = malloc(sizeof(char) * columns + 1); sokoban.map[j] = malloc(sizeof(char) * columns + 1);
sokoban.map_save[j] = malloc(sizeof(char) * columns + 1); sokoban.map_save[j] = malloc(sizeof(char) * columns + 1);
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];
@ -81,12 +86,14 @@ sokoban_t make_map(char const *path, sokoban_t sokoban)
sokoban.map_save[j][i+1] = '\0'; sokoban.map_save[j][i+1] = '\0';
k++; k++;
} }
k++; k++;
} }
return (sokoban); return (sokoban);
} }
int is_goal_cell(int y, int x, sokoban_t sokoban) int is_goal_cell(int y, int x, sokoban_t sokoban) {
{ return (sokoban.map_save[y][x] == '.') || \
return (sokoban.map_save[y][x] == '.') || (sokoban.map_save[y][x] == '+') || (sokoban.map_save[y][x] == '*'); (sokoban.map_save[y][x] == '+') || (sokoban.map_save[y][x] == '*');
} }

Binary file not shown.

View file

@ -5,148 +5,166 @@
** Function that make the player move ** Function that make the player move
*/ */
#include <ncurses.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
#include <ncurses.h>
#include <stdlib.h>
#include <unistd.h>
#include "../include/libmy.h" #include "../include/libmy.h"
#include "../include/sokoban.h" #include "../include/sokoban.h"
sokoban_t move_box_left(sokoban_t sokoban) {
if (sokoban.map[sokoban.player_y][sokoban.player_x - 2] == '$' || \
sokoban.map[sokoban.player_y][sokoban.player_x - 2] == '*') {
sokoban_t move_box_left(sokoban_t sokoban)
{
if (sokoban.map[sokoban.player_y][sokoban.player_x-2] == '$' || sokoban.map[sokoban.player_y][sokoban.player_x-2] == '*') {
return (sokoban); return (sokoban);
} else if (sokoban.map[sokoban.player_y][sokoban.player_x-2] == '#') { } else if (sokoban.map[sokoban.player_y][sokoban.player_x - 2] == '#') {
return (sokoban); return (sokoban);
} else { } else {
sokoban.map[sokoban.player_y][sokoban.player_x-1] = '@'; sokoban.map[sokoban.player_y][sokoban.player_x - 1] = '@';
if(sokoban.map[sokoban.player_y][sokoban.player_x-2] == '.') if (sokoban.map[sokoban.player_y][sokoban.player_x - 2] == '.') {
sokoban.map[sokoban.player_y][sokoban.player_x-2] = '*'; sokoban.map[sokoban.player_y][sokoban.player_x - 2] = '*';
else } else {
sokoban.map[sokoban.player_y][sokoban.player_x-2] = '$'; sokoban.map[sokoban.player_y][sokoban.player_x - 2] = '$';
}
sokoban.map[sokoban.player_y][sokoban.player_x] = ' '; sokoban.map[sokoban.player_y][sokoban.player_x] = ' ';
sokoban.player_x--; sokoban.player_x--;
} }
return (sokoban); return (sokoban);
} }
sokoban_t move_box_right(sokoban_t sokoban) sokoban_t move_box_right(sokoban_t sokoban) {
{ if (sokoban.map[sokoban.player_y][sokoban.player_x + 2] == '$' || \
if (sokoban.map[sokoban.player_y][sokoban.player_x+2] == '$' || sokoban.map[sokoban.player_y][sokoban.player_x+2] == '*') { sokoban.map[sokoban.player_y][sokoban.player_x + 2] == '*') {
return (sokoban); return (sokoban);
} else if (sokoban.map[sokoban.player_y][sokoban.player_x+2] == '#') { } else if (sokoban.map[sokoban.player_y][sokoban.player_x + 2] == '#') {
return (sokoban); return (sokoban);
} else { } else {
sokoban.map[sokoban.player_y][sokoban.player_x+1] = '@'; sokoban.map[sokoban.player_y][sokoban.player_x + 1] = '@';
if(sokoban.map[sokoban.player_y][sokoban.player_x+2] == '.') if (sokoban.map[sokoban.player_y][sokoban.player_x + 2] == '.') {
sokoban.map[sokoban.player_y][sokoban.player_x+2] = '*'; sokoban.map[sokoban.player_y][sokoban.player_x + 2] = '*';
else } else {
sokoban.map[sokoban.player_y][sokoban.player_x+2] = '$'; sokoban.map[sokoban.player_y][sokoban.player_x + 2] = '$';
}
sokoban.map[sokoban.player_y][sokoban.player_x] = ' '; sokoban.map[sokoban.player_y][sokoban.player_x] = ' ';
sokoban.player_x++; sokoban.player_x++;
} }
return (sokoban); return (sokoban);
} }
sokoban_t move_box_up(sokoban_t sokoban) sokoban_t move_box_up(sokoban_t sokoban) {
{ if (sokoban.map[sokoban.player_y - 2][sokoban.player_x] == '$' || \
if (sokoban.map[sokoban.player_y-2][sokoban.player_x] == '$' || sokoban.map[sokoban.player_y-2][sokoban.player_x] == '*') { sokoban.map[sokoban.player_y - 2][sokoban.player_x] == '*') {
return (sokoban); return (sokoban);
} else if (sokoban.map[sokoban.player_y-2][sokoban.player_x] == '#') { } else if (sokoban.map[sokoban.player_y - 2][sokoban.player_x] == '#') {
return (sokoban); return (sokoban);
} else { } else {
sokoban.map[sokoban.player_y-1][sokoban.player_x] = '@'; sokoban.map[sokoban.player_y - 1][sokoban.player_x] = '@';
if(sokoban.map[sokoban.player_y-2][sokoban.player_x] == '.') if (sokoban.map[sokoban.player_y - 2][sokoban.player_x] == '.') {
sokoban.map[sokoban.player_y-2][sokoban.player_x] = '*'; sokoban.map[sokoban.player_y - 2][sokoban.player_x] = '*';
else } else {
sokoban.map[sokoban.player_y-2][sokoban.player_x] = '$'; sokoban.map[sokoban.player_y - 2][sokoban.player_x] = '$';
}
sokoban.map[sokoban.player_y][sokoban.player_x] = ' '; sokoban.map[sokoban.player_y][sokoban.player_x] = ' ';
sokoban.player_y--; sokoban.player_y--;
} }
return (sokoban); return (sokoban);
} }
sokoban_t move_box_down(sokoban_t sokoban) sokoban_t move_box_down(sokoban_t sokoban) {
{ if (sokoban.map[sokoban.player_y + 2][sokoban.player_x] == '$' || \
if (sokoban.map[sokoban.player_y+2][sokoban.player_x] == '$' || sokoban.map[sokoban.player_y+2][sokoban.player_x] == '*') { sokoban.map[sokoban.player_y + 2][sokoban.player_x] == '*') {
return (sokoban); return (sokoban);
} else if (sokoban.map[sokoban.player_y+2][sokoban.player_x] == '#') { } else if (sokoban.map[sokoban.player_y + 2][sokoban.player_x] == '#') {
return (sokoban); return (sokoban);
} else { } else {
sokoban.map[sokoban.player_y+1][sokoban.player_x] = '@'; sokoban.map[sokoban.player_y + 1][sokoban.player_x] = '@';
if(sokoban.map[sokoban.player_y+2][sokoban.player_x] == '.')
sokoban.map[sokoban.player_y+2][sokoban.player_x] = '*';
else
sokoban.map[sokoban.player_y+2][sokoban.player_x] = '$';
if (sokoban.map[sokoban.player_y + 2][sokoban.player_x] == '.') {
sokoban.map[sokoban.player_y + 2][sokoban.player_x] = '*';
} else {
sokoban.map[sokoban.player_y + 2][sokoban.player_x] = '$';
}
sokoban.map[sokoban.player_y][sokoban.player_x] = ' '; sokoban.map[sokoban.player_y][sokoban.player_x] = ' ';
sokoban.player_y++; sokoban.player_y++;
} }
return (sokoban); return (sokoban);
} }
sokoban_t move_left(sokoban_t sokoban) {
if (sokoban.map[sokoban.player_y][sokoban.player_x - 1] != '#') {
if (sokoban.map[sokoban.player_y][sokoban.player_x - 1] == '$' || \
sokoban.map[sokoban.player_y][sokoban.player_x - 1] == '*') {
sokoban_t move_left(sokoban_t sokoban)
{
if (sokoban.map[sokoban.player_y][sokoban.player_x-1] != '#') {
if (sokoban.map[sokoban.player_y][sokoban.player_x-1] == '$' || sokoban.map[sokoban.player_y][sokoban.player_x-1] == '*') {
sokoban = move_box_left(sokoban); sokoban = move_box_left(sokoban);
} else { } else {
sokoban.map[sokoban.player_y][sokoban.player_x-1] = '@'; sokoban.map[sokoban.player_y][sokoban.player_x - 1] = '@';
sokoban.map[sokoban.player_y][sokoban.player_x] = ' '; sokoban.map[sokoban.player_y][sokoban.player_x] = ' ';
sokoban.player_x--; sokoban.player_x--;
} }
} }
return (sokoban); return (sokoban);
} }
sokoban_t move_right(sokoban_t sokoban) sokoban_t move_right(sokoban_t sokoban) {
{ if (sokoban.map[sokoban.player_y][sokoban.player_x + 1] != '#') {
if (sokoban.map[sokoban.player_y][sokoban.player_x+1] != '#') { if (sokoban.map[sokoban.player_y][sokoban.player_x + 1] == '$' || \
if (sokoban.map[sokoban.player_y][sokoban.player_x+1] == '$' || sokoban.map[sokoban.player_y][sokoban.player_x+1] == '*') { sokoban.map[sokoban.player_y][sokoban.player_x + 1] == '*') {
sokoban = move_box_right(sokoban); sokoban = move_box_right(sokoban);
} else { } else {
sokoban.map[sokoban.player_y][sokoban.player_x+1] = '@'; sokoban.map[sokoban.player_y][sokoban.player_x + 1] = '@';
sokoban.map[sokoban.player_y][sokoban.player_x] = ' '; sokoban.map[sokoban.player_y][sokoban.player_x] = ' ';
sokoban.player_x++; sokoban.player_x++;
} }
} }
return (sokoban); return (sokoban);
} }
sokoban_t move_up(sokoban_t sokoban) sokoban_t move_up(sokoban_t sokoban) {
{ if (sokoban.map[sokoban.player_y - 1][sokoban.player_x] != '#') {
if (sokoban.map[sokoban.player_y-1][sokoban.player_x] != '#') { if (sokoban.map[sokoban.player_y - 1][sokoban.player_x] == '$' || \
if (sokoban.map[sokoban.player_y-1][sokoban.player_x] == '$' || sokoban.map[sokoban.player_y-1][sokoban.player_x] == '*') { sokoban.map[sokoban.player_y - 1][sokoban.player_x] == '*') {
sokoban = move_box_up(sokoban); sokoban = move_box_up(sokoban);
} else { } else {
sokoban.map[sokoban.player_y-1][sokoban.player_x] = '@'; sokoban.map[sokoban.player_y - 1][sokoban.player_x] = '@';
sokoban.map[sokoban.player_y][sokoban.player_x] = ' '; sokoban.map[sokoban.player_y][sokoban.player_x] = ' ';
sokoban.player_y--; sokoban.player_y--;
} }
} }
return (sokoban); return (sokoban);
} }
sokoban_t move_down(sokoban_t sokoban) sokoban_t move_down(sokoban_t sokoban) {
{ if (sokoban.map[sokoban.player_y + 1][sokoban.player_x] != '#') {
if (sokoban.map[sokoban.player_y+1][sokoban.player_x] != '#') { if (sokoban.map[sokoban.player_y + 1][sokoban.player_x] == '$' || \
if (sokoban.map[sokoban.player_y+1][sokoban.player_x] == '$' || sokoban.map[sokoban.player_y+1][sokoban.player_x] == '*') { sokoban.map[sokoban.player_y + 1][sokoban.player_x] == '*') {
sokoban = move_box_down(sokoban); sokoban = move_box_down(sokoban);
} else { } else {
sokoban.map[sokoban.player_y+1][sokoban.player_x] = '@'; sokoban.map[sokoban.player_y + 1][sokoban.player_x] = '@';
sokoban.map[sokoban.player_y][sokoban.player_x] = ' '; sokoban.map[sokoban.player_y][sokoban.player_x] = ' ';
sokoban.player_y++; sokoban.player_y++;
} }
} }
return (sokoban); return (sokoban);
} }

Binary file not shown.

View file

@ -7,50 +7,45 @@
** Adapted by Nir Lipo, 2021 ** Adapted by Nir Lipo, 2021
*/ */
#include <ncurses.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
#include <ncurses.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../include/libmy.h" #include "../include/libmy.h"
#include "../include/sokoban.h" #include "../include/sokoban.h"
/********* /*********
* MACROS * * MACROS *
*********/ *********/
#include <string.h>
#define TERMINAL_TYPE (strcmp(getenv("TERM"), "xterm") == 0 ? "rxvt" : \ #define TERMINAL_TYPE (strcmp(getenv("TERM"), "xterm") == 0 ? "rxvt" : \
getenv("TERM")) getenv("TERM"))
SCREEN *mainScreen = NULL; SCREEN *mainScreen = NULL;
WINDOW *mainWindow = NULL; WINDOW *mainWindow = NULL;
int play(char const *path) {
int play(char const *path) // Load map
{
/**
* Load Map
*/
sokoban_t sokoban = make_map(path, sokoban); sokoban_t sokoban = make_map(path, sokoban);
sokoban.base_path = path;
/** // Count number of boxes and Storage locations
* Count number of boxes and Storage locations
*/
map_check(sokoban); map_check(sokoban);
/** // Locate player x,y position
* Locate player x,y position
*/
sokoban = find_player(sokoban); sokoban = find_player(sokoban);
sokoban.base_path = path;
mainScreen = newterm(TERMINAL_TYPE, stdout, stdin); mainScreen = newterm(TERMINAL_TYPE, stdout, stdin);
set_term(mainScreen); set_term(mainScreen);
int cols = 1; int cols = 1;
for(int i = 0; i < sokoban.lines; i++){
if(strlen(sokoban.map[i]) > (size_t) cols){ for (int i = 0; i < sokoban.lines; i++) {
if (strlen(sokoban.map[i]) > (size_t) cols) {
cols = strlen(sokoban.map[i]); cols = strlen(sokoban.map[i]);
} }
} }
mainWindow = newwin(sokoban.lines, cols, 0, 0); mainWindow = newwin(sokoban.lines, cols, 0, 0);
cbreak(); cbreak();
@ -63,18 +58,18 @@ int play(char const *path)
touchwin(mainWindow); touchwin(mainWindow);
wnoutrefresh(mainWindow); wnoutrefresh(mainWindow);
doupdate(); doupdate();
for (int i = 0; i < sokoban.lines; i++)
for (int i = 0; i < sokoban.lines; i++) {
mvprintw(i, 0, sokoban.map[i]); mvprintw(i, 0, sokoban.map[i]);
}
move(sokoban.player_y, sokoban.player_x); move(sokoban.player_y, sokoban.player_x);
sokoban = game_management(sokoban); sokoban = game_management(sokoban);
} }
} }
sokoban_t game_management(sokoban_t sokoban) sokoban_t game_management(sokoban_t sokoban) {
{ int key_pressed = getch();
int key_pressed = 0;
key_pressed = getch();
sokoban = key_check(sokoban, key_pressed); sokoban = key_check(sokoban, key_pressed);
sokoban = check_zone_reset(sokoban); sokoban = check_zone_reset(sokoban);
loose_check(sokoban); loose_check(sokoban);

Binary file not shown.

View file

@ -5,23 +5,23 @@
** Function that check if the game is won ** Function that check if the game is won
*/ */
#include <ncurses.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
#include <ncurses.h>
#include <stdlib.h>
#include <unistd.h>
#include "../include/libmy.h" #include "../include/libmy.h"
#include "../include/sokoban.h" #include "../include/sokoban.h"
void win_check(sokoban_t sokoban) void win_check(sokoban_t sokoban) {
{
for (int i = 0; i < sokoban.lines; i++) { for (int i = 0; i < sokoban.lines; i++) {
for (int j = 0; sokoban.map_save[i][j] != '\0'; j++) { for (int j = 0; sokoban.map_save[i][j] != '\0'; j++) {
if (sokoban.map[i][j] == '$') if (sokoban.map[i][j] == '$') {
return ; return;
}
} }
} }
endwin(); endwin();
exit (0); exit (0);
} }

Binary file not shown.

View file

@ -7,28 +7,25 @@
** Adpated by Nir 2021 ** Adpated by Nir 2021
*/ */
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include "../include/libmy.h" #include "../include/libmy.h"
#include "../include/sokoban.h" #include "../include/sokoban.h"
sokoban_t check_zone_reset(sokoban_t sokoban) sokoban_t check_zone_reset(sokoban_t sokoban) {
{ sokoban = reset_zone(sokoban.player_y + 1, sokoban.player_x, sokoban);
sokoban = reset_zone(sokoban.player_y+1, sokoban.player_x, sokoban); sokoban = reset_zone(sokoban.player_y - 1, sokoban.player_x, sokoban);
sokoban = reset_zone(sokoban.player_y-1, sokoban.player_x, sokoban); sokoban = reset_zone(sokoban.player_y, sokoban.player_x + 1, sokoban);
sokoban = reset_zone(sokoban.player_y, sokoban.player_x+1, sokoban); sokoban = reset_zone(sokoban.player_y, sokoban.player_x - 1, sokoban);
sokoban = reset_zone(sokoban.player_y, sokoban.player_x-1, sokoban);
return (sokoban); return (sokoban);
} }
sokoban_t reset_zone(int y, int x, sokoban_t sokoban) sokoban_t reset_zone(int y, int x, sokoban_t sokoban) {
{ if (is_goal_cell(y, x, sokoban ) && sokoban.map[y][x] == ' ') {
if ( is_goal_cell(y, x, sokoban ) && sokoban.map[y][x] == ' ') {
sokoban.map[y][x] = '.'; sokoban.map[y][x] = '.';
return(sokoban);
} }
return (sokoban); return (sokoban);
} }

Binary file not shown.