2023-12-29 11:42:21 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2023-12-29 22:15:11 +00:00
|
|
|
"database/sql"
|
2023-12-29 11:42:21 +00:00
|
|
|
"fmt"
|
2023-12-29 22:15:11 +00:00
|
|
|
"log"
|
2023-12-29 11:42:21 +00:00
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
|
|
|
|
"github.com/foolin/goview/supports/ginview"
|
|
|
|
"github.com/gin-contrib/sessions"
|
|
|
|
"github.com/gin-contrib/sessions/cookie"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
2023-12-29 22:15:11 +00:00
|
|
|
db, err := connectDB()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
defer db.Close()
|
|
|
|
|
2023-12-29 11:42:21 +00:00
|
|
|
r := gin.Default()
|
|
|
|
|
|
|
|
r.HTMLRender = ginview.Default()
|
|
|
|
|
|
|
|
store := cookie.NewStore([]byte("secret"))
|
|
|
|
r.Use(sessions.Sessions("mysession", store))
|
|
|
|
|
|
|
|
r.StaticFile("/favicon.ico", "./assets/favicon.ico")
|
|
|
|
r.StaticFile("/sgs.png", "./assets/sgs.png")
|
|
|
|
r.StaticFile("/en.png", "./assets/en.png")
|
2023-12-29 16:22:54 +00:00
|
|
|
r.StaticFile("/cross.png", "./assets/cross.png")
|
|
|
|
r.StaticFile("/nought.png", "./assets/nought.png")
|
2023-12-29 11:42:21 +00:00
|
|
|
|
|
|
|
r.GET("/", func(c *gin.Context) {
|
|
|
|
lang := getLang(c)
|
2023-12-29 16:58:23 +00:00
|
|
|
c.Redirect(http.StatusMovedPermanently, fmt.Sprintf("/%s/0/x", lang))
|
2023-12-29 11:42:21 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
r.GET("/:lang", func(c *gin.Context) {
|
|
|
|
lang := getLang(c)
|
2023-12-29 16:58:23 +00:00
|
|
|
c.Redirect(http.StatusMovedPermanently, fmt.Sprintf("/%s/0/x", lang))
|
2023-12-29 11:42:21 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
r.GET("/:lang/:ai_second/:game", func(c *gin.Context) {
|
|
|
|
lang := getLang(c)
|
|
|
|
gameFlow, gameState := getGameFlow(c)
|
|
|
|
|
|
|
|
aiSecond, err := strconv.ParseBool(c.Param("ai_second"))
|
|
|
|
if err != nil {
|
|
|
|
aiSecond = false
|
|
|
|
}
|
|
|
|
|
|
|
|
game := newGame(gameFlow, aiSecond)
|
|
|
|
|
2023-12-29 16:22:54 +00:00
|
|
|
if gameState == GameStateInProgress && !game.isFinished() {
|
2023-12-29 22:15:11 +00:00
|
|
|
gameFlow = gameFlow + getNewStep(db, game)
|
2023-12-29 16:22:54 +00:00
|
|
|
game = newGame(gameFlow, aiSecond)
|
|
|
|
}
|
|
|
|
|
2023-12-29 22:15:11 +00:00
|
|
|
if game.isFinished() {
|
|
|
|
saveGameLog(db, game)
|
|
|
|
}
|
|
|
|
|
|
|
|
stats := getStats(db)
|
|
|
|
fmt.Println(game)
|
2023-12-29 11:42:21 +00:00
|
|
|
|
|
|
|
c.HTML(http.StatusOK, "index", gin.H{
|
|
|
|
"title": "Index title!",
|
|
|
|
"lang": lang,
|
|
|
|
"gameFlow": gameFlow,
|
|
|
|
"game": game,
|
2023-12-29 16:22:54 +00:00
|
|
|
"fields": [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9},
|
|
|
|
"fieldClass": func(game *Game, fieldNum int) string {
|
|
|
|
fieldClass := FieldClass[fieldNum]
|
|
|
|
if field, ok := game.fields[fieldNum]; ok {
|
|
|
|
if len(field.image) > 0 {
|
|
|
|
fieldClass = fieldClass + " " + field.image
|
|
|
|
}
|
|
|
|
if field.line {
|
|
|
|
fieldClass = fieldClass + " line"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return fieldClass
|
|
|
|
},
|
|
|
|
"disabled": func(game *Game, fieldNum int) bool {
|
|
|
|
if field, ok := game.fields[fieldNum]; ok {
|
|
|
|
return field.disabled
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
},
|
2023-12-29 22:15:11 +00:00
|
|
|
"total": stats["total"],
|
|
|
|
"aiWon": stats["aiWon"],
|
|
|
|
"aiWonPercent": stats["aiWonPercent"],
|
|
|
|
"draw": stats["draw"],
|
|
|
|
"drawPercent": stats["drawPercent"],
|
|
|
|
"lastAiLost": stats["lastAiLost"],
|
2023-12-29 11:42:21 +00:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
r.Run()
|
|
|
|
}
|
|
|
|
|
|
|
|
func getLang(c *gin.Context) string {
|
|
|
|
session := sessions.Default(c)
|
|
|
|
|
2023-12-29 22:41:53 +00:00
|
|
|
lang := session.Get("lang")
|
|
|
|
if lang == nil {
|
|
|
|
lang = ""
|
|
|
|
} else {
|
|
|
|
lang = lang.(string)
|
|
|
|
}
|
|
|
|
|
2023-12-29 11:42:21 +00:00
|
|
|
pLang, hasParam := c.Params.Get("lang")
|
|
|
|
if hasParam && pLang != lang {
|
|
|
|
lang = pLang
|
|
|
|
session.Set("lang", lang)
|
|
|
|
session.Save()
|
|
|
|
}
|
|
|
|
|
|
|
|
if lang != "sgs" && lang != "en" {
|
|
|
|
lang = "sgs"
|
|
|
|
session.Set("lang", lang)
|
|
|
|
session.Save()
|
|
|
|
}
|
|
|
|
|
2023-12-29 22:41:53 +00:00
|
|
|
return lang.(string)
|
2023-12-29 11:42:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func getGameFlow(c *gin.Context) (string, int) {
|
|
|
|
gameFlow := c.Param("game")
|
|
|
|
if "0" == gameFlow {
|
2023-12-29 16:22:54 +00:00
|
|
|
return gameFlow, GameStateWaitingUser
|
2023-12-29 11:42:21 +00:00
|
|
|
}
|
|
|
|
|
2023-12-29 16:58:23 +00:00
|
|
|
if "x" == gameFlow {
|
|
|
|
return "", GameStateInProgress
|
|
|
|
}
|
|
|
|
|
2023-12-29 11:42:21 +00:00
|
|
|
if "0" == string(gameFlow[0]) {
|
|
|
|
gameFlow = string(gameFlow[1:])
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(gameFlow) >= 9 {
|
|
|
|
return gameFlow, GameStateEnded
|
|
|
|
}
|
|
|
|
|
|
|
|
return gameFlow, GameStateInProgress
|
|
|
|
}
|
|
|
|
|
2023-12-29 22:15:11 +00:00
|
|
|
func getNewStep(db *sql.DB, game *Game) string {
|
|
|
|
nextStep := getWinnerNextStep(db, game)
|
|
|
|
if "" != nextStep {
|
|
|
|
return nextStep
|
|
|
|
}
|
|
|
|
|
|
|
|
return difference("123456789", game.gameFlow)[0]
|
2023-12-29 11:42:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func difference(a, b string) []string {
|
|
|
|
mb := make(map[string]struct{}, len(b))
|
|
|
|
for _, x := range str2array(b) {
|
|
|
|
mb[x] = struct{}{}
|
|
|
|
}
|
|
|
|
var diff []string
|
|
|
|
for _, x := range str2array(a) {
|
|
|
|
if _, found := mb[x]; !found {
|
|
|
|
diff = append(diff, x)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return diff
|
|
|
|
}
|
|
|
|
|
|
|
|
func str2array(str string) []string {
|
|
|
|
chars := []rune(str)
|
|
|
|
var splited []string
|
|
|
|
for i := 0; i < len(chars); i++ {
|
|
|
|
splited = append(splited, string(chars[i]))
|
|
|
|
}
|
|
|
|
|
|
|
|
return splited
|
|
|
|
}
|
2023-12-29 22:15:11 +00:00
|
|
|
|
|
|
|
func getStats(db *sql.DB) map[string]string {
|
|
|
|
stats := make(map[string]string)
|
|
|
|
|
|
|
|
total, _ := getStatsCounter(db, "total")
|
|
|
|
stats["total"] = strconv.Itoa(total)
|
|
|
|
|
|
|
|
aiWon, _ := getStatsCounter(db, "ai_won")
|
|
|
|
stats["aiWon"] = strconv.Itoa(aiWon)
|
|
|
|
|
|
|
|
if total > 0 {
|
|
|
|
stats["aiWonPercent"] = fmt.Sprintf("%.2f%%", float64(aiWon)/float64(total)*100)
|
|
|
|
} else {
|
|
|
|
stats["aiWonPercent"] = "0%"
|
|
|
|
}
|
|
|
|
|
|
|
|
draw, _ := getStatsCounter(db, "draw")
|
|
|
|
stats["draw"] = strconv.Itoa(draw)
|
|
|
|
|
|
|
|
if total > 0 {
|
|
|
|
stats["drawPercent"] = fmt.Sprintf("%.2f%%", float64(draw)/float64(total)*100)
|
|
|
|
} else {
|
|
|
|
stats["drawPercent"] = "0%"
|
|
|
|
}
|
|
|
|
|
|
|
|
lastAiLost, _ := getStatsComment(db, "last_ai_lost")
|
|
|
|
stats["lastAiLost"] = lastAiLost
|
|
|
|
|
|
|
|
return stats
|
|
|
|
}
|