Files
game-cards/tests/run_validation.gd

158 lines
5.7 KiB
GDScript

extends Node
func _ready():
print("=== Guandan Card Game - Core Logic Validation ===\n")
_test_card()
_test_deck()
_test_hand_evaluator()
_test_rule_engine()
_test_game_state()
_test_ai()
print("\n=== All validation checks passed ===")
get_tree().quit(0)
func _assert_eq(actual, expected, name: String):
if actual == expected:
print(" PASS: %s" % name)
else:
printerr(" FAIL: %s (expected %s, got %s)" % [name, expected, actual])
func _assert_true(condition: bool, name: String):
_assert_eq(condition, true, name)
func _assert_false(condition: bool, name: String):
_assert_eq(condition, false, name)
func _make_card(orig_id: int, deck_idx: int = 0) -> Card:
var suit: int
var rank: int
if orig_id == 52:
suit = 4; rank = 15
elif orig_id == 53:
suit = 5; rank = 16
else:
suit = orig_id % 4
rank = 2 + (orig_id / 4)
var c := Card.create(orig_id, suit, rank)
c.card_id = Card.card_id_from_deck(orig_id, deck_idx)
return c
func _make_cards(ids: Array) -> Array[Card]:
var result: Array[Card] = []
for spec in ids:
if spec is int:
result.append(_make_card(spec as int))
elif spec is Array:
result.append(_make_card(spec[0] as int, spec[1] as int))
return result
func _test_card():
print("--- Card Tests ---")
var c := Card.create(0, 2, 10)
_assert_eq(c.card_id, 0, "card_id")
_assert_eq(c.suit(), 2, "suit")
_assert_eq(c.rank(), 10, "rank")
var a := Card.create(0, 2, 10)
var b := Card.create(1, 2, 10)
_assert_true(a.matches(b), "matches (same suit+rank)")
_assert_false(a.equals(b), "equals (different card_id)")
var low := Card.create(0, 0, 5)
var high := Card.create(1, 1, 14)
_assert_true(low.compare_to(high) < 0, "compare_to (5 < A)")
func _test_deck():
print("--- Deck Tests ---")
var deck := Deck.create()
_assert_eq(deck.remaining(), 108, "deck size 108")
var hand := deck.deal(27)
_assert_eq(hand.size(), 27, "deal 27 cards")
_assert_eq(deck.remaining(), 81, "remaining 81 after deal")
var d1 := Deck.create(42)
var d2 := Deck.create(42)
var all1 := d1.deal(27)
var all2 := d2.deal(27)
var deterministic := true
for i in range(27):
if all1[i].card_id != all2[i].card_id:
deterministic = false
_assert_true(deterministic, "deterministic shuffle (seed=42)")
func _test_hand_evaluator():
print("--- HandEvaluator Tests ---")
var config := RuleConfig.standard()
var single := HandEvaluator.evaluate(_make_cards([0]), 5, config)
_assert_eq(single.type, 0, "single card type")
var cards: Array[Card] = [_make_card(0, 0), _make_card(0, 1)]
var pair := HandEvaluator.evaluate(cards, 5, config)
_assert_eq(pair.type, 1, "pair type")
var straight := HandEvaluator.evaluate(_make_cards([4, 8, 12, 16, 20]), 5, config)
_assert_eq(straight.type, 4, "straight type (3-7)")
_assert_eq(straight.primary_rank, 7, "straight max rank=7")
var bomb_cards: Array[Card] = [_make_card(0, 0), _make_card(1, 0), _make_card(0, 1), _make_card(1, 1)]
var bomb := HandEvaluator.evaluate(bomb_cards, 5, config)
_assert_eq(bomb.type, 8, "bomb type (4 twos)")
_assert_true(bomb.is_pure_bomb, "is_pure_bomb")
var rocket_cards: Array[Card] = [_make_card(52, 0), _make_card(52, 1), _make_card(53, 0), _make_card(53, 1)]
var rocket := HandEvaluator.evaluate(rocket_cards, 5, config)
_assert_eq(rocket.type, 9, "rocket type")
func _test_rule_engine():
print("--- RuleEngine Tests ---")
var config := RuleConfig.standard()
var hand: Array[Card] = [_make_card(0), _make_card(4)]
var single := HandEvaluator.evaluate(_make_cards([0]), 5, config)
var result := RuleEngine.can_play(hand, single, [], -1, 5, config)
_assert_true(result.ok, "can play on fresh table")
var pure := HandEvaluator.EvaluatedPlay.new()
pure.type = 8; pure.primary_rank = 10; pure.is_pure_bomb = true
var mixed := HandEvaluator.EvaluatedPlay.new()
mixed.type = 8; mixed.primary_rank = 10; mixed.is_pure_bomb = false
_assert_eq(RuleEngine.compare_bombs(pure, mixed, config), 1, "pure bomb beats mixed")
_assert_eq(RuleEngine.compare_bombs(mixed, pure, config), -1, "mixed bomb loses to pure")
var rocket := HandEvaluator.EvaluatedPlay.new()
rocket.type = 9; rocket.primary_rank = 999
_assert_eq(RuleEngine.compare(rocket, pure, config), 1, "rocket beats bomb")
func _test_game_state():
print("--- GameState Tests ---")
var gs := GameState.create(RuleConfig.standard(), 42)
_assert_eq(gs.seed, 42, "seed=42")
_assert_eq(gs.teams.size(), 2, "2 teams")
_assert_eq(gs.current_rank, 2, "start at level 2")
var deck := Deck.create(1)
gs.deal_cards(deck)
for i in range(4):
_assert_eq(gs.get_hand(i).size(), 27, "player %d got 27 cards" % i)
var t := Actions.Team.create_team(0, 0, 2)
_assert_eq(t.teammate_of(0), 2, "teammate_of(0)=2")
_assert_eq(t.teammate_of(2), 0, "teammate_of(2)=0")
func _test_ai():
print("--- AI Tests ---")
var config := RuleConfig.standard()
var hand := _make_cards([0])
var l1 := L1BasicAI.new()
var table: Array[HandEvaluator.EvaluatedPlay] = []
var decision := l1.decide(hand, table, 5, config)
_assert_true(decision.type > 0 or decision.type == -1, "L1 AI returns valid play or pass")
var l2 := L2RuleAI.new()
var decision2 := l2.decide(hand, table, 5, config)
_assert_true(decision2.type > 0 or decision2.type == -1, "L2 AI returns valid play or pass")
var hand2 := _make_cards([0, 4, 8, 12, 16])
var decision3 := l1.decide(hand2, table, 5, config)
_assert_true(decision3.type == 4, "L1 AI should play straight when possible on fresh table")