viric@6: #include viric@6: #include viric@12: #include /**********************************PROVA */ 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@12: /* Prototipes */ viric@12: static Bool are_there_fixed_boxes(struct Map *m, viric@12: struct BoxMove movements[MAX_MOVES], int *num_movements); viric@12: static void force_move_box(struct Map *m, const struct BoxMove move); viric@12: static Bool search_did_found(struct Map maps[], int depth, viric@12: struct BoxMove movements[], viric@12: int num_movements, float percent, float total_percent); viric@12: static void fill_deps(struct Map *m); viric@12: 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@12: viric@12: static void force_move_box(struct Map *m, const struct BoxMove move) viric@6: { viric@12: struct Position newpos; viric@12: viric@6: viric@12: /* Add coords */ viric@12: newpos.x = m->Box[move.box].x + move.dir.x; viric@12: newpos.y = m->Box[move.box].y + move.dir.y; viric@6: viric@12: /* Be certain the move can be done */ viric@12: assert(m->Cells[newpos.y][newpos.x] != BOX); viric@12: assert(m->Cells[newpos.y][newpos.x] != WALL); viric@6: viric@12: /* Control if we moved the box to a platform */ viric@12: if(m->Cells[newpos.y][newpos.x] == PLATFORM) viric@6: { viric@12: m->NumBoxesInPlatform++; viric@6: } viric@6: viric@12: /* Control if we moved the box from a platform */ viric@12: if (m->Cells[m->Box[move.box].y][m->Box[move.box].x] == PLATFORM) viric@6: { viric@12: m->NumBoxesInPlatform--; viric@12: } viric@12: m->Man = m->Box[move.box]; viric@12: viric@12: m->Box[move.box] = newpos; viric@12: } viric@12: viric@12: viric@12: viric@12: static Bool search_did_found(struct Map maps[], int depth, viric@12: struct BoxMove movements[], viric@12: int num_movements, float percent, float total_percent) viric@12: { viric@12: struct BoxMove new_movements[MAX_MOVES]; viric@12: int num_new_movements; viric@12: struct Map *m; viric@12: int i; viric@12: float next_percent; viric@12: viric@12: next_percent = percent / num_movements; viric@12: viric@12: m = &maps[depth+1]; viric@12: if (depth > max_depth) viric@12: max_depth = depth; viric@12: if (depth > max_depth_period) viric@12: max_depth_period = depth; viric@12: if (depth < min_depth_period) viric@12: min_depth_period = depth; viric@12: viric@12: for (i=0; i < num_movements; i++) viric@12: { viric@12: CopyMap(m, &maps[depth]); viric@12: force_move_box(m, movements[i]); viric@12: /* Let's see if we finished */ viric@12: if (m->NumPlatforms == m->NumBoxesInPlatform) viric@6: { viric@12: PrintMove(movements[i]); viric@12: actual_map = &maps[depth+1]; viric@12: show_percent_and_map(); viric@12: return TRUE; viric@6: } viric@12: viric@12: if (is_new_map(maps, depth+1)) viric@6: { viric@12: actual_map = &maps[depth+1]; viric@12: #ifdef DEBUG /* to be out */ viric@12: show_percent_and_map(); viric@12: #endif viric@12: fill_deps(m); viric@12: if (are_there_fixed_boxes(m, viric@12: new_movements, &num_new_movements)) viric@12: { viric@12: /* That means that the map is illegal */ viric@12: /* Maybe we could update the percent here... */ viric@12: return FALSE; viric@12: } viric@12: /* the assert should be IN the function before, viric@12: before OVERfilling new_movements */ viric@12: assert(num_new_movements < MAX_MOVES); viric@6: } viric@6: else viric@12: num_new_movements = 0; viric@6: viric@12: if (num_new_movements == 0) viric@12: { viric@12: percent_to_show = total_percent + next_percent*i; viric@12: depth_to_show = depth; viric@12: } viric@12: else viric@12: { viric@12: if (depth+1 < MAX_STEPS) viric@12: { viric@12: if(search_did_found(maps, depth+1, new_movements, viric@12: num_new_movements, next_percent, viric@12: total_percent + next_percent*i) == TRUE) viric@12: { viric@12: PrintMove(movements[i]); viric@12: actual_map = &maps[depth+1]; viric@12: show_percent_and_map(); viric@12: return TRUE; viric@12: } viric@12: } viric@12: } viric@6: } viric@6: return FALSE; viric@6: } viric@6: viric@6: viric@12: /* It only fills the m->man_moves structure */ viric@12: static void paint_mancanmove(struct Map *m) 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@12: 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@12: m->man_moves[m->Box[i].y][m->Box[i].x] = WALL; 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@12: } viric@12: } viric@12: } viric@12: } viric@12: viric@12: /* Returns TRUE if there are fixed boxes that should be moved, FALSE otherwise*/ viric@12: /* For 'm' it modifies only m->boxes[][] */ viric@12: static Bool are_there_fixed_boxes(struct Map *m, viric@12: struct BoxMove movements[MAX_MOVES], int *num_movements) viric@12: { viric@12: int i,j; viric@12: enum e_direction d; viric@12: viric@12: /* Box dependencies. The first depends on seconds. */ viric@12: struct viric@12: { viric@12: Bool box[MAX_BOXES][MAX_BOXES]; viric@12: int ndeps[MAX_BOXES]; viric@12: } dep; viric@12: viric@12: /* Free boxes' arrays */ viric@12: struct viric@12: { viric@12: Bool box_is_free[MAX_BOXES]; /* This is only used in 'free' */ viric@12: int box[MAX_BOXES]; viric@12: int n; viric@12: } free, /* List of all boxes free-to-move */ viric@12: new_free, /* List of boxes for the next loop (code) */ viric@12: tfree; /* List of boxes of the loop (code) */ viric@12: viric@12: struct Position tpos; viric@12: viric@12: Bool is_not_set_free; viric@12: viric@12: /* Initialize to 0 the dependency structures */ viric@12: memset((void *) &dep, 0, sizeof(dep)); viric@12: for(i=0; iNumBoxes; i++) viric@12: { viric@12: new_free.box[i] = FALSE; viric@12: } viric@6: viric@12: /* Let's fill the structure */ viric@12: for(i=0; iNumBoxes; i++) viric@12: { viric@12: /* See if the box is blocked. That could be viric@12: done in fill_deps */ viric@12: if (m->box_deps[i].dep_dir[0] == BLOCKED && viric@12: m->box_deps[i].dep_dir[1] == BLOCKED && viric@12: m->box_deps[i].dep_dir[2] == BLOCKED && viric@12: m->box_deps[i].dep_dir[3] == BLOCKED ) viric@12: { viric@12: if (m->Cells[m->Box[i].y][m->Box[i].x] != viric@12: PLATFORM) viric@12: return TRUE; viric@12: /* This is not used actually viric@12: else viric@12: m->boxes[m->Box[i].y][m->Box[i].x] = viric@12: WALL; viric@12: */ viric@12: } viric@12: /* Let's take note of the dependencies */ viric@12: is_not_set_free = TRUE; viric@12: for(d=0; d<4; d++) viric@12: { viric@12: if(m->box_deps[i].dep_dir[d] > 0) viric@12: { viric@12: dep.box[i][m->box_deps[i].dep_dir[d]] = viric@12: TRUE; viric@12: dep.ndeps[i]++; viric@12: } else viric@12: if(m->box_deps[i].dep_dir[d] == FREE) viric@12: { viric@12: if (is_not_set_free) viric@12: { viric@12: new_free.box[new_free.n++] = i; viric@12: is_not_set_free = FALSE; viric@6: } viric@12: } viric@12: } viric@12: } viric@6: viric@12: /* Let's analyze if the free boxes can really be moved, and viric@12: set them as dependant, if they're dependant. viric@12: If some can be really moved, we should know _where to_. */ viric@12: viric@12: /* Paint MANCANMOVE at each cell the man can reach */ viric@12: paint_mancanmove(m); viric@12: viric@12: /* For each free movable box, let's see if the man can reach them viric@12: fine. If we can, add it to the possible movements. */ viric@12: *num_movements=0; viric@12: for(i=0; ibox_deps[i].dep_dir[d] == FREE) viric@12: { viric@12: add_position3(tpos, m->Box[i], move_vectors[OPPOSITE_DIR(d)]) viric@12: if (m->man_moves[tpos.y][tpos.x] == MANCANMOVE) viric@12: { viric@12: movements[*num_movements].box = i; viric@12: movements[*num_movements].dir = viric@12: move_vectors[d]; viric@12: (*num_movements)++; viric@12: } viric@12: /* ELSE - we should catch those cases, viric@12: where free boxes cannot be moved. Will they viric@12: ever be movable? viric@12: THIS HAS TO BE IMPROVED */ viric@6: } viric@6: } viric@6: } viric@6: viric@6: viric@12: /* ---------------- The next possible movements have been calculated -- viric@12: We can still find that this map is illegal. We need to find viric@12: further more if there are boxes unmovable (due to dependencies) */ viric@6: viric@12: /* Let's take out all dependencies from 'free' boxes */ viric@12: /* Prepare the 'free' list */ viric@12: for(i=0; iNumBoxes;i++) viric@12: free.box_is_free[i] = FALSE; viric@12: free.n = new_free.n; viric@12: for(i=0; i 0) viric@6: { viric@12: /* Copy new_free into free */ viric@12: tfree.n = new_free.n; viric@12: for(i=0; iNumBoxes; j++) viric@6: { viric@12: /* The box j no more depends on viric@12: the box tfree[i] */ viric@12: if(dep.box[j][tfree.box[i]]) viric@6: { viric@12: dep.box[j][tfree.box[i]] = FALSE; viric@12: dep.ndeps[j]--; viric@12: assert(dep.ndeps[j] >= 0); viric@12: if (dep.ndeps[j] == 0 && viric@12: !free.box_is_free[i]) viric@12: { viric@12: new_free.box[new_free.n++]=j; viric@12: free.box[free.n++]=j; viric@12: } viric@6: } viric@6: } viric@6: } viric@6: } viric@12: viric@12: /* Now are left only boxes which depend on others-non-free */ viric@12: for(i=0; iNumBoxes; i++) viric@12: { viric@12: for(j=0; jNumBoxes; j++) viric@12: { viric@12: /* We only do one-level search !!! */ viric@12: /* If the box only depends on another, viric@12: which also only depends on this... */ viric@12: if (dep.box[i][j] && dep.ndeps[i] == 1 viric@12: && dep.box[j][i] && dep.ndeps[j] == 1) viric@12: { viric@12: if (m->Cells[m->Box[i].y][m->Box[i].x]!= viric@12: PLATFORM) viric@12: { viric@12: return TRUE; viric@12: } viric@12: /* We don't set any wall here, they're not viric@12: important */ viric@12: } viric@12: } viric@12: } viric@12: viric@12: return FALSE; viric@12: } viric@12: viric@12: static void init_cell_boxes(struct Map *m) viric@12: { viric@12: int i,j; viric@12: viric@12: /* Let's the map with only walls in man_moves - other, blanks */ viric@12: for (j = 0; jSizeY; j++) viric@12: for (i=0; iSizeX; i++) viric@12: m->cells_boxes[j][i] = -1; viric@12: viric@12: for(i=0; iNumBoxes; i++) viric@12: { viric@12: m->cells_boxes[m->Box[i].y][m->Box[i].x] = i; viric@12: } viric@12: } viric@12: viric@12: /* It fills only m->box_deps */ viric@12: static void fill_deps(struct Map *m) viric@12: { viric@12: int i; viric@12: enum e_direction dir; viric@12: struct Position n; /* Position next to the box */ viric@12: viric@12: /* TO BE OPTIMIZED - get into force_move_box */ viric@12: init_cell_boxes(m); viric@12: viric@12: for(i=0; iNumBoxes; i++) viric@12: { viric@12: /* Initialize the move freedom */ viric@12: for(dir=0;dir<4; dir++) viric@12: { viric@12: m->box_deps[i].dep_dir[dir] = FREE; viric@12: } viric@12: viric@12: /* Limit the freedom */ viric@12: for(dir=0;dir<4; dir++) viric@12: { viric@12: add_position3(n,m->Box[i],move_vectors[dir]); viric@12: if(m->Cells[n.y][n.x] == WALL) viric@12: { viric@12: /* IMPROVEMENT: The fixed-box detection viric@12: could be done here */ viric@12: m->box_deps[i].dep_dir[dir] = BLOCKED; viric@12: m->box_deps[i].dep_dir[OPPOSITE_DIR(dir)] = viric@12: BLOCKED; viric@12: continue; viric@12: } viric@12: viric@12: /* if there is Wall limit, we don't want to set box viric@12: dependency */ viric@12: if(m->box_deps[i].dep_dir[dir] == WALL) viric@12: continue; viric@12: viric@12: /* Put the box dependency in the list */ viric@12: if(m->cells_boxes[n.y][n.x] >= 0) viric@12: { viric@12: m->box_deps[i].dep_dir[dir] = viric@12: m->cells_boxes[n.y][n.x]; viric@12: /* If the other site is not limited by another viric@12: box, we set it up too. */ viric@12: viric@12: /* *** MAYBE IT'S BETTER NOT TO SET IT */ viric@12: if(m->box_deps[i].dep_dir[dir] == FREE) viric@12: { viric@12: m->box_deps[i].dep_dir[OPPOSITE_DIR(dir)] = viric@12: m->cells_boxes[n.y][n.x]; viric@12: } viric@12: continue; viric@12: } viric@12: if(m->Cells[n.y][n.x] == CORNER) viric@12: m->box_deps[i].dep_dir[dir] = BLOCKED; viric@12: viric@12: } viric@12: } 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@12: fill_deps(&maps[0]); viric@12: assert(!are_there_fixed_boxes(&maps[0], new_movements, viric@12: &num_new_movements)); viric@12: search_did_found(maps, 0, new_movements, num_new_movements, 100, 0); viric@6: viric@12: return 0; viric@6: }