home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ragnaroek
/
Ragnaroek.img
/
OpponentApp
/
GameState.m
< prev
next >
Wrap
Text File
|
1991-12-08
|
11KB
|
316 lines
#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