diff --git a/context_compressor.py b/context_compressor.py index d939b35..42bb644 100644 --- a/context_compressor.py +++ b/context_compressor.py @@ -5,24 +5,27 @@ context_compressor.py — 계층적 컨텍스트 압축 담을 수 없음. 이 모듈은 공장을 '구역(zone)'으로 나눠 AI가 소화할 수 있는 크기로 압축한다. -압축 전: 건물 수백 개 * 좌표/상태 → 토큰 수천 개 -압축 후: 구역 요약 10줄 + 병목/문제 목록 → 토큰 200개 이하 +핵심 변경: game.player → game.players[1] (RCON 호환) """ import json import math from factorio_rcon import FactorioRCON -# ── 구역 설정 ──────────────────────────────────────────────────── # 공장을 이 크기의 격자로 나눔 (타일 단위) ZONE_SIZE = 64 +# 모든 Lua 코드 앞에 붙일 플레이어 참조 +P = """local p = game.players[1] +if not p then rcon.print("{}") return end +""" + class ContextCompressor: """ 게임 상태를 AI가 소화 가능한 크기로 압축. - 계층 구조: + 압축 구조: Level 0 (raw) : 모든 건물 좌표 + 상태 (토큰 수천) Level 1 (zone) : 구역별 건물 수 + 상태 요약 (토큰 ~300) Level 2 (global): 전체 공장 핵심 지표 + 문제 목록 (토큰 ~100) @@ -31,7 +34,7 @@ class ContextCompressor: def __init__(self, rcon: FactorioRCON): self.rcon = rcon - # ── 공개 API ──────────────────────────────────────────────── + # ── 공개 API ──────────────────────────────────────────────────── def get_compressed_state(self, detail_level: int = 1) -> str: """ @@ -56,13 +59,13 @@ class ContextCompressor: drilldown = self._drilldown_problem_zones(zones, problems) return self._format_level2(global_summary, zones, problems, drilldown, player) - # ── 글로벌 지표 ───────────────────────────────────────────── + # ── 글로벌 지표 ───────────────────────────────────────────────── def _get_global_summary(self) -> dict: - lua = """ -local surface = game.player.surface -local force = game.player.force -local center = game.player.position + lua = P + """ +local surface = p.surface +local force = p.force +local center = p.position -- 전체 건물 수 집계 local counts = {} @@ -92,11 +95,6 @@ for _, name in ipairs(entity_types) do end end --- 전력 현황 -local stats = force.get_entity_production_statistics(surface) -local power_produced = 0 -local power_consumed = 0 - -- 연구 진행 local current_tech = "none" local tech_progress = 0 @@ -123,16 +121,15 @@ rcon.print(game.table_to_json({ raw = self.rcon.lua(lua) return json.loads(raw) if raw else {} - # ── 구역 요약 ─────────────────────────────────────────────── + # ── 구역 요약 ─────────────────────────────────────────────────── def _get_zone_summaries(self) -> list[dict]: """공장을 ZONE_SIZE×ZONE_SIZE 격자로 나눠 구역별 요약""" - lua = f""" -local surface = game.player.surface -local center = game.player.position + lua = P + f""" +local surface = p.surface +local center = p.position local Z = {ZONE_SIZE} --- 활성 구역만 탐색 (플레이어 주변 ±512) local radius = 512 local zones = {{}} @@ -140,7 +137,6 @@ local function zone_key(x, y) return math.floor(x/Z) .. "," .. math.floor(y/Z) end --- 모든 엔티티를 구역으로 분류 local all_entities = surface.find_entities_filtered{{ area={{{{center.x-radius, center.y-radius}}, {{center.x+radius, center.y+radius}}}}, @@ -175,7 +171,6 @@ for _, e in ipairs(all_entities) do end end --- 배열로 변환 (entities > 0인 것만) local result = {{}} for _, z in pairs(zones) do if z.entities > 2 then @@ -187,13 +182,13 @@ rcon.print(game.table_to_json(result)) raw = self.rcon.lua(lua) return json.loads(raw) if raw else [] - # ── 문제 감지 ─────────────────────────────────────────────── + # ── 문제 감지 ─────────────────────────────────────────────────── def _detect_problems(self) -> list[str]: - lua = """ -local surface = game.player.surface -local force = game.player.force -local center = game.player.position + lua = P + """ +local surface = p.surface +local force = p.force +local center = p.position local problems = {} -- 1. 연료 없는 채굴기/제련소 @@ -244,7 +239,7 @@ if no_power > 0 then problems[#problems+1] = "전력 부족: " .. no_power .. "개 건물 전력 10% 미만" end --- 4. 자원 고갈 임박한 광맥 +-- 4. 자원 고갈 임박한 굴맥 local drills = surface.find_entities_filtered{ area={{center.x-300,center.y-300},{center.x+300,center.y+300}}, type="mining-drill" @@ -272,12 +267,11 @@ rcon.print(game.table_to_json(problems)) except Exception: return [] - # ── 드릴다운 (문제 구역 상세) ──────────────────────────────── + # ── 드릴다운 (문제 구역 상세) ──────────────────────────────────── def _drilldown_problem_zones(self, zones: list, problems: list) -> str: if not problems or not zones: return "" - # 엔티티가 가장 많은 상위 2개 구역 드릴다운 top = sorted(zones, key=lambda z: z.get("entities", 0), reverse=True)[:2] lines = ["#### 주요 구역 상세"] for z in top: @@ -289,15 +283,14 @@ rcon.print(game.table_to_json(problems)) ) return "\n".join(lines) - # ── 플레이어 정보 ──────────────────────────────────────────── + # ── 플레이어 정보 ─────────────────────────────────────────────── def _get_player_info(self) -> dict: - lua = """ -local p = game.player + lua = P + """ local inv = p.get_main_inventory() +if not inv then rcon.print("{}") return end local contents = inv.get_contents() --- 핵심 아이템만 추출 local key_items = { "iron-plate","copper-plate","steel-plate","iron-ore","copper-ore","coal", "stone","stone-furnace","burner-mining-drill","electric-mining-drill", @@ -323,7 +316,7 @@ rcon.print(game.table_to_json({ raw = self.rcon.lua(lua) return json.loads(raw) if raw else {} - # ── 포맷터 ────────────────────────────────────────────────── + # ── 포맷터 ────────────────────────────────────────────────────── def _format_global(self, g: dict, problems: list, player: dict) -> str: lines = [