home *** CD-ROM | disk | FTP | other *** search
- #import "GameState.h"
- #import <stdlib.h>
- #import <stdio.h>
- #import <string.h>
-
- //| the underlying board. Says whether a square is OFFBOARD, PLAIN,
- //| CORNER, or CENTER. Should never change.
- const unsigned char board[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 0, 0,
- 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
- 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
- 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
- 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
- 0, 0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 0, 0, 0,
- 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
- 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
- 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
- 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
- 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
- BOOL pawn_legal[256];
- BOOL loki_legal[256];
-
- //| These are used to short-circuit the slow, slow, slooow
- //| regular objc_msgsend() that takes place for every standard message.
- //| They are set in [GameState initialize]
- //| This direct-call method instead of the usual indirect-messaging
- //| does _not_ affect what you should do in any way. You can still
- //| call everything in the good ol' way you call any Objective-C method.
- IMPMakeMove makeMove, makeWhiteMove, makeBlackMove;
- IMPUndoMove undoMove, undoWhiteMove, undoBlackMove;
- IMPAnyLegalMoves anyLegalMoves;
-
-
- @implementation GameState
-
- + initialize
- {
- int i;
-
- makeMove = (IMPMakeMove)[self instanceMethodFor:@selector(makeMove:)];
- makeWhiteMove = (IMPMakeMove)[self instanceMethodFor:@selector(makeWhiteMove:)];
- makeBlackMove = (IMPMakeMove)[self instanceMethodFor:@selector(makeBlackMove:)];
- undoMove = (IMPUndoMove)[self instanceMethodFor:@selector(undoMove)];
- undoWhiteMove = (IMPUndoMove)[self instanceMethodFor:@selector(undoWhiteMove)];
- undoBlackMove = (IMPUndoMove)[self instanceMethodFor:@selector(undoBlackMove)];
- anyLegalMoves = (IMPAnyLegalMoves)[self instanceMethodFor:@selector(anyLegalMoves)];
- for (i=0; i<256; i++) {
- switch (board[i]) {
- case OFFBOARD:
- pawn_legal[i] = NO;
- loki_legal[i] = NO;
- break;
- case PLAIN:
- pawn_legal[i] = YES;
- loki_legal[i] = YES;
- break;
- case CENTER: case CORNER:
- pawn_legal[i] = NO;
- loki_legal[i] = YES;
- break;
- }
- }
-
- return [super initialize];
- }
-
- - init
- {
- [self resetState];
- return [super init];
- }
-
- - (void)resetState
- { int k;
- const unsigned char startingLocs[36] = { /* 24 white pawns */ XYTONUM(10,3), XYTONUM(6,0), XYTONUM(0,4), XYTONUM(9,5), XYTONUM(6,10), XYTONUM(5,1), XYTONUM(0,5), XYTONUM(10,6), XYTONUM(5,10), XYTONUM(0,3), XYTONUM(4,0), XYTONUM(5,9), XYTONUM(3,10), XYTONUM(7,0), XYTONUM(7,10), XYTONUM(4,10), XYTONUM(5,0), XYTONUM(1,5), XYTONUM(0,7), XYTONUM(10,4), XYTONUM(10,5), XYTONUM(0,6), XYTONUM(3,0), XYTONUM(10,7), /* 12 black pawns */ XYTONUM(6,6), XYTONUM(6,4), XYTONUM(4,4), XYTONUM(5,3), XYTONUM(5,4), XYTONUM(4,5), XYTONUM(7,5), XYTONUM(5,7), XYTONUM(3,5), XYTONUM(6,5), XYTONUM(4,6), XYTONUM(5,6) };
- for (k=0; k<256; k++)
- pieces[k] = (struct spot){NOBODY,0};
- for (k=0; k<24; k++)
- {
- pieceLocs[k] = startingLocs[k];
- pieces[startingLocs[k]] = (struct spot){W_PAWN,k};
- }
- for (k=24; k<36; k++)
- {
- pieceLocs[k] = startingLocs[k];
- pieces[startingLocs[k]] = (struct spot){B_PAWN,k};
- }
- pieceLocs[36] = XYTONUM(5,5);
- pieces[XYTONUM(5,5)] = (struct spot){LOKI,36};
- numPawns[WHITE] = 24;
- numPawns[BLACK] = 12;
- whoseTurn = WHITE;
- numMoves = 0;
- numCaptures = 0;
- }
-
- - (void)makeMove:(struct move)request
- {
- if (whoseTurn == WHITE)
- makeWhiteMove(self, @selector(makeWhiteMove:), request);
- else
- makeBlackMove(self, @selector(makeBlackMove:), request);
- }
-
- - (void)makeWhiteMove:(struct move)request
- {
- BOOL lokiFlag = NO;
-
- pieces[request.to] = pieces[request.from];
- pieceLocs[pieces[request.to].idnum] = request.to;
- pieces[request.from].who = NOBODY;
-
- #define WHITEPAWNCAP(DIR) \
- if (BLACKPIECE(request.to+DIR) && (WHITEPIECE(request.to+(2*DIR)) || CAPTURE_HELPER(request.to+(2*DIR)))) { \
- if (pieceLocs[36] == request.to+DIR) \
- lokiFlag = YES; \
- else { \
- captures[numCaptures].when = numMoves; \
- captures[numCaptures].where = request.to+DIR; \
- captures[numCaptures].idnum = pieces[request.to+DIR].idnum; \
- numCaptures++; \
- pieceLocs[pieces[request.to+DIR].idnum] = 0; \
- pieces[request.to+DIR].who = NOBODY; \
- numPawns[BLACK]--; \
- } \
- }
-
- WHITEPAWNCAP(NORTH);
- WHITEPAWNCAP(SOUTH);
- WHITEPAWNCAP(EAST);
- WHITEPAWNCAP(WEST);
-
- moves[numMoves] = request;
- numMoves++;
- whoseTurn = BLACK;
- if ((lokiFlag) && (((pieces[pieceLocs[36] + EAST].who == W_PAWN) || (pieceLocs[36] == XYTONUM(4,5))) && ((pieces[pieceLocs[36] + WEST].who == W_PAWN) || (pieceLocs[36] == XYTONUM(6,5))) && ((pieces[pieceLocs[36] + NORTH].who == W_PAWN) || (pieceLocs[36] == XYTONUM(5,4))) && ((pieces[pieceLocs[36] + SOUTH].who == W_PAWN) || (pieceLocs[36] == XYTONUM(5,6)))))
- whoseTurn = WHITE_WON;
- else if ((!anyLegalMoves(self, @selector(anyLegalMoves))) || ((numCaptures > 0) ? (numMoves - captures[numCaptures-1].when > 50) : (numMoves >= 50)))
- whoseTurn = DRAW;
- }
-
- - (void)makeBlackMove:(struct move)request
- {
- pieces[request.to] = pieces[request.from];
- pieceLocs[pieces[request.to].idnum] = request.to;
- pieces[request.from].who = NOBODY;
-
- #define BLACKPAWNCAP(DIR) \
- if (WHITEPIECE(request.to+DIR) && (BLACKPIECE(request.to+(2*DIR)) || CAPTURE_HELPER(request.to+(2*DIR)))) { \
- captures[numCaptures].when = numMoves; \
- captures[numCaptures].where = request.to+DIR; \
- captures[numCaptures].idnum = pieces[request.to+DIR].idnum; \
- numCaptures++; \
- pieceLocs[pieces[request.to+DIR].idnum] = 0; \
- pieces[request.to+DIR].who = NOBODY; \
- numPawns[WHITE]--; \
- }
-
- BLACKPAWNCAP(NORTH);
- BLACKPAWNCAP(SOUTH);
- BLACKPAWNCAP(EAST);
- BLACKPAWNCAP(WEST);
-
- moves[numMoves] = request;
- numMoves++;
- whoseTurn = WHITE;
- if (board[request.to] == CORNER)
- whoseTurn = BLACK_WON;
- else if ((!anyLegalMoves(self, @selector(anyLegalMoves))) || ((numCaptures > 0) ? (numMoves - captures[numCaptures-1].when > 50) : (numMoves >= 50)))
- whoseTurn = DRAW;
- }
-
- - (void)undoMove
- {
- if (numMoves % 2) /* if numMoves is odd, white just made a move */
- undoWhiteMove(self, @selector(undoWhiteMove));
- else /* otherwise black made the move */
- undoBlackMove(self, @selector(undoBlackMove));
- }
-
- - (void)undoWhiteMove
- {
- whoseTurn = WHITE;
- numMoves--;
- /* undo captures */
- if (numCaptures) while (captures[numCaptures-1].when == numMoves)
- {
- numCaptures--;
- numPawns[BLACK]++;
- pieces[captures[numCaptures].where] = (struct spot){B_PAWN, captures[numCaptures].idnum};
- pieceLocs[captures[numCaptures].idnum] = captures[numCaptures].where;
- }
- /* unmove piece */
- pieces[moves[numMoves].from] = pieces[moves[numMoves].to];
- pieceLocs[pieces[moves[numMoves].from].idnum] = moves[numMoves].from;
- pieces[moves[numMoves].to].who = NOBODY;
- }
-
- - (void)undoBlackMove
- {
- whoseTurn = BLACK;
- numMoves--;
- /* undo captures */
- if (numCaptures) while (captures[numCaptures-1].when == numMoves)
- {
- numCaptures--;
- numPawns[WHITE]++;
- pieces[captures[numCaptures].where] = (struct spot){W_PAWN, captures[numCaptures].idnum};
- pieceLocs[captures[numCaptures].idnum] = captures[numCaptures].where;
- }
- /* unmove piece */
- pieces[moves[numMoves].from] = pieces[moves[numMoves].to];
- pieceLocs[pieces[moves[numMoves].from].idnum] = moves[numMoves].from;
- pieces[moves[numMoves].to].who = NOBODY;
- }
-
- - (BOOL)anyLegalMoves
- {
- int k;
-
- if (whoseTurn == WHITE)
- {
- for (k=0; k<24; k++) if (pieceLocs[k] != 0)
- {
- if (UNOCCUPIED(pieceLocs[k]+EAST) && (pawn_legal[pieceLocs[k]+EAST])) return YES;
- if (UNOCCUPIED(pieceLocs[k]+WEST) && (pawn_legal[pieceLocs[k]+WEST])) return YES;
- if (UNOCCUPIED(pieceLocs[k]+NORTH) && (pawn_legal[pieceLocs[k]+NORTH])) return YES;
- if (UNOCCUPIED(pieceLocs[k]+SOUTH) && (pawn_legal[pieceLocs[k]+SOUTH])) return YES;
- }
- return NO;
- }
- else if (whoseTurn == BLACK)
- {
- for (k=24; k<36; k++) if (pieceLocs[k] != 0)
- {
- if (UNOCCUPIED(pieceLocs[k]+EAST) && (pawn_legal[pieceLocs[k]+EAST])) return YES;
- if (UNOCCUPIED(pieceLocs[k]+WEST) && (pawn_legal[pieceLocs[k]+WEST])) return YES;
- if (UNOCCUPIED(pieceLocs[k]+NORTH) && (pawn_legal[pieceLocs[k]+NORTH])) return YES;
- if (UNOCCUPIED(pieceLocs[k]+SOUTH) && (pawn_legal[pieceLocs[k]+SOUTH])) return YES;
- }
- if (UNOCCUPIED(pieceLocs[36]+EAST) && (loki_legal[pieceLocs[k]+EAST])) return YES;
- if (UNOCCUPIED(pieceLocs[36]+WEST) && (loki_legal[pieceLocs[k]+WEST])) return YES;
- if (UNOCCUPIED(pieceLocs[36]+NORTH) && (loki_legal[pieceLocs[k]+NORTH])) return YES;
- if (UNOCCUPIED(pieceLocs[36]+SOUTH) && (loki_legal[pieceLocs[k]+SOUTH])) return YES;
- return NO;
- }
- else return NO;
- }
-
- - (BOOL)checkMove :(struct move)request
- {
- int direction; unsigned char scanSpot;
- BOOL isLokiMove = NO;
-
- switch (pieces[request.from].who) {
- case NOBODY: return NO;
- case W_PAWN: case B_PAWN: break;
- case LOKI: isLokiMove = YES; break;
- }
- direction = request.to - request.from;
- if (((abs(direction) % 16 == 0) && (direction / 16 != 0)) ||
- ((abs(direction) % 16 != 0) && (direction / 16 == 0))) {
- direction = (direction % 16 == 0) ?
- 16 * direction / abs(direction) :
- (direction % 16) / abs(direction % 16);
- scanSpot=request.from;
- do {
- scanSpot+=direction;
- if (!UNOCCUPIED(scanSpot)) return NO;
- switch (board[scanSpot]) {
- case OFFBOARD: return NO;
- case CORNER: if (!isLokiMove) return NO;
- case CENTER: if (!isLokiMove) return NO;
- case PLAIN: break;
- }
- } while (scanSpot!=request.to);
- return YES;
- } else return NO;
- }
-
- - write:(NXTypedStream *)stream
- {
- [super write:stream];
- NXWriteArray(stream, "c", 37, &pieceLocs);
- NXWriteArray(stream, "{cc}", 256, &pieces);
- NXWriteTypes(stream, "ccc", &whoseTurn, &numPawns[WHITE], &numPawns[BLACK]);
- NXWriteArray(stream, "{cc}", 1024, &moves);
- NXWriteType(stream, "s", &numMoves);
- NXWriteArray(stream, "{scc}", 36, &captures);
- NXWriteType(stream, "s", &numCaptures);
- return self;
- }
-
- - read:(NXTypedStream *)stream
- {
- [super read:stream];
- NXReadArray(stream, "c", 37, &pieceLocs);
- NXReadArray(stream, "{cc}", 256, &pieces);
- NXReadTypes(stream, "ccc", &whoseTurn, &numPawns[WHITE], &numPawns[BLACK]);
- NXReadArray(stream, "{cc}", 1024, &moves);
- NXReadType(stream, "s", &numMoves);
- NXReadArray(stream, "{scc}", 36, &captures);
- NXReadType(stream, "s", &numCaptures);
- return self;
- }
-
- @end
-