openenv_hack / tests /fakes.py
thomasm6m6's picture
Initial Freeciv OpenEnv Space
8dc7642 verified
from __future__ import annotations
from copy import deepcopy
from freeciv_env.adapter import ActionRef, RawSnapshot
class FakeFreecivSession:
def __init__(self):
self.current = None
def reset(self, seed: int | None = None) -> RawSnapshot:
del seed
self.current = _initial_snapshot()
return deepcopy(self.current)
def apply_action(self, action_ref: ActionRef) -> RawSnapshot:
if self.current is None:
raise RuntimeError("session was not reset")
raw_action_key = action_ref.raw_action_key
if raw_action_key == "goto_0":
self.current = _moved_snapshot(self.current.turn)
elif raw_action_key == "build":
self.current = _built_snapshot(self.current.turn)
elif raw_action_key == "change_unit_prod_Settlers_0":
self.current = _production_snapshot(self.current.turn)
elif raw_action_key == "research_tech_Pottery_63":
self.current = _research_snapshot(self.current.turn)
else:
raise ValueError(f"unsupported fake action: {raw_action_key}")
return deepcopy(self.current)
def end_turn(self) -> RawSnapshot:
if self.current is None:
raise RuntimeError("session was not reset")
self.current = _advanced_turn_snapshot(self.current)
return deepcopy(self.current)
def close(self) -> None:
self.current = None
def _base_state(*, score: float, techs: int, status: list[list[int]], cities: dict, units: dict) -> dict:
return {
"player": {
"my_score": score,
"my_gold": 20,
"my_science": 60,
"my_techs_researched": techs,
"my_is_alive": True,
},
"map": {"status": status},
"city": cities,
"unit": units,
"tech": {},
}
def _base_actions(*, can_build: bool, can_move: bool, include_city_prod: bool, include_research: bool) -> dict:
unit_actions = {}
if can_move:
unit_actions["goto_0"] = True
if can_build:
unit_actions["build"] = True
city_actions = {"change_unit_prod_Settlers_0": True} if include_city_prod else {}
tech_actions = {"research_tech_Pottery_63": True} if include_research else {}
return {
"unit": {"201": unit_actions},
"city": {"101": city_actions},
"tech": {"cur_player": tech_actions},
}
def _initial_snapshot(turn: int = 1) -> RawSnapshot:
return RawSnapshot(
turn=turn,
state=_base_state(
score=10.0,
techs=0,
status=[[2, 2, 1], [1, 0, 0]],
cities={
"101": {
"id": 101,
"size": 1,
"prod_food": 4,
"prod_shield": 2,
"prod_trade": 1,
"surplus_food": 2,
"surplus_shield": 1,
"surplus_trade": 1,
"production_kind": 6,
"production_value": 0,
"turns_to_prod_complete": 2.0,
}
},
units={
"201": {
"health": 10,
"moves_left": 1,
"home_city": 101,
"type_rule_name": "Settlers",
"veteran": 0,
}
},
),
actions=_base_actions(can_build=True, can_move=True, include_city_prod=True, include_research=True),
)
def _moved_snapshot(turn: int) -> RawSnapshot:
return RawSnapshot(
turn=turn,
state=_base_state(
score=11.0,
techs=0,
status=[[2, 2, 2], [1, 1, 0]],
cities={
"101": {
"id": 101,
"size": 1,
"prod_food": 4,
"prod_shield": 2,
"prod_trade": 1,
"surplus_food": 2,
"surplus_shield": 1,
"surplus_trade": 1,
"production_kind": 6,
"production_value": 0,
"turns_to_prod_complete": 2.0,
}
},
units={
"201": {
"health": 10,
"moves_left": 0,
"home_city": 101,
"type_rule_name": "Settlers",
"veteran": 0,
}
},
),
actions=_base_actions(can_build=False, can_move=False, include_city_prod=True, include_research=True),
)
def _built_snapshot(turn: int) -> RawSnapshot:
return RawSnapshot(
turn=turn,
state=_base_state(
score=14.0,
techs=0,
status=[[2, 2, 1], [1, 0, 0]],
cities={
"101": {
"id": 101,
"size": 1,
"prod_food": 4,
"prod_shield": 2,
"prod_trade": 1,
"surplus_food": 2,
"surplus_shield": 1,
"surplus_trade": 1,
"production_kind": 6,
"production_value": 0,
"turns_to_prod_complete": 2.0,
},
"102": {
"id": 102,
"size": 1,
"prod_food": 2,
"prod_shield": 1,
"prod_trade": 1,
"surplus_food": 1,
"surplus_shield": 1,
"surplus_trade": 1,
"production_kind": 6,
"production_value": 3,
"turns_to_prod_complete": 4.0,
},
},
units={},
),
actions={
"unit": {},
"city": {
"101": {"change_unit_prod_Settlers_0": True},
"102": {"change_unit_prod_Settlers_0": True},
},
"tech": {"cur_player": {"research_tech_Pottery_63": True}},
},
)
def _production_snapshot(turn: int) -> RawSnapshot:
return RawSnapshot(
turn=turn,
state=_base_state(
score=10.0,
techs=0,
status=[[2, 2, 1], [1, 0, 0]],
cities={
"101": {
"id": 101,
"size": 1,
"prod_food": 4,
"prod_shield": 2,
"prod_trade": 1,
"surplus_food": 2,
"surplus_shield": 1,
"surplus_trade": 1,
"production_kind": 6,
"production_value": 0,
"turns_to_prod_complete": 1.0,
}
},
units={
"201": {
"health": 10,
"moves_left": 1,
"home_city": 101,
"type_rule_name": "Settlers",
"veteran": 0,
}
},
),
actions=_base_actions(can_build=True, can_move=True, include_city_prod=True, include_research=True),
)
def _research_snapshot(turn: int) -> RawSnapshot:
return RawSnapshot(
turn=turn,
state=_base_state(
score=10.0,
techs=1,
status=[[2, 2, 1], [1, 0, 0]],
cities={
"101": {
"id": 101,
"size": 1,
"prod_food": 4,
"prod_shield": 2,
"prod_trade": 1,
"surplus_food": 2,
"surplus_shield": 1,
"surplus_trade": 1,
"production_kind": 6,
"production_value": 0,
"turns_to_prod_complete": 2.0,
}
},
units={
"201": {
"health": 10,
"moves_left": 1,
"home_city": 101,
"type_rule_name": "Settlers",
"veteran": 0,
}
},
),
actions={
"unit": {"201": {"goto_0": True, "build": True}},
"city": {"101": {"change_unit_prod_Settlers_0": True}},
"tech": {"cur_player": {}},
},
)
def _advanced_turn_snapshot(current: RawSnapshot) -> RawSnapshot:
state = deepcopy(current.state)
state["player"]["my_score"] = float(state["player"].get("my_score", 0.0)) + 2.0
state["map"]["status"] = [[2, 2, 2], [2, 1, 0]]
if "201" in state.get("unit", {}):
state["unit"]["201"]["moves_left"] = 1
actions = _base_actions(can_build=True, can_move=True, include_city_prod=True, include_research=True)
return RawSnapshot(turn=current.turn + 1, state=state, actions=actions)