| … | … | @@ -5,9 +5,27 @@ from rocca.envs.wrappers.malmo_wrapper import MalmoWrapper |
| 5 | 5 | from rocca.envs.wrappers.utils import * |
| 6 | 6 | from builtins import range |
| 7 | 7 | import json |
| 8 | | import random |
| 9 | 8 | import math |
| 10 | | |
| 9 | import signal |
| 10 | from contextlib import contextmanager |
| 11 | |
| 12 | @contextmanager |
| 13 | def timeout(time): |
| 14 | # Register a function to raise a TimeoutError on the signal. |
| 15 | signal.signal(signal.SIGALRM, raise_timeout) |
| 16 | # Schedule the signal to be sent after ``time``. |
| 17 | signal.alarm(time) |
| 18 | try: |
| 19 | yield |
| 20 | except TimeoutError: |
| 21 | pass |
| 22 | finally: |
| 23 | # Unregister the signal so it won't be triggered |
| 24 | # if the timeout is not reached. |
| 25 | signal.signal(signal.SIGALRM, signal.SIG_IGN) |
| 26 | |
| 27 | def raise_timeout(signum, frame): |
| 28 | raise TimeoutError |
| 11 | 29 | |
| 12 | 30 | def drawBlock(x, y, z, type): |
| 13 | 31 | return """<DrawBlock x='{0}' y='{1}' z='{2}' type='{3}'/>""".format(x, y, z, type) |
| … | … | @@ -31,12 +49,16 @@ def build_house(x, y, z, width, length, height, blocktype): |
| 31 | 49 | x_cur = x |
| 32 | 50 | for j in range(width): |
| 33 | 51 | genstring = genstring + drawBlock(x_front, y_cur, z_cur, "glass") + "\n" |
| 34 | | genstring = genstring + drawBlock(x_back, y_cur, z_cur, blocktype) + "\n" |
| 52 | genstring = genstring + drawBlock(x_back, y_cur, z_cur, "diamond_block") + "\n" |
| 35 | 53 | z_cur = z_cur + 1 if z_cur >= 0 else z_cur-1 |
| 36 | 54 | |
| 37 | 55 | for k in range(length): |
| 38 | | genstring = genstring + drawBlock(x_cur, y_cur, z_left, blocktype) + "\n" |
| 39 | | genstring = genstring + drawBlock(x_cur, y_cur, z_right, blocktype) + "\n" |
| 56 | if k % 2 == 0: |
| 57 | genstring = genstring + drawBlock(x_cur, y_cur, z_left, "air") + "\n" |
| 58 | genstring = genstring + drawBlock(x_cur, y_cur, z_right, "air") + "\n" |
| 59 | else: |
| 60 | genstring = genstring + drawBlock(x_cur, y_cur, z_left, blocktype) + "\n" |
| 61 | genstring = genstring + drawBlock(x_cur, y_cur, z_right, blocktype) + "\n" |
| 40 | 62 | x_cur = x_cur + 1 if x_cur >= 0 else x_cur-1 |
| 41 | 63 | |
| 42 | 64 | y_cur = y_cur + 1 if y_cur >= 0 else y_cur-1 |
| … | … | @@ -48,10 +70,105 @@ def build_house(x, y, z, width, length, height, blocktype): |
| 48 | 70 | |
| 49 | 71 | return genstring |
| 50 | 72 | |
| 73 | # Initialize the location coordinates |
| 51 | 74 | agent_x, agent_y, agent_z, agent_yaw = 19, 230, -2, 90 |
| 52 | 75 | key_x, key_y, key_z = 7, 228, -10 |
| 53 | 76 | door_x, door_y, door_z = -4, 228, -3 |
| 54 | | diamond_x, diamond_y, diamond_z = -8, 228, -3 |
| 77 | diamond_x, diamond_y, diamond_z = -18, 228, -3 |
| 78 | start_x, start_y, start_z, width, length, height = -4, 226, -1,6,15,5 |
| 79 | |
| 80 | # relocates the agent to the starting point |
| 81 | def relocate_agent(agent): |
| 82 | agent.sendCommand("tp {} {} {}".format(agent_x, agent_y, agent_z)) |
| 83 | agent.sendCommand("setYaw {}".format(agent_yaw)) |
| 84 | |
| 85 | # stop the agent |
| 86 | def stop_condition(agent, blocktype, sec=5): |
| 87 | print("Moving to the {}".format(blocktype)) |
| 88 | def stop(agent, blocktype): |
| 89 | done = False |
| 90 | world_state = agent.peekWorldState() |
| 91 | while not done: |
| 92 | world_state = agent.peekWorldState() |
| 93 | if world_state.number_of_observations_since_last_state > 0: |
| 94 | ob = json.loads(world_state.observations[-1].text) |
| 95 | if blocktype in ob["BlocksInFront"]: |
| 96 | print("reached at {}".format(blocktype)) |
| 97 | agent.sendCommand("move 0") |
| 98 | done = True |
| 99 | try: |
| 100 | with timeout(sec): |
| 101 | stop(agent, blocktype) |
| 102 | return True |
| 103 | except TimeoutError: |
| 104 | print("Time out") |
| 105 | agent.sendCommand("move 0") |
| 106 | relocate_agent(agent) |
| 107 | return False |
| 108 | |
| 109 | # Get realtime location coordinates |
| 110 | def get_curr_loc(agent): |
| 111 | world_state = agent.peekWorldState() |
| 112 | while world_state.is_mission_running: |
| 113 | world_state = agent.peekWorldState() |
| 114 | if world_state.number_of_observations_since_last_state > 0: |
| 115 | ob = json.loads(world_state.observations[-1].text) |
| 116 | return (int(ob[u'XPos']), int(ob[u'YPos']), int(ob[u'ZPos'])) |
| 117 | else: |
| 118 | return (agent_x, agent_y, agent_z) |
| 119 | |
| 120 | # Turns the agent towards the location given |
| 121 | def turn_to(agent, x1, y1, z1, x2, y2, z2): |
| 122 | def get_angle(x1, y1, z1, x2, y2, z2): |
| 123 | x_dist = abs(x1 - x2) |
| 124 | z_dist = abs(z1 - z2) |
| 125 | h = math.sqrt(x_dist**2 + z_dist**2) |
| 126 | return math.degrees(z_dist/h) if h != 0 else 0 |
| 127 | |
| 128 | angle = get_angle(x1, y1, z1, x2, y2, z2) |
| 129 | yaw = 90 if x1 > x2 else -90 |
| 130 | if yaw > 0: |
| 131 | angle = yaw - angle if z1 < z2 else yaw + angle |
| 132 | else: |
| 133 | angle = yaw + angle if z1 < z2 else yaw - angle |
| 134 | agent.sendCommand("setYaw {}".format(angle)) |
| 135 | |
| 136 | # Move the agent towards the key |
| 137 | # reward=0 |
| 138 | def go_to_the_key(agent): |
| 139 | curr_x, curr_y, curr_z = get_curr_loc(agent) |
| 140 | turn_to(agent,curr_x, curr_y, curr_z, key_x, key_y, key_z) |
| 141 | time.sleep(0.2) |
| 142 | agent.sendCommand("move 1") |
| 143 | if stop_condition(agent, 'tripwire_hook'): |
| 144 | # agent.sendCommand("tp {} {} {}".format(key_x, key_y, key_z)) |
| 145 | agent.sendCommand("hotbar.2 1") |
| 146 | else: |
| 147 | relocate_agent(agent) |
| 148 | |
| 149 | # Move the agent towards the house and enter the house. |
| 150 | # reward = 0 |
| 151 | def go_to_the_house(agent): |
| 152 | curr_x, curr_y, curr_z = get_curr_loc(agent) |
| 153 | turn_to(agent, curr_x, curr_y, curr_z, door_x, door_y, door_z) |
| 154 | time.sleep(0.2) |
| 155 | agent.sendCommand("move 1") |
| 156 | if stop_condition(agent, 'dark_oak_door'): |
| 157 | agent.sendCommand("tp {} {} {}".format(door_x, door_y, door_z)) |
| 158 | else: |
| 159 | relocate_agent(agent) |
| 160 | |
| 161 | # Move the agent towards the diamond and collect it. |
| 162 | # reward = 1 |
| 163 | def go_to_the_diamonds(agent): |
| 164 | curr_x, curr_y, curr_z = get_curr_loc(agent) |
| 165 | turn_to(agent,curr_x, curr_y, curr_z, diamond_x, diamond_y, diamond_z) |
| 166 | time.sleep(0.2) |
| 167 | agent.sendCommand("move 1") |
| 168 | if stop_condition(agent, 'diamond_block'): |
| 169 | agent.sendCommand("tp {} {} {}".format(diamond_x, diamond_y, diamond_z)) |
| 170 | time.sleep(0.2) |
| 171 | relocate_agent(agent) |
| 55 | 172 | |
| 56 | 173 | missionXML = ''' |
| 57 | 174 | <?xml version="1.0" encoding="UTF-8" standalone="no" ?> |
| … | … | @@ -74,7 +191,7 @@ missionXML = ''' |
| 74 | 191 | <ServerHandlers> |
| 75 | 192 | <FlatWorldGenerator generatorString="3;7,220*1,5*3,2;1;biome_1"/> |
| 76 | 193 | <DrawingDecorator> |
| 77 | | '''+build_house(-4, 226, -1,6,6,5,"planks")+''' |
| 194 | '''+build_house(start_x, start_y, start_z, width, length, height,"planks")+''' |
| 78 | 195 | '''+drawBlock(diamond_x, diamond_y, diamond_z, "diamond_block")+''' |
| 79 | 196 | '''+drawLine(door_x, door_y-1, door_z, door_x, door_y, door_z, "dark_oak_door", "EAST")+''' |
| 80 | 197 | '''+drawBlock(key_x, key_y-1, key_z, "command_block")+''' |
| … | … | @@ -96,6 +213,7 @@ missionXML = ''' |
| 96 | 213 | </Inventory> |
| 97 | 214 | </AgentStart> |
| 98 | 215 | <AgentHandlers> |
| 216 | <ObservationFromFullStats/> |
| 99 | 217 | <ObservationFromGrid> |
| 100 | 218 | <Grid name="BlocksInFront"> |
| 101 | 219 | <min x="-1" y="1" z="-1"/> |
| … | … | @@ -107,96 +225,14 @@ missionXML = ''' |
| 107 | 225 | <AbsoluteMovementCommands /> |
| 108 | 226 | <InventoryCommands/> |
| 109 | 227 | <RewardForTouchingBlockType> |
| 110 | | <Block type="diamond_block" reward="1" /> |
| 228 | <Block type="diamond_block" reward="1.0"/> |
| 111 | 229 | </RewardForTouchingBlockType> |
| 112 | | <RewardForCollectingItem> |
| 113 | | <Item reward="1" type="diamond_block" /> |
| 114 | | </RewardForCollectingItem> |
| 115 | 230 | </AgentHandlers> |
| 116 | 231 | </AgentSection> |
| 117 | 232 | |
| 118 | 233 | </Mission> |
| 119 | 234 | |
| 120 | 235 | ''' |
| 121 | | def get_angle(x1, y1, z1, x2, y2, z2): |
| 122 | | x_dist = abs(x1 - x2) |
| 123 | | z_dist = abs(z1 - z2) |
| 124 | | h = math.sqrt(x_dist**2 + z_dist**2) |
| 125 | | return math.degrees(z_dist/h) if h != 0 else 0 |
| 126 | | |
| 127 | | # Turn the agent towards the location given |
| 128 | | def turn_to(agent, x1, y1, z1, yaw, x2, y2, z2): |
| 129 | | angle = get_angle(x1, y1, z1, x2, y2, z2) |
| 130 | | yaw = 90 if x1 > x2 else -90 |
| 131 | | if yaw > 0: |
| 132 | | angle = yaw - angle if z1 < z2 else yaw + angle |
| 133 | | else: |
| 134 | | angle = yaw + angle if z1 < z2 else yaw - angle |
| 135 | | agent.sendCommand("setYaw {}".format(angle)) |
| 136 | | |
| 137 | | # Agent goes to the key |
| 138 | | # reward=0 |
| 139 | | def go_to_the_key(agent): |
| 140 | | global agent_x, agent_y, agent_z |
| 141 | | turn_to(agent,agent_x, agent_y, agent_z, agent_yaw, key_x, key_y, key_z) |
| 142 | | time.sleep(0.2) |
| 143 | | agent.sendCommand("move 1") |
| 144 | | stop_condition(agent, 'tripwire_hook') |
| 145 | | agent_x, agent_y, agent_z = key_x, key_y, key_z |
| 146 | | |
| 147 | | # Agent stops and grab the key |
| 148 | | # observations: agent holds the key and reward=0 |
| 149 | | def get_the_key(agent): |
| 150 | | agent.sendCommand("move 0") |
| 151 | | agent.sendCommand("hotbar.2 1") |
| 152 | | |
| 153 | | # Agent goes to the house. The agent should have the key |
| 154 | | # observations: |
| 155 | | # - Agent is next to closed door |
| 156 | | # - Agent holds the key |
| 157 | | # - reward = 0 |
| 158 | | def go_to_the_house(agent): |
| 159 | | global agent_x, agent_y, agent_z |
| 160 | | turn_to(agent,agent_x, agent_y, agent_z, agent_yaw, door_x, door_y, door_z) |
| 161 | | time.sleep(0.2) |
| 162 | | agent.sendCommand("move 1") |
| 163 | | stop_condition(agent, 'dark_oak_door') |
| 164 | | agent_x, agent_y, agent_z = door_x, door_y, door_z |
| 165 | | |
| 166 | | # Agent opens the house. |
| 167 | | # observations: |
| 168 | | # - Agent next to opened door |
| 169 | | # - reward = 0 |
| 170 | | def open_the_door(agent): |
| 171 | | agent.sendCommand("move 0") |
| 172 | | agent.sendCommand("attack 1") |
| 173 | | |
| 174 | | # Agent goes to the diamond inside the house. |
| 175 | | # reward = 0 |
| 176 | | def go_to_the_diamonds(agent): |
| 177 | | global agent_x, agent_y, agent_z |
| 178 | | turn_to(agent,agent_x, agent_y, agent_z, agent_yaw, diamond_x, diamond_y, diamond_z) |
| 179 | | time.sleep(0.2) |
| 180 | | agent.sendCommand("move 1") |
| 181 | | stop_condition(agent, "diamond_block") |
| 182 | | agent_x, agent_y, agent_z = diamond_x, diamond_y, diamond_z |
| 183 | | |
| 184 | | def stop_condition(agent, block_type): |
| 185 | | done = False |
| 186 | | while not done: |
| 187 | | world_state = agent.getWorldState() |
| 188 | | if world_state.number_of_observations_since_last_state > 0: |
| 189 | | ob = world_state.observations[-1].text |
| 190 | | if block_type in ob: |
| 191 | | agent.sendCommand("move 0") |
| 192 | | done = True |
| 193 | | |
| 194 | | # Agent collects the diamond inside the house |
| 195 | | # reward = 1 |
| 196 | | def collect_diamonds(agent): |
| 197 | | agent.sendCommand("hotbar.1 1") |
| 198 | | agent.sendCommand("attack 1") |
| 199 | | |
| 200 | 236 | |
| 201 | 237 | if __name__ == "__main__": |
| 202 | 238 | """ |
| … | … | @@ -210,32 +246,20 @@ if __name__ == "__main__": |
| 210 | 246 | |
| 211 | 247 | malmoWrapper = MalmoWrapper(missionXML=missionXML, validate=True) |
| 212 | 248 | |
| 213 | | def stp_callback(action, ws): |
| 214 | | pass # you can do something here. |
| 215 | | |
| 216 | 249 | rw, ob, done = malmoWrapper.restart() |
| 217 | 250 | total_reward = 0 |
| 218 | | # main loop: |
| 219 | | time.sleep(0.5) |
| 220 | | malmoWrapper.step(mk_action("hotbar.1", 0)) |
| 221 | | malmoWrapper.step(mk_action("hotbar.2", 0)) |
| 222 | | |
| 223 | 251 | agent = malmoWrapper.agent_host |
| 224 | | |
| 225 | 252 | go_to_the_key(agent) |
| 226 | 253 | |
| 227 | | while not done: |
| 228 | | print(".", end="") |
| 229 | | time.sleep(0.5) |
| 230 | | world_state = malmoWrapper.agent_host.getWorldState() |
| 231 | | |
| 232 | | if world_state.number_of_observations_since_last_state > 0: |
| 233 | | ob = world_state.observations[-1].text |
| 234 | | go_to_the_house(agent) |
| 235 | | get_the_key(agent) |
| 236 | | open_the_door(agent) |
| 237 | | collect_diamonds(agent) |
| 238 | | malmoWrapper.step(mk_action("tp", "{} {} {}".format(19, 230, -2))) |
| 239 | | done = True |
| 254 | world_state = agent.getWorldState() |
| 255 | while world_state.is_mission_running: |
| 256 | world_state = agent.getWorldState() |
| 257 | if world_state.number_of_rewards_since_last_state > 0: |
| 258 | total_reward += world_state.rewards[-1].getValue() |
| 259 | print("total reward = {}".format(total_reward)) |
| 260 | go_to_the_key(agent) |
| 261 | go_to_the_house(agent) |
| 262 | go_to_the_diamonds(agent) |
| 263 | time.sleep(2) |
| 240 | 264 | print() |
| 241 | 265 | print("Mission ended") |