Tuesday, February 24, 2009

iPhone Journal 0110

Today, on 2/24/08, I planned to follow an objective-C tutorial so that I could understand how the language actually works without the additional layer of abstraction added by the iPhone API. I began to follow the tutorial that I mentioned yesterday, but soon realized that experimentation would be the most effective route to take. After a few simple tests that allowed me to understand the nature of Objects as pointers to memory locations rather than as normal variables that can be accessed with little thought. For example, copying an object by assigning a new variable to equal a previously created object actually creates a link between the objects; when a value is assigned to one, the same value is assigned to the equivalent structure in the other. My tests culminated in the first objective-C program I have ever written without templates: a command line application that allows two people to play a game of Checkers against each other. While it will not run on the iPhone without some additional interface logic, this application has allowed me to understand the framework of objective-C applications. I combined the knowledge I gained from the Harvard CS50 lectures (I am currently on week 7/13) (such as how to use the gdb debugger and how pointers actually work) with the tutorial and online forums to produce the following code and debug it. I might eventually include a video of the application in action, but for now:

//Constants.h
#define UNCHANGED -1

#define RED 0
#define BLACK 1

//Checkers.m
/**************************************************************************************/
/**************************************************************************************/
//*Checkers application written in Objective C
//*Date begun: 2/24/24
//*Creator: Julian Ceipek
//*copyright 2009 True Star Design
/**************************************************************************************/
/**************************************************************************************/
/*******************************************RULES:*************************************/
//Every turn, a player specifies a piece to move and a location to move it.
//Pawns, designated by P#, where #=0=RED and #=1=BLACK, can only move forwards
//diagonally or jump diagonally. Chained jumps are not permitted.
//Jumping is not required.
//When a pawn reaches the opposite side of the board, it becomes a King K#.
//Kings may move and jump in any diagonal direction.
//Objective: cause the opponent to lose all pieces or movement options.
/**************************************************************************************/

#import
//Objects
#import
//ObjC
#import
// Print

#import "Constants.h" //Constants: RED, BLACK, UNCHANGED

//Import Classes


#import "Board.h" //Gameboard Header

//Pieces
#import "Piece.h"
#import "Pawn.h"
#import "King.h"

int gameStatus;

//Implementation of game loop is here
int main (int argc, const char * argv[]) {
printf("Welcome to Checkers!\n");

//Setup Board
Board *board = [[Board alloc] init];
[board setUpBoard];

//Loop through game
do
{
//display board
[board display];
//move piece
[board askToMovePiece];
//switch player
[board changePlayer];

gameStatus = [board testForWin];

[board incrementMoves];
} while(gameStatus == UNCHANGED);

if (gameStatus == RED)
{
printf("Player RED has won the game.");
}
else
{
printf("Player BLACK has won the game");
}

printf("The game took %d moves.", [board getMoves]);

//Release memory
[board releasePieces];
[board release];
return 0; // 0 errors encountered.
}

//Board.h
#import

#import "Pawn.h"
#import "Piece.h"



@interface Board : NSObject
{
Piece *field[8][8];
int moves;
int currPlayer;
int gameStatus;
}

-(void)setUpBoard;
-(void)display;
-(void)releasePieces;

-(int)testForWin;

-(void)changePlayer;
-(BOOL)askToMovePiece;

-(void)incrementMoves;
-(int)getMoves;



@end

//Board.m
#import
// Print

#import "Constants.h" //Constants: RED, BLACK, UNCHANGED
//Red moves down; black moves up

#import "Board.h" //Header for curr class

//Pieces
#import "Piece.h"
#import "Pawn.h"
#import "King.h"



@implementation Board

