gamboupload/parser.go
2025-03-10 08:23:18 -07:00

144 lines
2.7 KiB
Go

package main
import (
"fmt"
"regexp"
"strconv"
"strings"
"time"
)
const (
gameTypeUnknown = iota
gameTypeClassic
)
type Game struct {
Timestamp time.Time `json:"timestamp"`
GameType int `json:"game_type"`
Wager int `json:"wager"`
Winner string `json:"winner"`
Loser string `json:"loser"`
HighRoll int `json:"high_roll"`
LowRoll int `json:"low_roll"`
Payout int `json:"payout"`
}
var (
reTimeStamp = regexp.MustCompile(`(\d/\d \d+:\d+:\d+.\d+)`)
reGameStart = regexp.MustCompile(`WoWGoldGambler: A new game has been started`)
reWager = regexp.MustCompile(`Game Mode - ([A-Z]+) - Wager - ([\d,]+)g$`)
reSignup = regexp.MustCompile(`([\p{L}']+)-[\p{L}'0-9]+: (1|-1)`)
reRoll = regexp.MustCompile(`([\p{L}']+) rolls (\d+) \(1-(\d+)\)$`)
reEnd = regexp.MustCompile(`([\p{L}']+) owes ([\p{L}']+) ([\d,]+) gold!`)
)
func parseGames(lines []string) ([]Game, error) {
games := make([]Game, 0)
var err error
i := 0
for i < len(lines) {
if reGameStart.MatchString(lines[i]) {
var game Game
game, i, err = parse(lines, i)
if err != nil {
return nil, err
}
games = append(games, game)
}
i++
}
return games, nil
}
func parse(lines []string, i int) (Game, int, error) {
var (
g Game
err error
)
// Timestamp
ts := reTimeStamp.FindString(lines[i])
if ts == "" {
return g, i, fmt.Errorf("failed to extract timestamp from %s", lines[i])
}
g.Timestamp, err = time.Parse("1/2 15:04:05.000", ts)
if err != nil {
return g, i, err
}
// Wager
i++
matches := reWager.FindStringSubmatch(lines[i])
switch matches[1] {
case "CLASSIC":
g.GameType = gameTypeClassic
default:
g.GameType = gameTypeUnknown
}
g.Wager, err = strconv.Atoi(strings.ReplaceAll(matches[2], ",", ""))
if err != nil {
return g, i, err
}
// Registration
for {
if strings.Contains(lines[i], "Registration has ended") {
break
}
i++
}
// Capture Rolls
rolls := make(map[string]int)
for {
if reEnd.MatchString(lines[i]) {
break
}
rollMatches := reRoll.FindStringSubmatch(lines[i])
if rollMatches == nil {
i++
continue
}
v, err := strconv.Atoi(rollMatches[3])
if err != nil {
return g, i, err
}
if v != g.Wager {
i++
continue
}
// Ignore extra rolls
if _, ok := rolls[rollMatches[1]]; !ok {
val, err := strconv.Atoi(rollMatches[2])
if err != nil {
return g, i, err
}
rolls[rollMatches[1]] = val
}
i++
}
endMatches := reEnd.FindStringSubmatch(lines[i])
p := strings.ReplaceAll(endMatches[3], ",", "")
payout, err := strconv.Atoi(p)
if err != nil {
return g, i, err
}
g.Payout = payout
g.Winner = endMatches[2]
g.HighRoll = rolls[g.Winner]
g.Loser = endMatches[1]
g.LowRoll = rolls[g.Loser]
return g, i, nil
}