remove dead gauntlet test files, prune cleanser tests from test_bot_gauntlet
This commit is contained in:
+11
-181
@@ -1,13 +1,11 @@
|
||||
extends GutTest
|
||||
|
||||
# =============================================================================
|
||||
# Test: Bot AI — Sticky Avoidance & Pathfinding Candy Survival #075]
|
||||
# Test: Bot AI — Sticky Avoidance & Pathfinding [Candy Survival]
|
||||
# Verifies the bot's strategic planner correctly:
|
||||
# • Detects Candy Survival mode and exposes helpers.
|
||||
# • Rejects sticky / telegraphed cells in _is_valid_move_target.
|
||||
# • Activates Cleanser when boxed in or standing on telegraphed ground.
|
||||
# • Honours an active Cleanser (treats sticky cells as passable).
|
||||
# • Calls rpc_activate_cleanser on the CandySurvivalManager when triggered.
|
||||
# • Uses CandySurvivalManager.is_sticky_cell() authority.
|
||||
# =============================================================================
|
||||
|
||||
const BotStrategicPlanner = preload("res://scripts/bot_strategic_planner.gd")
|
||||
@@ -27,21 +25,10 @@ class StubActor extends Node3D:
|
||||
return false
|
||||
|
||||
class StubCandySurvivalManager extends Node:
|
||||
# Mimics the slice of CandySurvivalManager API the bot planner depends on.
|
||||
var sticky_map: Dictionary = {} # Vector2i -> true
|
||||
var player_cleansers: Dictionary = {} # peer_id -> int
|
||||
var cleanser_active: Dictionary = {} # peer_id -> true
|
||||
var activate_rpc_calls: Array = [] # recorded [peer_id]
|
||||
|
||||
var sticky_map: Dictionary = {}
|
||||
func is_sticky_cell(pos: Vector2i) -> bool:
|
||||
return sticky_map.get(pos, false)
|
||||
|
||||
func is_cleanser_active(pid: int) -> bool:
|
||||
return cleanser_active.get(pid, false)
|
||||
|
||||
func rpc_activate_cleanser(pid: int) -> void:
|
||||
activate_rpc_calls.append(pid)
|
||||
|
||||
# ---- Test fixture -----------------------------------------------------------
|
||||
|
||||
var main_node: Node
|
||||
@@ -52,8 +39,6 @@ var planner: RefCounted
|
||||
|
||||
func before_each():
|
||||
main_node = Node.new()
|
||||
# Unique name per test to avoid collisions with previous runs that haven't
|
||||
# been fully freed yet.
|
||||
main_node.name = "BotTestMain_%d" % Time.get_ticks_usec()
|
||||
get_tree().get_root().add_child(main_node)
|
||||
|
||||
@@ -61,8 +46,6 @@ func before_each():
|
||||
gridmap.name = "EnhancedGridMap"
|
||||
var nwi: Array[int] = [4]
|
||||
gridmap.non_walkable_items = nwi
|
||||
# Pre-seed Floor 0 with a walkable tile (id 1) for every cell, so the bot's
|
||||
# `_is_valid_move_target` Floor 0 check passes by default.
|
||||
for x in range(20):
|
||||
for z in range(20):
|
||||
gridmap.set_cell_item(Vector3i(x, 0, z), 1)
|
||||
@@ -80,7 +63,6 @@ func before_each():
|
||||
planner = BotStrategicPlanner.new(actor, gridmap)
|
||||
planner.candy_survival_manager_override = candy_survival_manager
|
||||
|
||||
# Default to Candy Survival mode for these tests.
|
||||
LobbyManager.game_mode = "Candy Survival"
|
||||
|
||||
func after_each():
|
||||
@@ -90,7 +72,6 @@ func after_each():
|
||||
planner = null
|
||||
candy_survival_manager = null
|
||||
gridmap = null
|
||||
# Reset lobby mode so other tests aren't affected.
|
||||
LobbyManager.game_mode = "Freemode"
|
||||
|
||||
# =============================================================================
|
||||
@@ -117,20 +98,19 @@ func test_get_candy_survival_manager_resolves_from_main():
|
||||
|
||||
func test_overlay_unsafe_false_on_empty_layer2():
|
||||
assert_false(planner._is_overlay_unsafe(Vector2i(3, 3)),
|
||||
"Empty layer 2 → safe")
|
||||
"Empty layer 2 -> safe")
|
||||
|
||||
func test_overlay_unsafe_true_for_sticky_tile():
|
||||
gridmap.set_cell_item(Vector3i(3, 2, 3), 17) # TILE_STICKY
|
||||
gridmap.set_cell_item(Vector3i(3, 2, 3), 17)
|
||||
assert_true(planner._is_overlay_unsafe(Vector2i(3, 3)),
|
||||
"Sticky overlay is unsafe")
|
||||
|
||||
func test_overlay_unsafe_true_for_telegraph_tile():
|
||||
gridmap.set_cell_item(Vector3i(4, 2, 4), 18) # TILE_TELEGRAPH
|
||||
gridmap.set_cell_item(Vector3i(4, 2, 4), 18)
|
||||
assert_true(planner._is_overlay_unsafe(Vector2i(4, 4)),
|
||||
"Telegraph overlay is unsafe")
|
||||
|
||||
func test_overlay_unsafe_ignores_layer0_and_layer1():
|
||||
# Sticky value on the wrong layer should NOT be flagged as unsafe.
|
||||
gridmap.set_cell_item(Vector3i(3, 0, 3), 17)
|
||||
gridmap.set_cell_item(Vector3i(3, 1, 3), 17)
|
||||
assert_false(planner._is_overlay_unsafe(Vector2i(3, 3)),
|
||||
@@ -140,13 +120,12 @@ func test_overlay_unsafe_ignores_layer0_and_layer1():
|
||||
# _is_valid_move_target integration
|
||||
# =============================================================================
|
||||
|
||||
func test_valid_move_target_rejects_sticky_in_gauntlet():
|
||||
# Make a sticky cell pass all other checks (valid position, walkable floor).
|
||||
func test_valid_move_target_rejects_sticky_in_candy_survival():
|
||||
gridmap.set_cell_item(Vector3i(3, 2, 3), 17)
|
||||
assert_false(planner._is_valid_move_target(Vector2i(3, 3)),
|
||||
"Sticky cell rejected in Candy Survival mode")
|
||||
|
||||
func test_valid_move_target_rejects_telegraphed_in_gauntlet():
|
||||
func test_valid_move_target_rejects_telegraphed_in_candy_survival():
|
||||
gridmap.set_cell_item(Vector3i(5, 2, 5), 18)
|
||||
assert_false(planner._is_valid_move_target(Vector2i(5, 5)),
|
||||
"Telegraphed cell rejected in Candy Survival mode")
|
||||
@@ -156,36 +135,24 @@ func test_valid_move_target_accepts_clean_cells():
|
||||
"Clean cell accepted")
|
||||
|
||||
func test_valid_move_target_ignores_players_when_requested():
|
||||
# Even a sticky cell is bypassed when ignore_players path skips safety.
|
||||
gridmap.set_cell_item(Vector3i(3, 2, 3), 17)
|
||||
# ignore_players=true is used by find_nearest_tile_of_type for tile pickup;
|
||||
# safety must still apply, so this should still be rejected.
|
||||
assert_false(planner._is_valid_move_target(Vector2i(3, 3), true),
|
||||
"Safety check still active with ignore_players=true")
|
||||
|
||||
func test_valid_move_target_outside_candy_survival_allows_sticky():
|
||||
# Outside Candy Survival, layer-2 sticky overlays are not safety-relevant.
|
||||
LobbyManager.game_mode = "Freemode"
|
||||
gridmap.set_cell_item(Vector3i(3, 2, 3), 17)
|
||||
assert_true(planner._is_valid_move_target(Vector2i(3, 3)),
|
||||
"Sticky overlay ignored in non-Candy Survival modes")
|
||||
|
||||
func test_valid_move_target_allows_sticky_when_cleanser_active():
|
||||
candy_survival_manager.cleanser_active[actor.peer_id] = true
|
||||
gridmap.set_cell_item(Vector3i(3, 2, 3), 17)
|
||||
assert_true(planner._is_valid_move_target(Vector2i(3, 3)),
|
||||
"Active Cleanser grants temporary immunity")
|
||||
|
||||
# =============================================================================
|
||||
# Sticky-cell awareness via CandySurvivalManager authority
|
||||
# =============================================================================
|
||||
|
||||
func test_valid_move_target_uses_candy_survival_manager_sticky_map():
|
||||
# Even if the gridmap overlay hasn't landed yet (RPC in flight), the
|
||||
# CandySurvivalManager's authoritative sticky_cells map must block the move.
|
||||
candy_survival_manager.sticky_map[Vector2i(7, 7)] = true
|
||||
assert_false(planner._is_valid_move_target(Vector2i(7, 7)),
|
||||
"Manager's sticky map blocks moves before overlay tiles land")
|
||||
"Manager's sticky map blocks moves")
|
||||
|
||||
# =============================================================================
|
||||
# _count_unsafe_neighbors
|
||||
@@ -203,144 +170,7 @@ func test_count_unsafe_neighbors_four_when_surrounded():
|
||||
"All four neighbors sticky")
|
||||
|
||||
func test_count_unsafe_neighbors_partial_box():
|
||||
gridmap.set_cell_item(Vector3i(6, 2, 5), 17) # east
|
||||
gridmap.set_cell_item(Vector3i(5, 2, 6), 17) # south
|
||||
gridmap.set_cell_item(Vector3i(6, 2, 5), 17)
|
||||
gridmap.set_cell_item(Vector3i(5, 2, 6), 17)
|
||||
assert_eq(planner._count_unsafe_neighbors(Vector2i(5, 5)), 2,
|
||||
"Two unsafe neighbors")
|
||||
|
||||
# =============================================================================
|
||||
# should_activate_cleanser_now
|
||||
# =============================================================================
|
||||
|
||||
func test_should_activate_cleanser_false_without_charge():
|
||||
actor.current_position = Vector2i(5, 5)
|
||||
for d in [Vector2i(1, 0), Vector2i(-1, 0), Vector2i(0, 1), Vector2i(0, -1)]:
|
||||
var n = Vector2i(5, 5) + d
|
||||
gridmap.set_cell_item(Vector3i(n.x, 2, n.y), 17)
|
||||
assert_false(planner.should_activate_cleanser_now(),
|
||||
"Trapped but no charge → cannot activate")
|
||||
|
||||
func test_should_activate_cleanser_true_when_surrounded():
|
||||
candy_survival_manager.player_cleansers[actor.peer_id] = 1
|
||||
actor.current_position = Vector2i(5, 5)
|
||||
for d in [Vector2i(1, 0), Vector2i(-1, 0), Vector2i(0, 1), Vector2i(0, -1)]:
|
||||
var n = Vector2i(5, 5) + d
|
||||
gridmap.set_cell_item(Vector3i(n.x, 2, n.y), 17)
|
||||
assert_true(planner.should_activate_cleanser_now(),
|
||||
"Trapped with charge → activate Cleanser")
|
||||
|
||||
func test_should_activate_cleanser_true_when_on_telegraphed():
|
||||
candy_survival_manager.player_cleansers[actor.peer_id] = 1
|
||||
actor.current_position = Vector2i(5, 5)
|
||||
gridmap.set_cell_item(Vector3i(5, 2, 5), 18) # bot standing on telegraph
|
||||
# 3+ unsafe neighbors required by spec; add three.
|
||||
for d in [Vector2i(1, 0), Vector2i(-1, 0), Vector2i(0, 1)]:
|
||||
var n = Vector2i(5, 5) + d
|
||||
gridmap.set_cell_item(Vector3i(n.x, 2, n.y), 17)
|
||||
assert_true(planner.should_activate_cleanser_now(),
|
||||
"Standing on telegraph with 3 sticky neighbors → activate Cleanser")
|
||||
|
||||
func test_should_activate_cleanser_false_when_already_active():
|
||||
candy_survival_manager.player_cleansers[actor.peer_id] = 1
|
||||
candy_survival_manager.cleanser_active[actor.peer_id] = true
|
||||
actor.current_position = Vector2i(5, 5)
|
||||
for d in [Vector2i(1, 0), Vector2i(-1, 0), Vector2i(0, 1), Vector2i(0, -1)]:
|
||||
var n = Vector2i(5, 5) + d
|
||||
gridmap.set_cell_item(Vector3i(n.x, 2, n.y), 17)
|
||||
assert_false(planner.should_activate_cleanser_now(),
|
||||
"Already active → don't re-fire")
|
||||
|
||||
func test_should_activate_cleanser_false_outside_gauntlet():
|
||||
LobbyManager.game_mode = "Stop n Go"
|
||||
candy_survival_manager.player_cleansers[actor.peer_id] = 1
|
||||
actor.current_position = Vector2i(5, 5)
|
||||
for d in [Vector2i(1, 0), Vector2i(-1, 0), Vector2i(0, 1), Vector2i(0, -1)]:
|
||||
var n = Vector2i(5, 5) + d
|
||||
gridmap.set_cell_item(Vector3i(n.x, 2, n.y), 17)
|
||||
assert_false(planner.should_activate_cleanser_now(),
|
||||
"Outside Candy Survival → never auto-activate Cleanser")
|
||||
|
||||
func test_should_activate_cleanser_false_when_not_trapped():
|
||||
candy_survival_manager.player_cleansers[actor.peer_id] = 1
|
||||
actor.current_position = Vector2i(5, 5)
|
||||
# No sticky neighbors, plenty of room.
|
||||
assert_false(planner.should_activate_cleanser_now(),
|
||||
"Open field → no reason to burn Cleanser")
|
||||
|
||||
# =============================================================================
|
||||
# Cleanser charge helpers
|
||||
# =============================================================================
|
||||
|
||||
func test_bot_has_cleanser_charge_false_when_empty():
|
||||
assert_false(planner._bot_has_cleanser_charge(), "Empty by default")
|
||||
|
||||
func test_bot_has_cleanser_charge_true_when_granted():
|
||||
candy_survival_manager.player_cleansers[actor.peer_id] = 1
|
||||
assert_true(planner._bot_has_cleanser_charge(), "Charge granted")
|
||||
|
||||
func test_is_bot_cleanser_active_reflects_manager():
|
||||
assert_false(planner._is_bot_cleanser_active(), "Inactive by default")
|
||||
candy_survival_manager.cleanser_active[actor.peer_id] = true
|
||||
assert_true(planner._is_bot_cleanser_active(), "Manager reports active")
|
||||
|
||||
# =============================================================================
|
||||
# BotController → CandySurvivalManager RPC integration
|
||||
# =============================================================================
|
||||
|
||||
func test_bot_controller_requests_cleanser_when_trapped():
|
||||
var BotController = load("res://scripts/bot_controller.gd")
|
||||
var ctrl = BotController.new()
|
||||
# Attach as a child of the actor so _ready() resolves get_parent() correctly.
|
||||
actor.add_child(ctrl)
|
||||
ctrl.strategic_planner = planner
|
||||
ctrl.actor = actor
|
||||
|
||||
candy_survival_manager.player_cleansers[actor.peer_id] = 1
|
||||
actor.current_position = Vector2i(5, 5)
|
||||
for d in [Vector2i(1, 0), Vector2i(-1, 0), Vector2i(0, 1), Vector2i(0, -1)]:
|
||||
var n = Vector2i(5, 5) + d
|
||||
gridmap.set_cell_item(Vector3i(n.x, 2, n.y), 17)
|
||||
|
||||
var requested = ctrl._try_activate_cleanser()
|
||||
assert_true(requested, "Controller requests Cleanser when trapped")
|
||||
assert_eq(candy_survival_manager.activate_rpc_calls.size(), 1,
|
||||
"RPC called exactly once")
|
||||
assert_eq(candy_survival_manager.activate_rpc_calls[0], actor.peer_id,
|
||||
"Correct peer id sent")
|
||||
|
||||
ctrl.queue_free()
|
||||
|
||||
func test_bot_controller_does_not_request_when_safe():
|
||||
var BotController = load("res://scripts/bot_controller.gd")
|
||||
var ctrl = BotController.new()
|
||||
actor.add_child(ctrl)
|
||||
ctrl.strategic_planner = planner
|
||||
ctrl.actor = actor
|
||||
|
||||
candy_survival_manager.player_cleansers[actor.peer_id] = 1
|
||||
# No sticky anywhere.
|
||||
var requested = ctrl._try_activate_cleanser()
|
||||
assert_false(requested, "No request when not trapped")
|
||||
assert_eq(candy_survival_manager.activate_rpc_calls.size(), 0,
|
||||
"No RPC fired")
|
||||
|
||||
ctrl.queue_free()
|
||||
|
||||
func test_bot_controller_skips_cleanser_outside_gauntlet():
|
||||
var BotController = load("res://scripts/bot_controller.gd")
|
||||
var ctrl = BotController.new()
|
||||
actor.add_child(ctrl)
|
||||
ctrl.strategic_planner = planner
|
||||
ctrl.actor = actor
|
||||
|
||||
LobbyManager.game_mode = "Stop n Go"
|
||||
candy_survival_manager.player_cleansers[actor.peer_id] = 1
|
||||
actor.current_position = Vector2i(5, 5)
|
||||
for d in [Vector2i(1, 0), Vector2i(-1, 0), Vector2i(0, 1), Vector2i(0, -1)]:
|
||||
var n = Vector2i(5, 5) + d
|
||||
gridmap.set_cell_item(Vector3i(n.x, 2, n.y), 17)
|
||||
|
||||
var requested = ctrl._try_activate_cleanser()
|
||||
assert_false(requested, "No request outside Candy Survival")
|
||||
|
||||
ctrl.queue_free()
|
||||
Reference in New Issue
Block a user