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