-(void)setUpBoard
{
moves = 0;
currPlayer = 0;

//Set all to blank
for (int x=0; x<8; y="0;" x="0;" x="1;" currplayer ="=" x="1;" y="0;" x="0;" currplayer =" (currPlayer+1)%2;" rcount =" 0;" bcount =" 0;" y="0;" x="0;" rcount ="=" bcount ="=" x="0;" y="0;">7 || start[1]>7)
{
start[0]=-1;
printf("Invalid Location!");
}
//Check if square is empty
else if(field[start[0]][start[1]] == nil)
{
start[0]=-1;
printf("That Square is Empty!");
}
else if([field[start[0]][start[1]] getOwner] != currPlayer)
{
start[0]=-1;
printf("That Piece Belongs To Your Opponent!");
}
else if([field[start[0]][start[1]] canMoveAtX:start[0] Y:start[1] On:field] == NO && [field[start[0]][start[1]] canJumpAtX:start[0] Y:start[1] On:field] == NO)
{
start[0]=-1;
printf("That Piece Cannot Move!");
}

}
while (start[0]==-1);
//Valid piece was chosen

printf("Where do you want to move that piece?\n");
do
{
//Ask for destination
printf("XLoc:");
scanf("%d", &end[0]);
printf("YLoc:");
scanf("%d", &end[1]);
printf("\n");
end[0]--;
end[1]--;

//Check if square is on board
if (end[0]<0>7 || end[1]>7)
{
end[0]=-1;
printf("Invalid Location!");
}
//Check if square is empty
else if(field[end[0]][end[1]] != nil)
{
end[0]=-1;
printf("That Square is not Empty!");
}

else if([field[start[0]][start[1]] movePossibleFrom:start To:end On:field] == NO)
{
end[0]=-1;
printf("That Move is Illegal!");
}

}

while (end[0]==-1);
//Valid location was chosen

//Move Piece
//Jump? (test by checking if dist between start and end is 2;
//since only diagonal movement is possible, only x coords need be compared)
if ((end[0]-start[0])*(end[0]-start[0])/2 == 2)
{
//Eliminate through capture
printf("A piece was Captured!\n");
[field[(end[0]-start[0])/2+start[0]][(end[1]-start[1])/2+start[1]] release];
field[(end[0]-start[0])/2+start[0]][(end[1]-start[1])/2+start[1]] = nil;

//Add code for multiple jumps if desired....
}
//Move Piece
field[end[0]][end[1]] = field[start[0]][start[1]];
field[start[0]][start[1]] = nil;

//Crown King if necessary
if ([field[end[0]][end[1]] isaPawn])
{
if (end[1] == 7 && [field[end[0]][end[1]] getOwner] == RED)
{
[field[end[0]][end[1]] release];
field[end[0]][end[1]] = [[King alloc] init];
[field[end[0]][end[1]] setOwnerToPlayer:RED];
}
else if (end[1] == 0 && [field[end[0]][end[1]] getOwner] == BLACK)
{
[field[end[0]][end[1]] release];
field[end[0]][end[1]] = [[King alloc] init];
[field[end[0]][end[1]] setOwnerToPlayer:BLACK];
}
}


return YES;
}

@end

//Piece.h

#import


@interface Piece : NSObject
{
int owner;
}

-(void)setOwnerToPlayer:(int)player;
-(int)getOwner;


@end

//Piece.m

#import "Piece.h"

@implementation Piece

-(int)getOwner
{
return owner;
}

-(void)setOwnerToPlayer:(int)player
{
owner = player;
}


@end

//Pawn.h
#import "Piece.h"
#import "Board.h"

@interface Pawn : Piece
{

}

-(BOOL)movePossibleFrom:(int[2])start To:(int[2])end On:(Piece*[8][8])field;
-(BOOL)canMoveAtX:(int)x Y:(int)y On:(Piece*[8][8])field;
-(BOOL)canJumpAtX:(int)x Y:(int)y On:(Piece*[8][8])field;
-(BOOL)isaPawn;

@end


//Pawn.m
#import "Pawn.h"
#import "Constants.h" //Constants: RED, BLACK, UNCHANGED
//Red moves down; black moves up
#import


@implementation Pawn

