viric@6: #include viric@6: #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@6: static void force_move_box(struct Map *m, 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: static int is_new_map(struct Map maps[], int depth) viric@6: { viric@6: struct Map *m; viric@6: int i; viric@6: viric@6: m = &maps[depth]; viric@6: viric@6: for(i=0; iNumBoxesInPlatform != maps[i].NumBoxesInPlatform) viric@6: continue; viric@6: else viric@6: { viric@6: if (!are_boxes_equal(m->Box, maps[i].Box, m->NumBoxes)) viric@6: continue; viric@6: } viric@6: return FALSE; viric@6: } viric@6: return TRUE; viric@6: } viric@6: viric@6: viric@6: static int search_depth(struct Map maps[], int depth, viric@6: struct BoxMove movements[], viric@6: int num_movements, float percent, float total_percent) viric@6: { viric@6: struct BoxMove new_movements[MAX_MOVES]; viric@6: int num_new_movements; viric@6: struct Map *m; viric@6: int i; viric@6: float next_percent; viric@6: viric@6: next_percent = percent / num_movements; viric@6: viric@6: m = &maps[depth+1]; 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@6: viric@6: for (i=0; i < num_movements; i++) viric@6: { viric@6: CopyMap(m, &maps[depth]); viric@6: force_move_box(m, movements[i]); viric@6: if (m->NumPlatforms == m->NumBoxesInPlatform) viric@6: { viric@6: PrintMove(movements[i]); viric@6: return 0; viric@6: } viric@6: viric@6: if (is_new_map(maps, depth+1)) viric@6: { viric@6: num_new_movements = get_box_movements(m, new_movements); viric@6: assert(num_new_movements < MAX_MOVES); viric@6: } viric@6: else viric@6: num_new_movements = 0; viric@6: viric@6: if (num_new_movements == 0) viric@6: { viric@6: percent_to_show = total_percent + next_percent*i; viric@6: depth_to_show = depth; viric@6: actual_map = &maps[depth]; viric@6: #ifdef DEBUG /* to be out */ viric@6: show_percent_callback(0); viric@6: #endif viric@6: viric@6: } viric@6: else viric@6: { viric@6: if (depth+1 < MAX_STEPS) viric@6: { viric@6: if(search_depth(maps, depth+1, new_movements, viric@6: num_new_movements, next_percent, viric@6: total_percent + next_percent*i) == 0) viric@6: { viric@6: PrintMove(movements[i]); viric@6: return 0; viric@6: } viric@6: } viric@6: } viric@6: } viric@6: return 1; viric@6: } viric@6: viric@6: viric@6: int solve_map(const struct Map origin) viric@6: { viric@6: struct Map maps[MAX_STEPS+1]; viric@6: struct BoxMove new_movements[MAX_MOVES]; viric@6: int num_new_movements; viric@6: viric@6: CopyMap(&maps[0], &origin); viric@6: viric@6: num_new_movements = get_box_movements(&maps[0], new_movements); viric@6: assert(num_new_movements < MAX_MOVES); viric@6: assert(num_new_movements > 0); viric@6: viric@6: init_os(); viric@6: viric@6: return search_depth(maps, 0, new_movements, viric@6: num_new_movements, 100. / num_new_movements, viric@6: 0); viric@6: viric@6: }