patternMinor
First Tic Tac Toe game
Viewed 0 times
toetictacfirstgame
Problem
I've been learning Objective C for a few days so to test my skills I went ahead and made a simple Tic Tac Toe game using the console. I already have some experience with languages such as C++, Java and Python so I'm familiar with most of the concepts in Obj C.
How it works
```
#import
#include
// Game class
@interface Game : NSObject{
BOOL isPlayersTurn;
// players tokens (x or o)
char playerToken;
char computerToken;
// 2d array stores tile values
char board[3][3];
}
@end
@implementation Game
-(id)init{
self = [super init];
isPlayersTurn = YES;
// choosing players token
while(!(playerToken=='x' || playerToken=='o')){
NSLog(@"Choose your token (must be either x or o)");
scanf("%c",&playerToken);
}
// computer token is opposite of player token
computerToken = playerToken=='x'?'o':'x';
// set tiles of board to empty
for(int i=0; i<3; i++){
for(int j=0; j<3; j++){
board[i][j] = ' ';
}
}
return self;
}
-(BOOL)finished{
// check if someone has won
for(int i = 0; i < 3; i++){
// checks columns and rows
if(board[i][0]==board[i][1]&&board[i][1]==board[i][2]&&board[i][0]!=' '){
return true;
}
if(board[0][i]==board[1][i]&&board[1][i]==board[2][i]&&board[0][i]!=' '){
return true;
}
// check diagonals
if(board[0][0]==board[1][1]&&board[1][1]==board[2][2]&&board[0][0]!=' '){
return true;
}
if(board[2][0]==board[1][1]&&board[1][1]==board[0][2]&&board[2][0]!=' '){
return true;
}
}
return false;
How it works
- The player chooses their token (x or o)
- The player puts in the x and y coordinates of their token piece
- The computer makes its move
- Repeat 2 and 3 until someone wins
```
#import
#include
// Game class
@interface Game : NSObject{
BOOL isPlayersTurn;
// players tokens (x or o)
char playerToken;
char computerToken;
// 2d array stores tile values
char board[3][3];
}
@end
@implementation Game
-(id)init{
self = [super init];
isPlayersTurn = YES;
// choosing players token
while(!(playerToken=='x' || playerToken=='o')){
NSLog(@"Choose your token (must be either x or o)");
scanf("%c",&playerToken);
}
// computer token is opposite of player token
computerToken = playerToken=='x'?'o':'x';
// set tiles of board to empty
for(int i=0; i<3; i++){
for(int j=0; j<3; j++){
board[i][j] = ' ';
}
}
return self;
}
-(BOOL)finished{
// check if someone has won
for(int i = 0; i < 3; i++){
// checks columns and rows
if(board[i][0]==board[i][1]&&board[i][1]==board[i][2]&&board[i][0]!=' '){
return true;
}
if(board[0][i]==board[1][i]&&board[1][i]==board[2][i]&&board[0][i]!=' '){
return true;
}
// check diagonals
if(board[0][0]==board[1][1]&&board[1][1]==board[2][2]&&board[0][0]!=' '){
return true;
}
if(board[2][0]==board[1][1]&&board[1][1]==board[0][2]&&board[2][0]!=' '){
return true;
}
}
return false;
Solution
Some additional points:
In
are undefined, and testing their values in all the three
in that method is undefined behavior. Let's consider the last
loop as an example:
The values of
so this can easily crash your program or give a nonsensical result.
You should use a
Now
to the other
But there is another error: The array indices in
run from
returns. Subtracting one from
And the
Also note that
the so-called "modulo bias" (see e.g.
Why do people say there is modulo bias when using a random number generator?
or Arc4random modulo biased).
This
is not correct, because the game can be a tie (nobody wins).
Finally:
which each output. I would use a simple
print to the console, e.g.
In
-(void)makeMoves, the initial values ofint x;
int y;are undefined, and testing their values in all the three
while loopsin that method is undefined behavior. Let's consider the last
loop as an example:
// loop through until random tile is chosen that isn't already taken
while(board[(int)y-1][(int)x-1]!=' '){
x = arc4random()%3;
y = arc4random()%3;
}
board[(int)y-1][(int)x-1] = computerToken;The values of
x and y are undefined when the loop is entered,so this can easily crash your program or give a nonsensical result.
You should use a
do { } while () loop instead:do {
x = arc4random() % 3;
y = arc4random() % 3;
} while (board[(int)y-1][(int)x-1] != ' ')
board[(int)y-1][(int)x-1] = computerToken;Now
x and y are initialized before being tested. The same appliesto the other
while-loops in that method.But there is another error: The array indices in
board[][]run from
0 to 2, and that is exactly what arc4random() % 3returns. Subtracting one from
x and y is wrong here!And the
(int) cast is also not necessary:do {
x = arc4random() % 3;
y = arc4random() % 3;
} while (board[y][x] != ' ')
board[y][x] = computerToken;Also note that
arc4random_uniform() is preferred overarc4random when creating random integers in a range, to avoidthe so-called "modulo bias" (see e.g.
Why do people say there is modulo bias when using a random number generator?
or Arc4random modulo biased).
do {
x = arc4random_uniform(3);
y = arc4random_uniform(3);
} while (board[y][x] != ' ')
board[y][x] = computerToken;This
// winner is person who just had their move
NSLog([isPlayersTurn?@"Computer":@"Player" stringByAppendingString:@" wins!"]);is not correct, because the game can be a tie (nobody wins).
Finally:
NSLog() prints a timestamp, process name and process idwhich each output. I would use a simple
printf() instead to print to the console, e.g.
printf("Choose your x coordinate\n");Code Snippets
int x;
int y;// loop through until random tile is chosen that isn't already taken
while(board[(int)y-1][(int)x-1]!=' '){
x = arc4random()%3;
y = arc4random()%3;
}
board[(int)y-1][(int)x-1] = computerToken;do {
x = arc4random() % 3;
y = arc4random() % 3;
} while (board[(int)y-1][(int)x-1] != ' ')
board[(int)y-1][(int)x-1] = computerToken;do {
x = arc4random() % 3;
y = arc4random() % 3;
} while (board[y][x] != ' ')
board[y][x] = computerToken;do {
x = arc4random_uniform(3);
y = arc4random_uniform(3);
} while (board[y][x] != ' ')
board[y][x] = computerToken;Context
StackExchange Code Review Q#121347, answer score: 2
Revisions (0)
No revisions yet.