【问题标题】:Better alternative to lots of IF statements? Table of values大量 IF 语句的更好替代方案?数值表
【发布时间】:2016-08-16 11:13:22
【问题描述】:

我有一个动作表,可以根据玩家对 AI 的选择来决定是否获胜。用更多的动作想想石头、纸、剪刀。 我最终会用 Python 对其进行编码,但在开始之前,我想知道是否有更好的方法来执行此操作,而不是大量的 IF 语句?

表格如下所示:

我认为这些动作需要分配数字,或者类似的东西?我不知道从哪里开始...

【问题讨论】:

  • 也许可以创建一个名为 move 的类,并给出击败原始动作和输给原始动作的列表。通过名称识别动作,如果对方动作的名称在您使用该结果的预定义列表之一中

标签: python algorithm if-statement dictionary


【解决方案1】:

你可以使用字典吗?像这样的:

#dict of winning outcomes, the first layer represents the AI moves, and the inner 
#layer represent the player move and the outcome
ai = {
    'punch' : {
        'punch' : 'tie',
        'kick' : 'wins',
    },
    'stab' : {
        'punch' : 'loses',
        'kick' : 'loses'
    }
}

ai_move = 'punch'
player_move = 'kick'
print ai[ai_move][player_move] #output: wins


ai_move = 'stab'
player_move = 'punch'
print ai[ai_move][player_move] #output: loses

我没有画出所有的动作,但你明白了要点

【讨论】:

  • 哈哈,幸运的是我的编辑器在我的另一个屏幕上打开并准备好了@burakozgul
  • @dhdavvie 你的似乎是迄今为止最合乎逻辑的
  • @Jason 显然我有偏见,但我同意。写出整个表格会有点烦人,但是一旦完成,您就可以在任何地方引用它并且超级容易使用。
【解决方案2】:

您可以像这样创建类似于上表的攻击地图

map = [
    [0,-1,-1,1,1,-1],
    [1,0,-1,-1,1,-1],
    [1,1,0,-1,-1,1],
    [-1,1,1,0,-1,1],
    [-1,-1,1,1,0,-1],
    [1,1,-1,-1,1,0]
]

这里,0 是平局,1 是赢家,-1 是输家。

现在创建一个攻击数组,其中攻击的位置与上面的地图相对应。

attacks = ["Punch", "Kick", "Stab", "Throw", "Fling", "Uppercut"]

现在您可以轻松确定一种攻击是否胜过另一种攻击

map[attacks.index("Stab")][attacks.index("Punch")]

>>> 1

刺胜拳

【讨论】:

  • 注意:这是我第一次写python。如果有问题,请发表评论或编辑我的帖子。
  • imo 带有文本键/值的嵌套字典比带有映射值的二维数组更具可读性
  • @CraigBurgler 虽然您确实认为地图的可读性不如字典,但我认为紧凑性以及可以检索整数值而不是字符串的编程优势胜过缺点。以这种格式添加新攻击也更快。
  • 紧凑性的唯一价值是作为可读性的属性,清晰性更为重要。嵌套字典在用于获取结果时实际上稍微紧凑一些;具有映射值的二维数组仅在初始数据填充时更加紧凑。
  • 根据我们对 OP 用例的了解,从字符串中检索整数值也没有“编程优势”。如果有的话,我们可以轻松地将字典值更改为数字。
【解决方案3】:

我会为此使用二维列表。每次攻击都被解码为索引 0 到 5,胜负被解码为 1、0 和 -1。

所以列表看起来像这样(不是基于你的例子,我只是放了一些随机数):

table = [[1,0,-1,0,1,-1],[1,1,0,1,0,-1],...,etc.]

你会像这样检索它:

table[0][1]

【讨论】:

    【解决方案4】:

    是的,将决策作为键/值对存储在字典中,所有可能的组合作为键,决策作为结果。基本上为可能的动作制作一个查找表。

    这样可以加快决策速度,但必须存储所有可能的组合。

    def tie():
        print("It's a tie!")
    
    def lose():
        print("You lose")
    
    def win():
        print("You win")
    moves = { 
         # player_ai action
        'punch_punch': tie,
        'punch_kick': lose,
        'punch_stab': lose,
        <..>
    }
    player_move = <move>
    ai_move = <move>
    key = "_".join([player_move, ai_move])
    if key in moves:
        # Execute appropriate function
        return moves[key]()
    raise Exception("Invalid move")
    

    【讨论】:

      【解决方案5】:

      您可以使用 python 字典将移动映射到数字:

      move = {'Punch': 0, 'Kick': 1}
      

      然后使用矩阵来确定结果。 Numpy 可以用于此

      import numpy
      move = {'Punch': 0, 'Kick': 1}
      
      outcome = numpy.matrix([['Tie','Loses'],['Wins','Tie']])
      
      
      # Punch vs Punch => Tie
      print outcome[move['Punch'], move['Punch']]
      
      # Punch vs Kick => Punch loses
      print outcome[move['Punch'], move['Kick']]
      

      【讨论】:

        【解决方案6】:

        您可以尝试字典字典(嵌套字典)。以文本形式保存值和键,而不是映射到数字,以提高可读性。

        outcome = {}
        outcome['punch'] = {}
        outcome['punch']['punch'] = 'Tie'
        outcome['punch']['kick'] = 'Lose'
        ...
        outcome['kick'] = {}
        outcome['kick']['punch'] = 'Win'
        outcome['kick']['kick'] = 'Tie'
        ...
        i_do = 'punch'
        he_does = 'fling'
        ...
        if outcome[i_do][he_does] == 'Win':
            print("Woohoo!")
        

        【讨论】:

        • 对可读性的评论:这种方法的冗长使得代码很难维护。写下所有的攻击,也许再添加一些,你很快就会意识到这根本不容易阅读。
        • “冗长”有助于维护,实际上只是对可以在辅助函数中执行的初始数据填充更加冗长。当我进入我的代码逻辑时,我更愿意使用if outcome[i_do][he_does] == 'Win': 形式的语句而不是if map[attacks.index("i_do")][attacks.index("he_does")] == 1:
        猜你喜欢
        • 2016-03-04
        • 1970-01-01
        • 1970-01-01
        • 2012-04-19
        • 2012-10-10
        • 1970-01-01
        • 2014-05-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多