환각/temperature등 llm 설정을 위한 test 파일

테스트 결과가 llm 에 반영되어 더이상 메인 브랜치에 존재할 이유 x

import ollama
import json
import re

# 1. 로컬 DB 파일 읽어오기
try:
    with open('items.json', 'r', encoding='utf-8') as f:
        db = json.load(f)
except FileNotFoundError:
    print("🚨 items.json 파일을 찾을 수 없습니다!")
    exit()

def get_card_info(card_name):
    """DB에서 특정 카드 정보를 찾아 반환하는 헬퍼 함수"""
    for card in db.get("cards", []):
        if card["name"].lower() == card_name.lower():
            return card
    return None

# ==========================================
# 🎮 게임 클라이언트 상태 (파이썬이 관리하는 영역)
# ==========================================
energy = 3
hand = ["Swivel+", "Bash", "Dropkick", "Strike"]
buffs = [] # 파이썬이 실시간으로 추적하는 캐릭터의 버프 상태
enemies_state = "Enemy A (17 HP), Enemy B (15 HP), Enemy C (19 HP)"

print("⚔️ 1-Step AI 에이전트 턴 시작 ⚔️\\n" + "="*50)

turn_step = 1

# 에너지가 남아있고 패에 카드가 있는 동안 계속 루프(핑퐁)를 돕니다.
while energy > 0 and hand:
    print(f"\\n▶ [Step {turn_step}] 파이썬 상태 -> 에너지: {energy} | 버프: {buffs} | 패: {hand}")

    # 2. 현재 내 '패(Hand)'에 있는 카드 정보만 DB에서 추출
    db_text = "[Cards Database]\\n"
    seen = set()
    for c_name in hand:
        if c_name.lower() not in seen:
            seen.add(c_name.lower())
            info = get_card_info(c_name)
            if info:
                desc = info.get('description', '').replace('\\n', ' ')
                db_text += f"- {info['name']} (Type: {info.get('type')}, Cost: {info.get('cost')}): {desc}\\n"

    db_text += "\\n[Game Mechanics]\\n- [R]: Represents 1 Energy.\\n- Vulnerable: Take 50% more damage from Attacks.\\n"

    # 3. 1-Step 전용 범용 프롬프트 (미래 계획 금지, 당장 낼 1장만 선택)
    prompt = f"""
    {db_text}

    [Current State]
    - Energy: {energy}
    - Buffs: {', '.join(buffs) if buffs else 'None'}
    - Enemies: {enemies_state}
    - Hand: {', '.join(hand)}

    [Task]
    You are an expert Slay the Spire AI. Choose EXACTLY ONE card to play.
    To avoid mistakes, you MUST fill out the Reasoning section exactly in this order:

    Output EXACTLY in this format:
    Reasoning:
    1. Buff Check: Do I have 'Next Attack costs 0'? (Yes/No). If Yes, list the original costs of Attack cards in my hand to find the highest one.
    2. Vulnerable Check: Are any enemies Vulnerable right now? (Yes/No).
    3. Conclusion: Based on 1 and 2, the most logical card is [Card Name].
    Selected Card: [Card Name]
    Target: [Enemy A/B/C or Self]
    """

    # 4. LLM 호출
    response = ollama.chat(
        model='my_sts_qwen', 
        messages=[
            {'role': 'system', 'content': 'You are a precise Slay the Spire AI.'},
            {'role': 'user', 'content': prompt}
        ],
        options={'temperature': 0.0, 'num_predict': 256}
    )

    content = response['message']['content']
    print(f"🤖 LLM의 사고 과정:\\n{content.strip()}\\n")

    # 5. 파이썬의 결과 파싱 및 게임 상태 업데이트 (규칙 엔진 역할)
    match = re.search(r"Selected Card:\\s*(.+)", content, re.IGNORECASE)
    if match:
        selected_card = match.group(1).strip()
        
        # 패에 있는 카드인지 확인
        valid_card = None
        for c in hand:
            if c.lower() in selected_card.lower():
                valid_card = c
                break

        if not valid_card:
            print(f"🚨 LLM이 패에 없는 카드({selected_card})를 선택했습니다. 턴 강제 종료.")
            break

        # 카드 코스트 계산 및 버프 적용 로직
        info = get_card_info(valid_card)
        cost = int(info['cost']) if info['cost'].isdigit() else 0
        
        if info['type'] == 'Attack' and "Next Attack costs 0" in buffs:
            cost = 0
            buffs.remove("Next Attack costs 0")
            print("   ✨ 시스템: 버프 발동! 이번 공격 카드의 코스트가 0으로 처리됩니다.")

        # 에너지 차감 및 패에서 카드 제거
        if energy >= cost:
            energy -= cost
            hand.remove(valid_card)
            print(f"   ✅ 시스템: {valid_card} 사용 완료! (소모 에너지: {cost}, 남은 에너지: {energy})")
            
            # Swivel+ 를 냈을 경우 파이썬이 버프를 등록해 줌
            if valid_card == "Swivel+":
                buffs.append("Next Attack costs 0")
                print("   ✨ 시스템: 플레이어에게 'Next Attack costs 0' 버프가 부여되었습니다.")
        else:
            print("🚨 에너지가 부족하여 카드를 낼 수 없습니다. 턴 강제 종료.")
            break
    else:
        print("🚨 파싱 실패 (Selected Card 양식을 지키지 않음).")
        break

    turn_step += 1
    print("-" * 50)

print("\\n🏁 턴 종료! 더 이상 낼 카드가 없거나 에너지가 없습니다.")