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

  1. #import "GameState.h"
  2. #import <stdlib.h>
  3. #import <stdio.h>
  4. #import <string.h>
  5.  
  6. //| the underlying board.  Says whether a square is OFFBOARD, PLAIN,
  7. //| CORNER, or CENTER.  Should never change.
  8. const unsigned char board[256] = {
  9. 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0,
  10. 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0,
  11.  
  12. 0, 0,  3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3,  0, 0, 0,
  13. 0, 0,  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  0, 0, 0,
  14. 0, 0,  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  0, 0, 0,
  15. 0, 0,  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  0, 0, 0,
  16. 0, 0,  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  0, 0, 0,
  17. 0, 0,  1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1,  0, 0, 0,
  18. 0, 0,  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  0, 0, 0,
  19. 0, 0,  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  0, 0, 0,
  20. 0, 0,  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  0, 0, 0,
  21. 0, 0,  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  0, 0, 0,
  22. 0, 0,  3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3,  0, 0, 0,
  23.  
  24. 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0,
  25. 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0,
  26. 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0
  27. };
  28. BOOL pawn_legal[256];
  29. BOOL loki_legal[256];
  30.  
  31. //| These are used to short-circuit the slow, slow, slooow
  32. //| regular objc_msgsend() that takes place for every standard message.
  33. //| They are set in [GameState initialize]
  34. //| This direct-call method instead of the usual indirect-messaging
  35. //| does _not_ affect what you should do in any way.  You can still
  36. //| call everything in the good ol' way you call any Objective-C method.
  37. IMPMakeMove makeMove, makeWhiteMove, makeBlackMove;
  38. IMPUndoMove undoMove, undoWhiteMove, undoBlackMove;
  39. IMPAnyLegalMoves anyLegalMoves;
  40.  
  41.  
  42. @implementation GameState
  43.  
  44. + initialize
  45. {
  46.    int i;
  47.  
  48.    makeMove = (IMPMakeMove)[self instanceMethodFor:@selector(makeMove:)];
  49.    makeWhiteMove = (IMPMakeMove)[self instanceMethodFor:@selector(makeWhiteMove:)];
  50.    makeBlackMove = (IMPMakeMove)[self instanceMethodFor:@selector(makeBlackMove:)];
  51.    undoMove = (IMPUndoMove)[self instanceMethodFor:@selector(undoMove)];
  52.    undoWhiteMove = (IMPUndoMove)[self instanceMethodFor:@selector(undoWhiteMove)];
  53.    undoBlackMove = (IMPUndoMove)[self instanceMethodFor:@selector(undoBlackMove)];
  54.    anyLegalMoves = (IMPAnyLegalMoves)[self instanceMethodFor:@selector(anyLegalMoves)];
  55.    for (i=0; i<256; i++) {
  56.       switch (board[i]) {
  57.          case OFFBOARD:
  58.             pawn_legal[i] = NO;
  59.             loki_legal[i] = NO;
  60.          break;
  61.          case PLAIN:
  62.             pawn_legal[i] = YES;
  63.             loki_legal[i] = YES;
  64.          break;
  65.          case CENTER: case CORNER:
  66.             pawn_legal[i] = NO;
  67.             loki_legal[i] = YES;
  68.          break;
  69.       }
  70.    }
  71.  
  72.    return [super initialize];
  73. }
  74.  
  75. - init
  76. {
  77.    [self resetState];
  78.    return [super init];
  79. }
  80.  
  81. - (void)resetState
  82. { int k;
  83.   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) };
  84.    for (k=0; k<256; k++)
  85.       pieces[k] = (struct spot){NOBODY,0};
  86.    for (k=0; k<24; k++)
  87.    {
  88.       pieceLocs[k] = startingLocs[k];
  89.       pieces[startingLocs[k]] = (struct spot){W_PAWN,k};
  90.    }
  91.    for (k=24; k<36; k++)
  92.    {
  93.       pieceLocs[k] = startingLocs[k];
  94.       pieces[startingLocs[k]] = (struct spot){B_PAWN,k};
  95.    }
  96.    pieceLocs[36] = XYTONUM(5,5);
  97.    pieces[XYTONUM(5,5)] = (struct spot){LOKI,36};
  98.    numPawns[WHITE] = 24; 
  99.    numPawns[BLACK] = 12;
  100.    whoseTurn = WHITE;
  101.    numMoves = 0;
  102.    numCaptures = 0;
  103. }
  104.  
  105. - (void)makeMove:(struct move)request
  106. {
  107.    if (whoseTurn == WHITE)
  108.       makeWhiteMove(self, @selector(makeWhiteMove:), request);
  109.    else
  110.       makeBlackMove(self, @selector(makeBlackMove:), request);
  111. }
  112.  
  113. - (void)makeWhiteMove:(struct move)request
  114. {
  115.    BOOL lokiFlag = NO;
  116.  
  117.    pieces[request.to] = pieces[request.from];
  118.    pieceLocs[pieces[request.to].idnum] = request.to;
  119.    pieces[request.from].who = NOBODY;
  120.    
  121. #define WHITEPAWNCAP(DIR) \
  122. if (BLACKPIECE(request.to+DIR) && (WHITEPIECE(request.to+(2*DIR)) || CAPTURE_HELPER(request.to+(2*DIR)))) { \
  123.  if (pieceLocs[36] == request.to+DIR) \
  124.   lokiFlag = YES; \
  125.  else { \
  126.   captures[numCaptures].when = numMoves; \
  127.   captures[numCaptures].where = request.to+DIR; \
  128.   captures[numCaptures].idnum = pieces[request.to+DIR].idnum; \
  129.   numCaptures++; \
  130.   pieceLocs[pieces[request.to+DIR].idnum] = 0; \
  131.   pieces[request.to+DIR].who = NOBODY; \
  132.   numPawns[BLACK]--; \
  133.  } \
  134. }
  135.  
  136.    WHITEPAWNCAP(NORTH);
  137.    WHITEPAWNCAP(SOUTH);
  138.    WHITEPAWNCAP(EAST);
  139.    WHITEPAWNCAP(WEST);
  140.  
  141.    moves[numMoves] = request;
  142.    numMoves++;
  143.    whoseTurn = BLACK;
  144.    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)))))
  145.       whoseTurn = WHITE_WON;
  146.    else if ((!anyLegalMoves(self, @selector(anyLegalMoves))) || ((numCaptures > 0) ? (numMoves - captures[numCaptures-1].when > 50) : (numMoves >= 50)))
  147.       whoseTurn = DRAW;
  148. }
  149.  
  150. - (void)makeBlackMove:(struct move)request
  151. {
  152.    pieces[request.to] = pieces[request.from];
  153.    pieceLocs[pieces[request.to].idnum] = request.to;
  154.    pieces[request.from].who = NOBODY;
  155.  
  156. #define BLACKPAWNCAP(DIR) \
  157. if (WHITEPIECE(request.to+DIR) && (BLACKPIECE(request.to+(2*DIR)) || CAPTURE_HELPER(request.to+(2*DIR)))) { \
  158.   captures[numCaptures].when = numMoves; \
  159.   captures[numCaptures].where = request.to+DIR; \
  160.   captures[numCaptures].idnum = pieces[request.to+DIR].idnum; \
  161.   numCaptures++; \
  162.   pieceLocs[pieces[request.to+DIR].idnum] = 0; \
  163.   pieces[request.to+DIR].who = NOBODY; \
  164.   numPawns[WHITE]--; \
  165. }
  166.  
  167.    BLACKPAWNCAP(NORTH);
  168.    BLACKPAWNCAP(SOUTH);
  169.    BLACKPAWNCAP(EAST);
  170.    BLACKPAWNCAP(WEST);
  171.  
  172.    moves[numMoves] = request;
  173.    numMoves++;
  174.    whoseTurn = WHITE;
  175.    if (board[request.to] == CORNER)
  176.       whoseTurn = BLACK_WON;
  177.    else if ((!anyLegalMoves(self, @selector(anyLegalMoves))) || ((numCaptures > 0) ? (numMoves - captures[numCaptures-1].when > 50) : (numMoves >= 50)))
  178.       whoseTurn = DRAW;
  179. }
  180.  
  181. - (void)undoMove
  182. {
  183.    if (numMoves % 2) /* if numMoves is odd, white just made a move */
  184.       undoWhiteMove(self, @selector(undoWhiteMove));
  185.    else /* otherwise black made the move */
  186.       undoBlackMove(self, @selector(undoBlackMove));
  187. }
  188.  
  189. - (void)undoWhiteMove
  190. {
  191.    whoseTurn = WHITE;
  192.    numMoves--;
  193.    /* undo captures */
  194.    if (numCaptures) while (captures[numCaptures-1].when == numMoves)
  195.    {
  196.       numCaptures--;
  197.       numPawns[BLACK]++;
  198.       pieces[captures[numCaptures].where] = (struct spot){B_PAWN, captures[numCaptures].idnum};
  199.       pieceLocs[captures[numCaptures].idnum] = captures[numCaptures].where;
  200.    }
  201.    /* unmove piece */
  202.    pieces[moves[numMoves].from] = pieces[moves[numMoves].to];
  203.    pieceLocs[pieces[moves[numMoves].from].idnum] = moves[numMoves].from;
  204.    pieces[moves[numMoves].to].who = NOBODY;
  205. }
  206.  
  207. - (void)undoBlackMove
  208. {
  209.    whoseTurn = BLACK;
  210.    numMoves--;
  211.    /* undo captures */
  212.    if (numCaptures) while (captures[numCaptures-1].when == numMoves)
  213.    {
  214.       numCaptures--;
  215.       numPawns[WHITE]++;
  216.       pieces[captures[numCaptures].where] = (struct spot){W_PAWN, captures[numCaptures].idnum};
  217.       pieceLocs[captures[numCaptures].idnum] = captures[numCaptures].where;
  218.    }
  219.    /* unmove piece */
  220.    pieces[moves[numMoves].from] = pieces[moves[numMoves].to];
  221.    pieceLocs[pieces[moves[numMoves].from].idnum] = moves[numMoves].from;
  222.    pieces[moves[numMoves].to].who = NOBODY;
  223. }
  224.  
  225. - (BOOL)anyLegalMoves
  226. {
  227.    int k;
  228.  
  229.    if (whoseTurn == WHITE)
  230.    {
  231.       for (k=0; k<24; k++) if (pieceLocs[k] != 0)
  232.       {
  233.          if (UNOCCUPIED(pieceLocs[k]+EAST) && (pawn_legal[pieceLocs[k]+EAST])) return YES;
  234.          if (UNOCCUPIED(pieceLocs[k]+WEST) && (pawn_legal[pieceLocs[k]+WEST])) return YES;
  235.          if (UNOCCUPIED(pieceLocs[k]+NORTH) && (pawn_legal[pieceLocs[k]+NORTH])) return YES;
  236.          if (UNOCCUPIED(pieceLocs[k]+SOUTH) && (pawn_legal[pieceLocs[k]+SOUTH])) return YES;
  237.       }
  238.       return NO;
  239.    }
  240.    else if (whoseTurn == BLACK)
  241.    {
  242.       for (k=24; k<36; k++) if (pieceLocs[k] != 0)
  243.       {
  244.          if (UNOCCUPIED(pieceLocs[k]+EAST) && (pawn_legal[pieceLocs[k]+EAST])) return YES;
  245.          if (UNOCCUPIED(pieceLocs[k]+WEST) && (pawn_legal[pieceLocs[k]+WEST])) return YES;
  246.          if (UNOCCUPIED(pieceLocs[k]+NORTH) && (pawn_legal[pieceLocs[k]+NORTH])) return YES;
  247.          if (UNOCCUPIED(pieceLocs[k]+SOUTH) && (pawn_legal[pieceLocs[k]+SOUTH])) return YES;
  248.       }
  249.       if (UNOCCUPIED(pieceLocs[36]+EAST) && (loki_legal[pieceLocs[k]+EAST])) return YES;
  250.       if (UNOCCUPIED(pieceLocs[36]+WEST) && (loki_legal[pieceLocs[k]+WEST])) return YES;
  251.       if (UNOCCUPIED(pieceLocs[36]+NORTH) && (loki_legal[pieceLocs[k]+NORTH])) return YES;
  252.       if (UNOCCUPIED(pieceLocs[36]+SOUTH) && (loki_legal[pieceLocs[k]+SOUTH])) return YES;
  253.       return NO;
  254.    }
  255.    else return NO;
  256. }
  257.  
  258. - (BOOL)checkMove :(struct move)request
  259. {
  260.    int direction; unsigned char scanSpot;
  261.    BOOL isLokiMove = NO;
  262.  
  263.    switch (pieces[request.from].who) {
  264.       case NOBODY: return NO;
  265.       case W_PAWN: case B_PAWN: break;
  266.       case LOKI: isLokiMove = YES; break;
  267.    }
  268.    direction = request.to - request.from;
  269.    if (((abs(direction) % 16 == 0) && (direction / 16 != 0)) ||
  270.       ((abs(direction) % 16 != 0) && (direction / 16 == 0))) {
  271.       direction = (direction % 16 == 0) ?
  272.                      16 * direction / abs(direction) :
  273.                      (direction % 16) / abs(direction % 16);
  274.       scanSpot=request.from;
  275.       do {
  276.          scanSpot+=direction;
  277.          if (!UNOCCUPIED(scanSpot)) return NO;
  278.          switch (board[scanSpot]) {
  279.             case OFFBOARD: return NO;
  280.             case CORNER: if (!isLokiMove) return NO;
  281.             case CENTER: if (!isLokiMove) return NO;
  282.             case PLAIN: break;
  283.          }
  284.       } while (scanSpot!=request.to);
  285.       return YES;
  286.    } else return NO;
  287. }
  288.  
  289. - write:(NXTypedStream *)stream
  290. {
  291.    [super write:stream];
  292.    NXWriteArray(stream, "c", 37, &pieceLocs);
  293.    NXWriteArray(stream, "{cc}", 256, &pieces);
  294.    NXWriteTypes(stream, "ccc", &whoseTurn, &numPawns[WHITE], &numPawns[BLACK]);
  295.    NXWriteArray(stream, "{cc}", 1024, &moves);
  296.    NXWriteType(stream, "s", &numMoves);
  297.    NXWriteArray(stream, "{scc}", 36, &captures);
  298.    NXWriteType(stream, "s", &numCaptures);
  299.    return self;
  300. }
  301.  
  302. - read:(NXTypedStream *)stream
  303. {
  304.    [super read:stream];
  305.    NXReadArray(stream, "c", 37, &pieceLocs);
  306.    NXReadArray(stream, "{cc}", 256, &pieces);
  307.    NXReadTypes(stream, "ccc", &whoseTurn, &numPawns[WHITE], &numPawns[BLACK]);
  308.    NXReadArray(stream, "{cc}", 1024, &moves);
  309.    NXReadType(stream, "s", &numMoves);
  310.    NXReadArray(stream, "{scc}", 36, &captures);
  311.    NXReadType(stream, "s", &numCaptures);
  312.    return self;
  313. }
  314.  
  315. @end
  316.