Загрузка данных
import socket
import threading
import tkinter as tk
from tkinter import messagebox, simpledialog
PORT = 55555
class NetworkTicTacToe:
def __init__(self):
self.root = tk.Tk()
self.root.title("Сетевые Крестики-Нолики")
self.board = [" " for _ in range(9)]
self.my_turn = False
self.my_symbol = ""
self.opp_symbol = ""
self.conn = None
self.buttons = []
self.create_widgets()
self.choose_role()
def create_widgets(self):
# Создаем сетку кнопок 3х3
for i in range(9):
btn = tk.Button(
self.root,
text=" ",
font=("Arial", 24),
width=5,
height=2,
command=lambda idx=i: self.player_click(idx),
)
btn.grid(row=i // 3, column=i % 3)
self.buttons.append(btn)
# Статусная строка
self.status_label = tk.Label(
self.root, text="Выбор режима...", font=("Arial", 12)
)
self.status_label.grid(row=3, column=0, columnspan=3, sticky="we")
def choose_role(self):
# Всплывающее окно выбора роли при старте
role_window = tk.Toplevel(self.root)
role_window.title("Режим игры")
role_window.geometry("250x120")
role_window.grab_set() # Блокирует основное окно
tk.Label(role_window, text="Выберите режим:", font=("Arial", 12)).pack(
pady=10
)
def start_server():
role_window.destroy()
threading.Thread(target=self.init_server, daemon=True).start()
def start_client():
role_window.destroy()
threading.Thread(target=self.init_client, daemon=True).start()
tk.Button(
role_window, text="1. Создать сервер (X)", command=start_server
).pack(side="left", padx=20, pady=10)
tk.Button(
role_window, text="2. Подключиться (O)", command=start_client
).pack(side="right", padx=20, pady=10)
def init_server(self):
self.my_symbol = "X"
self.opp_symbol = "O"
self.my_turn = True # Сервер ходит первым
self.status_label.config(text="Ожидание игрока...")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.bind(("0.0.0.0", PORT))
s.listen(1)
self.conn, addr = s.accept()
self.status_label.config(text=f"Игрок подключен! Ваш ход ({self.my_symbol})")
threading.Thread(target=self.receive_data, daemon=True).start()
except Exception as e:
messagebox.showerror("Ошибка", f"Не удалось запустить сервер: {e}")
self.root.quit()
def init_client(self):
self.my_symbol = "O"
self.opp_symbol = "X"
self.my_turn = False # Клиент ждет ход сервера
# Спрашиваем IP-адрес сервера у пользователя
ip = simpledialog.askstring(
"Подключение", "Введите IP-адрес Сервера:", initialvalue="127.0.0.1"
)
if not ip:
self.root.quit()
return
self.status_label.config(text="Подключение к серверу...")
self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self.conn.connect((ip, PORT))
self.status_label.config(text=f"Подключено! Ход противника ({self.opp_symbol})")
threading.Thread(target=self.receive_data, daemon=True).start()
except Exception as e:
messagebox.showerror("Ошибка", f"Не удалось подключиться: {e}")
self.root.quit()
def player_click(self, idx):
# Проверяем, наш ли ход и свободна ли ячейка
if self.my_turn and self.board[idx] == " " and self.conn:
self.board[idx] = self.my_symbol
self.buttons[idx].config(text=self.my_symbol)
# Отправляем индекс сделанного хода по сети
try:
self.conn.send(str(idx).encode())
except:
messagebox.showerror("Ошибка", "Связь разорвана!")
return
self.my_turn = False
self.status_label.config(text=f"Ход противника ({self.opp_symbol})...")
self.check_game_status()
def receive_data(self):
# Поток для постоянного прослушивания сети
while True:
try:
data = self.conn.recv(1024).decode()
if not data:
break
idx = int(data)
# Обновляем поле ходом противника
self.board[idx] = self.opp_symbol
self.buttons[idx].config(text=self.opp_symbol)
self.my_turn = True
self.status_label.config(text=f"Ваш ход ({self.my_symbol})")
self.check_game_status()
except:
break
messagebox.showinfo("Инфо", "Противник отключился от игры.")
self.root.quit()
def check_game_status(self):
# Список победных комбинаций
win_coords = [
(0, 1, 2),
(3, 4, 5),
(6, 7, 8), # Горизонтали
(0, 3, 6),
(1, 4, 7),
(2, 5, 8), # Вертикали
(0, 4, 8),
(2, 4, 6), # Диагонали
]
# Проверка победы
for i, j, k in win_coords:
if (
self.board[i] == self.board[j] == self.board[k]
and self.board[i] != " "
):
winner = self.board[i]
if winner == self.my_symbol:
messagebox.showinfo("Победа!", "Поздравляем! Вы выиграли!")
else:
messagebox.showinfo("Поражение", "Вы проиграли. Повезет в следующий раз!")
self.root.quit()
return
# Проверка ничьей
if " " not in self.board:
messagebox.showinfo("Ничья", "Ничья! Свободных клеток не осталось.")
self.root.quit()
def run(self):
self.root.mainloop()
if __name__ == "__main__":
game = NetworkTicTacToe()
game.run()