package main import ( "database/sql" _ "github.com/mattn/go-sqlite3" ) var migrations = []string{ "ALTER TABLE Games ADD count INT DEFAULT 0;", } func connectDB() (*sql.DB, error) { db, err := sql.Open("sqlite3", "./game.db") if err != nil { return db, err } err = checkPreinstall(db) if err != nil { return db, err } return db, nil } func checkPreinstall(db *sql.DB) error { sqlStmt := ` CREATE TABLE IF NOT EXISTS Games (id INTEGER NOT NULL PRIMARY KEY, game_flow TEXT NOT NULL, first_won BOOL); CREATE UNIQUE INDEX IF NOT EXISTS game_flow_idx ON Games (game_flow); CREATE TABLE IF NOT EXISTS Stats (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL, count INT, comment TEXT); CREATE UNIQUE INDEX IF NOT EXISTS stats_idx ON Stats (name); INSERT OR IGNORE INTO Stats (name, count) VALUES ('total', 0); INSERT OR IGNORE INTO Stats (name, count) VALUES ('ai_won', 0); INSERT OR IGNORE INTO Stats (name, count) VALUES ('draw', 0); INSERT OR IGNORE INTO Stats (name, comment) VALUES ('last_ai_lost', NULL); INSERT OR IGNORE INTO Stats (name, count) VALUES ('last_migration', 0); ` _, err := db.Exec(sqlStmt) if err != nil { return err } err = runMigrations(db) if err != nil { return err } return nil } func runMigrations(db *sql.DB) error { lastMigration, err := getStatsCounter(db, "last_migration") if err != nil { return err } for i := lastMigration; i < len(migrations); i++ { sqlStmt := migrations[i] _, err := db.Exec(sqlStmt) if err != nil { return err } db.Exec("UPDATE Stats SET count=count+1 WHERE name='last_migration';") } return nil } func getStatsCounter(db *sql.DB, name string) (int, error) { stmt, err := db.Prepare("SELECT count FROM Stats WHERE name = ?") if err != nil { return 0, err } defer stmt.Close() var count int err = stmt.QueryRow(name).Scan(&count) if err != nil { return 0, nil } return count, nil } func getStatsComment(db *sql.DB, name string) (string, error) { stmt, err := db.Prepare("SELECT comment FROM Stats WHERE name = ?") if err != nil { return "", err } defer stmt.Close() var comment string err = stmt.QueryRow(name).Scan(&comment) if err != nil { return "", nil } return comment, nil } func saveGameLog(db *sql.DB, game *Game) { db.Exec("UPDATE Stats SET count=count+1 WHERE name='total';") if game.hasWinner() { db.Exec( "INSERT OR IGNORE INTO Games (game_flow, first_won) VALUES (?, ?);", game.gameFlow, game.isFirstWon(), ) db.Exec( "UPDATE Games SET count=count+1 WHERE game_flow=? AND first_won=?;", game.gameFlow, game.isFirstWon(), ) if game.isAiWon() { db.Exec("UPDATE Stats SET count=count+1 WHERE name='ai_won';") } else { db.Exec("UPDATE Stats SET comment=datetime() WHERE name='last_ai_lost';") } } else { db.Exec("UPDATE Stats SET count=count+1 WHERE name='draw';") } } func getWinnerNextStep(db *sql.DB, game *Game) string { stmt, err := db.Prepare( "SELECT game_flow FROM Games WHERE game_flow LIKE ? AND first_won = ? ORDER BY count DESC", ) if err != nil { return "" } defer stmt.Close() var gameFlow string err = stmt.QueryRow(game.gameFlow+"%", !game.aiSecond).Scan(&gameFlow) if err != nil { return "" } return gameFlow[len(game.gameFlow) : len(game.gameFlow)+1] }