我的代码用于井字棋游戏并检查平局状态,但我认为这个问题在一般意义上可能更有用。
我有一个代表董事会的列表,它看起来像这样:
board = [1,2,3,4,5,6,7,8,9]
当玩家移动时,他们移动的整数将被替换为他们的标记(“x”或“o”)。我已经进行了检查以寻找获胜状态。我不能做的是检查平局状态,其中列表值都不是整数,但尚未设置获胜状态。
我目前拥有的代码:
if any(board) != playerOne or any(board) != playerTwo:
print 'continue'
elif all(board) == playerOne or playerTwo:
print 'Draw'
if 语句有效,elif 则无效。我认为问题出在我的“或”运算符上。我想检查的是:板上的每个项目是否是
playerOne
标记或 playerTwo
标记。如果我要编写代码:
elif all(board) == playerOne or all(board) == playerTwo:
我会检查棋盘上的每个位置是否都是
playerOne
,或者棋盘上的每个位置都是playerTwo
,但事实并非如此。
那么如何检查棋盘是否被
playerOne
标记和 playerTwo
标记组合占据?
一般来说:
all
和 any
是接受一些可迭代对象并返回 True
、if 的函数
all
的情况下,迭代中的 没有值 是 falsy;any
的情况下,至少有一个 值为 truthy。值
x
是假值当且仅当 bool(x) == False
。
值 x
为真,当且仅当 bool(x) == True
。
可迭代中的任何非布尔元素都是完全可以接受的 -
bool(x)
映射,或强制,任何 x
根据这些规则:
0
、0.0
、None
、[]
、()
、[]
、set()
等空集合映射到False
True
。
bool
的文档字符串使用术语 'true'/'false' 表示 'truthy'/'falsy',并使用 True
/False
表示具体的布尔值。
在您的具体代码示例中:
您稍微误解了这些功能的工作原理。以下所做的事情与您的想法完全不同:
if any(foobars) == big_foobar:
...因为
any(foobars)
首先会被评估为 True
或 False
,然后将该布尔值与 big_foobar
进行比较,这通常总是给你 False
(除非 big_foobar
巧合地发生)为相同的布尔值)。
注意:迭代器可以是列表,但也可以是生成器或生成器表达式(≈延迟计算/生成列表),或任何其他迭代器。
你想要的是:
if any(x == big_foobar for x in foobars):
它基本上首先构造一个生成布尔值序列的迭代器 - 对于
foobars
中的每个项目,它将该项目与 big_foobar
保存的值进行比较,并(惰性地)将生成的布尔值发送到生成的布尔值序列中:
tmp = (x == big_foobar for x in foobars)
然后
any
遍历 tmp
中的所有项目,并在找到第一个真实元素后立即返回 True
。就好像您执行了以下操作:
In [1]: foobars = ['big', 'small', 'medium', 'nice', 'ugly']
In [2]: big_foobar = 'big'
In [3]: any(['big' == big_foobar, 'small' == big_foobar, 'medium' == big_foobar, 'nice' == big_foobar, 'ugly' == big_foobar])
Out[3]: True
注意: 正如 DSM 所指出的,
any(x == y for x in xs)
相当于 y in xs
,但后者更具可读性,写入速度更快,运行速度更快。
一些例子:
In [1]: any(x > 5 for x in range(4))
Out[1]: False
In [2]: all(isinstance(x, int) for x in range(10))
Out[2]: True
In [3]: any(x == 'Erik' for x in ['Erik', 'John', 'Jane', 'Jim'])
Out[3]: True
In [4]: all([True, True, True, False, True])
Out[4]: False
对于标题中的问题:
如果列表包含一组值或另一组值
使用集合运算可能更自然。换句话说,而不是
if any(x==playerOne for x in board) or any(x==playerTwo for x in board):
# or
if playerOne in board or playerTwo in board:
使用
set.issubset
(或set.intersection
1):
if {playerOne, playerTwo}.issubset(board):
# or
if {playerOne, playerTwo} & set(board):
如果
playerOne
和 playerTwo
是值的集合/列表/元组,则计算它们的并集并测试它是否是 board
的子集:
if {*playerOne,*playerTwo}.issubset(board):
如果问题是
如果板上的每个项目都是playerOne标记或playerTwo标记
然后代替
if all(x == playerOne or x == playerTwo for x in board):
测试集相等:1
if {playerOne, playerTwo} == set(board):
1 显然,您可以预先将
set(board)
分配给某个变量,这样您就不必每次需要测试此条件时都将 board
转换为集合。