Simpy:不明白为什么我的模拟永远不会结束

Simpy: don't understand why my simulation never ends

我正在尝试模拟 Counter Strike 游戏。基本上我有两支拥有不同球员的球队(目前所有球员都相同),我希望他们 "fight" 并且当一支球队的所有球员都死了时,模拟应该结束。

我试图理解为什么我正在 运行 进行的模拟永远不会结束。我觉得我误解了 simpy 的一些核心元素,但我真的不知道是什么。

所有流程和简单相关的代码都在main.py和player.py中。 一旦每个玩家都有 "died",我正试图让我的模拟结束。

基本上我希望每个玩家都是一个进程,不断检查他们周围的区域(他们所在的节点由 Hotspot class 表示)以查看是否有任何敌人。如果有任何敌人,他们会在 运行dom 和 "attack" 中选择一个。一旦任何一支球队的所有球员的健康状况都低于 0,模拟就应该结束,获胜的球队应该将他们的胜利计数增加 1。

编辑:另外值得注意的是,当我通过 pdb 运行 时,玩家的生命值似乎 none 正在下降并且游戏方法不是 运行。

编辑 2:我不认为需要阅读所有代码才能找到问题,我认为它主要出现在主文件和播放器文件中,但我不是 100% 确定,因为代码无限循环而没有错误

这是我的代码

main.py

from player import Player
from game_map import Game_Map
from team import Team
from sides import Sides
import simpy
import pdb


def main():
  team_a = Team("Team_A", Sides.CT)
  team_b = Team("Team_B", Sides.T)
  gmap = Game_Map()
  gmap.spawn_team(team_a)
  gmap.spawn_team(team_b)

  env = simpy.Environment()
  for team in (team_a, team_b):
    for player in team.players:
      env.process(player.play(env))

  env.run(until=round(team_a, team_b, env))

def round(team_a, team_b, env):

  while True:
    if team_a.all_dead():
      team_b.round_wins += 1
      print team_b
      env.exit()
    if team_b.all_dead():
      team_a.round_wins += 1
      print team_a
      env.exit()



if __name__ == "__main__":
  main()

player.py

import simpy
from sides import Sides
import numpy as np
import pdb

class Player(object):
  """ Class that represents a CSGO player"""

  def __init__(self, steam_id, team, acc, hs_percentage):
    # the player's id
    self.steam_id = steam_id
    # percentage of shots that hit, accuracy
    self.acc = acc
    # percentage of hits that hit the head
    self.hs_percentage = hs_percentage

    # the team 
    self.team = team
    # the player's health, this changes when the teams "fight"
    self.health = 100

    # the current hotspot that the player is in
    self.current_location = 0



    # if the player is alive or dead
    self.is_alive = True



  def play(self, env):
    """Process that simulates the player's actions. This is run once every round until
    the round is over"""
    while(self.is_alive):
      target = self.choose_target()
      if target == -1:
        continue
        yield env.timeout(5)
      else:
        target.inflict_self(self.determine_damage())        
        yield env.timeout(5)


  def determine_damage(self):
    """The amount of damage the player will inflict on the enemy"""
    return 27

  def choose_target(self):
    """Choose a target to attack from the enemies in the hotspot"""

    # 1 - side converts 0 to 1 and 1 to 0
    enemy_list = self.current_location.players[1 - self.team.side]
    num_enemies = len(enemy_list)

    # if there are no enemies currently in the same location of the player
    # simply return 0
    if num_enemies == 0:
      return -1

    # pick an enemy randomly from the list of enemies and return their object
    return enemy_list[np.random.random_integers(0, num_enemies - 1)]


  def get_side(self):
    return self.team.side

  def inflict_self(self, damage):
    """Inflict damage onto own class. If damage moves health below 0, mark the 
    player as "Dead" and remove them from the map"""
    self.health = self.health - damage
    if self.health <= 0:
      self.current_location.players[self.team.side].remove(self)
      self.is_alive = False


  def __str__(self):
    return "Steam id: {0}\tIs Alive: {1}\tCurrent Location: {2}".format(self.steam_id, self.is_alive, self.current_location)


