ThreeKingdomsSlingshot/Assets/Scripts/Runtime/AI/AiWeights.cs

93 lines
3.5 KiB
C#
Raw Permalink Normal View History

지형 기믹 레이어(PD #1097 세션 D) + 병종 규칙 개정 2건 · 예측 시뮬레이션 적 AI(PD #1098) - 데이터: Assets/Data/Gimmicks/{gimmicks,stage_gimmicks,tutorial_tips}.csv + Assets/Data/AI/ai_weights.csv(기획 tables/ 사본) → 메뉴 TKS/Import Gimmicks(검증 · 오류 시 자산 불변) → Resources/Gimmicks/GimmickDb(16)·StageGimmickTable(16 + 팁 3) · Resources/AI/AiWeights(32) - 레이어: GimmickLayer(전투 시작 = 스테이지 배치 · 배경 위 유닛 아래 · 원/사각/다각 · 색 도형 + 글자 · 내구 핍 · 강 콜라이더 = 다리 구간 제외 · 겹친 유닛 보정) · 장애물 = 병종별 내구 피해·튕김·창 목책 밀기·바위 굴림·기병 정지 · 투사체 pass/block/destroy · 폭약 광역(아군 포함)+밀기+불 · 책사 광역 덤불 제거 · 강 낙하 - 지대: 경로 스윕(독 1→2→3 % · 늪 ×2 · 불 10 % · 빙판 미끄러짐 · 고지 · 안개 · 군기 · 함정) · 양 진영 턴 시작 훅 - 규칙 개정: 보병 튕김 중 다른 적과 연쇄 1회 · 창병 반작용(spearRecoilRatio · 밀며 전진 폐기) · 기존 테스트 기대값 갱신 - 적 AI: Runtime/AI(Sim 가상 실행 · TacticalAI 후보·점수·난이도·턴 운영 · 1부 보스 액티브) · 조준선 = 가상 실행 예상 궤적·기믹 반응·지대 띠 · TKS/Gimmick Painter · 캡처 GimmickImporter.Capture - 검증: 컴파일 0 · 플레이모드 113/113(신규 26) · console error 0 · 적 10기 턴 결정 62 ms Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 16:20:07 +00:00
using System;
using System.Collections.Generic;
using System.Globalization;
using UnityEngine;
namespace TKS
{
/// <summary>
/// 적 AI 점수 가중치(PD #1098 · 전술규칙_적AI_기획서 §2-3 · SOT = Assets/Data/AI/ai_weights.csv = 기획 tables/ 사본) →
/// Resources/AI/AiWeights(메뉴 TKS/Import Gimmicks 가 함께 임포트). 코드는 키 이름만 안다(C45).
/// </summary>
public class AiWeights : ScriptableObject
{
public const string CsvPath = "Data/AI/ai_weights.csv"; // Assets/ 아래
public const string ResourcePath = "AI/AiWeights";
/// <summary>코드가 읽는 키(표에 없으면 임포트 오류).</summary>
public static readonly string[] Keys =
{
"dmg_player", "kill_base", "kill_hp_ratio", "dmg_own", "gimmick_dest_bonus", "chain", "support_reach", "pierce_hit",
지형 기믹 레이어(PD #1097 세션 D) + 병종 규칙 개정 2건 · 예측 시뮬레이션 적 AI(PD #1098) - 데이터: Assets/Data/Gimmicks/{gimmicks,stage_gimmicks,tutorial_tips}.csv + Assets/Data/AI/ai_weights.csv(기획 tables/ 사본) → 메뉴 TKS/Import Gimmicks(검증 · 오류 시 자산 불변) → Resources/Gimmicks/GimmickDb(16)·StageGimmickTable(16 + 팁 3) · Resources/AI/AiWeights(32) - 레이어: GimmickLayer(전투 시작 = 스테이지 배치 · 배경 위 유닛 아래 · 원/사각/다각 · 색 도형 + 글자 · 내구 핍 · 강 콜라이더 = 다리 구간 제외 · 겹친 유닛 보정) · 장애물 = 병종별 내구 피해·튕김·창 목책 밀기·바위 굴림·기병 정지 · 투사체 pass/block/destroy · 폭약 광역(아군 포함)+밀기+불 · 책사 광역 덤불 제거 · 강 낙하 - 지대: 경로 스윕(독 1→2→3 % · 늪 ×2 · 불 10 % · 빙판 미끄러짐 · 고지 · 안개 · 군기 · 함정) · 양 진영 턴 시작 훅 - 규칙 개정: 보병 튕김 중 다른 적과 연쇄 1회 · 창병 반작용(spearRecoilRatio · 밀며 전진 폐기) · 기존 테스트 기대값 갱신 - 적 AI: Runtime/AI(Sim 가상 실행 · TacticalAI 후보·점수·난이도·턴 운영 · 1부 보스 액티브) · 조준선 = 가상 실행 예상 궤적·기믹 반응·지대 띠 · TKS/Gimmick Painter · 캡처 GimmickImporter.Capture - 검증: 컴파일 0 · 플레이모드 113/113(신규 26) · console error 0 · 적 10기 턴 결정 62 ms Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 16:20:07 +00:00
"archer_cover", "high_ground", "cav_line", "splash_hit", "route_open", "zone_end", "banner", "skill_waste", "approach", "boss_accuracy", "mode_accuracy",
"noise_power", "top_n", "dirs", "dirs_many", "many_units", "power_1", "power_2", "power_3", "budget_ms", "boss_active", "active_max_chapter"
};
[Serializable]
public class Entry
{
public string key;
public float value;
public string desc;
}
public List<Entry> entries = new List<Entry>();
Dictionary<string, float> index;
public float this[string key]
{
get
{
if (index == null)
{
index = new Dictionary<string, float>();
foreach (var e in entries) index[e.key] = e.value;
}
float v;
if (index.TryGetValue(key, out v)) return v;
Debug.LogError("[TKS] ai_weights.csv 에 키 없음: " + key);
return 0f;
}
}
static AiWeights cached;
public static AiWeights Load()
{
if (cached == null) cached = Resources.Load<AiWeights>(ResourcePath);
return cached;
}
public static void Invalidate()
{
cached = null;
}
/// <summary>CSV(key,value,desc_ko) 해석 · 키 누락·숫자 아님 = errors.</summary>
public static List<Entry> Parse(string text, List<string> errors)
{
var list = new List<Entry>();
var seen = new HashSet<string>();
foreach (var r in StageTable.ReadCsv(text, "ai_weights.csv", errors))
{
string k, v, d;
r.TryGetValue("key", out k);
r.TryGetValue("value", out v);
r.TryGetValue("desc_ko", out d);
float f;
if (string.IsNullOrEmpty(k) || !float.TryParse(v, NumberStyles.Float, CultureInfo.InvariantCulture, out f))
{
errors.Add("ai_weights.csv 줄 " + r["#"] + ": key·value 형식(「" + k + "」 · 「" + v + "」)");
continue;
}
if (!seen.Add(k)) errors.Add("ai_weights.csv 줄 " + r["#"] + ": key 중복 「" + k + "」");
list.Add(new Entry { key = k, value = f, desc = d ?? "" });
}
foreach (var k in Keys)
{
if (!seen.Contains(k)) errors.Add("ai_weights.csv: 키 없음 「" + k + "」");
}
return list;
}
}
}