feat: explore 메서드에 wanted_ores 매개변수 추가 및 로직 개선
- explore 메서드에 wanted_ores 매개변수를 추가하여 특정 자원을 찾을 수 있도록 개선 - 원하는 자원이 발견될 때까지 계속 이동하며, 다른 자원이 발견되더라도 즉시 멈추지 않도록 로직 수정 - 시스템 프롬프트 및 README.md에 변경 사항 반영
This commit is contained in:
@@ -117,3 +117,4 @@ planner.set_goal(
|
|||||||
- `mine_resource`에서 실패한 채굴 타일 제외(`exclude`)는 Lua와 Python 양쪽에서 정수 타일 좌표(`tx, ty`) 키로 통일해, 제외한 좌표가 반복 선택되지 않도록 합니다.
|
- `mine_resource`에서 실패한 채굴 타일 제외(`exclude`)는 Lua와 Python 양쪽에서 정수 타일 좌표(`tx, ty`) 키로 통일해, 제외한 좌표가 반복 선택되지 않도록 합니다.
|
||||||
- 또한 채굴 시작(`mining_state`) 좌표는 정수 타일이 아니라, Lua가 찾은 실제 자원 엔티티의 `e.position`(정확 실수 좌표)을 사용해 “플레이어가 타일 위에 있는데도 즉시 채굴 감지 실패”를 줄입니다.
|
- 또한 채굴 시작(`mining_state`) 좌표는 정수 타일이 아니라, Lua가 찾은 실제 자원 엔티티의 `e.position`(정확 실수 좌표)을 사용해 “플레이어가 타일 위에 있는데도 즉시 채굴 감지 실패”를 줄입니다.
|
||||||
- `mine_resource`는 move 후 `p.position` 근처(반경 1.2)에서 실제로 해당 광물 엔티티가 있는지 재확인하고, 없으면 채굴을 시도하지 않고 다음 후보로 넘어갑니다.
|
- `mine_resource`는 move 후 `p.position` 근처(반경 1.2)에서 실제로 해당 광물 엔티티가 있는지 재확인하고, 없으면 채굴을 시도하지 않고 다음 후보로 넘어갑니다.
|
||||||
|
- `explore`는 `wanted_ores`가 있으면 해당 자원이 발견될 때까지 멈추지 않고 계속 이동해, `iron-ore`처럼 주변에 흔한 자원만 계속 발견되어 진행이 막히는 문제를 줄입니다.
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -41,7 +41,12 @@ class ActionExecutor:
|
|||||||
except Exception as e: return False, f"실행 오류: {e}"
|
except Exception as e: return False, f"실행 오류: {e}"
|
||||||
|
|
||||||
# ── 탐색 ─────────────────────────────────────────────────────────
|
# ── 탐색 ─────────────────────────────────────────────────────────
|
||||||
def explore(self, direction: str = "east", max_steps: int = 200) -> tuple[bool, str]:
|
def explore(
|
||||||
|
self,
|
||||||
|
direction: str = "east",
|
||||||
|
max_steps: int = 200,
|
||||||
|
wanted_ores: list[str] | None = None,
|
||||||
|
) -> tuple[bool, str]:
|
||||||
dir_map = {
|
dir_map = {
|
||||||
"north": "defines.direction.north", "south": "defines.direction.south",
|
"north": "defines.direction.north", "south": "defines.direction.south",
|
||||||
"east": "defines.direction.east", "west": "defines.direction.west",
|
"east": "defines.direction.east", "west": "defines.direction.west",
|
||||||
@@ -50,17 +55,39 @@ class ActionExecutor:
|
|||||||
}
|
}
|
||||||
lua_dir = dir_map.get(direction, "defines.direction.east")
|
lua_dir = dir_map.get(direction, "defines.direction.east")
|
||||||
self.rcon.lua(P + f"p.walking_state = {{walking = true, direction = {lua_dir}}}")
|
self.rcon.lua(P + f"p.walking_state = {{walking = true, direction = {lua_dir}}}")
|
||||||
|
wanted_ores = wanted_ores or []
|
||||||
|
# JSON에서 single string으로 올 수도 있으니 방어
|
||||||
|
if isinstance(wanted_ores, str):
|
||||||
|
wanted_ores = [wanted_ores]
|
||||||
|
|
||||||
|
wanted_lua = "local wanted = {}\n"
|
||||||
|
for name in wanted_ores:
|
||||||
|
safe = str(name).replace("\\", "\\\\").replace('"', '\\"')
|
||||||
|
wanted_lua += f'wanted["{safe}"] = true\n'
|
||||||
|
|
||||||
stuck_count, last_pos = 0, None
|
stuck_count, last_pos = 0, None
|
||||||
for step in range(max_steps):
|
for step in range(max_steps):
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
if step % 20 == 0:
|
if step % 20 == 0:
|
||||||
result = self.rcon.lua(P + """
|
result = self.rcon.lua(P + wanted_lua + """
|
||||||
local ok, data = pcall(function()
|
local ok, data = pcall(function()
|
||||||
local pos = p.position
|
local pos = p.position
|
||||||
local res = p.surface.find_entities_filtered{position = pos, radius = 50, type = "resource"}
|
local res = p.surface.find_entities_filtered{position = pos, radius = 50, type = "resource"}
|
||||||
if #res == 0 then return "NONE:" .. string.format("%.0f,%.0f", pos.x, pos.y) end
|
if #res == 0 then return "NONE:" .. string.format("%.0f,%.0f", pos.x, pos.y) end
|
||||||
local counts = {}
|
local counts = {}
|
||||||
for _, e in ipairs(res) do counts[e.name] = (counts[e.name] or 0) + 1 end
|
for _, e in ipairs(res) do counts[e.name] = (counts[e.name] or 0) + 1 end
|
||||||
|
-- wanted_ores가 지정된 경우: 그 중 하나라도 있으면 FOUND, 아니면 UNWANTED 반환
|
||||||
|
if wanted and next(wanted) ~= nil then
|
||||||
|
for n, _ in pairs(wanted) do
|
||||||
|
if counts[n] and counts[n] > 0 then
|
||||||
|
local parts = {}
|
||||||
|
for name, count in pairs(counts) do parts[#parts+1] = name .. "=" .. count end
|
||||||
|
return "FOUND:" .. string.format("%.0f,%.0f", pos.x, pos.y) .. "|" .. table.concat(parts, ",")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return "UNWANTED:" .. string.format("%.0f,%.0f", pos.x, pos.y)
|
||||||
|
end
|
||||||
|
|
||||||
local parts = {}
|
local parts = {}
|
||||||
for name, count in pairs(counts) do parts[#parts+1] = name .. "=" .. count end
|
for name, count in pairs(counts) do parts[#parts+1] = name .. "=" .. count end
|
||||||
return "FOUND:" .. string.format("%.0f,%.0f", pos.x, pos.y) .. "|" .. table.concat(parts, ",")
|
return "FOUND:" .. string.format("%.0f,%.0f", pos.x, pos.y) .. "|" .. table.concat(parts, ",")
|
||||||
@@ -72,6 +99,9 @@ if ok then rcon.print(data) else rcon.print("ERROR") end
|
|||||||
self.rcon.lua(P + "p.walking_state = {walking = false, direction = defines.direction.north}")
|
self.rcon.lua(P + "p.walking_state = {walking = false, direction = defines.direction.north}")
|
||||||
parts = result.replace("FOUND:", "").split("|")
|
parts = result.replace("FOUND:", "").split("|")
|
||||||
return True, f"자원 발견! 위치({parts[0]}), 자원: {parts[1] if len(parts)>1 else ''}"
|
return True, f"자원 발견! 위치({parts[0]}), 자원: {parts[1] if len(parts)>1 else ''}"
|
||||||
|
if result.startswith("UNWANTED:"):
|
||||||
|
# 원하는 자원이 아니면 계속 걷기
|
||||||
|
continue
|
||||||
if result.startswith("NONE:"):
|
if result.startswith("NONE:"):
|
||||||
pos_str = result.replace("NONE:", "")
|
pos_str = result.replace("NONE:", "")
|
||||||
if last_pos == pos_str: stuck_count += 1
|
if last_pos == pos_str: stuck_count += 1
|
||||||
|
|||||||
@@ -64,8 +64,9 @@ SYSTEM_PROMPT = """당신은 팩토리오 게임을 순수하게 플레이하는
|
|||||||
## 전체 action 목록
|
## 전체 action 목록
|
||||||
|
|
||||||
### 탐색 (★ 자원 없을 때 최우선! 걸으면서 자원 스캔)
|
### 탐색 (★ 자원 없을 때 최우선! 걸으면서 자원 스캔)
|
||||||
- "explore" → {"direction": "east|west|north|south|...", "max_steps": 200}
|
- "explore" → {"direction": "east|west|north|south|...", "max_steps": 200, "wanted_ores": ["stone","coal", ...]} (선택)
|
||||||
★ 자원이 보이지 않을 때 반드시 explore 사용! move 대신!
|
★ 자원이 보이지 않을 때 반드시 explore 사용! move 대신!
|
||||||
|
★ `wanted_ores`가 있으면: 해당 자원이 발견될 때까지 계속 걷고, 다른 자원(예: iron-ore)만 계속 발견되더라도 즉시 멈추지 말 것
|
||||||
★ 방향으로 걸으면서 반경 50타일 자원 스캔, 발견 즉시 멈춤
|
★ 방향으로 걸으면서 반경 50타일 자원 스캔, 발견 즉시 멈춤
|
||||||
★ 장애물 자동 감지. 막히면 다른 방향 시도
|
★ 장애물 자동 감지. 막히면 다른 방향 시도
|
||||||
★ 한 방향 실패 시 다음 방향 (east→north→south→west)
|
★ 한 방향 실패 시 다음 방향 (east→north→south→west)
|
||||||
|
|||||||
Reference in New Issue
Block a user