rabukasim / tools /debug /scripts /repro_shioriko.py
trioskosmos's picture
Upload folder using huggingface_hub
463f868 verified
import os
import sys
# Add project root to path
sys.path.append(os.getcwd())
from engine.game.enums import Phase
from engine.game.game_state import GameState
from engine.models.ability import Ability, AbilityCostType, Cost, Effect, EffectType, TargetType
from engine.models.card import MemberCard
def test_shioriko_ability():
# Setup card ID 264 (Shioriko PL!N-bp1-010-R)
# raw_text: {{toujyou.png|登場}}手札を1枚控え室に置いてもよい:自分のデッキの上からカードを3枚見る その中から1枚を手札に加え、残りを控え室に置く
gs = GameState(verbose=True)
p0 = gs.players[0]
# 1. Setup deck and stage
p0.main_deck = [1001, 1002, 1003, 1004, 1005]
p0.energy_zone = [5001, 5002] # Add real energy cards
p0.hand = [264, 999] # 999 is fodder for discard cost
# Mock Shioriko card in DB
shioriko_ability = Ability(
trigger=1, # ON_PLAY
effects=[
Effect(EffectType.LOOK_DECK, 3, TargetType.SELF),
Effect(EffectType.LOOK_AND_CHOOSE, 1, TargetType.SELF, {"reason": "look_and_choose"}),
],
costs=[Cost(type=AbilityCostType.DISCARD_HAND, value=1, is_optional=True)],
raw_text="登場時手札を1枚控え室に置いてもよい:デッキの上から3枚見て1枚手札に加え、残りを控え室に置く",
)
shioriko = MemberCard(
card_id=264,
card_no="PL!N-bp1-010-R",
name="三船栞子",
cost=1,
hearts=[1, 0, 0, 0, 0, 0, 0],
blade_hearts=[0, 0, 0, 0, 0, 0],
blades=1,
abilities=[shioriko_ability],
)
GameState.member_db[264] = shioriko
# 2. Play Shioriko
gs.phase = Phase.MAIN
gs.current_player = 0
# Action 1: Play member from hand index 0 (Shioriko) to slot 0
print(f"Starting Phase: {gs.phase.name} ({gs.phase.value})")
gs = gs.step(1) # Play Shioriko to slot 0 (1 + 0*3 + 0 = 1)
print(f"End Phase: {gs.phase.name} ({gs.phase.value})")
print(f"Pending Choices: {[{'type': pc[0], 'reason': pc[1].get('reason')} for pc in gs.pending_choices]}")
# Check if discard choice is present
if not gs.pending_choices or gs.pending_choices[0][0] != "TARGET_HAND":
print("FAIL: No discard choice presented")
return
# Scenario A: Cancel cost
gs_cancel = gs.copy()
gs_cancel.step(0) # Action 0 = Pass/Cancel optional cost
print("\nScenario A: Cancel Cost")
print(f"Pending Effects: {len(gs_cancel.pending_effects)}")
print(f"Pending Choices: {len(gs_cancel.pending_choices)}")
print(f"Deck Count: {len(gs_cancel.players[0].main_deck)}")
if len(gs_cancel.pending_effects) == 0 and len(gs_cancel.players[0].main_deck) == 5:
print("PASS: Ability aborted correctly")
else:
print("FAIL: Ability did not abort or deck was touched")
# Scenario B: Pay cost
gs_pay = gs.copy()
# Action 501: Discard card at index 1 (999)
# Hand is [264 (played but maybe still in list during step?), 999]
# Actually hand.pop(0) happens in play_member. So hand is [999].
gs_pay.step(500) # Discard card 999
print("\nScenario B: Pay Cost")
print(f"Pending Choices: {len(gs_pay.pending_choices)}")
if gs_pay.pending_choices and gs_pay.pending_choices[0][0] == "SELECT_FROM_LIST":
print("PASS: SELECT_FROM_LIST presented")
else:
print(f"FAIL: Expected SELECT_FROM_LIST, got {gs_pay.pending_choices}")
return
# 3. Verify SELECT_FROM_LIST cards
cards = gs_pay.pending_choices[0][1].get("cards", [])
print(f"Looked Cards: {cards}")
if cards == [1001, 1002, 1003]:
print("PASS: Correct cards looked at")
else:
print("FAIL: Incorrect cards in list")
# 4. Pick one (Action 601: index 1 -> 1002)
gs_pay.step(601)
print("\nResult of picking 1002")
print(f"Hand: {gs_pay.players[0].hand}")
print(f"Discard: {gs_pay.players[0].discard}")
print(f"Deck Count: {len(gs_pay.players[0].main_deck)}")
if 1002 in gs_pay.players[0].hand and 1001 in gs_pay.players[0].discard and 1003 in gs_pay.players[0].discard:
print("PASS: Card added to hand and others discarded")
else:
print("FAIL: Card movement incorrect")
# 5. Check Rule Log
print("\nRule Log entries (last 5):")
for entry in gs_pay.rule_log[-5:]:
print(f" {entry}")
if __name__ == "__main__":
test_shioriko_ability()