fix: context_compressor game.player → game.players[1]

This commit is contained in:
2026-03-25 15:12:07 +09:00
parent 6f220bc3f5
commit 954072bfdd

View File

@@ -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 = [