Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
StoneT2000 committed Nov 9, 2022
2 parents 29a402c + c3c7cb0 commit ae35006
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 13 deletions.
6 changes: 6 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# ChangeLog

### v1.0.6
- Fix bug where game ends at turns < 1000 (kaggle-environments bug)
- Fixed bug with self-destruct actions not being validated or added
- Log unit ids that collided. E.g. `14: 1 Units: (unit_11) collided at 33,44 with [1] unit_9 UnitType.HEAVY at (33, 44) surviving`
- Fixed bug where power costs were recomputed after state change in a single step, causing potentially negative energy in edge cases

### v1.0.5

Environment:
Expand Down
18 changes: 15 additions & 3 deletions luxai2022/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Action:
def __init__(self, act_type: str) -> None:
self.act_type = act_type
self.repeat = False
self.power_cost = 0

def state_dict():
raise NotImplementedError("")
Expand All @@ -30,6 +31,7 @@ class FactoryBuildAction(Action):
def __init__(self, unit_type: luxai_unit.UnitType) -> None:
super().__init__("factory_build")
self.unit_type = unit_type
self.power_cost = 0

def state_dict(self):
if self.unit_type == luxai_unit.UnitType.LIGHT:
Expand All @@ -41,7 +43,7 @@ class FactoryWaterAction(Action):
def __init__(self) -> None:
super().__init__("factory_water")
self.water_cost = None

self.power_cost = 0
def state_dict():
return 2

Expand All @@ -53,6 +55,7 @@ def __init__(self, move_dir: int, dist: int = 1, repeat=False) -> None:
self.move_dir = move_dir
self.dist = dist
self.repeat = repeat
self.power_cost = 0

def state_dict(self):
return np.array([0, self.move_dir, self.dist, 0, self.repeat])
Expand All @@ -66,6 +69,7 @@ def __init__(self, transfer_dir: int, resource: int, transfer_amount: int, repea
self.resource = resource
self.transfer_amount = transfer_amount
self.repeat = repeat
self.power_cost = 0

def state_dict(self):
return np.array([1, self.transfer_dir, self.resource, self.transfer_amount, self.repeat])
Expand All @@ -78,6 +82,7 @@ def __init__(self, resource: int, pickup_amount: int, repeat=False) -> None:
self.resource = resource
self.pickup_amount = pickup_amount
self.repeat = repeat
self.power_cost = 0

def state_dict(self):
return np.array([2, 0, self.resource, self.pickup_amount, self.repeat])
Expand All @@ -87,6 +92,7 @@ class DigAction(Action):
def __init__(self, repeat=False) -> None:
super().__init__("dig")
self.repeat = repeat
self.power_cost = 0

def state_dict(self):
return np.array([3, 0, 0, 0, self.repeat])
Expand All @@ -96,6 +102,7 @@ class SelfDestructAction(Action):
def __init__(self, repeat=False) -> None:
super().__init__("self_destruct")
self.repeat = repeat
self.power_cost = 0

def state_dict(self):
return np.array([4, 0, 0, 0, self.repeat])
Expand All @@ -106,6 +113,7 @@ def __init__(self, power: int, repeat=False) -> None:
super().__init__("recharge")
self.power = power
self.repeat = repeat
self.power_cost = 0

def state_dict(self):
return np.array([5, 0, 0, self.power, self.repeat])
Expand Down Expand Up @@ -307,6 +315,7 @@ def invalidate_action(msg):
)
continue
if valid_action:
move_action.power_cost = power_required
actions_by_type_validated["move"].append((unit, move_action))

for unit, self_destruct_action in actions_by_type["self_destruct"]:
Expand All @@ -319,7 +328,8 @@ def invalidate_action(msg):
)
continue
if valid_action:
actions_by_type_validated["self_destruct"].append((unit, move_action))
self_destruct_action.power_cost = power_required
actions_by_type_validated["self_destruct"].append((unit, self_destruct_action))

