class BlockDudeExtraHard(gym.Env): metadata = {'render.modes': ['human', 'rgb_array']} def __init__(self): pygame.init() self.play_on = True self.carry = False self.carried_bloc = -1 self.screen_width = 432 self.screen_height = 288 # pygame.display.set_caption("Block Dude") self.screen = pygame.display.set_mode( (self.screen_width, self.screen_height)) self.vel = 24 self.x_player_init = [24] self.y_player_init = [264 - self.vel] self.x_blocks_init = [120] self.y_blocks_init = [240] self.player = Player(self.screen, self.x_player_init, self.y_player_init, self.vel, self.vel) self.brick_bottom_x = [ i * self.vel for i in range(int(self.screen_width / self.vel)) ] self.brick_bottom_y = [ self.screen_height - self.vel for i in range(len(self.brick_bottom_x)) ] self.brick_bottom_x += [192, 192] self.brick_bottom_y += [264 - self.vel, 264 - 2 * self.vel] self.bricks = Component(self.screen, 'BD_sprites/Brick.png', self.brick_bottom_x, self.brick_bottom_y) self.blocks = Component(self.screen, 'BD_sprites/Block.png', self.x_blocks_init, self.y_blocks_init) self.door = Component(self.screen, 'BD_sprites/Door.png', [408], [240]) self.initial_obs = self.get_state() self.discrete_actions = [0, 1, 2, 3] self.action_space = Discrete(len(self.discrete_actions)) self.action = np.random.choice(self.discrete_actions) self.observation_space = Box(low=0, high=255, shape=(self.screen_height, self.screen_width, 3), dtype=np.uint8) self.n_step = 0 self.max_steps = 100 self.viewer = None def redraw(self): self.screen.fill((255, 255, 255)) self.player.draw() self.bricks.draw() self.blocks.draw() self.door.draw() pygame.display.update() def set_max_steps(self, steps): self.max_steps = steps def state(self): canvas = np.zeros((self.screen_width, self.screen_height, 3)) def reset(self): self.player.set_position(self.x_player_init, self.y_player_init) self.player.set_direction('LEFT') self.blocks.set_position(self.x_blocks_init, self.y_blocks_init) self.carry = False self.carried_bloc = -1 self.action = -1 self.n_step = 0 self.redraw() observation = self.get_state() return observation def gravity(self, agent, index=0): bricks_list = [] blocks_list = [] high_brick, high_block = [], [] for i in range(len(self.bricks.x)): if self.bricks.x[i] == agent.x[index]: if self.bricks.y[i] > agent.y[index]: bricks_list.append(i) for i in range(len(self.blocks.x)): if self.blocks.x[i] == agent.x[index]: if self.blocks.y[i] > agent.y[index]: blocks_list.append(i) if bricks_list: min_ind = bricks_list[np.argmin( [self.bricks.y[i] for i in bricks_list])] high_brick = [self.bricks.x[min_ind], self.bricks.y[min_ind]] if blocks_list: min_ind = blocks_list[np.argmin( [self.blocks.y[i] for i in blocks_list])] high_block = [self.blocks.x[min_ind], self.blocks.y[min_ind]] if (high_brick and not high_block): agent.y[index] = high_brick[1] - self.vel elif (high_block and not high_brick): agent.y[index] = high_block[1] - self.vel elif high_brick and high_brick: if high_brick[1] < high_block[1]: agent.y[index] = high_brick[1] - self.vel elif high_brick[1] > high_block[1]: agent.y[index] = high_block[1] - self.vel def step(self, action): self.n_step += 1 self.play_on = False brick_dir_left = self.bricks.is_component(self.player.x[0] - self.vel, self.player.y[0]) block_dir_left = self.blocks.is_component(self.player.x[0] - self.vel, self.player.y[0]) brick_dir_right = self.bricks.is_component(self.player.x[0] + self.vel, self.player.y[0]) block_dir_right = self.blocks.is_component(self.player.x[0] + self.vel, self.player.y[0]) brick_up_left = self.bricks.is_component(self.player.x[0] - self.vel, self.player.y[0] - self.vel) block_up_left = self.blocks.is_component(self.player.x[0] - self.vel, self.player.y[0] - self.vel) brick_up_right = self.bricks.is_component(self.player.x[0] + self.vel, self.player.y[0] - self.vel) block_up_right = self.blocks.is_component(self.player.x[0] + self.vel, self.player.y[0] - self.vel) # if player moves left if action == 0 and self.player.x[0] - self.vel >= 0: self.player.set_direction('LEFT') if not (brick_dir_left[0] or block_dir_left[0]): self.player.x[0] -= self.vel # if player moves right elif action == 1 and self.player.x[ 0] < self.screen_width - self.player.width: self.player.set_direction('RIGHT') if not (brick_dir_right[0] or block_dir_right[0]): self.player.x[0] += self.vel # if player moves up elif action == 2 and self.player.y[0] - self.vel > 0: if self.player.get_direction() == 'LEFT' and ( brick_dir_left[0] or block_dir_left[0] ) and not (brick_up_left[0] or block_up_left[0]): self.player.y[0] -= self.vel self.player.x[0] -= self.vel elif self.player.get_direction() == 'RIGHT' and ( brick_dir_right[0] or block_dir_right[0] ) and not (brick_up_right[0] or block_up_right[0]): self.player.y[0] -= self.vel self.player.x[0] += self.vel # if player picks or drops block elif action == 3: if not self.carry: if self.player.get_direction() == 'LEFT' and block_dir_left[ 0] and not brick_up_left[0] and not block_up_left[0]: self.carried_bloc = block_dir_left[1] self.carry = True elif self.player.get_direction( ) == 'RIGHT' and block_dir_right[ 0] and not brick_up_right[0] and not block_up_right[0]: self.carried_bloc = block_dir_right[1] self.carry = True elif self.carry: self.carry = False if self.player.x[0] != 0 and self.player.get_direction( ) == 'LEFT' and brick_dir_left[0] and not brick_up_left[ 0] and not block_dir_left[0] and not block_up_left[0]: self.blocks.x[self.carried_bloc] = self.bricks.x[ brick_dir_left[1]] self.blocks.y[self.carried_bloc] = self.bricks.y[ brick_dir_left[1]] - self.vel elif self.player.x[0] != 0 and self.player.get_direction( ) == 'LEFT' and block_dir_left[0] and not block_up_left[ 0] and not brick_dir_left[0] and not brick_up_left[0]: self.blocks.x[self.carried_bloc] = self.blocks.x[ block_dir_left[1]] self.blocks.y[self.carried_bloc] = self.blocks.y[ block_dir_left[1]] - self.vel elif self.player.get_direction( ) == 'RIGHT' and brick_dir_right[0] and not brick_up_right[ 0] and not block_dir_right[0] and not block_up_right[0]: self.blocks.x[self.carried_bloc] = self.bricks.x[ brick_dir_right[1]] self.blocks.y[self.carried_bloc] = self.bricks.y[ brick_dir_right[1]] - self.vel elif self.player.get_direction( ) == 'RIGHT' and block_dir_right[0] and not block_up_right[ 0] and not brick_dir_right[0] and not brick_up_right[0]: self.blocks.x[self.carried_bloc] = self.blocks.x[ block_dir_right[1]] self.blocks.y[self.carried_bloc] = self.blocks.y[ block_dir_right[1]] - self.vel elif self.player.get_direction( ) == 'RIGHT' and not brick_dir_right[0] and not block_dir_right[ 0] and not brick_up_right[0] and not block_up_right[0]: self.blocks.x[ self.carried_bloc] = self.player.x[0] + self.vel self.blocks.y[self.carried_bloc] = self.player.y[0] elif self.player.x[0] != 0 and self.player.get_direction( ) == 'LEFT' and not brick_dir_left[0] and not block_dir_left[ 0] and not brick_up_left[0] and not block_up_left[0]: self.blocks.x[ self.carried_bloc] = self.player.x[0] - self.vel self.blocks.y[self.carried_bloc] = self.player.y[0] else: self.carry = True # pull player down (gravity) if not action == 2: self.gravity(self.player) # pull block down, on player or using gravity if self.blocks.x: if self.carry: self.blocks.x[self.carried_bloc] = self.player.x[0] self.blocks.y[self.carried_bloc] = self.player.y[0] - self.vel else: self.gravity(self.blocks, self.carried_bloc) self.redraw() info = {} observation = self.get_state() if self.door.is_door(self.player.x, self.player.y): done = True reward = 50.0 self.reset() elif self.n_step > self.max_steps: done = True reward = -1.0 self.reset() else: done = False reward = -1.0 return observation, reward, done, info def sample_action(self): return np.random.choice(self.discrete_actions) def play(self): running = True while running: pygame.time.delay(50) for event in pygame.event.get(): if event.type == pygame.QUIT: running = False self.keys = pygame.key.get_pressed() num_keys = 0 for key in self.keys: num_keys += 1 if key == 1 else 0 if event.type == pygame.KEYDOWN and num_keys == 1 and self.play_on: if self.keys[pygame.K_q]: running = False self.reset() elif self.keys[pygame.K_r]: new_ob = self.reset() elif self.keys[pygame.K_LEFT]: self.action = 0 elif self.keys[pygame.K_RIGHT]: self.action = 1 elif self.keys[pygame.K_UP]: self.action = 2 elif self.keys[pygame.K_DOWN]: self.action = 3 if self.action != -1: observation, reward, done, _ = self.step(self.action) elif event.type == pygame.KEYUP: if not (self.keys[pygame.K_LEFT] and self.keys[pygame.K_RIGHT] and self.keys[pygame.K_UP] and self.keys[pygame.K_DOWN]): self.play_on = True self.redraw() def get_state(self): state = np.fliplr( np.flip( np.rot90( pygame.surfarray.array3d( pygame.display.get_surface()).astype(np.uint8)))) return state def render(self, mode='human', close=False): img = self.get_state() if mode == 'human': if self.viewer is None: self.viewer = rendering.SimpleImageViewer() self.viewer.imshow(img) elif mode == 'rgb_array': return img