Этот учебник является частью серии. Обязательно ознакомьтесь с предыдущим уроком, если вы еще этого не сделали.
В этом уроке мы добавим функциональность к игре Tic-Tac-Toe: Игрок против компьютера 👀.
- Логика в игре «Крестики-нолики» 🎮
- 1. Когда игра может быть выиграна на следующем ходу, либо компьютером, либо игроком
- Некоторые изменения в функции «check» в классе «WinningPossibility»
- 2. Если центр в данный момент не занят
- 3. Если центр уже занят, и в данный момент нет возможности выиграть.
- Объединив весь код, напишем функцию auto_play:
- Создание кнопки для переключения игры с компьютером или игры с человеком
- Результат
Логика в игре «Крестики-нолики» 🎮
Давайте создадим функцию для компьютера, которая будет определять ходы в этой игре.
def auto_play():
Прежде чем завершить код, давайте посмотрим на логику 🤔:
1. Когда игра может быть выиграна на следующем ходу, либо компьютером, либо игроком
Когда игра может быть выиграна на следующем ходу компьютером, ход должен быть сделан. Если игра может быть выиграна игроком на следующем ходу, лучшим вариантом будет предотвратить это. Это можно реализовать на языке Python следующим образом:
# If winning of computer is possible on the next move, go ahead and win the game
for winning_possibility in winning_possibilities:
winning_possibility.check('O') # Check how many conditions for winning of computer are satisfied
if winning_possibility.p1_satisfied and winning_possibility.p2_satisfied: # If condition 1 and 2 are satisfied, satisfy condition 3
for point in XO_points:
if point.x == winning_possibility.x3 and point.y == winning_possibility.y3 and point not in X_points + O_points: # Find the point that needs to be occupied to satisfy condtion 3 and make sure that it is not already occupied
point.set() # Occupy point
return # End the function
elif winning_possibility.p2_satisfied and winning_possibility.p3_satisfied: # If condition 2 and 3 are satisfied, satisfy condition 1
for point in XO_points:
if point.x == winning_possibility.x1 and point.y == winning_possibility.y1 and point not in X_points + O_points: # Find the point that needs to be occupied to satisfy condition 1 and make sure that it is not already occupied
point.set() # Occupy point
return # End the function
elif winning_possibility.p3_satisfied and winning_possibility.p1_satisfied: # If condition 1 and 3 are satisfied, satisfy condition 2
for point in XO_points:
if point.x == winning_possibility.x2 and point.y == winning_possibility.y2 and point not in X_points + O_points: # Find the point that needs to be occupied to satisfy condition 2 and make sure that it is not already occupied
point.set() # Occupy point
return # End the function
# If the player might win on the next move, prevent it
for winning_possibility in winning_possibilities:
winning_possibility.check('X') # Check how many conditions for winning of player are satisfied
if winning_possibility.p1_satisfied and winning_possibility.p2_satisfied: # If condition 1 and 2 are satisfied, prevent condition 3 from being satisfied
for point in XO_points:
if point.x == winning_possibility.x3 and point.y == winning_possibility.y3 and point not in X_points + O_points: # Find the point and make sure that it is not already occupied
point.set() # Occupy point
return # End function
elif winning_possibility.p2_satisfied and winning_possibility.p3_satisfied: # If condition 2 and 3 are satisfied, prevent condition 1 from being satisfied
for point in XO_points:
if point.x == winning_possibility.x1 and point.y == winning_possibility.y1 and point not in X_points + O_points: # Find the point and make sure that it is not already occupied
point.set() # Occupy point
return # End function
elif winning_possibility.p3_satisfied and winning_possibility.p1_satisfied: # If condition 1 and 3 are satisfied, prevent condition 2 from being satisfied
for point in XO_points:
if point.x == winning_possibility.x2 and point.y == winning_possibility.y2 and point not in X_points + O_points: # Find the point and make sure that it is not already occupied
point.set() # Occupy point
return # End function
Некоторые изменения в функции «check» в классе «WinningPossibility»
Чтобы проверить, сколько условий на данный момент выполнено для победы в игре, нам нужно сделать переменные p1_satisfied
, p2_satisfied
и p3_satisfied
доступными вне функции. Поэтому переименуем их в self.p1_satisfied
, self.p2_satisfied
и self.p3_satisfied
соответственно. Новый код функции будет выглядеть следующим образом:
def check(self, for_chr):
self.p1_satisfied = False
self.p2_satisfied = False
self.p3_satisfied = False
if for_chr == 'X':
for point in X_points:
if point.x == self.x1 and point.y == self.y1:
self.p1_satisfied = True
elif point.x == self.x2 and point.y == self.y2:
self.p2_satisfied = True
elif point.x == self.x3 and point.y == self.y3:
self.p3_satisfied = True
elif for_chr == 'O':
for point in O_points:
if point.x == self.x1 and point.y == self.y1:
self.p1_satisfied = True
elif point.x == self.x2 and point.y == self.y2:
self.p2_satisfied = True
elif point.x == self.x3 and point.y == self.y3:
self.p3_satisfied = True
return all([self.p1_satisfied, self.p2_satisfied, self.p3_satisfied])
2. Если центр в данный момент не занят
Хорошей идеей будет занять центр, если он не занят в данный момент. Это можно реализовать на языке Python следующим образом:
center_occupied = False
for point in X_points + O_points: # Check if center is already occupied
if point.x == 2 and point.y == 2:
center_occupied = True
break
if not center_occupied: # If center is not occupied
for point in XO_points:
if point.x == 2 and point.y == 2:
point.set() # Occupy center
return # End the function
3. Если центр уже занят, и в данный момент нет возможности выиграть.
В этом случае нужно занять либо угловую точку, либо среднюю. Если меньше двух углов занято игроком, «О» должен попытаться занять остальные. Если 2 или более углов заняты игроком, безопаснее занять средние точки. Это можно реализовать на языке Python следующим образом:
corner_points = [(1, 1), (1, 3), (3, 1), (3, 3)]
middle_points = [(1, 2), (2, 1), (2, 3), (3, 2)]
num_of_corner_points_occupied_by_X = 0
for point in X_points: # Iterate over all points occupied by the player
if (point.x, point.y) in corner_points:
num_of_corner_points_occupied_by_X += 1
if num_of_corner_points_occupied_by_X >= 2: # If two or more corner points are occupied by the player
for point in XO_points:
if (point.x, point.y) in middle_points and point not in X_points + O_points: # Find a middle point and make sure that it is not already occupied
point.set() # Occupy the point
return # End the function
elif num_of_corner_points_occupied_by_X < 2: # If less than two corner points are occupied by the player
for point in XO_points:
if (point.x, point.y) in corner_points and point not in X_points + O_points: # Find a corner point and make sure that it is not already occupied
point.set() # Occupy the point
return # End the function
Объединив весь код, напишем функцию auto_play
:
def auto_play():
# If winning is possible in the next move
for winning_possibility in winning_possibilities:
winning_possibility.check('O')
if winning_possibility.p1_satisfied and winning_possibility.p2_satisfied:
for point in XO_points:
if point.x == winning_possibility.x3 and point.y == winning_possibility.y3 and point not in X_points + O_points:
point.set()
return
elif winning_possibility.p2_satisfied and winning_possibility.p3_satisfied:
for point in XO_points:
if point.x == winning_possibility.x1 and point.y == winning_possibility.y1 and point not in X_points + O_points:
point.set()
return
elif winning_possibility.p3_satisfied and winning_possibility.p1_satisfied:
for point in XO_points:
if point.x == winning_possibility.x2 and point.y == winning_possibility.y2 and point not in X_points + O_points:
point.set()
return
# If the opponent can win in the next move
for winning_possibility in winning_possibilities:
winning_possibility.check('X')
if winning_possibility.p1_satisfied and winning_possibility.p2_satisfied:
for point in XO_points:
if point.x == winning_possibility.x3 and point.y == winning_possibility.y3 and point not in X_points + O_points:
point.set()
return
elif winning_possibility.p2_satisfied and winning_possibility.p3_satisfied:
for point in XO_points:
if point.x == winning_possibility.x1 and point.y == winning_possibility.y1 and point not in X_points + O_points:
point.set()
return
elif winning_possibility.p3_satisfied and winning_possibility.p1_satisfied:
for point in XO_points:
if point.x == winning_possibility.x2 and point.y == winning_possibility.y2 and point not in X_points + O_points:
point.set()
return
# If the center is free...
center_occupied = False
for point in X_points + O_points:
if point.x == 2 and point.y == 2:
center_occupied = True
break
if not center_occupied:
for point in XO_points:
if point.x == 2 and point.y == 2:
point.set()
return
# Occupy corner or middle based on what opponent occupies
corner_points = [(1, 1), (1, 3), (3, 1), (3, 3)]
middle_points = [(1, 2), (2, 1), (2, 3), (3, 2)]
num_of_corner_points_occupied_by_X = 0
for point in X_points:
if (point.x, point.y) in corner_points:
num_of_corner_points_occupied_by_X += 1
if num_of_corner_points_occupied_by_X >= 2:
for point in XO_points:
if (point.x, point.y) in middle_points and point not in X_points + O_points:
point.set()
return
elif num_of_corner_points_occupied_by_X < 2:
for point in XO_points:
if (point.x, point.y) in corner_points and point not in X_points + O_points:
point.set()
return
Создание кнопки для переключения игры с компьютером или игры с человеком
Давайте создадим кнопку, которая может переключать противников как человека, так и компьютер, а также сделаем обратный вызов для изменения текста и команды кнопки переключения.
play_with = "Computer"
def play_with_human():
global play_with
play_with = "Human" # switch opponent to human
play_with_button['text'] = "Play with computer" # switch text
play_with_button['command'] = play_with_computer # switch command so that the user can play with the computer again, if required
play_again() # restart game
def play_with_computer():
global play_with
play_with = "Computer" # switch opponent to computer
play_with_button['text'] = "Play with human" # switch text
play_with_button['command'] = play_with_human # switch command so that the user can play with a human again, if required
play_again() # restart game
play_with_button = tk.Button(root, text='Play with human', font=('Ariel', 15), command=play_with_human)
play_with_button.pack()
Нам нужно вызывать функцию auto_play
всякий раз, когда наступает очередь O и значение play_with
равно "Computer"
. Для этого добавьте следующий код в функцию set
в классе XOPoint
:
if play_with == "Computer" and status_label['text'] == "O's turn":
auto_play()
Результат
Если вы нашли эту статью полезной, поставьте лайк ⭐ и следуйте за мной, чтобы получать все мои последние материалы.
Полный код в репозитории GitHub: https://github.com/Jothin-kumar/tic-tac-toe/