/* Randomly choose a next cell to build the current maze segment. */ int maze_choose_next_cell(struct maze *mp, int prevrow, int prevcol, int currow, int curcol, int *nextrow, int *nextcol) { int d; /* Distance. */ int dr; /* Delta rows. */ int dc; /* Delta columns. */ int nr; /* Next row. */ int nc; /* Next column. */ struct segment_weights *swp = &mp->weights[prevrow != currow]; double w = drandom(); d = maze_get_cell_distance(mp, currow, curcol); if (w > swp->randweight) { /* Time to stop. */ return MAZE_END_SEGMENT; } if (w > swp->contweight && (prevrow != currow || prevcol != curcol)) { /* Erect a perpendicular vector. */ dr = -(curcol - prevcol); dc = currow - prevrow; /* Flip the vector if randomly required. */ if (pmrandom()) { dr = -dr; dc = -dc; } /* Try out the corresponding cell. */ nr = currow + dr; nc = curcol + dc; if (!maze_try_visit_cell(mp, currow, curcol, nr, nc, nextrow, nextcol, d + 1)) return MAZE_CONTINUE_SEGMENT; /* No go, try turning the opposite direction. */ nr = currow - dr; nc = curcol - dc; if (!maze_try_visit_cell(mp, currow, curcol, nr, nc, nextrow, nextcol, d + 1)) return MAZE_CONTINUE_SEGMENT; /* Neither worked, drop through and try straight. */ } nr = currow + (currow - prevrow); nc = curcol + (curcol - prevcol); if (!maze_try_visit_cell(mp, currow, curcol, nr, nc, nextrow, nextcol, d + 1)) return MAZE_CONTINUE_SEGMENT; /* No go, check all possibilities. Done being picky! */ if (maze_find_any_next_cell(mp, currow, curcol, nextrow, nextcol)) return MAZE_CONTINUE_SEGMENT; /* Nowhere left to go. */ return MAZE_STUCK_SEGMENT; }
/* Construct one segment (or passage) in the maze. */ void maze_construct_segment(struct maze *mp, int row1, int col1, int row2, int col2) { int prevrow = row1; int prevcol = col1; int currow = row2; int curcol = col2; int nextrow; int nextcol; /* If starting, pick an initial direction. */ if (prevrow == currow && prevcol == curcol) { if (!maze_find_any_next_cell(mp, currow, curcol, &nextrow, &nextcol)) return; maze_build_cell_walls(mp, prevrow, prevcol, currow, curcol, nextrow, nextcol); prevrow = currow; prevcol = curcol; currow = nextrow; curcol = nextcol; } /* Each pass through the following loop advances one cell. */ for (;;) { switch (maze_choose_next_cell(mp, prevrow, prevcol, currow, curcol, &nextrow, &nextcol)) { case MAZE_CONTINUE_SEGMENT: maze_build_cell_walls(mp, prevrow, prevcol, currow, curcol, nextrow, nextcol); prevrow = currow; prevcol = curcol; currow = nextrow; curcol = nextcol; break; case MAZE_END_SEGMENT: maze_build_cell_walls(mp, prevrow, prevcol, currow, curcol, prevrow, prevcol); case MAZE_STUCK_SEGMENT: return; } } }
/* * Child maze-solver process. Each child maintains its own ->visited[] * array, and the maze data structure is used to handle contention for * the same cell. Such contention indicates that a pair of child threads * has found a path to each other. */ void *maze_solve_child(void *arg) { int cr; int cc; int nr; int nc; cpu_set_t mask; int vi = 0; struct maze_child *mcp = (struct maze_child *)arg; struct maze_child_shared *mcsp = mcp->mcsp; struct maze *mp = mcsp->mp; static const struct timespec ts = { .tv_sec = 0, .tv_nsec = 3000 }; unsigned long long tstart = current_time(); mymcp = mcp; myid = mcp->myid; CPU_ZERO(&mask); CPU_SET(myid, &mask); sched_setaffinity(0, sizeof(mask), &mask); cr = mcp->visited[vi].row; cc = mcp->visited[vi].col; do { /* * Each pass through the following loop checks one cell * that has already been visited. When a cell is found * that has at least one remaining unexplored neighbor, * go to the following loop to do the exploration. */ while (!maze_find_any_next_cell(mp, cr, cc, &nr, &nc)) { if (++vi >= mcp->vi || ACCESS_ONCE(mcsp->done)) goto done; cr = mcp->visited[vi].row; cc = mcp->visited[vi].col; } /* * Each pass through the following loop attempts to extend * the current path one cell. */ do { if (ACCESS_ONCE(mcsp->done)) goto done; cr = nr; cc = nc; } while (maze_find_any_next_cell(mp, cr, cc, &nr, &nc)); /* * Reset back to the start of this path in case there is * another unexplored cell adjacent to it. */ cr = mcp->visited[vi].row; cc = mcp->visited[vi].col; } while (!maze_solve_child_done_check()); done: /* Capture time, and act as passthrough for visibility information. */ mcp->dt = current_time() - tstart; if (nthreads > 2) while (!maze_solve_child_done_check()) nanosleep(&ts, NULL); /* In case hardware bus-locks. */ return NULL; } /* * The thread encounters are stored, but only by the thread that discovered * the encounter. Copy any encounters to the location that the other * thread would have recorded them. */ void maze_solve_map_adj(struct maze *mp) { int i; int j; struct maze_child *mcp = mp->msp->mcp; for (i = 0; i < nthreads; i++) for (j = 0; j < nthreads; j++) if (mcp[i].adj[j].mr == -1) { mcp[i].adj[j].mr = mcp[j].adj[i].tr; mcp[i].adj[j].mc = mcp[j].adj[i].tc; mcp[i].adj[j].tr = mcp[j].adj[i].mr; mcp[i].adj[j].tc = mcp[j].adj[i].mc; } }