/* * Assign a child-thread starting point within the maze. Return 1 if * successful, return 0 if not. For example, if some other thread * already is starting at the desired point, a second attempt to assign * that same point will fail. Just ABORT() if invalid starting point * given. */ int maze_solve_start_assign(struct maze *mp, int tid, int r, int c) { cell_t *cp; int i; struct maze_child *mcp = mp->msp->mcp; /* Die if the point lies outside of the maze. */ if (!maze_cell_exists(mp, r, c) || tid >= nthreads) ABORT(); /* * Return 0 if this point is already assigned to some other thread. * Or if some other point is already assigned to this thread, for * that matter. */ cp = maze_get_cell_addr(mp, r, c); if (*cp & VISITED || mcp[tid].startrow != -1) return 0; /* Assign the point. */ mcp[tid].startrow = r; mcp[tid].startcol = c; mcp[tid].visited[0].row = r; mcp[tid].visited[0].col = c; mcp[tid].vi = 1; *cp |= VISITED | tid; maze_set_cell_distance(mp, r, c, 1); return 1; }
/* Remove visitation, solution, and distance tags to allow maze to be solved. */ void maze_unvisit_all(struct maze *mp) { cell_t *cp; int i; int j; for (i = 0; i < mp->nrows; i++) for (j = 0; j < mp->ncols; j++) { cp = maze_get_cell_addr(mp, i, j); *cp &= ~(VISITED | SOLUTION | COOKIE); maze_set_cell_distance(mp, i, j, 0); } mp->vi = 0; }
/* Visit the specified cell. Die if already visited. */ void maze_visit_cell(struct maze *mp, int row, int col, int distance) { cell_t *cp = maze_get_cell_addr(mp, row, col); if (*cp & VISITED) ABORT(); if (mp->visited != NULL) { if (mp->vi >= mp->nrows * mp->ncols) ABORT(); mp->visited[mp->vi].row = row; mp->visited[mp->vi].col = col; mp->vi++; } *cp |= VISITED; maze_set_cell_distance(mp, row, col, distance); }
/* Attempt to visit a cell, return 0 if it has already been visited. */ int maze_try_visit_cell(struct maze *mp, int cr, int cc, int tr, int tc, int *nextrow, int *nextcol, int distance) { cell_t t; cell_t *tp; int vi; if (!maze_cells_connected(mp, cr, cc, tr, tc)) return -1; tp = maze_get_cell_addr(mp, tr, tc); do { t = ACCESS_ONCE(*tp); if (t & VISITED) { record_encounter(mp, cr, cc, tr, tc); return 1; } } while (!__sync_bool_compare_and_swap(tp, t, t | VISITED | myid)); maze_set_cell_distance(mp, tr, tc, distance); *nextrow = tr; *nextcol = tc; /* If we are solving the maze, mymcp is non-NULL. */ if (mymcp != NULL) { /* Use this thread's state. */ vi = mymcp->vi++; mymcp->visited[vi].row = tr; mymcp->visited[vi].col = tc; if (nthreads == 1 && tr == mymcp->mcsp->endrow && tc == mymcp->mcsp->endcol) mymcp->mcsp->done = 1; } else { /* Use global state. */ vi = mp->vi++; mp->visited[vi].row = tr; mp->visited[vi].col = tc; } return 0; }