183 lines
3 KiB
Go
183 lines
3 KiB
Go
package main
|
|
|
|
import (
|
|
"strconv"
|
|
)
|
|
|
|
const (
|
|
GameStateInProgress int = 0
|
|
GameStateWaitingUser = 1
|
|
GameStateEnded = 2
|
|
GameStateDraw = 3
|
|
GameStateAIWon = 4
|
|
GameStateAILost = 5
|
|
)
|
|
|
|
const (
|
|
ImageCross string = "cross"
|
|
ImageNought = "nought"
|
|
)
|
|
|
|
const (
|
|
WinnerNone int = 0
|
|
WinnerAI = 1
|
|
WinnerUser = 2
|
|
)
|
|
|
|
var field2point = map[int][2]int{
|
|
1: {0, 0},
|
|
2: {0, 1},
|
|
3: {0, 2},
|
|
4: {1, 0},
|
|
5: {1, 1},
|
|
6: {1, 2},
|
|
7: {2, 0},
|
|
8: {2, 1},
|
|
9: {2, 2},
|
|
}
|
|
|
|
var FieldClass = map[int]string{
|
|
1: "tt-item br bb",
|
|
2: "tt-item bb",
|
|
3: "tt-item bl bb",
|
|
4: "tt-item br",
|
|
5: "tt-item",
|
|
6: "tt-item bl",
|
|
7: "tt-item bt br",
|
|
8: "tt-item bt",
|
|
9: "tt-item bl bt",
|
|
}
|
|
|
|
var winner = [][3]int{
|
|
{1, 2, 3},
|
|
{4, 5, 6},
|
|
{7, 8, 9},
|
|
{1, 4, 7},
|
|
{2, 5, 8},
|
|
{3, 6, 9},
|
|
{1, 5, 9},
|
|
{7, 5, 3},
|
|
}
|
|
|
|
type Field struct {
|
|
disabled bool
|
|
image string
|
|
line bool
|
|
}
|
|
|
|
type Game struct {
|
|
gameFlow string
|
|
aiSecond bool
|
|
aiFields []int
|
|
userFields []int
|
|
fields map[int]Field
|
|
state int
|
|
winnerFields [3]int
|
|
winner int
|
|
}
|
|
|
|
func newGame(gameFlow string, aiSecond bool) *Game {
|
|
fields := make(map[int]Field)
|
|
for i := 1; i < 10; i++ {
|
|
field := &Field{
|
|
disabled: false,
|
|
}
|
|
fields[i] = *field
|
|
}
|
|
|
|
game := &Game{
|
|
gameFlow: gameFlow,
|
|
aiSecond: aiSecond,
|
|
fields: fields,
|
|
winner: WinnerNone,
|
|
}
|
|
|
|
for i, f := range str2array(game.gameFlow) {
|
|
fieldNum, _ := strconv.ParseInt(f, 0, 16)
|
|
|
|
if field, ok := game.fields[int(fieldNum)]; ok {
|
|
field.disabled = true
|
|
|
|
if i%2 == 0 {
|
|
field.image = ImageCross
|
|
} else {
|
|
field.image = ImageNought
|
|
}
|
|
|
|
game.fields[int(fieldNum)] = field
|
|
}
|
|
|
|
if (i%2 == 0) == game.aiSecond {
|
|
game.userFields = append(game.userFields, int(fieldNum))
|
|
} else {
|
|
game.aiFields = append(game.aiFields, int(fieldNum))
|
|
}
|
|
}
|
|
|
|
game.calculateState()
|
|
|
|
if game.isFinished() && game.winner != WinnerNone {
|
|
for _, f := range game.winnerFields {
|
|
if field, ok := game.fields[f]; ok {
|
|
field.line = true
|
|
game.fields[f] = field
|
|
}
|
|
}
|
|
|
|
for i := 1; i < 10; i++ {
|
|
if field, ok := game.fields[i]; ok {
|
|
field.disabled = true
|
|
game.fields[i] = field
|
|
}
|
|
}
|
|
}
|
|
|
|
return game
|
|
}
|
|
|
|
func (game *Game) isFinished() bool {
|
|
return game.state > GameStateWaitingUser
|
|
}
|
|
|
|
func (game *Game) calculateState() {
|
|
game.state = GameStateInProgress
|
|
|
|
if "0" == game.gameFlow {
|
|
game.state = GameStateWaitingUser
|
|
return
|
|
}
|
|
|
|
for _, w := range winner {
|
|
if isSubArray(w[:], game.aiFields) {
|
|
game.state = GameStateAIWon
|
|
game.winnerFields = w
|
|
game.winner = WinnerAI
|
|
return
|
|
}
|
|
if isSubArray(w[:], game.userFields) {
|
|
game.state = GameStateAILost
|
|
game.winnerFields = w
|
|
game.winner = WinnerUser
|
|
return
|
|
}
|
|
}
|
|
|
|
if len(game.gameFlow) == 9 {
|
|
game.state = GameStateDraw
|
|
}
|
|
}
|
|
|
|
func isSubArray(a, b []int) bool {
|
|
mb := make(map[int]struct{}, len(b))
|
|
for _, x := range b {
|
|
mb[x] = struct{}{}
|
|
}
|
|
var diff []int
|
|
for _, x := range a {
|
|
if _, found := mb[x]; !found {
|
|
diff = append(diff, x)
|
|
}
|
|
}
|
|
|
|
return len(diff) == 0
|
|
}
|