Python, используя any() и all(), чтобы проверить, содержит ли список один набор значений или другой

Мой код предназначен для игры Tic Tac Toe и проверки состояния ничьей, но я думаю, что этот вопрос может быть более полезным в общем смысле.

У меня есть список, представляющий плату, он выглядит так:

board = [1,2,3,4,5,6,7,8,9]

Когда игрок совершает перемещение, int, в котором они были перемещены, заменяется их маркером ( "x" или "o" ), у меня уже есть проверки для поиска состояния выигрыша, что я не могу сделать, это проверить для состояния рисования, где ни одно из значений списка не является int, но состояние выигрыша не установлено.

Код, который у меня есть до сих пор:

if any(board) != playerOne or any(board) != playerTwo:
    print 'continue'
elif all(board) == playerOne or playerTwo:
    print 'Draw'

Оператор if работает, elif не делает, я думаю, что проблема - это мой оператор "или", что я хочу проверить: если каждый элемент на доске - либо маркер игрока или маркер игрока, либо я, где для создания кода:

elif all(board) == playerOne or all(board) == playerTwo:

Я бы проверял, было ли каждое место на доске playerOne, или все места на доске - playerTwo, чего не будет.

Итак, как я могу проверить, занята ли доска с помощью комбинации маркеров игрока и маркеров игрока?

Ответ 1

Вообще говоря:

all и any - это функции, которые принимают несколько итераций и возвращают True, если

  • в случае all() никакие значения в итерируемом не являются ложными;
  • в случае any() хотя бы одно значение является правдивым.

Значение x ложно, если bool(x) == False.

Значение x истинно, если bool(x) == True.


В ваших конкретных примерах кода:

Вы немного не поняли, как работают эти функции. Следовательно, следующее делает что-то совсем не то, что вы думали:

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, как только находит первый элемент True. Это как если бы вы сделали следующее:

foobars = ['big', 'small', 'medium', 'nice', 'ugly']
big_foobar = 'big'
any(['big' == big_foobar, 'small' == big_foobar, 'medium' == big_foobar, ...])

Примечание: Как указал DSM, any(x == y for x in xs) эквивалентен y in xs, но последний более читабелен, быстрее пишет и работает быстрее.

Некоторые примеры:

any(x > 5 for x in range(4))  # => False
all(isinstance(x, int) for x in range(10))  # => True
any(x == 'Erik' for x in ['Erik', 'John', 'Jane', 'Jim'])  # => True
all([True, True, True, False, True])  # => False

Я бы настоятельно рекомендовал просто поиграть с any и all с различными входными данными в оболочке Python или, что еще лучше, в оболочке IPython, чтобы понять, как это работает, прежде чем продолжить написание фактического кода.

Смотрите также: http://docs.python.org/2/library/functions.html#all