Example #1
0
void mm_look(MazeMap *mm, const char *line, RelDir rel_dir)
{
    Dir front = TURN(mm->dir, rel_dir),
        left  = TURN(front, LEFT),
        right = TURN(front, RIGHT),
        back  = TURN(front, BACK);

    int r = mm->loc.r,
        c = mm->loc.c;

    while (*line)
    {
        bool open_left = false, open_right = false;
        switch (*line++)
        {
        case 'B':  /* opening on both sides */
            open_left = open_right = true;
            break;
        case 'L':  /* opening on left side */
            open_left = true;
            break;
        case 'R':   /* opening on right side */
            open_right = true;
            break;
        case 'N':   /* no opening on either side */
            break;
        case 'W':  /* wall immediately ahead: */
            SET_WALL(mm, r, c, front, PRESENT);
            assert(*line == '\0');
            return;
        default:  /* invalid char */
            assert(0);
        }

        push_border(mm, r, c, front);
        r = RDR(r, front);
        c = CDC(c, front);

        SET_SQUARE(mm, r, c, PRESENT);
        SET_WALL(mm, r, c, back, ABSENT);
        SET_WALL(mm, r, c, left, open_left ? ABSENT : PRESENT);
        SET_WALL(mm, r, c, right, open_right ? ABSENT : PRESENT);

        if (open_left)
        {
            SET_SQUARE(mm, RDR(r, left), CDC(c, left), PRESENT);
            push_border(mm, r, c, left);
        }

        if (open_right)
        {
            SET_SQUARE(mm, RDR(r, right), CDC(c, right), PRESENT);
            push_border(mm, r, c, right);
        }
    }

    assert(0); /* shouldn't get here: every line must end with W */
    return;
}
Example #2
0
void mm_initialize(MazeMap *mm, int r, int c, Dir dir)
{
    mm_clear(mm);
    mm->loc.r = r;
    mm->loc.c = c;
    mm->dir   = dir;
    mm->border.top    = r;
    mm->border.left   = c;
    mm->border.bottom = (r + 1)%WIDTH;
    mm->border.right  = (c + 1)%HEIGHT;
    SET_SQUARE(mm, r, c, PRESENT);
}
Example #3
0
static bool mark_dead_end(MazeMap *mm, bool dead_end[HEIGHT][WIDTH],
                          int r, int c)
{
    int num_walls = 0, num_dead_adjacent = 0, dir;
    bool changed = false;

    if (dead_end[r][c]) return false;

    for (dir = 0; dir < 4; ++dir)
    {
        int w = WALL(mm, r, c, dir);
        if (w == PRESENT)
            ++num_walls;
        else
        if (w == ABSENT && dead_end[RDR(r, dir)][CDC(c, dir)])
            ++num_dead_adjacent;
    }
    assert(num_walls + num_dead_adjacent < 4);

    if (num_walls + num_dead_adjacent == 3)
    {
        dead_end[r][c] = true;
        if (SQUARE(mm, r, c) == UNKNOWN)
        {
            SET_SQUARE(mm, r, c, PRESENT);
            changed = true;
        }
        for (dir = 0; dir < 4; ++dir)
        {
            if (WALL(mm, r, c, dir) == UNKNOWN)
            {
                SET_WALL(mm, r, c, dir, ABSENT);
                changed = true;
            }
        }
        for (dir = 0; dir < 4; ++dir)
        {
            if (WALL(mm, r, c, dir) == ABSENT)
            {
                if (mark_dead_end(mm, dead_end, RDR(r, dir), CDC(c, dir)))
                    changed = true;
            }
        }
    }

    return changed;
}
Example #4
0
void mm_move(MazeMap *mm, char move)
{
    RelDir rel_dir;
    switch (move)
    {
    case 'F': rel_dir = FRONT; break;
    case 'T': rel_dir = BACK;  break;
    case 'L': rel_dir = LEFT;  break;
    case 'R': rel_dir = RIGHT; break;
    default: assert(0);   /* invalid char */
    }
    mm->dir = TURN(mm->dir, rel_dir);
    push_border(mm, mm->loc.r, mm->loc.c, mm->dir);
    mm->loc.r = RDR(mm->loc.r, mm->dir);
    mm->loc.c = CDC(mm->loc.c, mm->dir);
    SET_SQUARE(mm, mm->loc.r, mm->loc.c, PRESENT);
}
Example #5
0
static game_state *new_game(midend *me, const game_params *params,
                            const char *desc)
{
    game_grid *grid = snew(game_grid);
    game_state *state = snew(game_state);
    int area;

    state->params = *params;           /* structure copy */
    state->solid = solids[params->solid];

    area = grid_area(params->d1, params->d2, state->solid->order);
    grid->squares = snewn(area, struct grid_square);
    grid->nsquares = 0;
    enum_grid_squares(params, add_grid_square_callback, grid);
    assert(grid->nsquares == area);
    state->grid = grid;
    grid->refcount = 1;

    state->facecolours = snewn(state->solid->nfaces, int);
    memset(state->facecolours, 0, state->solid->nfaces * sizeof(int));

    state->bluemask = snewn((state->grid->nsquares + 31) / 32, unsigned long);
    memset(state->bluemask, 0, (state->grid->nsquares + 31) / 32 *
	   sizeof(unsigned long));

    /*
     * Set up the blue squares and polyhedron position according to
     * the game description.
     */
    {
	const char *p = desc;
	int i, j, v;

	j = 8;
	v = 0;
	for (i = 0; i < state->grid->nsquares; i++) {
	    if (j == 8) {
		v = *p++;
		if (v >= '0' && v <= '9')
		    v -= '0';
		else if (v >= 'A' && v <= 'F')
		    v -= 'A' - 10;
		else if (v >= 'a' && v <= 'f')
		    v -= 'a' - 10;
		else
		    break;
	    }
	    if (v & j)
		SET_SQUARE(state, i, TRUE);
	    j >>= 1;
	    if (j == 0)
		j = 8;
	}

	if (*p == ',')
	    p++;

	state->current = atoi(p);
	if (state->current < 0 || state->current >= state->grid->nsquares)
	    state->current = 0;	       /* got to do _something_ */
    }

    /*
     * Align the polyhedron with its grid square and determine
     * initial key points.
     */
    {
        int pkey[4];
        int ret;

        ret = align_poly(state->solid, &state->grid->squares[state->current], pkey);
        assert(ret);

        state->dpkey[0] = state->spkey[0] = pkey[0];
        state->dpkey[1] = state->spkey[0] = pkey[1];
        state->dgkey[0] = state->sgkey[0] = 0;
        state->dgkey[1] = state->sgkey[0] = 1;
    }

    state->previous = state->current;
    state->angle = 0.0;
    state->completed = 0;
    state->movecount = 0;

    return state;
}
Example #6
0
static game_state *execute_move(const game_state *from, const char *move)
{
    game_state *ret;
    float angle;
    struct solid *poly;
    int pkey[2];
    int skey[2], dkey[2];
    int i, j, dest;
    int direction;

    switch (*move) {
      case 'L': direction = LEFT; break;
      case 'R': direction = RIGHT; break;
      case 'U': direction = UP; break;
      case 'D': direction = DOWN; break;
      default: return NULL;
    }

    dest = find_move_dest(from, direction, skey, dkey);
    if (dest < 0)
        return NULL;

    ret = dup_game(from);
    ret->current = dest;

    /*
     * So we know what grid square we're aiming for, and we also
     * know the two key points (as indices in both the source and
     * destination grid squares) which are invariant between source
     * and destination.
     * 
     * Next we must roll the polyhedron on to that square. So we
     * find the indices of the key points within the polyhedron's
     * vertex array, then use those in a call to transform_poly,
     * and align the result on the new grid square.
     */
    {
        int all_pkey[4];
        align_poly(from->solid, &from->grid->squares[from->current], all_pkey);
        pkey[0] = all_pkey[skey[0]];
        pkey[1] = all_pkey[skey[1]];
        /*
         * Now pkey[0] corresponds to skey[0] and dkey[0], and
         * likewise [1].
         */
    }

    /*
     * Now find the angle through which to rotate the polyhedron.
     * Do this by finding the two faces that share the two vertices
     * we've found, and taking the dot product of their normals.
     */
    {
        int f[2], nf = 0;
        float dp;

        for (i = 0; i < from->solid->nfaces; i++) {
            int match = 0;
            for (j = 0; j < from->solid->order; j++)
                if (from->solid->faces[i*from->solid->order + j] == pkey[0] ||
                    from->solid->faces[i*from->solid->order + j] == pkey[1])
                    match++;
            if (match == 2) {
                assert(nf < 2);
                f[nf++] = i;
            }
        }

        assert(nf == 2);

        dp = 0;
        for (i = 0; i < 3; i++)
            dp += (from->solid->normals[f[0]*3+i] *
                   from->solid->normals[f[1]*3+i]);
        angle = (float)acos(dp);
    }

    /*
     * Now transform the polyhedron. We aren't entirely sure
     * whether we need to rotate through angle or -angle, and the
     * simplest way round this is to try both and see which one
     * aligns successfully!
     * 
     * Unfortunately, _both_ will align successfully if this is a
     * cube, which won't tell us anything much. So for that
     * particular case, I resort to gross hackery: I simply negate
     * the angle before trying the alignment, depending on the
     * direction. Which directions work which way is determined by
     * pure trial and error. I said it was gross :-/
     */
    {
        int all_pkey[4];
        int success;

        if (from->solid->order == 4 && direction == UP)
            angle = -angle;            /* HACK */

        poly = transform_poly(from->solid,
                              from->grid->squares[from->current].flip,
                              pkey[0], pkey[1], angle);
        flip_poly(poly, from->grid->squares[ret->current].flip);
        success = align_poly(poly, &from->grid->squares[ret->current], all_pkey);

        if (!success) {
            sfree(poly);
            angle = -angle;
            poly = transform_poly(from->solid,
                                  from->grid->squares[from->current].flip,
                                  pkey[0], pkey[1], angle);
            flip_poly(poly, from->grid->squares[ret->current].flip);
            success = align_poly(poly, &from->grid->squares[ret->current], all_pkey);
        }

        assert(success);
    }

    /*
     * Now we have our rotated polyhedron, which we expect to be
     * exactly congruent to the one we started with - but with the
     * faces permuted. So we map that congruence and thereby figure
     * out how to permute the faces as a result of the polyhedron
     * having rolled.
     */
    {
        int *newcolours = snewn(from->solid->nfaces, int);

        for (i = 0; i < from->solid->nfaces; i++)
            newcolours[i] = -1;

        for (i = 0; i < from->solid->nfaces; i++) {
            int nmatch = 0;

            /*
             * Now go through the transformed polyhedron's faces
             * and figure out which one's normal is approximately
             * equal to this one.
             */
            for (j = 0; j < poly->nfaces; j++) {
                float dist;
                int k;

                dist = 0;

                for (k = 0; k < 3; k++)
                    dist += SQ(poly->normals[j*3+k] -
                               from->solid->normals[i*3+k]);

                if (APPROXEQ(dist, 0)) {
                    nmatch++;
                    newcolours[i] = ret->facecolours[j];
                }
            }

            assert(nmatch == 1);
        }

        for (i = 0; i < from->solid->nfaces; i++)
            assert(newcolours[i] != -1);

        sfree(ret->facecolours);
        ret->facecolours = newcolours;
    }

    ret->movecount++;

    /*
     * And finally, swap the colour between the bottom face of the
     * polyhedron and the face we've just landed on.
     * 
     * We don't do this if the game is already complete, since we
     * allow the user to roll the fully blue polyhedron around the
     * grid as a feeble reward.
     */
    if (!ret->completed) {
        i = lowest_face(from->solid);
        j = ret->facecolours[i];
        ret->facecolours[i] = GET_SQUARE(ret, ret->current);
        SET_SQUARE(ret, ret->current, j);

        /*
         * Detect game completion.
         */
        j = 0;
        for (i = 0; i < ret->solid->nfaces; i++)
            if (ret->facecolours[i])
                j++;
        if (j == ret->solid->nfaces) {
            ret->completed = ret->movecount;
        }

    }

    sfree(poly);

    /*
     * Align the normal polyhedron with its grid square, to get key
     * points for non-animated display.
     */
    {
        int pkey[4];
        int success;

        success = align_poly(ret->solid, &ret->grid->squares[ret->current], pkey);
        assert(success);

        ret->dpkey[0] = pkey[0];
        ret->dpkey[1] = pkey[1];
        ret->dgkey[0] = 0;
        ret->dgkey[1] = 1;
    }


    ret->spkey[0] = pkey[0];
    ret->spkey[1] = pkey[1];
    ret->sgkey[0] = skey[0];
    ret->sgkey[1] = skey[1];
    ret->previous = from->current;
    ret->angle = angle;

    return ret;
}
Example #7
0
bool Board::Set_Piece_onSquare(pieces pc, squares sq)
{

    switch(pc)
    {

    case wP:

        White_Pawns |= SET_SQUARE(sq);
        White_Pieces |= SET_SQUARE(sq);
        Piece_Type_By_Square[sq] = wP;
        break;

    case wN:
        White_Knights |= SET_SQUARE(sq);
        White_Pieces |= SET_SQUARE(sq);
        Piece_Type_By_Square[sq] = wN;
        break;

    case wB:
        White_Bishops |= SET_SQUARE(sq);
        White_Pieces |= SET_SQUARE(sq);
        Piece_Type_By_Square[sq] = wB;
        break;

    case wR:
        White_Rooks |= SET_SQUARE(sq);
        White_Pieces |= SET_SQUARE(sq);
        Piece_Type_By_Square[sq] = wR;
        break;

    case wQ:
        White_Queens |= SET_SQUARE(sq);
        White_Pieces |= SET_SQUARE(sq);
        Piece_Type_By_Square[sq] = wQ;
        break;

    case wK:
        White_King |= SET_SQUARE(sq);
        White_Pieces |= SET_SQUARE(sq);
        Piece_Type_By_Square[sq] = wK;
        KingSquare[WHITE] = sq;
        break;

    case bP:
        Black_Pawns |= SET_SQUARE(sq);
        Black_Pieces |= SET_SQUARE(sq);
        Piece_Type_By_Square[sq] = bP;
        break;

    case bN:
        Black_Knights |= SET_SQUARE(sq);
        Black_Pieces |= SET_SQUARE(sq);
        Piece_Type_By_Square[sq] = bN;
        break;

    case bB:
        Black_Bishops |= SET_SQUARE(sq);
        Black_Pieces |= SET_SQUARE(sq);
        Piece_Type_By_Square[sq] = bB;
        break;

    case bR:
        Black_Rooks |= SET_SQUARE(sq);
        Black_Pieces |= SET_SQUARE(sq);
        Piece_Type_By_Square[sq] = bR;
        break;

    case bQ:
        Black_Queens |= SET_SQUARE(sq);
        Black_Pieces |= SET_SQUARE(sq);
        Piece_Type_By_Square[sq] = bQ;
        break;

    case bK:
        Black_King |= SET_SQUARE(sq);
        Black_Pieces |= SET_SQUARE(sq);
        Piece_Type_By_Square[sq] = bK;
        KingSquare[BLACK] = sq;
        break;

    default:
        return false;

    }

    All_Pieces  |= SET_SQUARE(sq);
    return true;
}