/* * engine.c * * The rules engine for 3Dc. */ /* 3Dc, a game of 3-Dimensional Chess Copyright (C) 1995 Paul Hicks This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. E-Mail: paulh@euristix.ie */ #include #include #include #include "machine.h" #include "3Dc.h" /* * Returns a pointer to any one piece of the specified colour threatening * the mentioned square. Will return NULL if the square is not * threatened. */ Global Piece * SquareThreatened(Colour bwSide, const File xFile, const Rank yRank, const Level zLevel) { int pieceIdx; for (pieceIdx = 0; pieceIdx < PIECES; ++pieceIdx) { if (Muster[bwSide][pieceIdx]->bVisible && PieceMayMove( Muster[bwSide][pieceIdx], xFile, yRank, zLevel )) return Muster[bwSide][pieceIdx]; } return NULL; } /* Go dist in given direction. Direction is positive, negative, 0, * with obvious meanings (think of the axes). * Return SQUARE_EMPTY, SQUARE_INVALID, or a pointer to the piece * first encountered (even if it is before the "destination" * location). * * SQUARE_EMPTY and SQUARE_INVALID are of type (Piece *); the only * legitimate value in them is xyzPos which is the coord of the * square in question (SQUARE_EMPTY) or the coord of the last * legitimate square on the route (SQAURE_INVALID). If any or all * members of the xyzPos struct are equal to UINT_MAX then there was * error which utterly precludes moving (e.g. dist == 0). */ Global Piece * TraverseDir(const Piece *piece, Dir xDir, Dir yDir, Dir zDir, unsigned dist) { int x, y, z, d = 0; /* Most move at least one in a real direction */ if ((dist == 0) || ((xDir == 0) && (yDir == 0) && (zDir == 0))) { SQUARE_INVALID->xyzPos.xFile = SQUARE_INVALID->xyzPos.yRank = SQUARE_INVALID->xyzPos.zLevel = UINT_MAX; return SQUARE_INVALID; } if ((piece->nName != knight) && (piece->nName != cannon)) { /* Make all directions be 1, -1 or 0 */ if (xDir != 0) xDir /= ABS(xDir); if (yDir != 0) yDir /= ABS(yDir); if (zDir != 0) zDir /= ABS(zDir); } else dist = 1; x = piece->xyzPos.xFile; y = piece->xyzPos.yRank; z = piece->xyzPos.zLevel; do { x += xDir; y += yDir; z += zDir; if (!((x >= 0) && (y >= 0) && (z >= 0) && (x < FILES) && (y < RANKS) && (z < LEVELS))) { SQUARE_INVALID->xyzPos.xFile = x; SQUARE_INVALID->xyzPos.yRank = y; SQUARE_INVALID->xyzPos.zLevel = z; return SQUARE_INVALID; } if (Board[z][y][x]) { if (Board[z][y][x]->bwSide == piece->bwSide) { SQUARE_INVALID->xyzPos.xFile = x; SQUARE_INVALID->xyzPos.yRank = y; SQUARE_INVALID->xyzPos.zLevel = z; return SQUARE_INVALID; } else return Board[z][y][x]; } } while (++d < dist); /* * At this point, because we haven't returned, we know these things: * We have not encountered another piece. * We have moved dist spaces. */ if ((x >= 0) && (y >= 0) && (z >= 0) && (z < LEVELS) && (y < RANKS) && (x < FILES)) { /* Valid (empty) square */ SQUARE_EMPTY->xyzPos.xFile = x; SQUARE_EMPTY->xyzPos.yRank = y; SQUARE_EMPTY->xyzPos.zLevel = z; return SQUARE_EMPTY; } /* * We fell off the board. Go back one place to the last valid * location. */ SQUARE_INVALID->xyzPos.xFile = x - xDir; SQUARE_INVALID->xyzPos.yRank = y - yDir; SQUARE_INVALID->xyzPos.zLevel = z - zDir; return SQUARE_INVALID; } /* * Return TRUE if the king is checked in the current board layout. */ Inline Global Boolean IsKingChecked( Colour bwSide ) { Coord xyz; xyz = Muster[ bwSide ][ MusterIdx( king, 0 ) ]->xyzPos; return ( SquareThreatened( (bwSide == WHITE) ? BLACK : WHITE, xyz.xFile, xyz.yRank, xyz.zLevel ) != NULL ); } /* Check move re. putting own king in check */ Inline Global Boolean FakeMoveAndIsKingChecked( Piece *piece, const File x, const Rank y, const Level z) { Piece *temp; Boolean retVal; Coord xyz; xyz = piece->xyzPos; temp = Board[z][y][x]; if ( temp != NULL ) temp->bVisible = FALSE; Board[z][y][x] = piece; Board[xyz.zLevel][xyz.yRank][xyz.xFile] = NULL; if (piece->nName == king) { /* We're moving the king, so it's xyzPos may not be accurate. * check manually. */ retVal = (SquareThreatened( (piece->bwSide == WHITE) ? BLACK : WHITE, x, y, z ) != NULL) ; } else retVal = IsKingChecked(piece->bwSide); Board[z][y][x] = temp; if ( temp != NULL ) temp->bVisible = TRUE; Board[xyz.zLevel][xyz.yRank][xyz.xFile] = piece; return retVal; }