ai-code-battle/cmd/acb-maps-loader/main.go
jedarden 1839f5e7d1 style: format Go files with gofmt
- cmd/acb-maps-loader/main.go
- wasm/bots/guardian/main.go
- wasm/bots/hunter/main.go
- wasm/bots/random/main.go
- web/package-lock.json (npm ci update)
2026-05-25 15:33:38 -04:00

182 lines
4.9 KiB
Go

package main
import (
"database/sql"
"encoding/json"
"fmt"
"log"
"os"
"path/filepath"
"strings"
_ "github.com/lib/pq"
)
// MapFile represents the structure of map JSON files in the maps/ directory.
type MapFile struct {
ID string `json:"id"`
Players int `json:"players"`
Rows int `json:"rows"`
Cols int `json:"cols"`
WallDensity float64 `json:"wall_density"`
Walls []Position `json:"walls"`
Cores []Core `json:"cores"`
EnergyNodes []Position `json:"energy_nodes"`
Generated string `json:"generated,omitempty"`
}
// Position represents a row/column position.
type Position struct {
Row int `json:"row"`
Col int `json:"col"`
}
// Core represents a core with position and owner.
type Core struct {
Position Position `json:"position"`
Owner int `json:"owner"`
}
// MapGeometry represents the geometry stored in map_json.
type MapGeometry struct {
Walls []Position `json:"walls"`
Cores []MapDatabaseCore `json:"cores"`
EnergyNodes []Position `json:"energy_nodes"`
}
// MapDatabaseCore represents a core as stored in the database map_json.
type MapDatabaseCore struct {
Position Position `json:"position"`
Owner int `json:"owner"`
}
func main() {
// Default connection string - override with environment variables
connStr := os.Getenv("DATABASE_URL")
if connStr == "" {
connStr = "host=localhost port=5432 user=postgres password=postgres dbname=acb sslmode=disable"
}
db, err := sql.Open("postgres", connStr)
if err != nil {
log.Fatalf("Failed to connect to database: %v", err)
}
defer db.Close()
if err := db.Ping(); err != nil {
log.Fatalf("Failed to ping database: %v", err)
}
// Get the project root directory
projectRoot := os.Getenv("ACB_PROJECT_ROOT")
if projectRoot == "" {
// Try to detect from current directory
if _, err := os.Stat("maps"); err == nil {
projectRoot = "."
} else if _, err := os.Stat("../maps"); err == nil {
projectRoot = ".."
} else {
log.Fatal("Cannot find project root. Set ACB_PROJECT_ROOT environment variable or run from project root.")
}
}
mapsDir := filepath.Join(projectRoot, "maps")
// Load maps for each player count
playerCounts := []int{2, 3, 4, 6}
totalLoaded := 0
for _, players := range playerCounts {
playerDir := filepath.Join(mapsDir, fmt.Sprintf("%dplayer", players))
loaded, err := loadMapsForPlayerCount(db, playerDir, players)
if err != nil {
log.Printf("Error loading maps for %d players: %v", players, err)
continue
}
totalLoaded += loaded
log.Printf("Loaded %d maps for %d players", loaded, players)
}
log.Printf("Total maps loaded: %d", totalLoaded)
}
func loadMapsForPlayerCount(db *sql.DB, dir string, playerCount int) (int, error) {
entries, err := os.ReadDir(dir)
if err != nil {
return 0, fmt.Errorf("failed to read directory %s: %w", dir, err)
}
loaded := 0
for _, entry := range entries {
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".json") {
continue
}
filePath := filepath.Join(dir, entry.Name())
if err := loadMapFile(db, filePath, playerCount); err != nil {
log.Printf("Warning: failed to load %s: %v", filePath, err)
continue
}
loaded++
}
return loaded, nil
}
func loadMapFile(db *sql.DB, filePath string, playerCount int) error {
data, err := os.ReadFile(filePath)
if err != nil {
return fmt.Errorf("failed to read file: %w", err)
}
var mapFile MapFile
if err := json.Unmarshal(data, &mapFile); err != nil {
return fmt.Errorf("failed to parse JSON: %w", err)
}
// Count energy nodes
energyCount := len(mapFile.EnergyNodes)
// Build map_json geometry
geometry := MapGeometry{
Walls: mapFile.Walls,
Cores: make([]MapDatabaseCore, len(mapFile.Cores)),
EnergyNodes: mapFile.EnergyNodes,
}
for i, c := range mapFile.Cores {
geometry.Cores[i] = MapDatabaseCore{
Position: c.Position,
Owner: c.Owner,
}
}
mapJSON, err := json.Marshal(geometry)
if err != nil {
return fmt.Errorf("failed to marshal map_json: %w", err)
}
// Use the map ID from the file if present, otherwise generate one
mapID := mapFile.ID
if mapID == "" {
mapID = fmt.Sprintf("map_%dp_%s", playerCount, strings.TrimSuffix(filepath.Base(filePath), ".json"))
}
// Insert or update the map
query := `
INSERT INTO maps (map_id, player_count, status, engagement, wall_density, energy_count, grid_width, grid_height, map_json)
VALUES ($1, $2, 'active', 0.0, $3, $4, $5, $6, $7)
ON CONFLICT (map_id) DO UPDATE SET
wall_density = EXCLUDED.wall_density,
energy_count = EXCLUDED.energy_count,
grid_width = EXCLUDED.grid_width,
grid_height = EXCLUDED.grid_height,
map_json = EXCLUDED.map_json
`
_, err = db.Exec(query, mapID, playerCount, mapFile.WallDensity, energyCount, mapFile.Cols, mapFile.Rows, mapJSON)
if err != nil {
return fmt.Errorf("failed to insert map: %w", err)
}
return nil
}