viric@6: #include viric@6: #include viric@28: #include viric@6: #include "general.h" viric@6: viric@6: /* Variables related to the showing of information by os */ viric@6: extern float percent_to_show; viric@6: extern int depth_to_show; viric@6: viric@6: extern int max_depth; viric@6: extern int min_depth_period; viric@6: extern int max_depth_period; viric@6: extern struct Map * actual_map; viric@6: viric@6: #if 0 /*** THIS IS AN ERROR!!! The box_will_be_blocked function doesn't work!*/ viric@6: Situation: viric@6: viric@6: ->@$ # viric@6: $ viric@6: */ viric@6: int box_will_be_blocked(const struct Map * m, const struct Position mov, viric@6: const struct Position box_pos) viric@6: { viric@6: struct Position next_pos2, tmp, tmp2[2]; viric@6: int i; viric@6: viric@6: next_pos2.x = box_pos.x + mov.x; viric@6: next_pos2.y = box_pos.y + mov.y; viric@6: viric@6: tmp.x = next_pos2.x + mov.x; viric@6: tmp.y = next_pos2.y + mov.y; viric@6: tmp2[0].x = next_pos2.x + mov.y; viric@6: tmp2[0].y = next_pos2.y + mov.x; viric@6: tmp2[1].x = next_pos2.x - mov.y; viric@6: tmp2[1].y = next_pos2.y - mov.x; viric@6: for (i=0; i < 2; i++) viric@6: { viric@6: if (m->man_moves[tmp.y][tmp.x] == WALL && viric@6: m->man_moves[tmp2[i].y][tmp2[i].x] == BOX) viric@6: { viric@6: return TRUE; viric@6: } viric@6: else if (m->man_moves[tmp.y][tmp.x] == BOX && viric@6: m->man_moves[tmp2[i].y][tmp2[i].x] == WALL) viric@6: { viric@6: return TRUE; viric@6: } viric@6: else if (m->man_moves[tmp.y][tmp.x] == BOX && viric@6: m->man_moves[tmp2[i].y][tmp2[i].x] == BOX) viric@6: { viric@6: return TRUE; viric@6: } viric@6: } viric@6: viric@6: return FALSE; viric@6: } viric@6: viric@6: int is_corner_area(const struct Map * m, const struct Position p, viric@6: const struct Position box, const struct Position new_box) viric@6: { viric@6: int NumMoves, NewMoves; viric@6: struct Position pos[MAX_MOVES]; viric@6: struct Position new_pos[MAX_MOVES]; viric@6: char corners[MAX_Y][MAX_X]; viric@6: int i,j; viric@6: struct Position next_pos; viric@6: char *next_cell; viric@6: viric@6: viric@6: /* Blank the garden */ viric@6: for (j = 0; jSizeY; j++) viric@6: for (i=0; iSizeX; i++) viric@6: corners[j][i] = m->Cells[j][i]; viric@6: viric@6: /* Let's put the boxes */ viric@6: for (i = 0; iNumBoxes; i++) viric@6: corners[m->Box[i].y][m->Box[i].x] = BOX; viric@6: viric@6: /* Let's put our box - it can be simply added */ viric@6: corners[new_box.y][new_box.x] = BOX; viric@6: /* Let's remove the original box. */ viric@6: corners[box.y][box.x] = BLANK; viric@6: viric@6: NewMoves = 1; viric@6: new_pos[0] = p; viric@6: while (NewMoves > 0) viric@6: { viric@6: /* The before named "New Moves" become the moves we have viric@6: to analyze */ viric@6: NumMoves = NewMoves; viric@6: for (i=0; iCells[p2.y][p2.x] == CORNER) viric@6: { viric@6: if (is_corner_area(m, p2, box_pos, p)) viric@6: return TRUE; viric@6: } viric@6: viric@6: p2.x = p.x + mov.y; viric@6: p2.y = p.y + mov.x; viric@6: if (m->Cells[p2.y][p2.x] == CORNER) viric@6: { viric@6: if (is_corner_area(m, p2, box_pos, p)) viric@6: return TRUE; viric@6: } viric@6: viric@6: p2.x = p.x - mov.y; viric@6: p2.y = p.y - mov.x; viric@6: if (m->Cells[p2.y][p2.x] == CORNER) viric@6: { viric@6: if (is_corner_area(m, p2, box_pos, p)) viric@6: return TRUE; viric@6: } viric@6: return FALSE; viric@6: } viric@6: #endif viric@6: viric@6: /* viric@6: Catch the situation where a box is moved next to a corner, where the box viric@6: next to it will not be able to be moved. viric@6: */ viric@6: static int is_dead1(const struct Map * m, const struct Position mov, viric@6: const struct Position new_pos) viric@6: { viric@6: struct Position opposite1, opposite2; viric@6: viric@6: /* The wall corners must exist */ viric@6: opposite1.x = -mov.y; viric@6: opposite1.y = -mov.x; viric@6: opposite2.x = mov.y; viric@6: opposite2.y = mov.x; viric@6: viric@6: #ifdef DEBUG viric@6: ShowMap(m); viric@6: #endif viric@6: viric@6: /* Test the first corner */ viric@6: if (m->Cells[new_pos.y+mov.y+opposite1.y][new_pos.x+mov.x+opposite1.x] viric@6: == WALL) viric@6: { viric@6: /* Test wall at opposites 1*/ viric@6: if (m->Cells[new_pos.y+opposite1.y][new_pos.x+opposite1.x] viric@6: == WALL && viric@6: m->man_moves[new_pos.y+mov.y][new_pos.x+mov.x] == BOX) viric@6: { viric@6: return TRUE; viric@6: } viric@6: else viric@6: if (m->man_moves[new_pos.y+opposite1.y][new_pos.x+opposite1.x] viric@6: == BOX && viric@6: m->Cells[new_pos.y+mov.y][new_pos.x+mov.x] == WALL) viric@6: { viric@6: return TRUE; viric@6: } viric@6: /* Test wall at opposites 2 */ viric@6: if (m->Cells[new_pos.y+opposite2.y][new_pos.x+opposite2.x] viric@6: == WALL && viric@6: m->man_moves[new_pos.y+mov.y][new_pos.x+mov.x] == BOX) viric@6: { viric@6: return TRUE; viric@6: } viric@6: else viric@6: if (m->man_moves[new_pos.y+opposite2.y][new_pos.x+opposite2.x] viric@6: == BOX && viric@6: m->Cells[new_pos.y+mov.y][new_pos.x+mov.x] == WALL) viric@6: { viric@6: return TRUE; viric@6: } viric@6: } viric@6: viric@6: /* Test the second corner */ viric@6: if (m->Cells[new_pos.y+mov.y+opposite2.y][new_pos.x+mov.x+opposite2.x] viric@6: == WALL) viric@6: { viric@6: /* Test wall at opposites 1*/ viric@6: if (m->Cells[new_pos.y+opposite1.y][new_pos.x+opposite1.x] viric@6: == WALL && viric@6: m->man_moves[new_pos.y+mov.y][new_pos.x+mov.x] == BOX) viric@6: { viric@6: return TRUE; viric@6: } viric@6: else viric@6: if (m->man_moves[new_pos.y+opposite1.y][new_pos.x+opposite1.x] viric@6: == BOX && viric@6: m->Cells[new_pos.y+mov.y][new_pos.x+mov.x] == WALL) viric@6: { viric@6: return TRUE; viric@6: } viric@6: /* Test wall at opposites 2 */ viric@6: if (m->Cells[new_pos.y+opposite2.y][new_pos.x+opposite2.x] viric@6: == WALL && viric@6: m->man_moves[new_pos.y+mov.y][new_pos.x+mov.x] == BOX) viric@6: { viric@6: return TRUE; viric@6: } viric@6: else viric@6: if (m->man_moves[new_pos.y+opposite2.y][new_pos.x+opposite2.x] viric@6: == BOX && viric@6: m->Cells[new_pos.y+mov.y][new_pos.x+mov.x] == WALL) viric@6: { viric@6: return TRUE; viric@6: } viric@6: } viric@6: viric@6: return FALSE; viric@6: } viric@6: viric@6: /* viric@6: Catch the situation where a corner gets surrounded by boxes. viric@6: */ viric@6: static int is_dead2(const struct Map * m, const struct Position mov, viric@6: const struct Position new_pos) viric@6: { viric@6: struct Position next, opposite1, opposite2; viric@6: viric@6: next.x = new_pos.x+mov.x; viric@6: next.y = new_pos.y+mov.y; viric@6: viric@6: /* The corner must exist */ viric@6: if (m->Cells[next.y][next.x] != CORNER) viric@6: return FALSE; viric@6: viric@6: viric@6: /* The wall corners must exist */ viric@6: opposite1.x = next.x -mov.y; viric@6: opposite1.y = next.y -mov.x; viric@6: opposite2.x = next.x + mov.y; viric@6: opposite2.y = next.y + mov.x; viric@6: viric@6: if (m->man_moves[opposite1.y][opposite1.x] == BOX) viric@6: { viric@6: if(m->Cells[opposite1.y+mov.y][opposite1.x+mov.x] == WALL viric@6: && m->Cells[opposite1.y-mov.y][opposite1.x-mov.x] == WALL) viric@6: return TRUE; viric@6: } viric@6: viric@6: if (m->man_moves[opposite2.y][opposite2.x] == BOX) viric@6: { viric@6: if(m->Cells[opposite2.y+mov.y][opposite2.x+mov.x] == WALL viric@6: && m->Cells[opposite2.y-mov.y][opposite2.x-mov.x] == WALL) viric@6: return TRUE; viric@6: } viric@6: return FALSE; viric@6: } viric@6: viric@6: static int is_box_movable(const struct Map * m, const struct Position mov, viric@6: const struct Position box_pos) viric@6: { viric@6: struct Position next_pos2; viric@6: viric@6: next_pos2.x = box_pos.x + mov.x; viric@6: next_pos2.y = box_pos.y + mov.y; viric@6: viric@6: if((m->Cells[next_pos2.y][next_pos2.x] != BLANK && viric@6: m->Cells[next_pos2.y][next_pos2.x] != PLATFORM) || viric@6: m->man_moves[next_pos2.y][next_pos2.x] == BOX) viric@6: { viric@6: return FALSE; viric@6: } viric@6: else if (is_dead1(m, mov, next_pos2) == TRUE) viric@6: { viric@6: return FALSE; viric@6: } viric@6: else if (is_dead2(m, mov, next_pos2) == TRUE) viric@6: { viric@6: return FALSE; viric@6: } viric@6: return TRUE; viric@6: } viric@6: viric@6: /* It modifies m->man_moves */ viric@6: static int get_box_movements(struct Map * m, viric@6: struct BoxMove movements[]) viric@6: { viric@6: struct Position pos[MAX_MOVES]; viric@6: struct Position new_pos[MAX_MOVES]; viric@6: int NumMoves, NewMoves; viric@6: int j, i; viric@6: struct Position next_pos; viric@6: char *next_cell; viric@6: int num_box_movements = 0; viric@6: viric@6: /* Let's the map with only walls in man_moves - other, blanks */ viric@6: for (j = 0; jSizeY; j++) viric@6: for (i=0; iSizeX; i++) viric@6: { viric@6: if (m->Cells[j][i] == WALL) viric@6: m->man_moves[j][i] = WALL; viric@6: else viric@6: m->man_moves[j][i] = BLANK; viric@6: } viric@6: viric@6: /* Let's put the boxes */ viric@6: for (i = 0; iNumBoxes; i++) viric@6: { viric@6: m->man_moves[m->Box[i].y][m->Box[i].x] = BOX; viric@6: m->cells_boxes[m->Box[i].y][m->Box[i].x] = i; viric@6: } viric@6: viric@6: NewMoves = 1; viric@6: new_pos[0].x = m->Man.x; viric@6: new_pos[0].y = m->Man.y; viric@6: m->man_moves[m->Man.y][m->Man.x] = MANCANMOVE; viric@6: while (NewMoves > 0) viric@6: { viric@6: /* The before named "New Moves" become the moves we have viric@6: to analyze */ viric@6: NumMoves = NewMoves; viric@6: for (i=0; iman_moves[next_pos.y][next_pos.x]; viric@6: if(*next_cell == BLANK) viric@6: { viric@6: new_pos[NewMoves] = next_pos; viric@6: *next_cell = MANCANMOVE; viric@6: NewMoves++; viric@6: } viric@6: else if (*next_cell == BOX) viric@6: { viric@6: viric@6: /* Check if the box is movable */ viric@6: viric@6: if (is_box_movable(m, move_vectors[j], viric@6: next_pos )) viric@6: { viric@6: { viric@6: movements[num_box_movements].box = viric@6: m->cells_boxes[next_pos.y][next_pos.x]; viric@6: movements[num_box_movements].dir = viric@6: move_vectors[j]; viric@6: num_box_movements++; viric@6: } viric@6: } viric@6: viric@6: } viric@6: viric@6: } viric@6: } viric@6: } viric@6: viric@6: return num_box_movements; viric@6: } viric@6: viric@10: static void force_move_box(struct Map *m, const struct BoxMove move) viric@6: { viric@6: struct Position newpos; viric@6: viric@6: viric@6: /* Add coords */ viric@6: newpos.x = m->Box[move.box].x + move.dir.x; viric@6: newpos.y = m->Box[move.box].y + move.dir.y; viric@6: viric@6: /* Be certain the move can be done */ viric@6: assert(m->Cells[newpos.y][newpos.x] != BOX); viric@6: assert(m->Cells[newpos.y][newpos.x] != WALL); viric@6: viric@6: /* Control if we moved the box to a platform */ viric@6: if(m->Cells[newpos.y][newpos.x] == PLATFORM) viric@6: { viric@6: m->NumBoxesInPlatform++; viric@6: } viric@6: viric@6: /* Control if we moved the box from a platform */ viric@6: if (m->Cells[m->Box[move.box].y][m->Box[move.box].x] == PLATFORM) viric@6: { viric@6: m->NumBoxesInPlatform--; viric@6: } viric@6: m->Man = m->Box[move.box]; viric@6: viric@6: m->Box[move.box] = newpos; viric@6: } viric@6: viric@6: viric@28: static void update_depth_counters(const int depth) viric@6: { viric@6: if (depth > max_depth) viric@6: max_depth = depth; viric@6: if (depth > max_depth_period) viric@6: max_depth_period = depth; viric@6: if (depth < min_depth_period) viric@6: min_depth_period = depth; viric@28: } viric@6: viric@28: struct Map *all_maps; viric@28: struct BoxMove *all_movements; /* DEPTH movements of MAX_MOVES */ viric@28: int *all_mov_tries; /* The actual step in movements for every depth */ viric@28: int *all_mov_max; /* Maximum of movements per all_movement element */ viric@28: float *percent; viric@28: float *percent_part; viric@28: int depth; viric@28: viric@28: int search_loop(const struct Map *origin) viric@28: { viric@28: int found; /* bool */ viric@28: viric@28: all_maps = malloc(sizeof(*all_maps) * (MAX_STEPS+1)); viric@28: all_movements = malloc(sizeof(*all_movements)*MAX_MOVES*(MAX_STEPS+1)); viric@28: all_mov_tries = malloc(sizeof(*all_mov_tries)*(MAX_STEPS+1)); viric@28: all_mov_max = malloc(sizeof(*all_mov_max)*(MAX_STEPS+1)); viric@28: percent = malloc(sizeof(*percent)*(MAX_STEPS+1)); viric@28: percent_part = malloc(sizeof(*percent)*(MAX_STEPS+1)); viric@28: viric@28: viric@28: if (load_state()) viric@28: { viric@28: --depth; viric@28: if (all_mov_tries[depth] != 0) viric@28: all_mov_tries[depth] = 0; viric@28: } else viric@6: { viric@28: depth = 0; viric@28: CopyMap(&all_maps[0], origin); viric@28: all_mov_max[0] = get_box_movements(&all_maps[0], &all_movements[0]); viric@28: assert(all_mov_max[0] < MAX_MOVES); viric@28: assert(all_mov_max[0] > 0); viric@28: percent[0] = 0.; viric@28: percent_part[0] = 100.; viric@28: all_mov_tries[0] = 0; viric@28: } viric@28: viric@28: viric@28: found = 0; viric@28: do viric@28: { viric@28: struct BoxMove *new_movements = &all_movements[(depth+1)*MAX_MOVES]; viric@28: struct BoxMove *movements = &all_movements[depth*MAX_MOVES]; viric@28: int num_movements = all_mov_max[depth]; viric@28: int *num_new_movements = &all_mov_max[depth+1]; viric@28: int *step = &all_mov_tries[depth]; viric@28: struct Map *new_map = &all_maps[depth+1]; viric@28: viric@28: update_depth_counters(depth); viric@28: viric@28: percent_part[depth+1] = percent_part[depth] / num_movements; viric@28: viric@28: CopyMap(new_map, &all_maps[depth]); viric@28: viric@28: /* DEBUG */ viric@28: #if DEBUG viric@28: ShowMap(new_map); viric@28: show_tries(depth); viric@28: printf("Nummovs[%i]: %i\n", depth, num_movements); viric@28: printf("Step[%i]: %i\n", depth, *step); viric@28: #endif viric@28: viric@28: /* Now four things can happen: viric@28: * - look for depth + 1 viric@28: * - keep looking for movements in depth viric@28: * - go one depth back. viric@28: * - solve the puzle */ viric@28: viric@28: /* Go one depth back */ viric@28: if (*step >= num_movements) viric@6: { viric@28: --depth; viric@28: continue; viric@6: } viric@6: viric@28: force_move_box(new_map, movements[(*step)]); viric@28: viric@28: ++(*step); viric@28: viric@28: /* Solve the puzzle */ viric@28: if (new_map->NumPlatforms == new_map->NumBoxesInPlatform) viric@6: { viric@28: PrintMoves(all_movements, all_mov_tries, depth+1); viric@28: actual_map = &all_maps[depth+1]; viric@28: show_percent_and_map(); viric@28: save_state(); viric@28: found = 1; viric@28: } viric@28: viric@28: if (is_new_map(all_maps, depth+1)) viric@28: { viric@28: *num_new_movements = viric@28: get_box_movements(new_map, new_movements); viric@28: assert(*num_new_movements < MAX_MOVES); viric@6: } viric@6: else viric@28: *num_new_movements = 0; viric@6: viric@28: percent[depth] = percent[depth] + percent_part[depth+1]; viric@28: percent_to_show = percent[depth]; viric@28: viric@28: /* Keep looking for movements in depth */ viric@28: if (*num_new_movements == 0) viric@6: { viric@28: depth_to_show = depth; viric@28: actual_map = &all_maps[depth]; viric@28: continue; viric@6: } viric@28: viric@28: /* Look for depth + 1*/ viric@28: if (depth+1 < MAX_STEPS) viric@28: { viric@28: percent[depth+1] = percent[depth]; viric@28: all_mov_tries[depth+1] = 0; viric@28: ++depth; viric@28: } viric@28: } while(!found && depth >= 0); viric@28: free(all_maps); viric@28: free(all_movements); viric@28: free(all_mov_tries); viric@28: free(all_mov_max); viric@28: viric@28: return found; viric@6: } viric@6: viric@6: viric@26: int solve_map(const struct Map *origin) viric@6: { viric@6: struct BoxMove new_movements[MAX_MOVES]; viric@6: int num_new_movements; viric@26: int ret; viric@6: viric@6: init_os(); viric@6: viric@28: ret = search_loop(origin); viric@28: viric@26: return ret; viric@6: }