-(BOOL)movePossibleFrom:(int[2])start To:(int[2])end On:(Piece*[8][8])field
{

//Warning: Feed this function no out of bound values!

//Is Slide Possible?
if ((start[0]-end[0])*(start[0]-end[0]) == 1)
{
if ([self getOwner] == RED)
{
if ((start[1]-end[1]) == -1)
{
return YES;
}
}
if ([self getOwner] == BLACK)
{
if ((start[1]-end[1]) == 1)
{
return YES;
}
}
}

//Is Jump Possible?
if ([self getOwner] == RED)
{
if ((start[1]-end[1]) == -2)
{
//Right
if(start[0]-end[0] == -2)
{
if (field[start[0]+1][start[1]+1] != nil)
{
return YES;
}
}
//Left
if(start[0]-end[0] == 2)
{
if (field[start[0]-1][start[1]+1] != nil)
{
return YES;
}
}
}
}
if ([self getOwner] == BLACK)
{
if ((start[1]-end[1]) == 2)
{
//Right
if(start[0]-end[0] == -2)
{
if (field[start[0]+1][start[1]-1] != nil)
{
return YES;
}
}
//Left
if(start[0]-end[0] == 2)
{
if (field[start[0]-1][start[1]-1] != nil)
{
return YES;
}
}
}
}

return NO;
}

-(BOOL)canMoveAtX:(int)x Y:(int)y On:(Piece*[8][8])field
{
if ([self getOwner] == RED && y+1 <>= 0)
{
if (field[x-1][y+1] == nil)
return YES;
}
if (x+1 <>= 0)
{
if (x-1 >= 0)
{
if (field[x-1][y-1] == nil)
return YES;
}
if (x+1 <>= 0)
{
if (field[x-1][y+1] != nil)
{
return YES;
}
}
}
if ([self getOwner] == BLACK && y-2>=0)
{
//Right
if(x+2 <>= 0)
{
if (field[x-1][y-1] != nil)
{
return YES;
}
}
}

return NO;

}

-(BOOL)isaPawn
{
return YES;
}

@end

//King.h
#import "Piece.h"

@interface King : Piece
{

}

-(BOOL)movePossibleFrom:(int[2])start To:(int[2])end On:(Piece*[8][8])field;
-(BOOL)canMoveAtX:(int)x Y:(int)y On:(Piece*[8][8])field;
-(BOOL)canJumpAtX:(int)x Y:(int)y On:(Piece*[8][8])field;
-(BOOL)isaPawn;

@end

//King.m
#import "King.h"


@implementation King

-(BOOL)movePossibleFrom:(int[2])start To:(int[2])end On:(Piece*[8][8])field
{

//Warning: Feed this function no out of bound values!

//Is Slide Possible?
if ((start[0]-end[0])*(start[0]-end[0]) == 1)
{
if ((start[1]-end[1]) == -1)
{
return YES;
}
if ((start[1]-end[1]) == 1)
{
return YES;
}
}

//Is Jump Possible?
if ((start[1]-end[1]) == -2)
{
//Right
if(start[0]-end[0] == -2)
{
if (field[start[0]+1][start[1]+1] != nil)
{
return YES;
}
}
//Left
if(start[0]-end[0] == 2)
{
if (field[start[0]-1][start[1]+1] != nil)
{
return YES;
}
}
}

if ((start[1]-end[1]) == 2)
{
//Right
if(start[0]-end[0] == -2)
{
if (field[start[0]+1][start[1]-1] != nil)
{
return YES;
}
}
//Left
if(start[0]-end[0] == 2)
{
if (field[start[0]-1][start[1]-1] != nil)
{
return YES;
}
}
}


return NO;
}

-(BOOL)canMoveAtX:(int)x Y:(int)y On:(Piece*[8][8])field
{
if (y+1 <>= 0)
{
if (field[x-1][y+1] == nil)
return YES;
}
if (x+1 <>= 0)
{
if (x-1 >= 0)
{
if (field[x-1][y-1] == nil)
return YES;
}
if (x+1 <>= 0)
{
if (field[x-1][y+1] != nil)
{
return YES;
}
}
}
if (y-2>=0)
{
//Right
if(x+2 <>= 0)
{
if (field[x-1][y-1] != nil)
{
return YES;
}
}
}

return NO;

}

-(BOOL)isaPawn
{
return NO;
}

@end

Sadly, the formatting is somewhat lost by pasting the program here. Copying and pasting to a text editor such as that included in XCode and re-indenting will produce my actual code. Note that the file names are comments in boldface
Tomorrow, I plan to figure out exactly what "@property" does and to get further in my textbook.

No comments:

Post a Comment