feat: 추가된 메모리 기능으로 광맥 및 마지막 행동 저장
- 에이전트가 발견한 광맥 좌표를 `ore_patch_memory.json`에 저장하여 재시작 시 활용 가능 - 마지막 실행한 행동과 결과를 `agent_last_action_memory.json`에 저장하여 다음 상태 요약에서 참고 가능 - `state_reader.py`에서 메모리 로드 및 상태 요약에 포함 - `ai_planner.py`에서 시스템 프롬프트에 기억된 광맥 및 마지막 행동 관련 가이드 추가 - `README.md`에 새로운 메모리 기능 설명 추가
This commit is contained in:
@@ -11,6 +11,13 @@ RCON을 통해 팩토리오 게임 상태를 읽어오는 모듈
|
||||
import json
|
||||
import os
|
||||
from factorio_rcon import FactorioRCON
|
||||
from ore_patch_memory import (
|
||||
load_ore_patch_memory,
|
||||
save_ore_patch_memory,
|
||||
update_ore_patch_memory,
|
||||
compute_distance_sq,
|
||||
)
|
||||
from agent_last_action_memory import load_last_action_memory
|
||||
|
||||
|
||||
P = 'local p = game.players[1] if not p then rcon.print("{}") return end '
|
||||
@@ -144,6 +151,8 @@ class StateReader:
|
||||
"resources": self.scan_resources(),
|
||||
"buildings": self.get_buildings(),
|
||||
"tech": self.get_research_status(),
|
||||
"ore_patch_memory": load_ore_patch_memory(),
|
||||
"last_action_memory": load_last_action_memory(),
|
||||
}
|
||||
|
||||
def get_player_info(self) -> dict:
|
||||
@@ -400,7 +409,51 @@ if not ok then rcon.print("{}") end
|
||||
"""
|
||||
try:
|
||||
raw = self.rcon.lua(lua)
|
||||
return json.loads(raw) if raw and raw.startswith("{") else {}
|
||||
res = json.loads(raw) if raw and raw.startswith("{") else {}
|
||||
# scan_resources() 결과로도 광맥 좌표를 기억한다.
|
||||
ore_mem = load_ore_patch_memory()
|
||||
changed = False
|
||||
if isinstance(res, dict) and res:
|
||||
for ore, info in res.items():
|
||||
if not isinstance(info, dict):
|
||||
continue
|
||||
tx = info.get("anchor_tile_x")
|
||||
ty = info.get("anchor_tile_y")
|
||||
cnt = info.get("count")
|
||||
if isinstance(tx, int) and isinstance(ty, int):
|
||||
before_patches = ore_mem.get(ore)
|
||||
before_set: set[tuple[int, int]] = set()
|
||||
if isinstance(before_patches, list):
|
||||
for pp in before_patches:
|
||||
if not isinstance(pp, dict):
|
||||
continue
|
||||
bx = pp.get("tile_x")
|
||||
by = pp.get("tile_y")
|
||||
if isinstance(bx, int) and isinstance(by, int):
|
||||
before_set.add((bx, by))
|
||||
|
||||
ore_mem = update_ore_patch_memory(
|
||||
ore_mem,
|
||||
ore,
|
||||
tx,
|
||||
ty,
|
||||
count=cnt if isinstance(cnt, int) else None,
|
||||
)
|
||||
after_patches = ore_mem.get(ore)
|
||||
after_set: set[tuple[int, int]] = set()
|
||||
if isinstance(after_patches, list):
|
||||
for ap in after_patches:
|
||||
if not isinstance(ap, dict):
|
||||
continue
|
||||
ax = ap.get("tile_x")
|
||||
ay = ap.get("tile_y")
|
||||
if isinstance(ax, int) and isinstance(ay, int):
|
||||
after_set.add((ax, ay))
|
||||
if before_set != after_set:
|
||||
changed = True
|
||||
if changed:
|
||||
save_ore_patch_memory(ore_mem)
|
||||
return res
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
@@ -452,6 +505,8 @@ if not ok then rcon.print("{}") end
|
||||
inv = state.get("inventory", {})
|
||||
res = state.get("resources", {})
|
||||
bld = state.get("buildings", {})
|
||||
ore_mem = state.get("ore_patch_memory", {}) or {}
|
||||
last_action = state.get("last_action_memory", {}) or {}
|
||||
|
||||
lines = [
|
||||
"## 현재 게임 상태",
|
||||
@@ -496,6 +551,47 @@ if not ok then rcon.print("{}") end
|
||||
else:
|
||||
lines.append("- 반경 500타일 내 자원 없음 — 더 멀리 탐색 필요")
|
||||
|
||||
lines += ["", "### 기억된 광맥 (좌표)"]
|
||||
if ore_mem:
|
||||
px = p.get('x', 0)
|
||||
py = p.get('y', 0)
|
||||
known = []
|
||||
for ore, patches in ore_mem.items():
|
||||
if not isinstance(patches, list):
|
||||
continue
|
||||
for patch in patches:
|
||||
if not isinstance(patch, dict):
|
||||
continue
|
||||
tx = patch.get("tile_x")
|
||||
ty = patch.get("tile_y")
|
||||
if isinstance(tx, int) and isinstance(ty, int):
|
||||
dist = int(compute_distance_sq(px, py, tx, ty) ** 0.5)
|
||||
known.append((ore, patch, dist))
|
||||
known.sort(key=lambda x: x[2])
|
||||
for ore, info, dist in known[:10]:
|
||||
lines.append(
|
||||
f"- {ore}: ({info.get('tile_x')},{info.get('tile_y')}) "
|
||||
f"[거리: ~{dist}타일] count={info.get('count','?')}"
|
||||
)
|
||||
else:
|
||||
lines.append("- 없음")
|
||||
|
||||
lines += ["", "### 마지막 행동(기억)"]
|
||||
if last_action and isinstance(last_action, dict) and last_action.get("action"):
|
||||
# state_summary 크기 방지를 위해 필드만 요약
|
||||
act = last_action.get("action", "")
|
||||
params = last_action.get("params", {})
|
||||
success = last_action.get("success", None)
|
||||
msg = last_action.get("message", "")
|
||||
lines.append(f"- action={act} success={success} message={msg}")
|
||||
if params:
|
||||
try:
|
||||
lines.append(f"- params={json.dumps(params, ensure_ascii=False)}")
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
lines.append("- 없음")
|
||||
|
||||
lines += ["", "### 건설된 건물"]
|
||||
if bld:
|
||||
for name, count in sorted(bld.items(), key=lambda x: -x[1])[:10]:
|
||||
|
||||
Reference in New Issue
Block a user