如何在 Python 3.7 中的一组固定选项内进行高性能比较?

How to do high performance comparisons within a fixed set of options in Python 3.7?

我正在努力寻找表示一组固定选项(扑克牌特征)的正确方法,以便在开发后期进行最有效的比较。

在扑克牌示例中,您有等级(2 到 10,J、K、Q、A)和花色(红桃、方块、梅花、黑桃)。在我的代码的其他区域,我可能有类似的选项,例如预设随机播放模式(No Shuffle、Fisher-Yates 等)。由于该应用程序实际上是一个模拟,因此这些比较将很频繁并且需要尽可能高效。例如,检查一张牌是否是特定花色。

在 Python 3.7(或更高版本)中执行此操作的最佳方法是什么?我总是可以使用纯字符串,但这可能会更慢。我可以在任何地方都使用整数,但这会使代码更难阅读(记住 3 是 Clubs,或者 0 是 No Shuffle)。我可以使用枚举,但我的研究揭示了一些糟糕的性能特征。

在 C# 中,我使用枚举(Rank/Suit/Shuffle Mode)结合结构(Rank=Ace,Suit=Spade)来表示一张牌。比较是有效的并且代码可读,因为它实际上是整数比较。

在现代 Python 版本中执行此操作的最佳方法是什么?

TL;DR - 如果你有一组固定的选项(比如视频游戏中的魔法元素或其他东西),你必须非常频繁地(每次你造成伤害)在比较中使用,你会如何你代表那些最佳性能的选择?

将卡片表示为字符串是倒退的想法。弦乐是为人服务的;计算机使用数字。当您需要与人交流时,按数字查找 table 个字符串既简单又快捷;通过字符串查找数字要慢得多,也难得多,尽管 Python 通过将其内置到语言中来向您隐藏这种困难,让您产生它很容易的错觉。

使用带有单独整数的纸牌对象来表示等级和花色是可以的,但我最喜欢的表示纸牌的方式只是简单的整数,比如 0 到 51(甚至 8 到 59),从四个开始平分,然后是四个三分,等等,所以 8 = 梅花二分,9 = 方块二分,10 = 红心二分,11 = 黑桃二分,12 = 梅花三分,.. . .到 59 是黑桃 A。

按照这个编号,一张牌的点数就是(c >> 2),花色是(c & 3)。有时您甚至不需要将等级和花色分开来进行比较。例如,如果二十一点手牌是这些整数的数组,这里是计算其值的函数,以及它是硬的还是软的:

def value(hand):
  total = 0
  found_ace = False

  for card in hand:
    if card >= 56:
      found_ace = True
      total += 1
    elif card >= 40:
      total += 10
    else:
      total += (card >> 2)

  if total < 12 and found_ace:
    return total + 10, True
  return total, False

print(value([9, 22, 59])) # deuce, five, ace

在此代码中,总数是通过一些比较、加法和移位计算得出的,所有这些加在一起可能比仅查找 "Seven" 的值为 7 花费的时间更少。如果您这样做需要名片,也很简单:

rank_names = [ "?", "?", "Deuce", "Trey", "Four", "Five", "Six", "Seven",
  "Eight", "Nine", "Ten", "Jack", "Queen", "King", "Ace" ]
suit_names = [ "Club", "Diamond", "Heart", "Spade" ];

def name(card):
  return rank_names[card >> 2] + " of " + suit_names[card & 3] + "s"