-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
152 lines (136 loc) · 4.77 KB
/
main.go
File metadata and controls
152 lines (136 loc) · 4.77 KB
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
// Package main implements a Hexapawn game with machine learning capabilities.
// Hexapawn is a simplified chess variant played on a 3x3 board (or larger) with only pawns.
// The game includes options for human players and AI opponents that learn from their mistakes.
package main
import (
"log"
"log/slog"
"os"
"github.com/pavelanni/hexapawn-go/hexapawn"
flag "github.com/spf13/pflag"
)
const (
// Default configuration values
defaultBoardRows = 3
defaultNumPlayers = 2
defaultNumGames = 20
defaultMachineFile = "machine.json"
defaultLogFile = "hexapawn_log.json"
// Validation constraints
minBoardRows = 3
maxBoardRows = 9
minNumPlayers = 0
maxNumPlayers = 2
minNumGames = 1
)
// Configuration holds all game settings
type Config struct {
boardRows int
numPlayers int
numGames int
machineFile string
logFile string
visualize bool
interactive bool
replay bool
}
func main() {
var config Config
flag.IntVarP(&config.boardRows, "rows", "r", defaultBoardRows, "Number of rows in the board, must be at least 3, at most 9. Default is 3.")
flag.IntVarP(&config.numPlayers, "players", "p", defaultNumPlayers, "Number of human players: 0, 1, or 2. Default is 2.")
flag.IntVarP(&config.numGames, "games", "g", defaultNumGames, "Number of games to play: at least 1. Default is 20.")
flag.StringVarP(&config.machineFile, "filename", "f", defaultMachineFile, "Load the machine from this file. If it doesn't exist, a new machine will be created and saved into this file. Default is 'machine.json'.")
flag.StringVarP(&config.logFile, "logfile", "l", defaultLogFile, "Log the game into this file. Default is 'hexapawn_log.json'.")
flag.BoolVarP(&config.visualize, "visualize", "v", false, "Show text summary of played games after completion.")
flag.BoolVarP(&config.interactive, "interactive", "i", false, "Show interactive TUI game viewer (requires compatible terminal).")
flag.BoolVarP(&config.replay, "replay", "R", false, "Show step-by-step replay of the most recent game.")
flag.Parse()
if config.boardRows < minBoardRows || config.boardRows > maxBoardRows {
log.Fatalf("Invalid board dimensions. Rows and Cols must be equal and at least %d, at most %d.", minBoardRows, maxBoardRows)
}
if config.numPlayers < minNumPlayers || config.numPlayers > maxNumPlayers {
log.Fatalf("Invalid number of players. Must be %d, %d, or %d.", minNumPlayers, 1, maxNumPlayers)
}
if config.numGames < minNumGames {
log.Fatalf("Invalid number of games. Must be at least %d.", minNumGames)
}
if config.machineFile == "" {
log.Printf("Machine file is not specified. Using '%s'.", defaultMachineFile)
config.machineFile = defaultMachineFile
}
if config.logFile == "" {
log.Printf("Log file is not specified. Using '%s'.", defaultLogFile)
config.logFile = defaultLogFile
}
machine := hexapawn.NewMachine()
// if machineFile exists, load it
config.machineFile = os.ExpandEnv(config.machineFile)
machine.MachineFile = config.machineFile
_, err := os.Stat(machine.MachineFile)
if !os.IsNotExist(err) && err != nil {
log.Fatal(err)
}
if err != nil {
// if it doesn't exist, create a new machine and save it
err := machine.Init(config.boardRows, config.numPlayers)
if err != nil {
log.Fatal(err)
}
err = machine.Save()
if err != nil {
log.Fatal(err)
}
log.Printf("Machine saved to %s", machine.MachineFile)
} else {
// if it exists, load it
err := machine.Load()
if err != nil {
log.Fatal(err)
}
log.Printf("Machine loaded from %s", machine.MachineFile)
}
logFile := os.ExpandEnv(config.logFile)
l, err := os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatal(err)
}
logger := slog.New(slog.NewJSONHandler(l, nil))
if logger == nil {
log.Fatal("slog.NewJSONHandler failed")
}
logger.Info("Starting hexapawn", slog.String("filename", machine.MachineFile))
machine.Logger = logger
err = machine.Play(config.numGames)
if err != nil {
log.Fatal(err)
}
err = machine.Save()
if err != nil {
log.Fatal(err)
}
log.Printf("Machine saved to %s", machine.MachineFile)
// Show visualization if requested
if config.visualize {
log.Printf("Starting game text summary...")
err = hexapawn.ShowGamesText(machine.GamesPlayed, config.boardRows)
if err != nil {
log.Printf("Visualization error: %v", err)
}
}
// Show interactive TUI if requested
if config.interactive {
log.Printf("Starting interactive game viewer...")
err = hexapawn.RunGameViewerTUI(machine.GamesPlayed, config.boardRows)
if err != nil {
log.Printf("Interactive viewer error: %v", err)
}
}
// Show step-by-step replay if requested
if config.replay {
log.Printf("Starting game replay...")
err = hexapawn.ShowGameReplay(machine.GamesPlayed, config.boardRows)
if err != nil {
log.Printf("Replay error: %v", err)
}
}
}