[英]Is there a more pythonic way to write multiple comparisons
我正在写一个简单的纸牌游戏(类似于Snap)。 我已经让它工作,没有问题,但我觉得应该有一个更优雅的解决方案。 给出一组胜利条件:
Y击败R.
R节拍B.
B击败Y.
等等
我想比较两个玩家的牌并将两张牌分配给获胜者。 警告:我在中学教学(没有OOP),并希望能够与学生讨论最终的代码。
我已经离开了最后一个条件作为elif,因为我想回去并在选项列表中添加额外的卡片
if - elif链没有问题; 我想知道是否有更优雅的解决方案。
#I have code that randomly selects from a list, but this is the basic
#idea:
p1=input("enter r,y or b")
p2=input("enter r,y or b")
stack1=[]
stack2=[]
if p1=="r" and p2=="b":
stack1.extend([p1,p2])
elif p1=="y" and p2=="r":
stack1.extend([p1,p2])
elif p1 =="b" and p2 =="y":
stack1.extend([p1,p2])
elif p2 =="r" and p1 =="b":
stack2.extend([p1,p2])
elif p2 =="y" and p1 =="r":
stack2.extend([p1,p2])
elif p2 =="b" and p1 =="y":
stack2.extend([p1,p2])
print(stack1)
print(stack2)
我从其余部分摘录了代码 - 这些卡都是随机生成的,因此实际上不需要用户输入。
使用Y,R,B创建一个新的字典,每个字典映射到0,1,2。
win_map = {"Y": 0, "R": 1, "B": 2}
我们可以在这看到一个循环关系。 0节拍1,1节拍2和节拍0.前两种情况很容易使用简单的>
确定,但考虑第三种情况需要另一种方法。 通过一点巧思,我们可以看到我们可以通过添加1并使用模运算%
来“换行”。 (0+1) % 3 == 1
, (1+1) % 3 == 2
,并且(2+1) % 3 == 0
,这3种情况是确定获胜者的唯一情况。
if (win_map[p1] + 1) % 3 == win_map[p2]: ... # p1 wins
else if (win_map[p2] + 1) % 3 == win_map[p1]: ... # p2 wins
我不确定这会如何传达给学生,但这是一个更清洁的解决方案。
注意:此方法不适用于更多卡,因为循环关系将被破坏。
因此,您的胜利条件看起来像(赢家,输家)对的集合,并将您的(p1, p2)
输入与它们进行比较看起来最简单的事情。
win_conditions = {
('y', 'r'),
('r', 'b'),
('b', 'y')
}
p1=input("enter r,y or b")
p2=input("enter r,y or b")
stack1=[]
stack2=[]
if (p1, p2) in win_conditions:
stack1.extend([p1,p2])
elif (p2, p1) in win_conditions:
stack2.extend([p1,p2])
else:
raise ValueError('{} and {} cannot beat each other.'.format(p1, p2))
请注意,如果您认为胜利条件是详尽的,则可以简化代码。
如果你向他们展示如何通过在具有正确名称的函数中强化低级操作来提高他们的可读性,我认为你会帮助你的学生,这样他们的意图就更明显了。
def beats(p1, p2):
return (p1, p2) in win_conditions
if beats(p1, p2):
stack1.extend([p1,p2])
elif beats(p2, p1):
stack2.extend([p1,p2])
else:
raise ValueError('"{}" and "{}" cannot beat each other.'.format(p1, p2))
也许你可以通过扩展列表为你想要的任何东西找到一个更好的名字。
像您这样的小规模问题的“标准”解决方案是将所有可能性放入地图:
result_map = { ('r', 'b'): 1, ('b', 'y'): 1, ('y', 'r'): 1,
('b', 'r'): 2, ('y', 'b'): 2, ('r', 'y'): 2 }
v = result_map.get((p1, p2), None)
if v == 1:
stack1.extend([p1, p2])
elif v == 2:
stack2.extend([p1, p2])
为什么这样? 因为它为你提供了简单的方法来改变胜利/宽松状态(只是改变一个字典),胜利/宽松的规则可以是完全随意的,并且很容易遵循代码(图像你有一些奇怪的if-else条件和其他人来看在这个代码和奇迹,发生了什么以及为什么)。
你重复同样的事情太多次,有两个extend
调用,每个重复3次。
您可以使用or
关键字大大简化代码:
# extend to "stack1"
if (p1 == "r" and p2 == "b") or (p1 == "y" and p2 == "r") or (p1 == "b" and p2 == "y"):
stack1.extend([p1, p2])
# extend to "stack2"
elif (p2 == "r" and p1 == "b") or (p2 == "y" and p1 == "r") or (p2 == "b" and p1 == "y"):
stack2.extend([p1, p2])
祝好运。
只是另一种比较方式,也许它可以用于for循环或dict映射,以帮助重构代码,如果有必要,性能并不重要。
from operator import and_
from functools import partial
def compare(a, b, c, d):
return and_(a == c, b == d)
p1 = 'r'
p2 = 'b'
cmp_p1_p2 = partial(compare, p1, p2)
cmp_p2_p1 = partial(compare, p2, p1)
cmp_p1_p2('r', 'b')
# True
cmp_p2_p1('b', 'r')
# True
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.