for factory, build_action in actions_by_type["factory_build"]:
valid_action = True
Expand All @@ -330,10 +340,12 @@ def invalidate_action(msg):
if factory.cargo.metal < unit_cfg.METAL_COST:
invalidate_action(f"Invalid factory build action for factory {factory} - Insufficient metal, factory has {factory.cargo.metal}, but requires {unit_cfg.METAL_COST} to build {build_action.unit_type}")
continue
if factory.power < math.ceil(unit_cfg.POWER_COST * weather_cfg["power_loss_factor"]):
power_required = math.ceil(unit_cfg.POWER_COST * weather_cfg["power_loss_factor"])
if factory.power < power_required:
invalidate_action(f"Invalid factory build action for factory {factory} - Insufficient power, factory has {factory.power}, but requires ceil({unit_cfg.POWER_COST} x {weather_cfg['power_loss_factor']}) to build {build_action.unit_type.name}. Power cost factor is {weather_cfg['power_loss_factor']}")
continue
if valid_action:
build_action.power_cost = power_required
actions_by_type_validated["factory_build"].append((factory, build_action))
pass

Expand Down
16 changes: 7 additions & 9 deletions luxai2022/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,10 +348,10 @@ def _handle_factory_build_actions(self, actions_by_type: ActionsByType, weather_
)
if factory_build_action.unit_type == UnitType.HEAVY:
factory.sub_resource(3, self.env_cfg.ROBOTS["HEAVY"].METAL_COST)
factory.sub_resource(4, math.ceil(self.env_cfg.ROBOTS["HEAVY"].POWER_COST * weather_cfg["power_loss_factor"]))
factory.sub_resource(4, factory_build_action.power_cost)
else:
factory.sub_resource(3, self.env_cfg.ROBOTS["LIGHT"].METAL_COST)
factory.sub_resource(4, math.ceil(self.env_cfg.ROBOTS["LIGHT"].POWER_COST * weather_cfg["power_loss_factor"]))
factory.sub_resource(4, factory_build_action.power_cost)
def _handle_movement_actions(self, actions_by_type: ActionsByType, weather_cfg):
new_units_map: Dict[str, List[Unit]] = defaultdict(list)
heavy_entered_pos: Dict[str, List[Unit]] = defaultdict(list)
Expand All @@ -364,9 +364,7 @@ def _handle_movement_actions(self, actions_by_type: ActionsByType, weather_cfg):
continue
old_pos_hash = self.state.board.pos_hash(unit.pos)
target_pos = unit.pos + move_action.dist * move_deltas[move_action.move_dir]
rubble = self.state.board.rubble[target_pos.y, target_pos.x]
power_required = unit.unit_cfg.MOVE_COST + unit.unit_cfg.RUBBLE_MOVEMENT_COST * rubble
power_required = math.ceil(power_required * weather_cfg["power_loss_factor"])
power_required = move_action.power_cost
unit.pos = target_pos
new_pos_hash = self.state.board.pos_hash(unit.pos)

Expand Down Expand Up @@ -405,7 +403,7 @@ def _handle_movement_actions(self, actions_by_type: ActionsByType, weather_cfg):
for u in units:
if u.unit_id != surviving_unit.unit_id:
destroyed_units.add(u)
self._log(f"{len(destroyed_units)} Units collided at {pos_hash} with {surviving_unit} surviving")
self._log(f"{len(destroyed_units)} Units: ({', '.join([u.unit_id for u in destroyed_units])}) collided at {pos_hash} with {surviving_unit} surviving")
new_units_map_after_collision[pos_hash].append(surviving_unit)
else:
# check for stationary heavy unit there
Expand Down Expand Up @@ -524,9 +522,9 @@ def step(self, actions):
continue
unit.power -= update_power_req
self.state.units[agent][unit_id].action_queue = formatted_actions
except ValueError as e:
except Exception as e:
# catch errors when trying to format unit or factory actions
print(e)
print(e.with_traceback())
failed_agents[agent] = True

# 2. store actions by type
Expand All @@ -549,7 +547,7 @@ def step(self, actions):
# update information for lichen growing and cache it
factory.cache_water_info(self.state.board, self.env_cfg)

# 3. validate all actions against current state, throw away impossible actions TODO
# 3. validate all actions against current state, throw away impossible actions
actions_by_type = validate_actions(self.env_cfg, self.state, actions_by_type, verbose=self.env_cfg.verbose, weather_cfg=weather_cfg)

self._handle_transfer_actions(actions_by_type)
Expand Down
2 changes: 1 addition & 1 deletion visualizer/src/store/autoplay/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ export const SPEEDS = [0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512] as const

export type Speed = (typeof SPEEDS)[number]

export const initialSpeed: Speed = 128
export const initialSpeed: Speed = 16

export const speedToIndex: Map<Speed, number> = new Map(SPEEDS.map((x, i) => [x, i]))

0 comments on commit ae35006

Please sign in to comment.