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
This commit is contained in:
parent
16d474aceb
commit
18ac1ff2b4
5 changed files with 45 additions and 17 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue