def _kick_test(board, blast_st, bomb_life, my_position, direction): def moving_bomb_check(moving_bomb_pos, p_dir, time_elapsed): pos2=utility.get_next_position(moving_bomb_pos, p_dir) dist=0 for i in range(10): dist +=1 if not utility.position_on_board(board, pos2): break if not (utility.position_is_powerup(board, pos2) or utility.position_is_passage(board, pos2)): break life_now=bomb_life[pos2] - time_elapsed if bomb_life[pos2]>0 and life_now>=-2 and life_now <= 0 and dist<blast_st[pos2]: return False pos2=utility.get_next_position(pos2, p_dir) return True next_position=utility.get_next_position(my_position, direction) assert(utility.position_in_items(board, next_position, [constants.Item.Bomb])) life_value=int(bomb_life[next_position]) strength=int(blast_st[next_position]) dist=0 pos=utility.get_next_position(next_position, direction) perpendicular_dirs=[constants.Action.Left, constants.Action.Right] if direction == constants.Action.Left or direction == constants.Action.Right: perpendicular_dirs=[constants.Action.Down, constants.Action.Up] for i in range(life_value): if utility.position_on_board(board, pos) and utility.position_is_passage(board, pos): #do a check if this position happens to be in flame when the moving bomb arrives! if not (moving_bomb_check(pos, perpendicular_dirs[0], i) and moving_bomb_check(pos, perpendicular_dirs[1], i)): break dist +=1 else: break pos=utility.get_next_position(pos, direction) #can kick and kick direction is valid return dist > strength
def _djikstra(board, my_position, bombs, enemies, depth=None, exclude=None): assert (depth is not None) if exclude is None: exclude = [ constants.Item.Fog, constants.Item.Rigid, constants.Item.Flames ] def out_of_range(p_1, p_2): '''Determines if two points are out of rang of each other''' x_1, y_1 = p_1 x_2, y_2 = p_2 return abs(y_2 - y_1) + abs(x_2 - x_1) > depth items = defaultdict(list) dist = {} prev = {} Q = queue.PriorityQueue() my_x, my_y = my_position for r in range(max(0, my_x - depth), min(len(board), my_x + depth)): for c in range(max(0, my_y - depth), min(len(board), my_y + depth)): position = (r, c) if any([ out_of_range(my_position, position), utility.position_in_items(board, position, exclude), ]): continue if position == my_position: dist[position] = 0 else: dist[position] = np.inf prev[position] = None Q.put((dist[position], position)) for bomb in bombs: if bomb['position'] == my_position: items[constants.Item.Bomb].append(my_position) while not Q.empty(): _, position = Q.get() if utility.position_is_passable(board, position, enemies): x, y = position val = dist[(x, y)] + 1 for row, col in [(-1, 0), (1, 0), (0, -1), (0, 1)]: new_position = (row + x, col + y) if new_position not in dist: continue if val < dist[new_position]: dist[new_position] = val prev[new_position] = position item = constants.Item(board[position]) items[item].append(position) return items, dist, prev
def position_has_no_escape(obs, flame_positions, consider_enemy=False): directions = [ constants.Action.Left, constants.Action.Up, constants.Action.Right, constants.Action.Down ] my_position, can_kick, board, bomb_life, blast_st, enemies, teammate=obs['position'], \ obs['can_kick'], obs['board'], obs['bomb_life'], obs['bomb_blast_strength'], obs['enemies'], obs['teammate'] next_step_flaming_positions = get_next_step_flaming_positions( my_position, board, bomb_life, blast_st, enemies, teammate) future_flaming_positions = [] for pos in list(zip(*np.where(bomb_life > 0))): sz = int(blast_st[pos]) x, y = pos future_flaming_positions.append(pos) for i in range(1, sz): pos2_list = [(x + i, y), (x - i, y), (x, y + i), (x, y - i)] for pos2 in pos2_list: if utility.position_on_board(board, pos2): future_flaming_positions.append(pos2) valid_directions = [] num_passable = 0 passable_position = None for direction in directions: next_pos = utility.get_next_position(my_position, direction) if not utility.position_on_board(board, next_pos): continue if can_kick and utility.position_in_items(board, next_pos, [constants.Item.Bomb]): if kick_test(board, blast_st, bomb_life, my_position, direction): #passed kick test, so at least kick direction is an escape return False continue flag_passable = position_is_passable(board, next_pos, enemies) if not flag_passable: continue elif flag_passable and consider_enemy and next_pos in future_flaming_positions and passable_may_next_to_enemy( board, next_pos, enemies): continue else: num_passable += 1 passable_position = next_pos if next_pos in flame_positions or next_pos in next_step_flaming_positions: continue valid_directions.append(direction) if num_passable == 0: return True if (my_position not in flame_positions) and (my_position not in next_step_flaming_positions): return False return len(valid_directions) == 0
def _fire_bomb(game_data, row, col, row_off, col_off, strength): if strength <= 0: return next_row = row + row_off next_col = col + col_off if not EnvSimulator._position_on_board(game_data, next_row, next_col): return if utility.position_in_items( game_data, (next_row, next_col), [constants.Item.Rigid, constants.Item.Wood]): return EnvSimulator._set_fire(game_data, next_row, next_col, False) EnvSimulator._fire_bomb(game_data, next_row, next_col, row_off, col_off, strength - 1)
def _get_fire_positions_in_direction(board, x, y, strength, x_dir, y_dir, fire_pos): if strength <= 0 or not utility.position_on_board(board, (x, y)): return next_x = x + x_dir next_y = y + y_dir if not utility.position_on_board(board, (next_x, next_y)): return if utility.position_in_items( board, (next_x, next_y), [constants.Item.Rigid, constants.Item.Wood]): return fire_pos.append((next_x, next_y)) EnvSimulator._get_fire_positions_in_direction(board, next_x, next_y, strength - 1, x_dir, y_dir, fire_pos)
def passable_may_next_to_enemy(board, position, enemies): #means enemy can get here in 2 steps thus block you! assert (position_is_passable(board, position, enemies)) directions = [ constants.Action.Left, constants.Action.Up, constants.Action.Right, constants.Action.Down ] for direction in directions: next_pos = utility.get_next_position(position, direction) if not utility.position_on_board(board, next_pos): continue if utility.position_in_items(board, next_pos, enemies): return True #if position_is_passable(board, next_pos): # for d2 in directions: # next_pos2=utility.get_next_position(next_pos, direction) # if not utility.position_on_board(board, next_pos2): # continue # if utility.position_in_items(board, next_pos2, enemies): # return True return False
def _get_items_in_direction(board, pos, strength, x_dir, y_dir, items): if strength <= 0 or not utility.position_on_board(board, pos): return x, y = pos next_x = x + x_dir next_y = y + y_dir if not utility.position_on_board(board, (next_x, next_y)): return item = board[(next_x, next_y)] try: if type(item) == tuple: print(item) if not item in items: items.append(item) except: if type(item) == tuple: print(item) print(item, items) if utility.position_in_items( board, (next_x, next_y), [constants.Item.Rigid, constants.Item.Wood]): return EnvSimulator._get_items_in_direction(board, (next_x, next_y), strength - 1, x_dir, y_dir, items)
def _compute_safe_actions(obs, exclude_kicking=False, prev_two_obs=(None, None)): dirs = _all_directions(exclude_stop=True) ret = set() my_position, board, blast_st, bomb_life, can_kick = obs['position'], obs['board'], obs['bomb_blast_strength'], obs[ 'bomb_life'], obs['can_kick'] kick_dir = None bomb_real_life_map = _all_bomb_real_life(board, bomb_life, blast_st) flag_cover_passages = [] for direction in dirs: position = utility.get_next_position(my_position, direction) if not utility.position_on_board(board, position): continue if (not exclude_kicking) and utility.position_in_items(board, position, [constants.Item.Bomb]) and can_kick: # filter kick if kick is unsafe if _kick_test(board, blast_st, bomb_real_life_map, my_position, direction): ret.add(direction.value) kick_dir = direction.value gone_flame_pos = None if (prev_two_obs[0] != None and prev_two_obs[1] != None) and _check_if_flame_will_gone(obs, prev_two_obs, position): # three consecutive flames means next step this position must be good # make this a candidate obs['board'][position] = constants.Item.Passage.value gone_flame_pos = position if utility.position_is_passage(board, position) or utility.position_is_powerup(board, position): my_id = obs['board'][my_position] obs['board'][my_position] = constants.Item.Bomb.value if bomb_life[ my_position] > 0 else constants.Item.Passage.value flag_cover, min_cover_value, max_cover_value = _position_covered_by_bomb(obs, position, bomb_real_life_map) flag_cover_passages.append(flag_cover) if not flag_cover: ret.add(direction.value) else: min_escape_step = _compute_min_evade_step(obs, [position], position, bomb_real_life_map) assert (min_escape_step > 0) if min_escape_step < min_cover_value: ret.add(direction.value) obs['board'][my_position] = my_id if gone_flame_pos is not None: obs['board'][gone_flame_pos] = constants.Item.Flames.value # Test Stop action only when agent is covered by bomb, # otherwise Stop is always an viable option my_id = obs['board'][my_position] obs['board'][my_position] = constants.Item.Bomb.value if bomb_life[ my_position] > 0 else constants.Item.Passage.value # REMEMBER: before compute min evade step, modify board accordingly first.. flag_cover, min_cover_value, max_cover_value = _position_covered_by_bomb(obs, my_position, bomb_real_life_map) if flag_cover: min_escape_step = _compute_min_evade_step(obs, [None, my_position], my_position, bomb_real_life_map) if min_escape_step < min_cover_value: ret.add(constants.Action.Stop.value) else: ret.add(constants.Action.Stop.value) obs['board'][my_position] = my_id # REMEBER: change the board back # Now test bomb action if not (obs['ammo'] <= 0 or obs['bomb_life'][obs['position']] > 0): # place bomb might be possible assert (BOMBING_TEST in ['simple', 'simple_adjacent', 'lookahead']) if BOMBING_TEST == 'simple': if not flag_cover: ret.add(constants.Action.Bomb.value) elif BOMBING_TEST == 'simple_adjacent': if (not flag_cover) and (not any(flag_cover_passages)): ret.add(constants.Action.Bomb.value) else: # lookahead if (constants.Action.Stop.value in ret) and len(ret) > 1 and (kick_dir is None): obs2 = copy.deepcopy(obs) my_pos = obs2['position'] obs2['board'][my_pos] = constants.Item.Bomb.value obs2['bomb_life'][my_pos] = min_cover_value if flag_cover else 10 obs2['bomb_blast_strength'][my_pos] = obs2['blast_strength'] bomb_life2, bomb_blast_st2, board2 = obs2['bomb_life'], obs2['bomb_blast_strength'], obs2['board'] bomb_real_life_map = _all_bomb_real_life(board2, bomb_life2, bomb_blast_st2) min_evade_step = _compute_min_evade_step(obs2, [None, my_position], my_pos, bomb_real_life_map) current_cover_value = obs2['bomb_life'][my_pos] if min_evade_step < current_cover_value: ret.add(constants.Action.Bomb.value) return ret
def search_time_expanded_network(list_boards, my_position, id=None): """ Find survivable time-positions in the list of boards from my position Parameters ---------- list_boards : list list of boards, generated by _board_sequence my_position : tuple my position, where the search starts Return ------ survivable : list list of the set of survivable time-positions at each time survivable[t] : set of survivable positions at time t prev : list prev[t] : dict prev[t][position] : list of positions from which one can reach the position at time t succ : list succ[t] : dict succ[t][position] : list of positions to which one can reach the position at time t + 1 subtree : list subtree[t] : dict subtree[t][position] : set of time-positions that are the children of (t, position) """ depth = len(list_boards) passable = [ constants.Item.Passage, constants.Item.ExtraBomb, constants.Item.IncrRange, constants.Item.Kick ] if list_boards[0][my_position] == constants.Item.Flames.value: if id is None: return [set()] * depth else: return [set()] * depth, id # Forward search for reachable positions # reachable[(t,x,y]): whether can reach (x,y) at time t reachable = np.full((depth, ) + board_shape, False) reachable[(0, ) + my_position] = True next_positions = set([my_position]) my_position_get_flame = False for t in range(1, depth): if list_boards[t][my_position] == constants.Item.Flames.value: my_position_get_flame = True curr_positions = next_positions _next_positions = list() # add all possible positions for curr_position in curr_positions: _next_positions.append(curr_position) x, y = curr_position for row, col in [(0, 0), (-1, 0), (1, 0), (0, -1), (0, 1)]: _next_positions.append((x + row, y + col)) next_positions = list() for position in set(_next_positions): if not on_board(position[0], position[1]): # remove out of positions continue if any([ position == my_position and not my_position_get_flame, utility.position_in_items(list_boards[t], position, passable) ]): next_positions.append(position) for position in next_positions: reachable[(t, ) + position] = True # Backward search for survivable positions # survivable[t]: set of survavable positions at time t survivable = [set() for _ in range(depth)] survivable[-1] = next_positions prev = [defaultdict(list) for _ in range(depth + 1)] for t in range(depth - 1, 0, -1): for position in survivable[t]: # for each position surviving at time t # if the position is on a bomb, I must have stayed there since I placed the bomb if list_boards[t][position] == constants.Item.Bomb.value: if reachable[(t - 1, ) + position]: prev[t][position].append(position) continue # otherwise, standard case x, y = position for row, col in [(0, 0), (-1, 0), (1, 0), (0, -1), (0, 1)]: # consider the prev_position at time t - 1 prev_position = (x + row, y + col) if not on_board(prev_position[0], prev_position[1]): # discard the prev_position if out of board continue if reachable[(t - 1, ) + prev_position]: # can reach the position at time t # from the prev_position at time t-1 prev[t][position].append(prev_position) # the set of prev_positions at time t-1 # from which one can reach the surviving positions at time t survivable[t - 1] = set( [position for prevs in prev[t].values() for position in prevs]) if id is None: return survivable else: return survivable, id
def _djikstra(board, my_position, bombs, enemies, depth=None, exclude=None): """ Dijkstra method Parameters ---------- board = np.array(obs['board']) my_position = tuple(obs['position']) bombs = convert_bombs(np.array(obs['bomb_blast_strength'])) enemies = [constants.Item(e) for e in obs['enemies']] """ if depth is None: depth = len(board) * 2 if exclude is None: exclude = [ constants.Item.Fog, constants.Item.Rigid, constants.Item.Flames ] def out_of_range(p1, p2): x1, y1 = p1 x2, y2 = p2 return abs(y2 - y1) + abs(x2 - x1) > depth items = defaultdict(list) for bomb in bombs: if bomb['position'] == my_position: items[constants.Item.Bomb].append(my_position) dist = {} prev = {} mx, my = my_position for r in range(max(0, mx - depth), min(len(board), mx + depth)): for c in range(max(0, my - depth), min(len(board), my + depth)): position = (r, c) if any([ out_of_range(my_position, position), utility.position_in_items(board, position, exclude), ]): continue if position == my_position: dist[position] = 0 else: dist[position] = np.inf prev[position] = None item = constants.Item(board[position]) items[item].append(position) # Djikstra H = [] heapq.heappush(H, (0, my_position)) while H: min_dist, position = heapq.heappop(H) if not utility.position_is_passable(board, position, enemies): continue x, y = position for row, col in [(-1, 0), (1, 0), (0, -1), (0, 1)]: new_position = (row + x, col + y) if new_position not in dist: continue if min_dist + 1 < dist[new_position]: dist[new_position] = min_dist + 1 prev[new_position] = position heapq.heappush(H, (dist[new_position], new_position)) return items, dist, prev
def _search_time_expanded_network(self, list_boards, my_position): """ Find survivable time-positions in the list of boards from my position Parameters ---------- list_boards : list list of boards, generated by _board_sequence my_position : tuple my position, where the search starts Return ------ survivable : list list of the set of survivable time-positions at each time survivable[t] : set of survivable positions at time t prev : list prev[t] : dict prev[t][position] : list of positions from which one can reach the position at time t """ depth = len(list_boards) # TODO : what to do with Fog? exclude = [constants.Item.Fog, constants.Item.Rigid, constants.Item.Wood, constants.Item.Bomb, constants.Item.Flames, constants.Item.AgentDummy] if list_boards[0][my_position] == constants.Item.Flames.value: return [set()] * depth, [list()] * depth # Forward search for reachable positions # reachable[(t,x,y]): whether can reach (x,y) at time t reachable = np.full((depth,) + self.board_shape, False) reachable[(0,)+my_position] = True next_positions = set([my_position]) my_position_get_flame = False for t in range(1, depth): if list_boards[t][my_position] == constants.Item.Flames.value: my_position_get_flame = True curr_positions = next_positions next_positions = set() # add all possible positions for curr_position in curr_positions: next_positions.add(curr_position) x, y = curr_position for row, col in [(0, 0), (-1, 0), (1, 0), (0, -1), (0, 1)]: next_positions.add((x + row, y + col)) for position in next_positions.copy(): if not self._on_board(position): # remove out of positions next_positions.remove(position) elif list_boards[t][position] == constants.Item.AgentDummy.value: # TODO: this may be too conservative # avoid contact to other agents next_positions.remove(position) elif position == my_position and not my_position_get_flame: # can stay even on bomb until getting flame continue elif utility.position_in_items(list_boards[t], position, exclude): # remove blocked next_positions.remove(position) elif utility.position_is_agent(list_boards[t], position): # if occupied by another agent next_positions.remove(position) for position in next_positions: reachable[(t,)+position] = True # Backward search for survivable positions # survivable[t]: set of survavable positions at time t # prev[t][position]: list of positions from which # one can reach the position at time t survivable = [set() for _ in range(depth)] survivable[-1] = next_positions prev = [defaultdict(list) for _ in range(depth+1)] for t in range(depth-1, 0, -1): for position in survivable[t]: # for each position surviving at time t # if the position is on a bomb, I must have stayed there since I placed the bomb if list_boards[t][position] == constants.Item.Bomb.value: if reachable[(t-1,)+position]: prev[t][position].append(position) continue # otherwise, standard case x, y = position for row, col in [(0, 0), (-1, 0), (1, 0), (0, -1), (0, 1)]: # consider the prev_position at time t - 1 prev_position = (x + row, y + col) if not self._on_board(prev_position): # discard the prev_position if out of board continue if reachable[(t-1,)+prev_position]: # can reach the position at time t # from the prev_position at time t-1 prev[t][position].append(prev_position) # the set of prev_positions at time t-1 # from which one can reach the surviving positions at time t survivable[t-1] = set([position for prevs in prev[t].values() for position in prevs]) return survivable, prev
def get_filtered_directions(obs, next_step_flaming_positions, exclude_kicking=False): ret = set() my_position, board, blast_st, bomb_life, can_kick = obs['position'], obs[ 'board'], obs['bomb_blast_strength'], obs['bomb_life'], obs['can_kick'] enemies = obs['enemies'] teammate = obs['teammate'].value kick_dir = None could_be_occupied_dir = None for direction in [ constants.Action.Left, constants.Action.Up, constants.Action.Right, constants.Action.Down ]: position = utility.get_next_position(my_position, direction) if not utility.position_on_board(board, position): continue if position in next_step_flaming_positions: continue if not exclude_kicking and utility.position_in_items( board, position, [constants.Item.Bomb]) and can_kick: #filter kick if kick is unsafe if kick_test(board, blast_st, bomb_life, my_position, direction): ret.add(direction.value) kick_dir = direction.value if position_is_passable(board, position, enemies): if bomb_life[my_position] > 0 and not agent_on_bomb_next_move_test( my_position, direction, board, bomb_life, blast_st): #if moving to this passage leads to a long corridor continue if my_position in next_step_flaming_positions and not _opponent_test( board, position, enemies): # if I am in danger, I should not go to a position which may also be the next position of enemies # unless this is the only passage could_be_occupied_dir = direction.value continue if not _teammate_test(board, position, teammate, next_step_flaming_positions): continue new_obs = step_to(obs, position) #one step lookahead search see if this new position would lead to no way dodge #if not is_going_into_siege(observ, old_pos, new_pos): flame_positions = next_step_flaming_positions # after step to the new_position, when check around, remember to # exclude those flame positions computed previously since they must have been filed with flames if not position_has_no_escape( new_obs, flame_positions, consider_enemy=False): ret.add(direction.value) if len(ret) == 0 and could_be_occupied_dir is not None: ret.add(could_be_occupied_dir) if my_position not in next_step_flaming_positions and ( not (kick_dir and len(ret) == 1)): new_obs = step_to(obs, my_position) if not (bomb_life[my_position] > 0 and bomb_life[my_position] <= 3) and not position_has_no_escape( new_obs, next_step_flaming_positions, consider_enemy=True): ret.add(constants.Action.Stop.value) return ret
def _djikstra(board, my_position, bombs, enemies, bomb_timer=None, depth=None, exclude=None): if depth is None: depth = len(board) * 2 if exclude is None: exclude = [ constants.Item.Fog, constants.Item.Rigid, constants.Item.Flames ] def out_of_range(p1, p2): x1, y1 = p1 x2, y2 = p2 return abs(y2 - y1) + abs(x2 - x1) > depth items = defaultdict(list) for bomb in bombs: if bomb['position'] == my_position: items[constants.Item.Bomb].append(my_position) dist = {} prev = {} mx, my = my_position for r in range(max(0, mx - depth), min(len(board), mx + depth)): for c in range(max(0, my - depth), min(len(board), my + depth)): position = (r, c) if any([ out_of_range(my_position, position), utility.position_in_items(board, position, exclude), ]): continue if position == my_position: dist[position] = 0 else: dist[position] = np.inf prev[position] = None item = constants.Item(board[position]) items[item].append(position) # Djikstra H = [] heapq.heappush(H, (0, my_position)) while H: min_dist, position = heapq.heappop(H) if (board[position] != constants.Item.Bomb.value ) and not utility.position_is_passable(board, position, enemies): continue x, y = position for row, col in [(-1, 0), (1, 0), (0, -1), (0, 1)]: new_position = (row + x, col + y) if new_position not in dist: continue if not utility.position_is_passable(board, new_position, enemies): continue if bomb_timer is not None: t = bomb_timer[new_position] if t > 0 and abs((min_dist + 1) - t) < 2: continue if min_dist + 1 < dist[new_position]: dist[new_position] = min_dist + 1 prev[new_position] = position heapq.heappush(H, (dist[new_position], new_position)) return items, dist, prev
def get_dijkstra_act(obs_nf, goal_abs, exclude=None, rang=11): # 放炸弹 if goal_abs == rang * rang: return 5 # 停止在原地 my_position = tuple(obs_nf['position']) goal = extra_position(goal_abs, obs_nf) if goal == my_position: return 0 board = np.array(obs_nf['board']) enemies = [constants.Item(e) for e in obs_nf['enemies']] if exclude is None: exclude = [ constants.Item.Rigid, constants.Item.Wood, ] dist = {} prev = {} Q = queue.Queue() # my_x, my_y = my_position for r in range(0, rang): for c in range(0, rang): position = (r, c) if any([utility.position_in_items(board, position, exclude)]): continue prev[position] = None if position == my_position: Q.put(position) dist[position] = 0 else: dist[position] = np.inf while not Q.empty(): position = Q.get() if position_is_passable(board, position, enemies): x, y = position val = dist[(x, y)] + 1 for row, col in [(-1, 0), (1, 0), (0, -1), (0, 1)]: new_position = (row + x, col + y) if new_position not in dist: continue if val < dist[new_position]: dist[new_position] = val prev[new_position] = position Q.put(new_position) elif val == dist[new_position] and random.random() < .5: dist[new_position] = val prev[new_position] = position row_g, col_g = goal my_x, my_y = my_position up = (-1, 0) down = (1, 0) left = (0, -1) right = (0, 1) # 判断goal是否可以达到 while goal in dist and prev[goal] != my_position: goal = prev[goal] legal_act = [] # 无法到达有效目的 if goal not in dist: # 可以向下行走 if row_g > my_x: if isLegal_act(obs_nf, down, rang=rang): legal_act.append(2) elif row_g < my_x: if isLegal_act(obs_nf, up, rang=rang): legal_act.append(1) # 可以向右行走 if col_g > my_x: if isLegal_act(obs_nf, right, rang=rang): legal_act.append(4) elif col_g < my_x: if isLegal_act(obs_nf, left, rang=rang): legal_act.append(3) if legal_act: return random.choice(legal_act) # 可以达到的目的 else: count = 1 for act_to in [up, down, left, right]: row, col = act_to if goal == (my_x + row, my_y + col): return count count += 1 return 0
def _djikstra_act_v1(obs_nf, goal_abs, exclude=None): if goal_abs == 121: return 5 board = np.array(obs_nf['board']) my_position = tuple(obs_nf['position']) enemies = [constants.Item(e) for e in obs_nf['enemies']] if exclude is None: exclude = [ constants.Item.Rigid, constants.Item.Wood, ] dist = {} prev = {} Q = queue.Queue() # my_x, my_y = my_position for r in range(0, 11): for c in range(0, 11): position = (r, c) if any([utility.position_in_items(board, position, exclude)]): continue prev[position] = None if position == my_position: Q.put(position) dist[position] = 0 else: dist[position] = np.inf while not Q.empty(): position = Q.get() if position_is_passable(board, position, enemies): x, y = position val = dist[(x, y)] + 1 for row, col in [(-1, 0), (1, 0), (0, -1), (0, 1)]: new_position = (row + x, col + y) if new_position not in dist: continue if val < dist[new_position]: dist[new_position] = val prev[new_position] = position Q.put(new_position) elif val == dist[new_position] and random.random() < .5: dist[new_position] = val prev[new_position] = position goal = extra_goal(goal_abs) while goal in dist and prev[goal] != my_position: goal = prev[goal] # up, down, left, right my_x, my_y = my_position count = 1 for act_abs in [(-1, 0), (1, 0), (0, -1), (0, 1)]: row, col = act_abs if goal == (my_x + row, my_y + col): return count count += 1 return 0
def _djikstra_act_v4(obs_nf, goal_abs, exclude=None, rang=11): # 放炸弹 if goal_abs == rang * rang: print_info('释放炸弹') return 5 # 停止在原地 my_position = tuple(obs_nf['position']) goal = extra_goal(goal_abs, rang=rang) # print('goal', goal) if goal == my_position: print_info('停在原地') return 0 board = np.array(obs_nf['board']) enemies = [constants.Item(e) for e in obs_nf['enemies']] if exclude is None: exclude = [ constants.Item.Rigid, constants.Item.Wood, ] dist = {} prev = {} Q = queue.Queue() # my_x, my_y = my_position for r in range(0, rang): for c in range(0, rang): position = (r, c) if any([utility.position_in_items(board, position, exclude)]): continue prev[position] = None if position == my_position: Q.put(position) dist[position] = 0 else: dist[position] = np.inf while not Q.empty(): position = Q.get() if position_is_passable(board, position, enemies): x, y = position val = dist[(x, y)] + 1 for row, col in [(-1, 0), (1, 0), (0, -1), (0, 1)]: new_position = (row + x, col + y) if new_position not in dist: continue if val < dist[new_position]: dist[new_position] = val prev[new_position] = position Q.put(new_position) elif val == dist[new_position] and random.random() < .5: dist[new_position] = val prev[new_position] = position row_g, col_g = goal my_x, my_y = my_position up = (-1, 0) down = (1, 0) left = (0, -1) right = (0, 1) # 判断goal是否可以达到 while goal in dist and prev[goal] != my_position: goal = prev[goal] legal_act = [] # 无法到达有效目的 if goal not in dist: # print('random') goal_abs = random.randint(0, rang * rang) return _djikstra_act_v4(obs_nf, goal_abs, rang=rang) # 可以达到的目的 else: count = 1 for act_to in [up, down, left, right]: row, col = act_to if goal == (my_x + row, my_y + col): print_info('向目的地移动') return count count += 1 print_info('非法的移动动作') return 0