def tests():
  return

if __name__ == "__main__":
  tests()

game_map.py

import networkx as nx
from hotspot import Hotspot
import matplotlib.pyplot as plt
class Game_Map(object):
  """ Generic map that represents general outline of all counter strike maps"""

  def __init__(self):
    self.graph = nx.Graph()
    self.spawns = [Hotspot()]
    self.graph.add_node(self.spawns[0])

  def add_team(team):
    #side = team.side
    # side is 0 because for testing the simulation
    # we are only using one node
    side = 0
    for player in team.players:
      self.spawns[side].move_into(player)

  def spawn_team(self, team):
    for player in team.players:
      self.spawns[0].move_into(player)


  def draw(self):
    nx.draw(self.graph)
    plt.show()

def tests():
  """Tests to see that Game_Map class works properly"""

  # initialize the map
  gmap = Game_Map()
  gmap.draw()



# if this module is being run explicitly from the command line
# run tests to assure that this module is working properly
if __name__ == "__main__":
  tests()

hotspot.py

import simpy
from player import Player
from team import Team
from sides import Sides
class Hotspot(object):
  """Hotspots are the representation for different areas of the map. This is where players 'fight'."""

  def __init__(self):
    self.players = [[], []]


  def move_into(self, player):
    side = player.get_side()
    self.players[side].append(player)
    player.current_location = self

    return 1


  def __eq__(self, other):
    return id(self) == id(other)

  def __hash__(self):
    return id(self)


def tests():
  """Tests to see that hotspot works properly"""
  hotspot_list = []
  for i in range(5):
    hotspot_list.append(Hotspot())

  for spot in hotspot_list:
    team_a = Team("team_a", Sides.CT)
    team_b = Team("team_b", Sides.T)
    spot.move_into(Player(1, team_a, .5, .5))
    spot.move_into(Player(1, team_b, .5, .5))

    print "Hotspot id = {0}".format(id(spot))
    for team in spot.players:
      for player in team:
        print "player = {0} in team {1}".format(player, player.team)

if __name__ == "__main__":
  tests()

sides.py

class Sides(object):
  """Enum object, simply represents CT (Counter Terrorists) as 0 and 
  T (Terrorists) as 1"""
  CT, T = range(2)

team.py

from player import Player
class Team(object):
  """Class that holds critical team information"""
  def __init__(self, name, side):
    self.round_wins = 0
    self.players = []
    self.name = name
    self.side = side
    self.generate_team()

  def all_dead(self):
    count = 0
    for player in self.players:
      if player.is_alive == False:
        count += 1
    if count == 5:
      return True
    else: 
      return False



  def __str__(self):
    rep = "Team: {0}, Round Wins: {1}\n".format(self.name, self.round_wins)
    for player in self.players:
      rep += player.__str__() + '\n'

    return rep


  def generate_team(self):
    for i in range(5):
      self.players.append(Player(1, self, .5, .2))

  __rep__ = __str__

requirements.txt

decorator==3.4.2
matplotlib==1.4.3
mock==1.0.1
networkx==1.9.1
nose==1.3.6
numpy==1.9.2
pyparsing==2.0.3
python-dateutil==2.4.2
pytz==2015.2
scipy==0.15.1
simpy==3.0.7
six==1.9.0

我感觉这可能是一个无限循环:

while(self.is_alive):
  target = self.choose_target()
  if target == -1:
    continue
    yield env.timeout(5)

您可能想在 continue 之前让步(无论如何都不需要)。

你的 round() 函数是罪魁祸首:

env.run(until=round(team_a, team_b, env))

def round(team_a, team_b, env):

  while True:
    if team_a.all_dead():
      team_b.round_wins += 1
      print team_b
      env.exit()
    if team_b.all_dead():
      team_a.round_wins += 1
      print team_a
      env.exit()

该函数包含一个没有任何产量的无限循环。这意味着它永远不会 returns 甚至 env.run() 都不会执行。