1. Обнаружение того, произошел ли выигрыш.
Мы определяем «выигрыш» для игрока X как случай, когда одно из следующего является Истиной:
- Один ряд состоит из X
- Один столбец состоит из X
- диагональ от верхнего левого до нижнего правого состоит из X
- диагональ от нижнего левого до верхнего правого состоит из X
Как мы можем перевести это на Python?
Строка - это просто подсписок в вашем кортеже (это типы, которые вы использовали), поэтому мы можем просто написать board[row]
, чтобы получить строку. Чтобы проверить, если any
(обратите внимание на формат кода) * строка 1022 * состоит из «X», мы должны проверить, что all
его значение равно «X». Итак, мы можем написать any(all(field == 'X' for field in row) for row in board)
.
Столбцы сложнее, потому что мы должны работать с индексами. Но, по сути, это то же самое, только наоборот: any
столбец с all
полями "X":
any(all(board[row][column] == 'X' for row in range(3)) for column in range(3))
Диагонали: у нас только одна строка, поэтому нам нужен только один цикл.
Для TL-> BR оба индекса равны. Итак, мы хотим, чтобы all
полей с равными индексами были равны «X». all(board[i][i] == 'X' for i in range(3))
для BL-> TR один индекс равен 2-other_index
(, а не 3, поскольку последовательности индексируются нулем). Мы хотим, чтобы all
поля с двумя индексами были равны "X" all(board[i][2-i] for i in range(3))
Вопрос: что произойдет, если вы инвертируете i
и 2-i
? Если вы не знаете, пусть это будет распечатано.
Возможно, вы захотите написать check_win(board, player)
функцию, которая сделает все вышеперечисленное для общего player
- здесь «X» или «O», но, если вы решите включить трех игроков на большую доску позже на ...
2. Создание CPU AI:
Если вы действительно хотите создать CPU , это неправильное место для запроса.
Если вы хотите создать (простой) AI , читайте дальше. Если вы хотите, чтобы это было сложно, задайте новый вопрос.
Подумайте, что он должен делать:
- он должен предпочитать некоторые поля из-за их положения?
- Должен ли он попытаться быстро заблокировать противника?
- Должен ли он попытаться создать несколько возможностей выигрыша или сосредоточиться на одной?
- если это ...?
Хотя в этом случае, вероятно, проще будет просто смоделировать несколько ходов и выбрать те, которые имеют наилучшие возможности для выигрыша, задать себе вопросы выше и написать что-то, что также будет работать с (намного) большими досками, будет интересно.
3. Переключатель поворотов.
Одна возможность:
У вас есть последовательность (str, list или tuple) игроков, например: "XO"
и переменная round_counter
, которая всегда увеличивается. Затем вы используете PLAYERS[round_counter % len(PLAYERS)]
, чтобы получить текущего игрока. Используйте оператор модуля %
, чтобы всегда получать действительный индекс.
Альтернатива:
Использование itertools.cycle
:
цикл ('ABCD') -> A B C D A B C D A B C D ...
Это проще (for current_player in itertools.cycle("XO"):
), но с первой альтернативой у вас есть номер, по которому вам нужно будет позвонить enumerate(itertools.cycle("XO"))
, и вы ограничите использование библиотеки (если этот код кому-то показывается, вы можете хочу объяснить как это работает).
4. Как обнаружить ничью:
Ничья происходит, когда all
поля not
пусты (в вашем случае, !=
тире); это равносильно тому, что есть поле not
any
с тире.
См. Понимание списка , чтобы выровнять доску:
>>> # flatten a list using a listcomp with two 'for'
>>> vec = [[1,2,3], [4,5,6], [7,8,9]]
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
- второй-последний пример