def dig_in_direction(self, direction: Direction): """Try digging towards a direction""" dig_mapping = { Direction.up: turtle.digUp, Direction.down: turtle.digDown, Direction.front: turtle.dig } if direction not in dig_mapping: raise ValueError(f"You can't dig in the direction: {direction}") # Actually dig the block try: lua_errors.run(dig_mapping[direction]) except lua_errors.UnbreakableBlockError as e: e.direction = direction raise e # Mark all slots as unconfirmed, since we don't know where that material # moved to self.inventory.mark_all_slots_unconfirmed() # Since the block was successfully removed, remove it as a potential # obstacle in the map. with self.state as state: map = state.map.read() obstacle_position = math_utils.coordinate_in_turtle_direction( curr_pos=map.position, curr_angle=map.direction, direction=direction) map.remove_obstacle(obstacle_position) state.map.write(map)
def place_in_direction(self, direction: Direction): place_mapping = { Direction.up: turtle.placeUp, Direction.down: turtle.placeDown, Direction.front: turtle.place } if direction not in place_mapping: raise ValueError(f"You can't place in the direction: {direction}") lua_errors.run(place_mapping[direction]) # Track the change in inventory, since no errors occurred self.inventory.selected.refresh()
def drop_in_direction(self, direction: Direction, amount=None): drop_mapping = { Direction.up: turtle.dropUp, Direction.down: turtle.dropDown, Direction.front: turtle.drop } if direction not in drop_mapping: raise ValueError(f"You can't drop in the direction: {direction}") lua_errors.run(drop_mapping[direction], amount) # Now that items have been potentially dropped, update the inventory: self.inventory.selected.refresh()
def suck_in_direction(self, direction: Direction, amount=None): suck_mapping = { Direction.up: turtle.suckUp, Direction.down: turtle.suckDown, Direction.front: turtle.suck } if direction not in suck_mapping: raise ValueError(f"You can't suck in the direction: {direction}") lua_errors.run(suck_mapping[direction], amount=amount) # Mark all slots as unconfirmed, since we don't know where that material # moved to self.inventory.mark_all_slots_unconfirmed()
def __init__(self): # First, ensure state is retrieved via GPS initially gps_loc = gps.locate() if gps_loc is None: raise StateRecoveryError( "The turtle must have a wireless modem and be " "within range of GPS satellites!") self.computer_id = lua_errors.run(os.getComputerID) self.state = StateFile(computer_id=self.computer_id) """Representing (x, y, z) positions""" """Direction on the XZ plane in degrees. A value between 0-360 """ self.state.map = StateAttr(self.state, "map", Map(position=gps_loc, direction=0)) self.direction_verified = False """This is set to True if the Turtle ever moves and is able to verify that the angle it thinks is pointing is actually the angle it is pointing. It uses GPS to verify two points before and after a move to do this. """ self.inventory = Inventory.from_turtle(selected_slot=1) """This will scan the entire inventory and record the contents, and leave the turtle with selected_slot selected""" self._maybe_recover_location(gps_loc)
def move_in_direction(self, direction: Direction): """Move forwards or backwards in the sign of direction""" direction_mapping = { Direction.front: turtle.forward, Direction.back: turtle.back, Direction.up: turtle.up, Direction.down: turtle.down, } if direction not in direction_mapping: raise ValueError(f"You can't move in the direction: {direction}") map = self.state.map.read() old_position = map.position new_position = math_utils.coordinate_in_turtle_direction( curr_pos=map.position, curr_angle=map.direction, direction=direction) with self.state as state: try: lua_errors.run(direction_mapping[direction]) except lua_errors.TurtleBlockedError as e: # TODO: Think of something smart to do when direction isn't # verified but the turtle is still blocked! map.add_obstacle(new_position) state.map.write(map) e.direction = direction raise e horizontal_dirs = (Direction.front, Direction.back) if not self.direction_verified and direction in horizontal_dirs: gps_position = gps.locate() # If the move_sign is negative, flip the order of to/from # to represent a move backwards sign = 1 if direction is Direction.front else -1 to_from = (old_position, gps_position)[::sign] verified_direction = math_utils.get_angle(*to_from) new_position = gps_position map.direction = verified_direction # Flag the turtle as super verified and ready to roll self.direction_verified = True map.move_to(new_position) state.map.write(map)
def turn_degrees(self, degrees: int): """Turn `degrees` amount. The direction is determined by the sign. Only 90, 0, or -90 is allowed. 0 performs nothing """ if degrees == 0: return if degrees not in (90, -90): raise ValueError(f"Invalid value for degrees! {degrees}") map = self.state.map.read() map.direction = (map.direction + degrees) % 360 with self.state: if degrees == 90: lua_errors.run(turtle.turnRight) elif degrees == -90: lua_errors.run(turtle.turnLeft) self.state.map.write(map)
def inspect_in_direction(self, direction: Direction) \ -> Optional[Dict[bytes, bytes]]: inspect_mapping = { Direction.up: turtle.inspectUp, Direction.down: turtle.inspectDown, Direction.front: turtle.inspect } if direction not in inspect_mapping: raise ValueError( f"You can't inspect in the direction: {direction}") return lua_errors.run(inspect_mapping[direction])
def maybe_refuel(nav_turtle: NavigationTurtle, refuel_spot, destructive=False): """Top off fuel if necessary. This function roughly predicts the distance to refuel and decides if it's necessary to refuel""" fuel_level = lua_errors.run(turtle.getFuelLevel) if fuel_level < TURTLE_FUEL_LIMIT * 0.5: # Whether we are consuming fuel or getting it from a chest, we always # want to do so from the fuel slot nav_turtle.select(FUEL_SLOT) if nav_turtle.inventory.selected.count > 1: nav_turtle.refuel(1) # Go grab fuel nav_turtle.move_toward(to_pos=refuel_spot, destructive=destructive) nav_turtle.suck_in_direction(Direction.down, end_step=False) nav_turtle.inventory.slot(FUEL_SLOT).refresh()
def __init__(self, computer_id: int = None): self.dict = None """When being held, this shows all the key/value pairs of state""" self._last_saved_dict = None """Used to prevent saving to the StateFile when it's deemed unnecessary """ self.being_held = 0 """When this hits 0 on __exit__, all things are saved to the file""" computer_id = computer_id or lua_errors.run(os.getComputerID) self._state_path = STATE_DIR / str(computer_id) / STATE_FILE """The location to cache all the turtles states. The reason the CC filesystem isn't used is because it's unreliable during program startup and shutdown, leading to inconsistent states.""" self._state_path.parent.mkdir(exist_ok=True, parents=True)
def refuel(self, fuel_amount): lua_errors.run(turtle.refuel, fuel_amount) self.inventory.selected.refresh()
def select(self, slot_id): if self.inventory.selected.slot_id is not slot_id: lua_errors.run(turtle.select, slot_id) self.inventory.selected_id = slot_id