def run_dijkstra(graph, source, target): """Dijkstra's shortest path algorithm""" queue = PriorityQueue() dist = {source: 0} prev = {} for vertex in graph: if vertex != source: dist[vertex] = float("inf") queue.insert(vertex, dist[vertex]) while not queue.is_empty(): u_dist, u = queue.pop() u_node = graph[u] if u == target: break for v in u_node['linkTo']: if queue.is_node_in_queue(v): alt = dist[u] + \ calc_distance(int(u_node['x']), int(u_node['y']), int(graph[v]['x']), int(graph[v]['y'])) if alt < dist[v]: dist[v] = alt prev[v] = u queue.insert(v, alt) path = [] curr = target while curr in prev: path.append(curr) curr = prev[curr] path.append(source) return path[::-1]
def run_dijkstra(graph, source, target): """Dijkstra's shortest path algorithm""" queue = PriorityQueue() dist = {source: 0} prev = {} for vertex in graph: if vertex != source: dist[vertex] = float("inf") queue.insert(vertex, dist[vertex]) while not queue.is_empty(): u_dist, u = queue.pop() u_node = graph[u] if u == target: break for v in u_node['linkTo']: if queue.is_node_in_queue(v): alt = dist[u] + \ calc_distance(int(u_node['x']), int(u_node['y']), int(graph[v]['x']), int(graph[v]['y'])) if alt < dist[v]: dist[v] = alt prev[v] = u queue.insert(v, alt) path = [] curr = target while curr in prev: path.append(curr) curr = prev[curr] path.append(source) return path[::-1]
def Dijkstra(G, src): #initialization dist = {} # prev = {} Q = PriorityQueue() # print(g["home"].keys()) #출발노드 s는 자신까지의 거리가 0이고 자신의 predecessor dist[src] = 0 # prev[s] = None #다른 노드들은 모두 거리를 infinity로 설정하고 predecessor는 일단 None으로 설정하고 '''for n in g: dist[n[0]] = float('inf') prev[n[0]] = None dist[n[1]] = float('inf') prev[n[1]] = None ''' #그러면서 PQ에다가 노드들을 넣어줍니다. for node in G.keys(): if node != src: dist[node] = float('inf') #prev[n] = None ''' if n in g[s].keys(): dist[n] = float('inf') prev[n] = None ''' Q.insert(dist[node], node) # n이 우선순위 dist가 value #PQ가 빌때까지 계속 루프를 돌면서, while Q.size() > 0: p, u = Q.pop() #현재까지 가장 짧은 거리를 갖고 있는 노드를 pop #꺼낸 노드의 각 이웃들까지의 거리를 현재 자신까지의 minimum cost와 더한 후 #이웃들이 가지고 있는 거리보다 작으면 이것으로 업데이트 시키고 다시 PQ에 넣거나 update합니다 #pd insert 기능에 포함되어 있다고 한다. '''for v in g[u].keys(): # alt = dist[u] + g[u][v].get('weight',1) alt = dist[u] + g[u][v] if alt < dist[v]: dist[v] = alt prev[v] = u Q.insert(dist[v],v) #for v in g.neighbors(u): ''' for v in G[u].keys(): #alt = dist[u] + g[u][v].get('weight',1) alt = dist[u] + G[u][v] if alt < dist[v]: dist[v] = alt Q.insert(dist[v], v) return dist
def getMove(self, state, nslaves=1): '''Make the AI make a move. Args: state: <State> Returns: <Move> in the move_list of 'state' ''' hash_fn = lambda node: node.state.compressed #TODO remove #value_fn = lambda node: node._global_log_prob #TODO strengthen value_fn = lambda node: node.depth pq = PriorityQueue(hash_fn, value_fn) player_info = PlayerInfo(turn=state.player_turn, prob_power=0.1, max_uncertainty=self._max_uncertainty, q=self.q_choice) root = StateNode(state, player_info) pq.add(root) redundant = dict() slave_procs = [] slave_pipes = [] for pidx in range(nslaves): slave_pipe, pipe = Pipe() proc = Process(target=AIPlayer.evalStates, args=(self, pipe)) slave_procs += [proc] slave_pipes += [slave_pipe] proc.start() nchecked = 0 target_slave = 0 flying_nodes = 0 while nchecked < self._max_states and len( pq) + flying_nodes: #terminal condition if len(pq): next = pq.pop() next_state = next.state compressed = next_state.compressed if compressed not in redundant: redundant[compressed] = next else: original = redundant[compressed] #next = redundant[compressed] #for new_node in next.parent._addChild(): for new_node in next.reportRedundant(original): pq.add(new_node) continue pipe = slave_pipes[target_slave] pipe.send(next_state) flying_nodes += 1 nchecked += 1 for pipe in slave_pipes: if pipe.poll(): try: obj = pipe.recv() flying_nodes -= 1 if not obj: print('ERROR: slave closed before master [E1]') heur_bundle, compressed = obj new_nodes = redundant[compressed].check(heur_bundle) for new_node in new_nodes: pq.add(new_node) except EOFError: print('ERROR: slave closed before master [E2]') for pipe in slave_pipes: pipe.send(None) active_pipes = copy.copy(slave_pipes) while active_pipes: for pipe in active_pipes: try: obj = pipe.recv() if not obj: active_pipes.remove(pipe) continue heur_bundle, compressed = obj redundant[compressed].check(heur_bundle) except EOFError: pipes.remove(pipe) if self.train_iterations: X = [] Y = [] while len(player_info.training_nodes): _, training_state, value, err = player_info.training_nodes.pop( ) #value = node._expected_value #err = (node._expected_value - node._self_value) ** 2 x = training_state.features() y = torch.FloatTensor([value, err]) X += [x] Y += [y] if self._model: self.train(X, Y) #cleanNode(root) #for child in root.children: # child.recalcValue(verbose=True) # find best move # PENDING: add randomness best_node = None moves = [] uprobs = [] for node in root.children: #print(node.value, node._self_value # TODO re add #print(node.state.toString()) # TODO re add if not best_node or (node.value - best_node.value) * ( 2 * state.player_turn - 1) > 0: best_node = node moves += [node.move] uprobs += [ get_uprob(get_utility(node.value, state.player_turn), node.uncertainty, player_info.q) ] if self.train_iterations > 0: prob_scale = random.uniform(0, sum(uprobs)) for i in range(len(uprobs)): prob_scale -= uprobs[i] if prob_scale <= 0: return moves[i] #return state.moves[0] #TEMP return best_node.move
class GameLevel: def __init__(self, dm, level_num, length, width, category): self.dm = dm self.eventQueue = PriorityQueue() self.cameras = {} self.light_sources = [] self.security_lockdown = False self.upStairs = '' self.downStairs = '' self.map = [] self.lvl_length = length self.lvl_width = width self.level_num = level_num self.category = category self.initialize_dungeon_locs() self.monsters = [] self.melee = MeleeResolver(dm, dm.dui) self.subnet_nodes = [] self.cameras_active = random() < 0.8 self.security_active = True # It would be nice if instead of alerting all monsters within a # certain radius, if the sound were blocked by walls, muffled by # doors etc. A flood-fill algorithm of some sort? def handle_stealth_check(self, player): _loudness = do_d10_roll(1,1) _roll = player.stealth_roll() _roll = int(round(_roll / 10.0)) _volume = _loudness - _roll if _roll < 1: _roll = 1 _radius = 6 - _roll if _radius < 1: _radius = 1 _noise = Noise(_volume, player, player.row, player.col, 'walking') self.monsters_react_to_noise(_radius, _noise) def monsters_react_to_noise(self, radius, noise): for _m in self.monsters: _d = calc_distance(noise.row, noise.col, _m.row, _m.col) if _d <= radius: _spotted = _m.react_to_noise(noise) # I can later use success or failure of action to count # as practice toward the player improving his skills # ie., if noise.description == 'walking'... # is a location a valid square in the current map def in_bounds(self,r,c): return r >= 0 and r < self.lvl_length and c >= 0 and c < self.lvl_width def is_cyberspace(self): return False def add_item_to_sqr(self, row, col, item): if not hasattr(self.dungeon_loc[row][col], 'item_stack'): setattr(self.dungeon_loc[row][col], 'item_stack', ItemStack()) self.dungeon_loc[row][col].item_stack.append(item) def size_of_item_stack(self, row, col): _loc = self.dungeon_loc[row][col] if not hasattr(_loc, 'item_stack'): return 0 return len(_loc.item_stack) def add_light_source(self, light_source): _sc = Shadowcaster(self.dm, light_source.radius, light_source.row, light_source.col) light_source.illuminates = _sc.calc_visible_list() light_source.illuminates[(light_source.row, light_source.col)] = 0 self.light_sources.append(light_source) def clear_bresenham_points(self, row, col, radius): _pts = [] x = radius y = 0 error = 0 sqrx_inc = 2 * radius - 1 sqry_inc = 1 while (y <= x): if self.is_clear(row+y, col+x): _pts.append((row+y, col+x)) if self.is_clear(row-y, col+x): _pts.append((row-y, col+x)) if self.is_clear(row+y, col-x): _pts.append((row+y, col-x)) if self.is_clear(row-y, col-x): _pts.append((row-y, col-x)) if self.is_clear(row+x, col+y): _pts.append((row+x, col+y)) if self.is_clear(row-x, col+y): _pts.append((row-x, col+y)) if self.is_clear(row+x, col-y): _pts.append((row+x, col-y)) if self.is_clear(row-x, col-y): _pts.append((row-x, col-y)) y += 1 error += sqry_inc sqry_inc = sqry_inc + 2 if error > x: x -= 1 error -= sqrx_inc sqrx_inc -= 2 return _pts def disable_lifts(self): if self.upStairs != '': _up = self.map[self.upStairs[0]][self.upStairs[1]] _up.activated = False if self.downStairs != '': _down = self.map[self.downStairs[0]][self.downStairs[1]] _down.activated = False def douse_squares(self, ls): self.eventQueue.pluck(('extinguish', ls.row, ls.col, ls)) self.light_sources.remove(ls) for _d in ls.illuminates: self.dungeon_loc[_d[0]][_d[1]].lit = False def end_of_turn(self): self.dm.meatspace_end_of_turn_cleanup() if self.dm.turn % 20 == 0: self.dm.player.add_hp(1) if self.dm.turn % 50 == 0: for m in self.monsters: m.add_hp(1) if random() < 0.5: self.add_monster() self.dm.turn += 1 def end_security_lockdown(self): self.security_lockdown = False def extinguish_light_source(self, light_source): stack = self.dungeon_loc[light_source.row][light_source.col].item_stack for item in stack: if item == light_source: self.douse_squares(light_source) if isinstance(item, Items.LitFlare): stack.remove(item) _msg = light_source.get_name() + ' has gone out.' self.dm.alert_player_to_event(light_source.row, light_source.col, self, _msg, True) # this could maybe be moved to GamePersistence? def generate_save_object(self): for m in self.monsters: m.dm = '' self.clear_occupants() _exit_point = (self.dm.player.row,self.dm.player.col) _save_obj = (self.map,self.dungeon_loc,self.eventQueue,self.light_sources,self.monsters, \ self.category,self.level_num,_exit_point,self.cameras,self.upStairs,self.downStairs,\ self.security_lockdown, self.subnet_nodes, self.cameras_active, self.security_active) return _save_obj # I'm going to use the Bresenham circle algorithm to generate # "circles" to check, and work my way out until I find a clear # space. # # Sanity check: if we've searched radius > 10 and not found # a clear spot, then we're probably not going to find one. def get_nearest_clear_space(self, r, c): _radius = 1 while True: _pts = self.clear_bresenham_points(r, c, _radius) if len(_pts) > 0: return choice(_pts) _radius += 1 if _radius > 10: return None def get_occupant(self, r, c): return self.dungeon_loc[r][c].occupant def is_clear(self,r,c): if not self.in_bounds(r,c): return False return self.map[r][c].is_passable() and self.dungeon_loc[r][c].occupant == '' def place_sqr(self, sqr, target_type): while True: r = randrange(1,self.lvl_length-1) c = randrange(1,self.lvl_width-1) if self.map[r][c].get_type() == target_type: break self.map[r][c] = sqr def remove_monster(self, monster, row, col): self.dungeon_loc[row][col].occupant = '' self.monsters.remove(monster) def resolve_events(self): while len(self.eventQueue) > 0 and self.eventQueue.peekAtNextPriority() <= self.dm.turn: event = self.eventQueue.pop() if event[0] == 'explosion': self.dm.handle_explosion(self, event[1],event[2],event[3]) # bomb is returned, return tile to what it was _sqr = self.map[event[1]][event[2]] if isinstance(_sqr,Terrain.Trap): self.map[event[1]][event[2]] = _sqr.previousTile self.dm.update_sqr(self, event[1], event[2]) elif event[0] == 'extinguish': self.extinguish_light_source(event[3]) def clear_occupants(self): for row in self.dungeon_loc: for cell in row: cell.occupant = '' def add_feature_to_map(self, feature): while True: r = randrange(1,self.lvl_length-1) c = randrange(1,self.lvl_width-1) if self.map[r][c].get_type() == FLOOR: feature.row = r feature.col = c self.map[r][c] = feature break def remove_light_source(self, light_source): _target = '' for _ls in self.light_sources: if _ls == light_source: _target = _ls if _target != '': self.light_sources.remove(_target) def add_item(self, _chart): _item = _chart.get_item(self.level_num) while True: r = randrange(self.lvl_length) c = randrange(self.lvl_width) if self.map[r][c].get_type() == FLOOR: self.add_item_to_sqr(r,c,_item) break def add_pack(self, monster_name, low, high, r, c): for j in range(randrange(low,high+1)): _sqr = self.get_nearest_clear_space(r,c) if _sqr != None: _monster = MonsterFactory.get_monster_by_name(self.dm, monster_name, _sqr[0], _sqr[1]) self.add_monster_to_dungeon(_monster, _sqr[0], _sqr[1]) def add_monster(self, monster=''): # This loop currently doesn't handle the oddball case where the dungeon is full! # Should be fixed, otherwise it will be an infinite loop, and unpleasant for the # player! while True: try_r = randrange(0,self.lvl_length) try_c = randrange(0,self.lvl_width) _sqr = self.map[try_r][try_c] # This'll prevent a monster from being generated where the player will # appear when first entering the level if _sqr.get_type() in (UP_STAIRS, DOWN_STAIRS): continue if self.is_clear(try_r,try_c): r = try_r c = try_c break if monster.level < self.level_num: monster.level = self.level_num self.add_monster_to_dungeon(monster, r, c) def add_monster_to_dungeon(self, monster, r, c): monster.row = r monster.col = c self.dungeon_loc[r][c].occupant = monster self.monsters.append(monster) def get_player_start_loc(self): return self.player_start_loc def initialize_dungeon_locs(self): self.dungeon_loc = [] for r in range(0,self.lvl_length): row = [] for c in range(0,self.lvl_width): row.append(DungeonSqr(False, False, False)) self.dungeon_loc.append(row) def begin_security_lockdown(self): pass