186 lines
8.0 KiB
GDScript
186 lines
8.0 KiB
GDScript
extends GutTest
|
|
|
|
# =============================================================================
|
|
# Test: Gauntlet Candidate Scoring System (v2) [Gauntlet #073]
|
|
# Covers each score component, camping accumulation, and full-formula
|
|
# composition. Runs headless (no multiplayer peer), so elapsed_time = 0 and
|
|
# the final-30s window is inactive unless a test sets elapsed_time directly.
|
|
# =============================================================================
|
|
|
|
const GauntletManager = preload("res://scripts/managers/gauntlet_manager.gd")
|
|
var manager
|
|
var main_mock: Node
|
|
var gridmap_mock: Node
|
|
|
|
func before_each():
|
|
main_mock = Node.new()
|
|
add_child(main_mock)
|
|
gridmap_mock = Node.new()
|
|
gridmap_mock.name = "EnhancedGridMap"
|
|
main_mock.add_child(gridmap_mock)
|
|
manager = GauntletManager.new()
|
|
main_mock.add_child(manager)
|
|
manager.initialize(main_mock, gridmap_mock)
|
|
manager.current_phase = 0
|
|
|
|
func after_each():
|
|
if main_mock:
|
|
main_mock.queue_free()
|
|
|
|
# =============================================================================
|
|
# LayerPriority
|
|
# =============================================================================
|
|
|
|
func test_layer_priority_matches_phase_weights():
|
|
manager.current_phase = 0
|
|
# Outer ring cell (corner-ish) gets the phase-0 outer weight (+60).
|
|
assert_eq(manager._score_layer_priority(Vector2i(2, 2)), 60.0, "Phase 0 outer = +60")
|
|
# Inner cell near center gets phase-0 inner weight (-40).
|
|
assert_eq(manager._score_layer_priority(Vector2i(9, 8)), -40.0, "Phase 0 inner = -40")
|
|
|
|
func test_layer_priority_phase3_inner():
|
|
manager.current_phase = 2
|
|
assert_eq(manager._score_layer_priority(Vector2i(9, 8)), 60.0, "Phase 2 inner = +60")
|
|
|
|
# =============================================================================
|
|
# StickyNeighbor
|
|
# =============================================================================
|
|
|
|
func test_sticky_neighbor_score_scales():
|
|
assert_eq(manager._score_sticky_neighbor(Vector2i(5, 5)), 0.0, "No neighbors = 0")
|
|
manager.sticky_cells[Vector2i(5, 6)] = true
|
|
assert_eq(manager._score_sticky_neighbor(Vector2i(5, 5)), 8.0, "One neighbor = +8")
|
|
|
|
func test_sticky_neighbor_score_capped():
|
|
# Surround (5,5) on all 8 sides → 8 * 8 = 64, capped at 64.
|
|
for dx in range(-1, 2):
|
|
for dz in range(-1, 2):
|
|
if dx == 0 and dz == 0:
|
|
continue
|
|
manager.sticky_cells[Vector2i(5 + dx, 5 + dz)] = true
|
|
assert_eq(manager._score_sticky_neighbor(Vector2i(5, 5)), 64.0, "Capped at +64")
|
|
|
|
# =============================================================================
|
|
# InwardPressure
|
|
# =============================================================================
|
|
|
|
func test_inward_pressure_higher_near_center():
|
|
manager.current_phase = 2
|
|
var near = manager._score_inward_pressure(Vector2i(8, 8)) # close to center
|
|
var far = manager._score_inward_pressure(Vector2i(1, 1)) # far corner
|
|
assert_true(near > far, "Inward pressure stronger near center")
|
|
|
|
func test_inward_pressure_phase_scaling():
|
|
# Same cell, later phase => higher inward pressure ceiling.
|
|
var pos := Vector2i(8, 8)
|
|
manager.current_phase = 0
|
|
var p0 = manager._score_inward_pressure(pos)
|
|
manager.current_phase = 2
|
|
var p2 = manager._score_inward_pressure(pos)
|
|
assert_true(p2 > p0, "Later phase pushes inward harder")
|
|
|
|
# =============================================================================
|
|
# PlayerPressure
|
|
# =============================================================================
|
|
|
|
func test_player_pressure_ring():
|
|
# 3 cells from a player → +20.
|
|
var players = [Vector2i(5, 5)]
|
|
assert_eq(manager._score_player_pressure(Vector2i(8, 5), players), 20.0, "2-4 cells away = +20")
|
|
|
|
func test_player_pressure_under_player_penalized():
|
|
var players = [Vector2i(5, 5)]
|
|
# elapsed_time 0, round 180 → not final window → directly under = -50.
|
|
assert_eq(manager._score_player_pressure(Vector2i(5, 5), players), -50.0, "Under player (early) = -50")
|
|
|
|
func test_player_pressure_under_player_final_window():
|
|
manager.elapsed_time = manager.gauntlet_round_duration() - 5.0 # within final 30s
|
|
var players = [Vector2i(5, 5)]
|
|
assert_eq(manager._score_player_pressure(Vector2i(5, 5), players), 10.0, "Under player (final) = +10")
|
|
|
|
func test_player_pressure_no_players():
|
|
assert_eq(manager._score_player_pressure(Vector2i(5, 5), []), 0.0, "No players = 0")
|
|
|
|
# =============================================================================
|
|
# ClusterGrowth
|
|
# =============================================================================
|
|
|
|
func test_cluster_growth_none():
|
|
assert_eq(manager._score_cluster_growth(Vector2i(5, 5)), 0.0, "No sticky neighbors = 0")
|
|
|
|
func test_cluster_growth_expand():
|
|
manager.sticky_cells[Vector2i(5, 6)] = true
|
|
assert_eq(manager._score_cluster_growth(Vector2i(5, 5)), 15.0, "Expanding cluster = +15")
|
|
|
|
func test_cluster_growth_connect():
|
|
manager.sticky_cells[Vector2i(4, 5)] = true
|
|
manager.sticky_cells[Vector2i(6, 5)] = true
|
|
manager.sticky_cells[Vector2i(5, 6)] = true
|
|
assert_eq(manager._score_cluster_growth(Vector2i(5, 5)), 25.0, "Connecting clusters = +25")
|
|
|
|
# =============================================================================
|
|
# CampingPressure
|
|
# =============================================================================
|
|
|
|
func test_camp_region_grouping():
|
|
assert_eq(manager._region_of(Vector2i(0, 0)), Vector2i(0, 0), "Cells 0-3 → region 0")
|
|
assert_eq(manager._region_of(Vector2i(5, 7)), Vector2i(1, 1), "Cells 4-7 → region 1")
|
|
|
|
func test_camping_pressure_thresholds():
|
|
var region: Vector2i = manager._region_of(Vector2i(8, 8))
|
|
manager._camp_tracking[1] = {"region": region, "time": 6.0}
|
|
assert_eq(manager._score_camping_pressure(Vector2i(8, 8)), 20.0, ">5s = +20")
|
|
manager._camp_tracking[1]["time"] = 9.0
|
|
assert_eq(manager._score_camping_pressure(Vector2i(8, 8)), 40.0, ">8s = +40")
|
|
manager._camp_tracking[1]["time"] = 11.0
|
|
assert_eq(manager._score_camping_pressure(Vector2i(8, 8)), 60.0, ">10s = +60")
|
|
|
|
func test_camping_pressure_none():
|
|
assert_eq(manager._score_camping_pressure(Vector2i(8, 8)), 0.0, "No camping = 0")
|
|
|
|
# =============================================================================
|
|
# Repetition
|
|
# =============================================================================
|
|
|
|
func test_repetition_penalty():
|
|
manager._last_tick_cells = [Vector2i(5, 5)]
|
|
assert_eq(manager._score_repetition(Vector2i(5, 6)), -30.0, "Adjacent to last tick = -30")
|
|
assert_eq(manager._score_repetition(Vector2i(15, 15)), 0.0, "Far from last tick = 0")
|
|
|
|
# =============================================================================
|
|
# PathSafety (soft penalty)
|
|
# =============================================================================
|
|
|
|
func test_path_safety_no_players_no_penalty():
|
|
assert_eq(manager._score_path_safety(Vector2i(5, 5)), 0.0, "No players = no penalty")
|
|
|
|
# =============================================================================
|
|
# Camp tracking accumulation
|
|
# =============================================================================
|
|
|
|
func test_camp_time_for_region_picks_max():
|
|
var region := Vector2i(1, 1)
|
|
manager._camp_tracking[1] = {"region": region, "time": 3.0}
|
|
manager._camp_tracking[2] = {"region": region, "time": 7.0}
|
|
assert_almost_eq(manager._camp_time_for_region(region), 7.0, 0.001, "Longest camp time wins")
|
|
|
|
# =============================================================================
|
|
# Full formula composition
|
|
# =============================================================================
|
|
|
|
func test_full_score_runs_and_is_finite():
|
|
var s = manager._calculate_candidate_score(Vector2i(5, 5), [])
|
|
assert_true(is_finite(s), "Full score is a finite number")
|
|
|
|
func test_full_score_rewards_sticky_cluster():
|
|
# A cell hugging an existing cluster should generally beat an isolated one.
|
|
# Average several samples to wash out RandomNoise (±20).
|
|
manager.sticky_cells[Vector2i(5, 6)] = true
|
|
manager.sticky_cells[Vector2i(6, 5)] = true
|
|
var clustered := 0.0
|
|
var isolated := 0.0
|
|
for _i in range(40):
|
|
clustered += manager._calculate_candidate_score(Vector2i(5, 5), [])
|
|
isolated += manager._calculate_candidate_score(Vector2i(15, 15), [])
|
|
assert_true(clustered > isolated, "Clustered cell scores higher on average")
|