From 18ac1ff2b4d35166d86ed923aa5a749f6d03cb6e Mon Sep 17 00:00:00 2001 From: jedarden Date: Sun, 24 May 2026 10:10:57 -0400 Subject: [PATCH] feat(engine): reduce default map size to 40x40 and add skirmish map class Reduce default 2-player map size from 60x60 to 40x40 (from 3600 to 1600 tiles) to increase encounter frequency and combat density. Add -skirmish flag to acb-mapgen for generating even smaller dense maps (32x32, 0.20 wall density, 15 energy nodes) with "skirmish_" ID prefix. Changes: - engine/types.go: DefaultConfig() returns 40x40, ConfigForPlayers() uses 800 tiles/player for 2-player (40x40) and 2000 tiles/player for 3+ players - cmd/acb-matchmaker/tickers.go: gridForPlayers() returns 40x40 for 2 players - cmd/acb-map-evolver/main.go: gridForPlayers() returns 40x40 for 2 players - cmd/acb-mapgen/main.go: defaults to 40x40, adds -skirmish flag for 32x32 high-density maps - cmd/acb-matchmaker/tickers_test.go: update test expectations for new 40x40 default Closes: bf-39wt --- cmd/acb-map-evolver/main.go | 4 +++- cmd/acb-mapgen/main.go | 29 ++++++++++++++++++++++++----- cmd/acb-matchmaker/tickers.go | 7 ++++--- cmd/acb-matchmaker/tickers_test.go | 2 +- engine/types.go | 20 +++++++++++++------- 5 files changed, 45 insertions(+), 17 deletions(-) diff --git a/cmd/acb-map-evolver/main.go b/cmd/acb-map-evolver/main.go index 08f2a22..05d9fa1 100644 --- a/cmd/acb-map-evolver/main.go +++ b/cmd/acb-map-evolver/main.go @@ -1047,9 +1047,11 @@ func (e *MapEvolver) saveMap(ctx context.Context, m *Map) error { } // gridForPlayers returns default grid dimensions for a given player count. +// For 2-player matches, uses 40x40 (down from 60x60) to increase encounter frequency. +// For 3+ players, targets ~2000 tiles per player. func gridForPlayers(n int) (rows, cols int) { if n <= 2 { - return 60, 60 + return 40, 40 } side := int(math.Sqrt(float64(2000 * n))) if side < 40 { diff --git a/cmd/acb-mapgen/main.go b/cmd/acb-mapgen/main.go index 4980479..2ac6333 100644 --- a/cmd/acb-mapgen/main.go +++ b/cmd/acb-mapgen/main.go @@ -39,13 +39,14 @@ type Core struct { func main() { // Command-line flags players := flag.Int("players", 2, "Number of players (2, 3, 4, or 6)") - rows := flag.Int("rows", 60, "Grid rows") - cols := flag.Int("cols", 60, "Grid columns") + rows := flag.Int("rows", 40, "Grid rows") + cols := flag.Int("cols", 40, "Grid columns") wallDensity := flag.Float64("wall-density", 0.15, "Wall density (0.0-0.3)") energyNodes := flag.Int("energy-nodes", 20, "Energy nodes") seed := flag.Int64("seed", time.Now().UnixNano(), "Random seed") output := flag.String("output", "", "Output file (default: stdout)") maxAttempts := flag.Int("max-attempts", 100, "Max attempts to generate a connected map") + skirmish := flag.Bool("skirmish", false, "Generate a skirmish map (32x32, higher density)") help := flag.Bool("help", false, "Show help") flag.Usage = func() { @@ -58,6 +59,8 @@ func main() { fmt.Fprintf(flag.CommandLine.Output(), " 3 players: 120° rotational\n") fmt.Fprintf(flag.CommandLine.Output(), " 4 players: 90° rotational\n") fmt.Fprintf(flag.CommandLine.Output(), " 6 players: 60° rotational\n\n") + fmt.Fprintf(flag.CommandLine.Output(), "Map presets:\n") + fmt.Fprintf(flag.CommandLine.Output(), " -skirmish Small dense map (32x32, 0.20 wall density, 15 energy)\n\n") fmt.Fprintf(flag.CommandLine.Output(), "Options:\n") flag.PrintDefaults() } @@ -69,6 +72,14 @@ func main() { os.Exit(0) } + // Apply skirmish preset if requested + if *skirmish { + *rows = 32 + *cols = 32 + *wallDensity = 0.20 + *energyNodes = 15 + } + // Validate player count validPlayers := map[int]bool{2: true, 3: true, 4: true, 6: true} if !validPlayers[*players] { @@ -91,8 +102,12 @@ func main() { os.Exit(1) } - // Generate map ID - m.ID = generateMapID(rng) + // Generate map ID with skirmish prefix if applicable + if *skirmish { + m.ID = generateMapIDWithPrefix(rng, "skirmish") + } else { + m.ID = generateMapID(rng) + } m.Generated = time.Now().UTC() // Output @@ -114,12 +129,16 @@ func main() { } func generateMapID(rng *rand.Rand) string { + return generateMapIDWithPrefix(rng, "map") +} + +func generateMapIDWithPrefix(rng *rand.Rand, prefix string) string { const chars = "abcdefghijklmnopqrstuvwxyz0123456789" b := make([]byte, 8) for i := range b { b[i] = chars[rng.Intn(len(chars))] } - return "map_" + string(b) + return prefix + "_" + string(b) } func generateMap(numPlayers, rows, cols int, wallDensity float64, numEnergyNodes int, rng *rand.Rand) *Map { diff --git a/cmd/acb-matchmaker/tickers.go b/cmd/acb-matchmaker/tickers.go index 57726cc..9a26c0c 100644 --- a/cmd/acb-matchmaker/tickers.go +++ b/cmd/acb-matchmaker/tickers.go @@ -348,11 +348,12 @@ func (m *Matchmaker) selectMapLRU(ctx context.Context, playerCount int, rng *ran return fmt.Sprintf("map_%d", seed%100000), rows, cols, seed } -// gridForPlayers returns default grid dimensions for a given player count, -// mirroring the formula in engine.ConfigForPlayers (~2000 tiles per player). +// gridForPlayers returns default grid dimensions for a given player count. +// For 2-player matches, uses 40x40 (down from 60x60) to increase encounter frequency. +// For 3+ players, targets ~2000 tiles per player. func gridForPlayers(n int) (rows, cols int) { if n <= 2 { - return 60, 60 + return 40, 40 } side := int(math.Sqrt(float64(2000 * n))) if side < 40 { diff --git a/cmd/acb-matchmaker/tickers_test.go b/cmd/acb-matchmaker/tickers_test.go index cd7629c..2eaaffb 100644 --- a/cmd/acb-matchmaker/tickers_test.go +++ b/cmd/acb-matchmaker/tickers_test.go @@ -187,7 +187,7 @@ func TestGridForPlayers(t *testing.T) { minArea int maxArea int }{ - {2, 3000, 4200}, // 60x60 = 3600 + {2, 1200, 2000}, // 40x40 = 1600 (reduced from 60x60 for combat density) {3, 4000, 6000}, {4, 5000, 8500}, {6, 7000, 12000}, diff --git a/engine/types.go b/engine/types.go index 3bbbe1b..4e548e7 100644 --- a/engine/types.go +++ b/engine/types.go @@ -182,8 +182,8 @@ type Config struct { // DefaultConfig returns the default game configuration. func DefaultConfig() Config { return Config{ - Rows: 60, - Cols: 60, + Rows: 40, + Cols: 40, MaxTurns: 500, VisionRadius2: 49, // ~7 tiles AttackRadius2: 5, // ~2.24 tiles @@ -199,7 +199,8 @@ func DefaultConfig() Config { } // ConfigForPlayers returns a config scaled for the given player count and cores per player. -// Uses ~1800-2000 tiles per player (following aichallenge Ants sizing). +// For 2 players, uses 40x40 (800 tiles per player) to increase encounter frequency. +// For 3+ players, uses ~2000 tiles per player (following aichallenge Ants sizing). func ConfigForPlayers(numPlayers, coresPerPlayer int) Config { cfg := DefaultConfig() cfg.CoresPerPlayer = coresPerPlayer @@ -207,14 +208,19 @@ func ConfigForPlayers(numPlayers, coresPerPlayer int) Config { cfg.CoresPerPlayer = 1 } - // Scale grid: ~2000 tiles per player, square grid - areaPerPlayer := 2000 + // Scale grid: smaller maps for 2-player, ~2000 tiles/player for 3+ players + var areaPerPlayer int + if numPlayers == 2 { + areaPerPlayer = 800 // 40x40 for 2 players + } else { + areaPerPlayer = 2000 + } totalArea := areaPerPlayer * numPlayers side := int(math.Sqrt(float64(totalArea))) // Clamp to valid range - if side < 40 { - side = 40 + if side < 30 { + side = 30 } if side > 200 { side = 200