This is SplatRules.m in view mode; [Download] [Up]
/* * SplatRules * description: subclass of the Rules object: rules for the game Splat * history: * 2/15/93 [Erik Kay] - created * 6/13/93 [Erik Kay] - converted from Rules into SplatRules */ #import "SplatRules.h" #import "SplatView.h" #import "SplatGame.h" #import "Player.h" @implementation SplatRules - init { [super init]; possible_moves.prev = possible_moves.next = NULL; return self; } // return a list of valid moves - (List *)validMoves:(Board *)b forPlayer:(square_state)piece { int rows, cols, i; List *boardlist = [[List alloc] init]; Board *newb, *tmpb; move_list *mvlist; location *from, *to; rows = [b rows]; cols = [b cols]; tmpb = [[[Board alloc] initCols:cols Rows:rows] clearBoard]; // cycle through the list of possible moves, looking for available moves for (mvlist = &possible_moves; mvlist != NULL; mvlist = mvlist->next) { from = &(mvlist->mv.from); i = from->col + from->row * cols; if (b->board[i] != piece) continue; to = &(mvlist->mv.to); i = to->col + to->row * cols; if (b->board[i] != SQUARE_EMPTY) // can only move on to empty squares continue; // is this a move or a jump? if (IS_MOVE(mvlist->mv)) { if (tmpb->board[i] == SQUARE_EMPTY) { newb = [b trueCopy]; [self addPiece:piece onBoard:newb at:to]; [tmpb setPiece:piece at:to]; } else continue; } else { newb = [b trueCopy]; [self movePiece:&mvlist->mv onBoard:newb]; } [newb setCurrentMove:&mvlist->mv]; [boardlist addObject:newb]; } [tmpb free]; return boardlist; } // is a move a valid move or jump? - (BOOL)validMove:(move *)mv onBoard:(Board *)b { int value; value = [b pieceAt:mv->to.col :mv->to.row]; if (value != SQUARE_EMPTY) return NO; if (((abs(mv->from.row - mv->to.row) <= 1) && (abs(mv->from.col - mv->to.col) <= 1)) || ((abs(mv->from.row - mv->to.row) <= 2) && (abs(mv->from.col - mv->to.col) <= 2))) return YES; return NO; } // do a move on the board - doMove:(move *)mv onBoard:(Board *)b { square_state piece; piece = [b pieceAt:mv->from.col :mv->from.row]; if ((abs(mv->from.col - mv->to.col) < 2) && (abs(mv->from.row - mv->to.row) < 2)) [self addPiece:piece onBoard:b at:mv->to.col :mv->to.row]; else [self movePiece:mv onBoard:b]; return self; } // undo the last move // This is done by re-doing all of the moves except for the last one - (Board *)undoMove:(move_list *)mvlist { Board *newBoard; int count = 0; newBoard = [initialBoard trueCopy]; // do all but the last move; while (mvlist->next) { if ((mvlist->next->next)) { [self doMove:&mvlist->mv onBoard:newBoard]; count++; } mvlist = mvlist->next; } return newBoard; } // add a piece to the board (a copy) - addPiece:(square_state)piece onBoard:(Board *)b at:(int)col :(int)row { int r, rm, c, cm, value, rows, cols, i; rows = [b rows]; cols = [b cols]; b->board[col + row * cols] = piece; if (piece == SQUARE_ONE) { b->numone++; } else { b->numtwo++; } for (cm = -1; cm <= 1; cm++) { c = col + cm; if ((c < 0) || (c > (cols-1))) continue; for (rm = -1; rm <= 1; rm++) { r = row + rm; if ((r < 0) || (r > (rows-1))) continue; i = c + r * cols; value = b->board[i]; if ((value == SQUARE_BLOCKED) || (value == SQUARE_EMPTY)) continue; if (value != piece) { b->board[i] = piece; if (piece == SQUARE_ONE) { b->numone++; b->numtwo--; } else { b->numtwo++; b->numone--; } } } } return self; } - addPiece:(square_state)piece onBoard:(Board *)b at:(location *)loc { return [self addPiece:piece onBoard:b at:loc->col :loc->row]; } // move a piece from one square to another - movePiece:(move *)mv onBoard:(Board *)b { [self addPiece:[b pieceAt:mv->from.col :mv->from.row] onBoard:b at:mv->to.col :mv->to.row]; [b setPiece:SQUARE_EMPTY at:mv->from.col :mv->from.row]; return self; } // build up a list of possible moves - setInitialBoard:(Board *)b { int count, rows, cols; move mv; move_list *mvlist, *next; [super setInitialBoard:b]; mvlist = &possible_moves; rows = [b rows]; cols = [b cols]; count = rows * cols; next = NULL; for (mv.from.col = 0; mv.from.col < cols; mv.from.col++) { for (mv.from.row = 0; mv.from.row < rows; mv.from.row++) { for (mv.to.col = mv.from.col - 2; mv.to.col <= mv.from.col + 2; mv.to.col++) { if ((mv.to.col < 0) || (mv.to.col > (cols - 1))) continue; for (mv.to.row = mv.from.row - 2; mv.to.row <= mv.from.row + 2; mv.to.row++) { if ((mv.to.row == mv.from.row) && (mv.to.col == mv.from.col)) continue; if ((mv.to.row < 0) || (mv.to.row > (rows - 1))) continue; if ([b pieceAt:&mv.to] == SQUARE_BLOCKED) continue; if ([b pieceAt:&mv.from] == SQUARE_BLOCKED) continue; if (next) { mvlist->next = next; next->prev = mvlist; mvlist = next; } mvlist->mv = mv; next = malloc(sizeof(move_list)); } } } } mvlist->next = NULL; free(next); return self; } - free { move_list *list; list = possible_moves.next; while (list->next) { list = list->next; free(list->prev); } free(list); [super free]; return self; } // test to see if player has any moves left - (BOOL)gameOver:(Board *)b forPlayer:(square_state)player { int count; List *moves; moves = [self validMoves:b forPlayer:player]; count = [moves count]; [[moves freeObjects] free]; if (count == 0) { return YES; } else { return NO; } } // who's the winner? - winner:game { int num1, num2; Board *b; b = [game board]; num1 = [b numberOfPiece:[[game player1] pieceType]]; num2 = [b numberOfPiece:[[game player2] pieceType]]; if (num1 > num2) return [game player1]; else if (num1 < num2) return [game player2]; else return NULL; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.