This is Board.m in view mode; [Download] [Up]
/*
* Board
* description: the object that stores the state of a Splat Board
* history:
* 2/14/93 [Erik Kay] - created
* < I wasn't keeping track of my changes here >
* 6/8/93 [Erik Kay] - added bycopy support
*/
#import "Board.h"
@implementation Board
// initialization
- initCols:(int)c Rows:(int)r
{
[super init];
maxRow = r;
maxCol = c;
numone = 0;
numtwo = 0;
board = malloc (sizeof (int *) * (maxCol + 1) * (maxRow + 1));
filename = NULL;
return self;
}
- init
{
[self initCols:8 Rows:8];
[self clearBoard];
filename = NULL;
return self;
}
- free
{
free(board);
free(filename);
[super free];
return self;
}
// loading a .board file
+ newFromFile:(const char *)fname
{
int maxr, maxc;
char line[256];
id newb;
FILE *f;
if ((f = fopen(fname,"r")) == NULL)
return nil;
fgets (line, 255, f);
maxc = strlen(line)/2;
maxr = 0;
do {
if (strlen(line)/2 != maxc) {
return nil;
}
maxr++;
} while (fgets(line, 255, f));
fclose(f);
newb = [[Board alloc] initCols:maxc Rows:maxr];
[newb setFilename:fname];
[newb clearBoard];
[newb reloadFromFile];
return newb;
}
- reloadFromFile
{
int r, c;
char line[256];
FILE *f;
if (!filename || ((f = fopen(filename,"r")) == NULL))
return nil;
r = c = 0;
fseek(f,0,SEEK_SET);
while (fgets(line, 255, f)) {
for (c = 0; c < maxCol; c++) {
switch (line[c*2]) {
case '+':
[self setPiece:SQUARE_BLOCKED at:c :(maxRow -1 - r)];
break;
case '1':
[self setPiece:SQUARE_ONE at:c :(maxRow -1 - r)];
break;
case '2':
[self setPiece:SQUARE_TWO at:c :(maxRow -1 - r)];
break;
default:
[self setPiece:SQUARE_EMPTY at:c :(maxRow -1 - r)];
break;
}
}
r++;
}
fclose(f);
return self;
}
- setFilename:(const char *)f
{
filename = malloc(strlen(f) + 1);
strcpy (filename,f);
return self;
}
- (const char *)filename
{
return (const char *)filename;
}
//! NOT FINISHED - should be able to archive to a .board file
- writeToFile:(const char *)filename
{
return self;
}
// board utilities
- clearBoard
{
int i;
for (i = 0; i < maxCol * maxRow; i++)
board[i] = SQUARE_EMPTY;
numone = numtwo = 0;
return self;
}
// used by the game over code to fill all empty squares with a given piece
- fillEmptyWith:(square_state)type
{
int i, c;
for (i = 0, c = 0; i < maxCol * maxRow; i++)
if (board[i] == SQUARE_EMPTY) {
board[i] = type;
c++;
}
if (type == SQUARE_ONE)
numone += c;
else if (type == SQUARE_TWO)
numtwo += c;
return self;
}
- trueCopy
{
int i, c;
square_state *from, *to;
Board *newb = [[Board alloc] initCols:maxCol Rows:maxRow];
from = board;
to = newb->board;
c = maxCol * maxRow;
for (i = 0; i < c; i++)
*to++ = *from++;
newb->numone = numone;
newb->numtwo = numtwo;
newb->currentMove = currentMove;
[newb setFilename:filename];
return newb;
}
// individually addressing board squares
// we keep track of how many pieces there are on a board
// This is very useful to most of the computer players that use a greedy-like
// strategy. It speeds things up quite a bit.
- setPiece:(square_state)value at:(int)col :(int)row
{
int i;
if ((col >= maxCol) || (row >= maxRow) || (col < 0) || (row < 0))
return self;
i = col + (row * maxCol);
switch (value) {
case SQUARE_ONE:
numone++;
break;
case SQUARE_TWO:
numtwo++;
break;
default:
break;
}
switch (board[i]) {
case SQUARE_ONE:
numone--;
break;
case SQUARE_TWO:
numtwo--;
break;
default:
break;
}
board[i] = value;
return self;
}
- setPiece:(square_state)value at:(location *)loc
{
return [self setPiece:value at:loc->col :loc->row];
}
- clearPieceAt:(int)col :(int)row
{
return self;
}
- (square_state)pieceAt:(int)col :(int)row
{
if ((col >= maxCol) || (row >= maxRow) || (col < 0) || (row < 0))
return SQUARE_ERROR;
return board[col + (row * maxCol)];
}
- (square_state)pieceAt:(location *)loc
{
if ((loc->col >= maxCol) || (loc->row >= maxRow) ||
(loc->col < 0) || (loc->row < 0))
return SQUARE_ERROR;
return board[loc->col + (loc->row * maxCol)];
}
// querying other board information
- (int)rows
{
return maxRow;
}
- (int)cols
{
return maxCol;
}
- (int)numberOfPiece:(square_state)type
{
unsigned int count = 0, i;
switch (type) {
case SQUARE_ONE:
return numone;
break;
case SQUARE_TWO:
return numtwo;
break;
default:
for (i = 0; i < maxCol * maxRow; i++) {
if (board[i] == type)
count++;
}
break;
}
return count;
}
// return an array of all of the pieces of a given type (their locations)
- (location *)pieces:(square_state)type
{
int count, current, i;
location *pieces;
count = [self numberOfPiece:type];
pieces = malloc(sizeof(location) * count);
current = 0;
for (i = 0; i < maxCol * maxRow; i++) {
if (board[i] == type) {
pieces[current].col = (i % maxCol);
pieces[current].row = (i / maxCol);
current++;
}
}
return pieces;
}
// keep track of the last move
- setCurrentMove:(move *)mv
{
currentMove = *mv;
return self;
}
- (move *)currentMove
{
return ¤tMove;
}
// keep track of a 'score' or rating for the board
- (int)score
{
return score;
}
- setScore:(int)s
{
score = s;
return self;
}
/*
* Transport protocol
*/
- encodeRemotelyFor:(NXConnection *)connection
freeAfterEncoding:(BOOL *)flagp
isBycopy:(BOOL)isBycopy
{
if (isBycopy)
return self;
else
return [super encodeRemotelyFor:connection freeAfterEncoding:flagp
isBycopy:NO];
}
- encodeUsing:(id <NXEncoding>)portal
{
// char buf[10];
int count, i, val;
// send the count first, so that the destination can allocate enough
count = (maxRow + 1) * (maxCol + 1);
[portal encodeData:&count ofType:"i"];
// can't send an enum across the wire, so we send it as a series of ints
for (i = 0; i < count; i++) {
val = board[i];
[portal encodeData:&val ofType:"i"];
}
[portal encodeData:&maxRow ofType:"i"];
[portal encodeData:&maxCol ofType:"i"];
// can't send nested structs, so we send them individually
[portal encodeData:¤tMove.from.col ofType:"i"];
[portal encodeData:¤tMove.from.row ofType:"i"];
[portal encodeData:¤tMove.to.col ofType:"i"];
[portal encodeData:¤tMove.to.row ofType:"i"];
[portal encodeData:&numone ofType:"i"];
[portal encodeData:&numtwo ofType:"i"];
[portal encodeData:&score ofType:"i"];
[portal encodeData:&filename ofType:"*"];
return self;
}
- decodeUsing:(id <NXDecoding>)portal
{
// char buf[10];
int count, i, val;
// find out how many squares there are, and allocate accordingly
[portal decodeData:&count ofType:"i"];
board = malloc(sizeof(int *) * count);
// cast these ints into square_states
for (i = 0; i < count; i++) {
[portal decodeData:&val ofType:"i"];
board[i] = val;
}
[portal decodeData:&maxRow ofType:"i"];
[portal decodeData:&maxCol ofType:"i"];
[portal decodeData:¤tMove.from.col ofType:"i"];
[portal decodeData:¤tMove.from.row ofType:"i"];
[portal decodeData:¤tMove.to.col ofType:"i"];
[portal decodeData:¤tMove.to.row ofType:"i"];
[portal decodeData:&numone ofType:"i"];
[portal decodeData:&numtwo ofType:"i"];
[portal decodeData:&score ofType:"i"];
[portal decodeData:&filename ofType:"*"];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.