-
Notifications
You must be signed in to change notification settings - Fork 0
/
tictactoe.go
205 lines (179 loc) · 4.39 KB
/
tictactoe.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
package tictactoe
import (
"errors"
"fmt"
"strings"
)
const playerX string = "X"
const playerO string = "O"
const noPlayer string = "#"
//var o, x = 0, 1
/*Game containing board type [][]string,lastplayed type string,
winner type bool*/
type Game struct {
Board [][]string
Lastplayed string
Status int
}
var GameStatusOngoing = 0
var GameStatusEndWithWinner = 1
var GameStatusEndWithDraw = 2
/*Coord Creates a struct for coordinates*/
type Coord struct {
X uint
Y uint
}
/*NewGame initializes and returns game struct*/
func NewGame(size int) Game {
var matrix [][]string
for i := 0; i < size; i++ {
matrix = append(matrix, []string{}) //append another slice, size times
for j := 0; j < size; j++ {
matrix[i] = append(matrix[i], noPlayer)
}
}
var Game Game
Game.Board = matrix
Game.Lastplayed = noPlayer
Game.Status = GameStatusOngoing
return Game
}
/*Play :place the play, receiving the char, the coordinates
and the board itself. Returns string(char winner //or draw//), the board,
and error if:
game not available
place not available,
correct player,
correct turn,*/
func Play(char string, coordinate Coord, game *Game) error {
if game.Status != GameStatusOngoing {
return errors.New("cannot play, create another board to start again")
}
if game.Lastplayed == noPlayer || char != game.Lastplayed {
err := checkAndPlace(char, coordinate, &game.Board)
if err != nil {
return err
}
game.Lastplayed = char
} else {
return errors.New("hey, let the other player play too :)")
}
checkWinner(game)
return nil
}
/*Called by Play.check if the player was correct and place the play otherwise returns errors:
* check if the place is available to play : else occupied error, no board error
*/
func checkAndPlace(char string, coordinate Coord, board *[][]string) error {
x := int(coordinate.X) //row
y := int(coordinate.Y) //column
player := strings.ToUpper(char)
//check if player is the correct letter
if player != playerX && player != playerO {
return errors.New("not a valid player")
}
matrix := *board
//check if coordinates are on the limits
if l := len(*board); x < l && y < l {
//if place its not occupied, place it
if matrix[x][y] == noPlayer {
matrix[x][y] = player
} else {
return fmt.Errorf("coordinate {%d %d} Occupied ! Try other place again", x, y)
}
} else {
return fmt.Errorf("{%d %d} Oh oh, there is no board there my friend :/", x, y)
}
return nil
}
/*Check the game for winners. Used by Play, returns the player winner or empty(?*/
func checkWinner(game *Game) {
type conditions struct {
row [2]int
column [2]int
diag1 [2]int
diag2 [2]int
}
var plays conditions
o, x := 0, 1
win := len(game.Board)
for row := 0; row < len(game.Board); row++ {
for column := 0; column < len(game.Board); column++ {
matrix := game.Board
rowPick := matrix[row][column]
columnPick := matrix[column][row]
if rowPick == noPlayer && columnPick == noPlayer {
continue
}
switch rowPick {
case playerX:
plays.row[x]++
case playerO:
plays.row[o]++
}
switch columnPick {
case playerX:
plays.column[x]++
case playerO:
plays.column[o]++
}
if row == column {
if rowPick == playerX {
plays.diag1[x]++
} else {
plays.diag1[o]++
}
}
if row+column == len(game.Board)-1 {
if rowPick == playerX {
plays.diag2[x]++
} else {
plays.diag2[o]++
}
}
} // end inner for
if plays.row[o] == win {
game.Status = GameStatusEndWithWinner
return
}
plays.row[o] = 0
if plays.row[x] == win {
game.Status = GameStatusEndWithWinner
return
}
plays.row[x] = 0
if plays.column[o] == win {
game.Status = GameStatusEndWithWinner
return
}
plays.column[o] = 0
if plays.column[x] == win {
game.Status = GameStatusEndWithWinner
return
}
plays.column[x] = 0
} //end of for
if plays.diag1[x] == win || plays.diag1[o] == win || plays.diag2[x] == win || plays.diag2[o] == win {
game.Status = GameStatusEndWithWinner
}
if game.Status == GameStatusOngoing {
for _, row := range game.Board {
for _, column := range row {
if column == noPlayer {
return
}
}
}
game.Status = GameStatusEndWithDraw
}
}
/*PrintBoard prints a board nicely in cmd-line.*/
func PrintBoard(game *Game) {
for i, innerArray := range game.Board {
for j := range innerArray {
fmt.Printf(game.Board[i][j])
}
fmt.Println("")
}
fmt.Println("_")
}