# Method to check if TicTacToe board has a winner

I have a class called TicTacToeBoard that has a [3][3] array of TicTacToeBoardCells. Doc neck if board has a winner, I check if any of the 8 possible combinations have 3 of these are type.

Is there any way to make the check of the 8 states more elegant? I am not looking for optimizations like reducing number of checks using a hash table or using check of an earlier nomination, but more about ideas on how I can make my checks more elegant.

TicTacToeBoardCell.h

typedef NS_ENUM(NSInteger,TicTacToeStates)
{
playerA=-1,
notSet,
playerB
};

@interface TicTacToeBoardCell : NSObject

@property TicTacToeStates state;

@end


TicTacToeBoard.h

@interface TicTacToeBoard : NSObject
{
TicTacToeBoardCell* cells[3][3];
}

-(BOOL) checkForWinner;
-(void) changeStateOfPoint:(CGPoint)cell toState:(TicTacToeStates)state;

@end


TicTacToeBoard.m

//Can this be made more elegant?
-(BOOL) checkForWinner
{
int sum;

for (int x=0; x<3; x++)
{
sum = 0;
for(int y=0; y<3;y++)
{
sum += cells[x][y].state;
}
if (sum == -3 || sum == 3)
{
return TRUE;
}
}

for (int y=0; y<3; y++)
{
sum = 0;
for(int x=0; x<3;x++)
{
sum += cells[x][y].state;
}
if (sum == -3 || sum == 3)
{
return TRUE;
}
}

sum = cells[0][0].state + cells[1][1].state + cells[2][2].state;
if (sum == -3 || sum == 3)
{
return TRUE;
}

sum = cells[2][0].state + cells[1][1].state + cells[0][2].state;
if (sum == -3 || sum == 3)
{
return TRUE;
}

return FALSE;
}

• Could you be more specific about what you find inelegant? – jscs May 24 '16 at 2:27

Just in case you find the for loops inelegant, here is an alternative solution. I don't know Objective C, but the following Go code uses only simple integer arithmetic and decimal formatting, so it should be easy to translate to almost any other language. It was fun to write, so have fun solving this little puzzle.

package main

import (
"fmt"
"strings"
)

type Board struct {
b [3][3]int
}

func (bo *Board) HasWinner() bool {
b := bo.b
st := 555555555 +
b[0][0]*110010010 +
b[1][0]*101010000 +
b[2][0]*100110001 +
b[0][1]*110001000 +
b[1][1]*101001011 +
b[2][1]*100101000 +
b[0][2]*110000101 +
b[1][2]*101000100 +
b[2][2]*100100110
str := fmt.Sprintf("%d", st%100000000)
return strings.Contains(str, "2") || strings.Contains(str, "8")
}

func main() {
b := &Board{[3][3]int{{1, 1, 1}, {0, -1, -1}, {0, -1, -1}}}
fmt.Println(b.HasWinner())
}


Hints and spoilers:

! The leading 1s in the number block prevent the numbers from being interpreted as octal. The modulo operation later discards these digits. If performance is critical, you can remove each leading 1 and all following 0s, as well as the % operation. Alternatively you can subtract 100000000 from each of the factors, as well as remove the % operation.

! The 555555555 prevents overflow amongst the separate digits. It has to be 9 digits long because of the extra leading 1s in the number block. The st variable could become negative otherwise. If you remove the leading 1s, the leading 5 can be removed as well.

! Each column in the number block represents one winning combination. First horizontally, then vertically, then diagonally. Therefore, each column has exactly three 1s. If your programming language allows underscores in integer literals, each factor should look like 1_hhh_vvv_dd.

! Each digit of st starts at 5 and is incremented or decremented depending on the relevant cells. When there are 3 relevant cells in either direction (+1, -1), it is a winning combination. Since every column has only 3 1s, overflow cannot happen.

Instead of checking if (sum == -3 || sum == 3) which you repeatedly do you can check abs(sum) == 3