【问题标题】:Simpy: don't understand why my simulation never endsSimpy:不明白为什么我的模拟永远不会结束
【发布时间】:2015-06-26 06:05:20
【问题描述】:

我正在尝试模拟反恐精英游戏。基本上我有两支不同球员的球队(现在所有球员都是相同的),我希望他们“战斗”,当一个球队的所有球员都死了时,模拟应该结束。

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

所有流程和simpy相关的代码都在main.py和player.py中。 我试图让我的模拟在每个玩家“死亡”后结束。

基本上我希望每个玩家都是一个进程,不断检查他们周围的区域(他们所在的节点由 Hotspot 类表示)以查看是否有任何敌人。如果有任何敌人,他们会随机选择一个并“攻击”他们。一旦任何球队的所有球员的生命值都低于 0,模拟应该结束,获胜的球队应该将他们的胜利计数增加 1。

编辑:另外值得注意的是,当我通过 pdb 运行它时,似乎玩家的生命值没有下降,并且播放方法没有运行。

编辑 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()

热点.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

【问题讨论】:

  • 我认为你很难让人们通读所有这些代码并找出问题所在。你能试着缩小问题的范围吗?
  • 在 game_map add_team 中,您只使用 0 面 - 这不意味着您的所有玩家最终都在同一个团队中吗?这可以解释为什么没有造成伤害?
  • 这不是问题,因为我只使用一个节点。有两次需要边,当我在模拟开始之前第一次将玩家添加到地图时(在这种情况下我保留边 0,因为我没有测试节点之间的移动,即此时热点,我只是添加每个人都到同一个节点来测试战斗部分)以及当玩家被添加到他们各自的 Hotspot 类列表中时(重要的是,这是玩家寻找要“战斗”的敌人的地方。

标签: python simulation simpy


【解决方案1】:

你的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()

该函数包含一个没有任何收益的无限循环。这意味着它永远不会返回,env.run() 甚至不会被执行。

【讨论】:

  • 您对如何在不结束模拟的情况下使其屈服有什么建议吗?
  • yield env.timeout(x) 在循环内将是一个好的开始。正如其他人已经建议的那样,您也许应该阅读 SimPy 的教程、示例和主题指南。 simpy.readthedocs.org/en/latest
【解决方案2】:

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

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

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

【讨论】:

  • 谢谢,我已经修复了,但模拟仍然没有完成
  • @vicg:在调试器中中断程序,看看挂在哪里。
  • 当我点击 env.run(until=round(team_a, team_b, env)) 时它挂起
  • 你真的需要在这里应用一些基本的调试技巧。如果您对调试器不满意,请尝试将 print 语句插入到关键函数中,尤其是 play 方法,以获得有关正在发生的事情的一些输出。
  • 阅读本文并完成示例:simpy.readthedocs.org/en/latest/simpy_intro
猜你喜欢
  • 2015-08-28
  • 2011-08-04
  • 2020-09-11
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
  • 2013-09-11
  • 2018-04-09
  • 2017-05-21
相关资源
最近更新 更多