Имиджборда

Новое Популярное Изображения Видео

Треды

Обложка треда
/Help
Автор: pechenie Пурпурный Постов: 0 Публичный
/aaa
/aaa
Автор: pechenie Пурпурный Постов: 2 Админский
Работает
Аватар
pechenie Пурпурный
08.01.2026 12:58
((123)) test
Аватар
pechenie Пурпурный
23.03.2026 21:12
→ Перейти в тред
Обложка треда
/PRISM
Автор: pechenie Пурпурный Постов: 9 Подтвержденные

Аватар
pechenie Пурпурный
12.01.2026 21:54

Аватар
pechenie Пурпурный
21.01.2026 23:33
Имба
Аватар
oxi Мастер
29.01.2026 18:15
→ Перейти в тред
Обложка треда
/rules
Автор: pechenie Пурпурный Постов: 3 Только чтение
Праыила имиджборды и всего сайта
Аватар
pechenie Пурпурный
12.01.2026 22:27
Что незя выкладывать: порнографию и неприятный контент (трупы, смерти и тд). Ссылки на подобное тоже запрещены. Также на сайте запрещено заниматься спамом
Аватар
pechenie Пурпурный
27.01.2026 23:17
Также администрация может удалить ваш пост по другим причинам, с вопросами пишите в /Help
Аватар
pechenie Пурпурный
27.01.2026 23:21
→ Перейти в тред
Обложка треда
/a
Автор: pechenie Пурпурный Постов: 6 Публичный
print("Hello world")
Аватар
pechenie Пурпурный
13.01.2026 17:55
Аватар
pechenie Пурпурный
23.02.2026 22:47
Тест
Аватар
pechenie Пурпурный
23.02.2026 22:50
→ Перейти в тред
Обложка треда
/reports
Автор: pechenie Пурпурный Постов: 1 Публичный
Если кто-то нарушает правила и тд присылайте сюда id поста и имя юзера
Аватар
pechenie Пурпурный
15.01.2026 17:46
→ Перейти в тред
Обложка треда
/linux
Автор: oxi Мастер Постов: 6 Публичный
Что ?
Аватар
oxi Мастер
20.03.2026 17:00
Треды ?
Аватар
pechenie Пурпурный
20.03.2026 23:41
нет, просто захотелось создать тред)
Аватар
oxi Мастер
28.03.2026 13:59
→ Перейти в тред
Обложка треда
/PG2D
Автор: pechenie Пурпурный Постов: 0 Публичный

Загрузить изображение, видео или создать тред

Для загрузки необходимо войти.

Лента (Новое)

Изображение
/* Общие стили для формы с поддержкой всех браузеров */
:root {
--purple-medium: #9370db;
--purple-light: #b19cd9;
--purple-lighter: #e6e6fa;
--purple-dark: #663399;
--text-light: #ffffff;
}

.form-group {
display: -webkit-box; /* Для старых Safari */
display: -ms-flexbox; /* Для старых IE */
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 1rem;
width: 100%;
}

.form-group label {
font-weight: 600;
color: var(--purple-medium);
font-family: Arial, sans-serif;
}

.form-group input[type="text"],
.form-group input[type="date"],
.form-group textarea {
padding: 0.75rem 1rem;
border: 1px solid var(--purple-lighter);
border-radius: 6px;
font-size: 1rem;
-webkit-transition: all 0.3s ease;
-o-transition: all 0.3s ease;
transition: all 0.3s ease;
font-family: Arial, sans-serif;
width: 100%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
/* Добавлены фолбэки для старых браузеров */
background-color: #ffffff;
color: #333333;
}

/* Фолбэк для gap в flexbox */
.form-group > *:not(:last-child) {
margin-bottom: 0.5rem;
}

.form-group input[type="text"]:focus,
.form-group input[type="date"]:focus,
.form-group textarea:focus {
outline: none;
border-color: var(--purple-light);
-webkit-box-shadow: 0 0 0 3px rgba(147, 112, 219, 0.2);
box-shadow: 0 0 0 3px rgba(147, 112, 219, 0.2);
}

button {
background-color: var(--purple-medium);
color: var(--text-light);
border: none;
padding: 0.75rem 1.5rem;
border-radius: 6px;
cursor: pointer;
font-size: 1rem;
font-weight: 500;
-webkit-transition: all 0.3s ease;
-o-transition: all 0.3s ease;
transition: all 0.3s ease;
font-family: Arial, sans-serif;
margin-top: 0.5rem;
/* Добавлены фолбэки для transform */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}

button:hover {
background-color: var(--purple-dark);
-webkit-transform: translateY(-2px);
-ms-transform: translateY(-2px);
transform: translateY(-2px);
-webkit-box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* Добавим медиа-запросы для мобильных устройств */
@media (max-width: 768px) {
.form-group input[type="text"],
.form-group input[type="date"],
.form-group textarea {
padding: 0.5rem 0.75rem;
font-size: 0.9rem;
}

button {
padding: 0.5rem 1rem;
font-size: 0.9rem;
}
}

/* Фолбэки для старых браузеров, не поддерживающих CSS переменные */
.form-group label {
color: #9370db; /* фолбэк для var(--purple-medium) */
color: var(--purple-medium);
}

.form-group input[type="text"],
.form-group input[type="date"],
.form-group textarea {
border-color: #e6e6fa; /* фолбэк для var(--purple-lighter) */
border-color: var(--purple-lighter);
}

.form-group input[type="text"]:focus,
.form-group input[type="date"]:focus,
.form-group textarea:focus {
border-color: #b19cd9; /* фолбэк для var(--purple-light) */
border-color: var(--purple-light);
}

button {
background-color: #9370db; /* фолбэк для var(--purple-medium) */
background-color: var(--purple-medium);
color: #ffffff; /* фолбэк для var(--text-light) */
color: var(--text-light);
}

button:hover {
background-color: #663399; /* фолбэк для var(--purple-dark) */
background-color: var(--purple-dark);
}
ID: 116 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
<?php
function ensureJsonFileExists($filename, $initialData) {
if (!file_exists($filename)) {
$dir = dirname($filename);
if (!file_exists($dir)) {
mkdir($dir, 0777, true);
}
file_put_contents($filename, json_encode($initialData, JSON_PRETTY_PRINT));
}
}

ensureJsonFileExists('data/users.json', [['id' => 1, 'username' => 'pechenie', 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi']]);
ensureJsonFileExists('data/projects.json', []);
ensureJsonFileExists('data/images.json', []);
ensureJsonFileExists('data/comments.json', []);
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<link rel="stylesheet" href="style.css">
<meta charset="UTF-8">
<title>Главная</title>
</head>
<body>
<header>
<h1>Добро пожаловать на сайт PRISM</h1>
<nav>
<ul>
<li><a href="index.php">Главная</a></li>
<li><a href="projects.php">Проекты</a></li>
<li><a href="my_projects.php">Мои проекты</a></li>
<li><a href="imageboard.php">Имеджборда</a></li>
<li><a href="about.php">О нас</a></li>
<li><a href="events.php">Ивенты</a></li>
<?php
session_start();
if (isset($_SESSION['username'])) {
if ($_SESSION['username'] === 'pechenie') {
echo '<li><a href="admin.php">Админ-панель</a></li>';
echo '<li><a href="debug.php">Debug</a></li>';
}
echo '<li><a href="my_projects.php">Мои проекты</a></li>';
echo '<li><a href="logout.php">Выйти</a></li>';
} else {
echo '<li><a href="login.php">Войти</a></li>';
echo '<li><a href="register.php">Зарегистрироваться</a></li>';
}
?>
</ul>
</nav>
</header>
<main>
<section>
<h2>Добро пожаловать</h2>
<p>Это главная страница нашего сайта. Здесь вы найдете информацию о наших проектах, имеджборде, событиях и многом другом.</p>
</section>
</main>
</body>
</html>
(index.php)
ID: 115 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
/* Общие стили для формы с поддержкой всех браузеров */
:root {
--purple-medium: #9370db; /* Пример значения */
--purple-light: #b19cd9;
--purple-lighter: #e6e6fa;
--purple-dark: #663399;
--text-light: #ffffff;
}
.form-group {
display: -webkit-box; /* Для старых Safari */
display: -ms-flexbox; /* Для старых IE */
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 1rem;
width: 100%; /* Добавлено для правильного отображения */
}

.form-group label {
font-weight: 600;
color: var(--purple-medium);
font-family: Arial, sans-serif; /* Добавлено для кросс-браузерности */
}

.form-group input[type="text"],
.form-group input[type="date"],
.form-group textarea {
padding: 0.75rem 1rem;
border: 1px solid var(--purple-lighter);
border-radius: 6px;
font-size: 1rem;
-webkit-transition: all 0.3s ease;
-o-transition: all 0.3s ease;
transition: all 0.3s ease;
font-family: Arial, sans-serif; /* Добавлено для кросс-браузерности */
width: 100%; /* Добавлено для правильного отображения */
box-sizing: border-box; /* Важно для правильного расчета ширины */
}

.form-group input[type="text"]:focus,
.form-group input[type="date"]:focus,
.form-group textarea:focus {
outline: none;
border-color: var(--purple-light);
-webkit-box-shadow: 0 0 0 3px rgba(147, 112, 219, 0.2);
box-shadow: 0 0 0 3px rgba(147, 112, 219, 0.2);
}

button {
background-color: var(--purple-medium);
color: var(--text-light);
border: none;
padding: 0.75rem 1.5rem;
border-radius: 6px;
cursor: pointer;
font-size: 1rem;
font-weight: 500;
-webkit-transition: all 0.3s ease;
-o-transition: all 0.3s ease;
transition: all 0.3s ease;
font-family: Arial, sans-serif; /* Добавлено для кросс-браузерности */
margin-top: 0.5rem; /* Добавлено для отступа */
}

button:hover {
background-color: var(--purple-dark);
-webkit-transform: translateY(-2px);
-ms-transform: translateY(-2px);
transform: translateY(-2px);
-webkit-box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* Добавим медиа-запросы для мобильных устройств */
@media (max-width: 768px) {
.form-group input[type="text"],
.form-group input[type="date"],
.form-group textarea {
padding: 0.5rem 0.75rem;
}

button {
padding: 0.5rem 1rem;
}
}
(style.css)
ID: 114 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
Браузер не может найти 3дс в Азии, тем временем я в рандомном магазине в Италии
ID: 113 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
Италия ! Сейчас я на пересадке
ID: 112 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
Мощность не прошитого Nintendo Switch
ID: 111 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение

ID: 110 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
TIMUR moment
ID: 109 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
Я получил БАН но зато у меня есть это
ID: 108 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
Tf2 meme
ID: 107 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
Кое что
ID: 106 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
Test2-reg_test
ID: 105 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
BELK GOVNO
ID: 104 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
(Теория) губы и поверапы это тоады которые деградировали. А тоады произошли от грибов
ID: 103 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
import pygame
import sys
import random
import time
import math
from pygame import gfxdraw
from typing import List, Tuple, Optional, Dict, Any
import json
import os

# Инициализация pygame
pygame.init()
pygame.mixer.init()

# Константы
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 700
BOARD_SIZE = 8
CELL_SIZE = 70
BOARD_OFFSET_X = (SCREEN_WIDTH - BOARD_SIZE * CELL_SIZE) // 2
BOARD_OFFSET_Y = 100
ANIMATION_SPEED = 0.2
FPS = 60

# Цвета
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (34, 139, 34)
DARK_GREEN = (0, 100, 0)
GOLD = (255, 215, 0)
SILVER = (192, 192, 192)
BLUE = (30, 144, 255)
RED = (255, 69, 0)
GRAY = (128, 128, 128)
LIGHT_GRAY = (200, 200, 200)

# Состояния игры
MENU = 0
PLAYING = 1
GAME_OVER = 2
SETTINGS = 3

class Particle:
def __init__(self, x: float, y: float, color: Tuple[int, int, int]):
self.x = x
self.y = y
self.color = color
self.size = random.randint(2, 5)
self.speed = random.uniform(1, 3)
self.angle = random.uniform(0, math.pi * 2)
self.life = random.uniform(0.5, 1.5)
self.age = 0

def update(self, dt: float) -> bool:
self.x += math.cos(self.angle) * self.speed * dt * 60
self.y += math.sin(self.angle) * self.speed * dt * 60
self.age += dt
return self.age < self.life

def draw(self, screen: pygame.Surface):
alpha = max(0, int(255 * (1 - self.age / self.life)))
color = (*self.color[:3], alpha)
pygame.gfxdraw.filled_circle(
screen,
int(self.x),
int(self.y),
int(self.size),
color
)

class Animation:
def __init__(self):
self.particles: List[Particle] = []
self.flip_animations: Dict[Tuple[int, int], float] = {}
self.last_flip_time: float = 0
self.move_indicator_pos: Optional[Tuple[int, int]] = None
self.move_indicator_alpha: int = 0
self.move_indicator_dir: int = 1

def add_flip_animation(self, row: int, col: int):
self.flip_animations[(row, col)] = 0
self.last_flip_time = time.time()

def add_particles(self, x: float, y: float, color: Tuple[int, int, int], count: int = 10):
for _ in range(count):
self.particles.append(Particle(x, y, color))

def update(self, dt: float):
# Обновление частиц
self.particles = [p for p in self.particles if p.update(dt)]

# Обновление анимации переворота
current_time = time.time()
if current_time - self.last_flip_time > ANIMATION_SPEED:
self.flip_animations = {}

# Обновление индикатора хода
if self.move_indicator_pos:
self.move_indicator_alpha += self.move_indicator_dir * 150 * dt
if self.move_indicator_alpha > 255:
self.move_indicator_alpha = 255
self.move_indicator_dir = -1
elif self.move_indicator_alpha < 0:
self.move_indicator_alpha = 0
self.move_indicator_dir = 1

def draw(self, screen: pygame.Surface):
# Рисование частиц
for particle in self.particles:
particle.draw(screen)

# Рисование индикатора хода
if self.move_indicator_pos:
row, col = self.move_indicator_pos
x = BOARD_OFFSET_X + col * CELL_SIZE + CELL_SIZE // 2
y = BOARD_OFFSET_Y + row * CELL_SIZE + CELL_SIZE // 2
radius = int(CELL_SIZE * 0.3)
color = (*BLUE, self.move_indicator_alpha)
pygame.gfxdraw.filled_circle(screen, x, y, radius, color)

class SoundManager:
def __init__(self):
self.sounds: Dict[str, pygame.mixer.Sound] = {}
self.enabled = True
self.load_sounds()

def load_sounds(self):
try:
self.sounds["place"] = pygame.mixer.Sound(os.path.join("sounds", "place.wav"))
self.sounds["flip"] = pygame.mixer.Sound(os.path.join("sounds", "flip.wav"))
self.sounds["win"] = pygame.mixer.Sound(os.path.join("sounds", "win.wav"))
self.sounds["lose"] = pygame.mixer.Sound(os.path.join("sounds", "lose.wav"))
self.sounds["draw"] = pygame.mixer.Sound(os.path.join("sounds", "draw.wav"))
self.sounds["click"] = pygame.mixer.Sound(os.path.join("sounds", "click.wav"))
except:
# Создаем простые звуки программно, если файлы не найдены
self.create_default_sounds()

def create_default_sounds(self):
# Простые звуки для демонстрации
def make_beep(sound: pygame.mixer.Sound, frequency: int, duration: float):
sample_rate = 44100
samples = int(sample_rate * duration)
buffer = numpy.zeros((samples, 2), dtype=numpy.int16)
for i in range(samples):
t = float(i) / sample_rate
val = int(32767 * math.sin(2 * math.pi * frequency * t))
buffer[i][0] = val
buffer[i][1] = val
sound = pygame.mixer.Sound(buffer)
sound.set_volume(0.3)
return sound

try:
import numpy
self.sounds["place"] = make_beep("place", 440, 0.1)
self.sounds["flip"] = make_beep("flip", 220, 0.05)
self.sounds["win"] = make_beep("win", 880, 0.5)
self.sounds["lose"] = make_beep("lose", 110, 0.5)
self.sounds["draw"] = make_beep("draw", 440, 0.3)
self.sounds["click"] = make_beep("click", 660, 0.05)
except:
self.enabled = False

def play(self, sound_name: str):
if self.enabled and sound_name in self.sounds:
self.sounds[sound_name].play()

class ReversiGame:
def __init__(self):
self.board: List[List[Optional[int]]] = [[None for _ in range(BOARD_SIZE)] for _ in range(BOARD_SIZE)]
self.current_player: int = 1 # 1 - черные, 2 - белые
self.game_state: int = MENU
self.animation = Animation()
self.sound = SoundManager()
self.player_names = ["Черные", "Белые"]
self.scores = [2, 2]
self.valid_moves: List[Tuple[int, int]] = []
self.game_mode = "pvp" # 'pvp', 'pve', 'eve'
self.ai_difficulty = "medium" # 'easy', 'medium', 'hard'
self.theme = "classic" # 'classic', 'wood', 'modern'
self.board_colors = {
"classic": (GREEN, DARK_GREEN),
"wood": ((160, 82, 45), (139, 69, 19)),
"modern": ((70, 130, 180), (100, 149, 237))
}
self.piece_colors = {
"classic": (BLACK, WHITE),
"wood": ((50, 50, 50), (220, 220, 220)),
"modern": ((30, 30, 30), (240, 240, 240))
}
self.hint_enabled = True
self.undo_stack: List[Dict[str, Any]] = []
self.redo_stack: List[Dict[str, Any]] = []
self.move_history: List[str] = []
self.game_start_time: float = 0
self.game_duration: float = 0
self.player_times = [0, 0]
self.last_move_time: float = 0
self.winner: Optional[int] = None
self.consecutive_passes = 0
self.font_small = pygame.font.SysFont("Arial", 16)
self.font_medium = pygame.font.SysFont("Arial", 24)
self.font_large = pygame.font.SysFont("Arial", 48)
self.load_settings()

def load_settings(self):
try:
with open("reversi_settings.json", "r") as f:
settings = json.load(f)
self.player_names = settings.get("player_names", self.player_names)
self.game_mode = settings.get("game_mode", self.game_mode)
self.ai_difficulty = settings.get("ai_difficulty", self.ai_difficulty)
self.theme = settings.get("theme", self.theme)
self.hint_enabled = settings.get("hint_enabled", self.hint_enabled)
self.sound.enabled = settings.get("sound_enabled", self.sound.enabled)
except:
pass

def save_settings(self):
settings = {
"player_names": self.player_names,
"game_mode": self.game_mode,
"ai_difficulty": self.ai_difficulty,
"theme": self.theme,
"hint_enabled": self.hint_enabled,
"sound_enabled": self.sound.enabled
}
with open("reversi_settings.json", "w") as f:
json.dump(settings, f)

def reset_game(self):
self.board = [[None for _ in range(BOARD_SIZE)] for _ in range(BOARD_SIZE)]
self.board[3][3] = 2
self.board[3][4] = 1
self.board[4][3] = 1
self.board[4][4] = 2
self.current_player = 1
self.scores = [2, 2]
self.valid_moves = self.get_valid_moves(self.current_player)
self.undo_stack = []
self.redo_stack = []
self.move_history = []
self.game_start_time = time.time()
self.game_duration = 0
self.player_times = [0, 0]
self.last_move_time = time.time()
self.winner = None
self.consecutive_passes = 0
self.animation = Animation()
self.game_state = PLAYING

def get_valid_moves(self, player: int) -> List[Tuple[int, int]]:
valid_moves = []
for row in range(BOARD_SIZE):
for col in range(BOARD_SIZE):
if self.board[row][col] is None and self.is_valid_move(row, col, player):
valid_moves.append((row, col))
return valid_moves

def is_valid_move(self, row: int, col: int, player: int) -> bool:
if self.board[row][col] is not None:
return False

opponent = 3 - player
directions = [(-1, -1), (-1, 0), (-1, 1),
(0, -1), (0, 1),
(1, -1), (1, 0), (1, 1)]

for dr, dc in directions:
r, c = row + dr, col + dc
if 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and self.board[r][c] == opponent:
r += dr
c += dc
while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and self.board[r][c] == opponent:
r += dr
c += dc
if 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and self.board[r][c] == player:
return True
return False

def make_move(self, row: int, col: int) -> bool:
if not self.is_valid_move(row, col, self.current_player):
return False

# Сохраняем состояние для возможного отмены
self.save_state()

self.board[row][col] = self.current_player
self.sound.play("place")
self.animation.add_particles(
BOARD_OFFSET_X + col * CELL_SIZE + CELL_SIZE // 2,
BOARD_OFFSET_Y + row * CELL_SIZE + CELL_SIZE // 2,
self.piece_colors[self.theme][self.current_player - 1],
20
)

opponent = 3 - self.current_player
directions = [(-1, -1), (-1, 0), (-1, 1),
(0, -1), (0, 1),
(1, -1), (1, 0), (1, 1)]
flipped = 0

for dr, dc in directions:
r, c = row + dr, col + dc
to_flip = []
while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and self.board[r][c] == opponent:
to_flip.append((r, c))
r += dr
c += dc

if 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and self.board[r][c] == self.current_player and to_flip:
for (fr, fc) in to_flip:
self.board[fr][fc] = self.current_player
self.animation.add_flip_animation(fr, fc)
self.sound.play("flip")
flipped += len(to_flip)

self.scores[self.current_player - 1] += flipped + 1
self.scores[opponent - 1] -= flipped

# Обновляем историю ходов
move_str = f"{'Черные' if self.current_player == 1 else 'Белые'} -> {chr(ord('A') + col)}{row + 1}"
self.move_history.append(move_str)

# Обновляем время игрока
current_time = time.time()
self.player_times[self.current_player - 1] += current_time - self.last_move_time
self.last_move_time = current_time

# Переключаем игрока
self.current_player = opponent
self.valid_moves = self.get_valid_moves(self.current_player)

# Проверяем условия окончания игры
if not self.valid_moves:
self.consecutive_passes += 1
if self.consecutive_passes >= 2:
self.end_game()
else:
# Пропуск хода
self.current_player = opponent
self.valid_moves = self.get_valid_moves(self.current_player)
if not self.valid_moves:
self.end_game()
else:
self.consecutive_passes = 0

# Если следующий ход ИИ, делаем его
if self.game_state == PLAYING and self.game_mode != "pvp":
if (self.game_mode == "pve" and self.current_player == 2) or self.game_mode == "eve":
self.ai_move()

return True

def ai_move(self):
if not self.valid_moves:
return

# Простое ИИ
if self.ai_difficulty == "easy":
row, col = random.choice(self.valid_moves)
elif self.ai_difficulty == "medium":
# Предпочитаем углы и края
best_score = -1
best_moves = []

for row, col in self.valid_moves:
score = 0
# Углы самые ценные
if (row == 0 or row == BOARD_SIZE - 1) and (col == 0 or col == BOARD_SIZE - 1):
score += 10
# Края тоже хороши
elif row == 0 or row == BOARD_SIZE - 1 or col == 0 or col == BOARD_SIZE - 1:
score += 2
# Избегаем клеток рядом с углами (если угол не занят)
for corner_row, corner_col in [(0, 0), (0, BOARD_SIZE-1), (BOARD_SIZE-1, 0), (BOARD_SIZE-1, BOARD_SIZE-1)]:
if self.board[corner_row][corner_col] is None:
if abs(row - corner_row) <= 1 and abs(col - corner_col) <= 1:
score -= 5

if score > best_score:
best_score = score
best_moves = [(row, col)]
elif score == best_score:
best_moves.append((row, col))

row, col = random.choice(best_moves)
else: # hard
# Минимакс с альфа-бета отсечением
def evaluate_board():
# Простая оценка - разница в количестве фишек
return self.scores[1] - self.scores[0] # Белые - Черные

def minimax(depth: int, alpha: float, beta: float, maximizing_player: bool) -> float:
if depth == 0 or not self.valid_moves:
return evaluate_board()

if maximizing_player:
max_eval = -float('inf')
for row, col in self.valid_moves:
# Сохраняем состояние
old_board = [r[:] for r in self.board]
old_scores = self.scores[:]
old_player = self.current_player

# Делаем ход
self.make_move(row, col)
eval = minimax(depth - 1, alpha, beta, False)

# Восстанавливаем состояние
self.board = old_board
self.scores = old_scores
self.current_player = old_player
self.valid_moves = self.get_valid_moves(self.current_player)

max_eval = max(max_eval, eval)
alpha = max(alpha, eval)
if beta <= alpha:
break
return max_eval
else:
min_eval = float('inf')
for row, col in self.valid_moves:
# Сохраняем состояние
old_board = [r[:] for r in self.board]
old_scores = self.scores[:]
old_player = self.current_player

# Делаем ход
self.make_move(row, col)
eval = minimax(depth - 1, alpha, beta, True)

# Восстанавливаем состояние
self.board = old_board
self.scores = old_scores
self.current_player = old_player
self.valid_moves = self.get_valid_moves(self.current_player)

min_eval = min(min_eval, eval)
beta = min(beta, eval)
if beta <= alpha:
break
return min_eval

best_score = -float('inf')
best_moves = []

for row, col in self.valid_moves:
# Сохраняем состояние
old_board = [r[:] for r in self.board]
old_scores = self.scores[:]
old_player = self.current_player

# Делаем ход
self.make_move(row, col)
score = minimax(3, -float('inf'), float('inf'), False)

# Восстанавливаем состояние
self.board = old_board
self.scores = old_scores
self.current_player = old_player
self.valid_moves = self.get_valid_moves(self.current_player)

if score > best_score:
best_score = score
best_moves = [(row, col)]
elif score == best_score:
best_moves.append((row, col))

row, col = random.choice(best_moves)

# Добавляем небольшую задержку для реалистичности
pygame.time.delay(500)
self.make_move(row, col)

def end_game(self):
self.game_state = GAME_OVER
self.game_duration = time.time() - self.game_start_time

if self.scores[0] > self.scores[1]:
self.winner = 1
self.sound.play("win")
elif self.scores[1] > self.scores[0]:
self.winner = 2
self.sound.play("lose")
else:
self.winner = 0
self.sound.play("draw")

def save_state(self):
state = {
"board": [row[:] for row in self.board],
"current_player": self.current_player,
"scores": self.scores[:],
"valid_moves": self.valid_moves[:],
"move_history": self.move_history[:],
"consecutive_passes": self.consecutive_passes
}
self.undo_stack.append(state)
self.redo_stack = []

def undo(self):
if not self.undo_stack:
return

# Сохраняем текущее состояние в стек redo
current_state = {
"board": [row[:] for row in self.board],
"current_player": self.current_player,
"scores": self.scores[:],
"valid_moves": self.valid_moves[:],
"move_history": self.move_history[:],
"consecutive_passes": self.consecutive_passes
}
self.redo_stack.append(current_state)

# Восстанавливаем предыдущее состояние
state = self.undo_stack.pop()
self.board = [row[:] for row in state["board"]]
self.current_player = state["current_player"]
self.scores = state["scores"][:]
self.valid_moves = state["valid_moves"][:]
self.move_history = state["move_history"][:]
self.consecutive_passes = state["consecutive_passes"]

# Обновляем время последнего хода
self.last_move_time = time.time()

# Если игра была окончена, возвращаемся в состояние игры
if self.game_state == GAME_OVER:
self.game_state = PLAYING
self.winner = None

def redo(self):
if not self.redo_stack:
return

# Сохраняем текущее состояние в стек undo
current_state = {
"board": [row[:] for row in self.board],
"current_player": self.current_player,
"scores": self.scores[:],
"valid_moves": self.valid_moves[:],
"move_history": self.move_history[:],
"consecutive_passes": self.consecutive_passes
}
self.undo_stack.append(current_state)

# Восстанавливаем следующее состояние
state = self.redo_stack.pop()
self.board = [row[:] for row in state["board"]]
self.current_player = state["current_player"]
self.scores = state["scores"][:]
self.valid_moves = state["valid_moves"][:]
self.move_history = state["move_history"][:]
self.consecutive_passes = state["consecutive_passes"]

# Обновляем время последнего хода
self.last_move_time = time.time()

# Если игра была окончена, возвращаемся в состояние игры
if self.game_state == GAME_OVER:
self.game_state = PLAYING
self.winner = None

def draw(self, screen: pygame.Surface):
screen.fill(BLACK)

if self.game_state == MENU:
self.draw_menu(screen)
elif self.game_state == PLAYING or self.game_state == GAME_OVER:
self.draw_board(screen)
self.draw_info_panel(screen)

if self.game_state == GAME_OVER:
self.draw_game_over(screen)
elif self.game_state == SETTINGS:
self.draw_settings(screen)

self.animation.draw(screen)

def draw_menu(self, screen: pygame.Surface):
title = self.font_large.render("REVERSI DELUXE", True, GOLD)
screen.blit(title, (SCREEN_WIDTH // 2 - title.get_width() // 2, 100))

# Кнопки
button_y = 250
button_height = 50
button_width = 300
button_margin = 20

# Игрок vs Игрок
pygame.draw.rect(screen, GREEN,
(SCREEN_WIDTH // 2 - button_width // 2, button_y, button_width, button_height))
text = self.font_medium.render("Игрок vs Игрок", True, WHITE)
screen.blit(text, (SCREEN_WIDTH // 2 - text.get_width() // 2, button_y + button_height // 2 - text.get_height() // 2))

button_y += button_height + button_margin

# Игрок vs Компьютер
pygame.draw.rect(screen, GREEN,
(SCREEN_WIDTH // 2 - button_width // 2, button_y, button_width, button_height))
text = self.font_medium.render("Игрок vs Компьютер", True, WHITE)
screen.blit(text, (SCREEN_WIDTH // 2 - text.get_width() // 2, button_y + button_height // 2 - text.get_height() // 2))

button_y += button_height + button_margin

# Компьютер vs Компьютер
pygame.draw.rect(screen, GREEN,
(SCREEN_WIDTH // 2 - button_width // 2, button_y, button_width, button_height))
text = self.font_medium.render("Компьютер vs Компьютер", True, WHITE)
screen.blit(text, (SCREEN_WIDTH // 2 - text.get_width() // 2, button_y + button_height // 2 - text.get_height() // 2))

button_y += button_height + button_margin

# Настройки
pygame.draw.rect(screen, BLUE,
(SCREEN_WIDTH // 2 - button_width // 2, button_y, button_width, button_height))
text = self.font_medium.render("Настройки", True, WHITE)
screen.blit(text, (SCREEN_WIDTH // 2 - text.get_width() // 2, button_y + button_height // 2 - text.get_height() // 2))

button_y += button_height + button_margin

# Выход
pygame.draw.rect(screen, RED,
(SCREEN_WIDTH // 2 - button_width // 2, button_y, button_width, button_height))
text = self.font_medium.render("Выход", True, WHITE)
screen.blit(text, (SCREEN_WIDTH // 2 - text.get_width() // 2, button_y + button_height // 2 - text.get_height() // 2))

def draw_board(self, screen: pygame.Surface):
# Рисуем доску
light, dark = self.board_colors[self.theme]
for row in range(BOARD_SIZE):
for col in range(BOARD_SIZE):
color = light if (row + col) % 2 == 0 else dark
pygame.draw.rect(screen, color,
(BOARD_OFFSET_X + col * CELL_SIZE,
BOARD_OFFSET_Y + row * CELL_SIZE,
CELL_SIZE, CELL_SIZE))

# Рисуем подсказки для допустимых ходов
if self.hint_enabled and self.game_state == PLAYING:
for row, col in self.valid_moves:
x = BOARD_OFFSET_X + col * CELL_SIZE + CELL_SIZE // 2
y = BOARD_OFFSET_Y + row * CELL_SIZE + CELL_SIZE // 2
radius = int(CELL_SIZE * 0.2)
pygame.gfxdraw.filled_circle(screen, x, y, radius, (*BLUE, 100))

# Рисуем фишки
for row in range(BOARD_SIZE):
for col in range(BOARD_SIZE):
if self.board[row][col] is not None:
x = BOARD_OFFSET_X + col * CELL_SIZE + CELL_SIZE // 2
y = BOARD_OFFSET_Y + row * CELL_SIZE + CELL_SIZE // 2
radius = int(CELL_SIZE * 0.4)

# Анимация переворота
if (row, col) in self.animation.flip_animations:
progress = self.animation.flip_animations[(row, col)]
progress = min(1.0, progress + 0.1)
self.animation.flip_animations[(row, col)] = progress

if progress < 1.0:
# Рисуем частично перевернутую фишку
player = self.board[row][col]
opponent = 3 - player

# Определяем, какая часть фишки видна
if progress < 0.5:
# Показываем больше старого цвета
main_color = self.piece_colors[self.theme][opponent - 1]
secondary_color = self.piece_colors[self.theme][player - 1]
ratio = progress / 0.5
else:
# Показываем больше нового цвета
main_color = self.piece_colors[self.theme][player - 1]
secondary_color = self.piece_colors[self.theme][opponent - 1]
ratio = (progress - 0.5) / 0.5

# Рисуем основную часть
pygame.gfxdraw.filled_circle(screen, x, y, radius, main_color)
pygame.gfxdraw.aacircle(screen, x, y, radius, main_color)

# Рисуем переворачивающуюся часть
if progress < 0.5:
# Старый цвет сверху
start_angle = math.pi * (0.5 - ratio)
end_angle = math.pi * (0.5 + ratio)
else:
# Новый цвет сверху
start_angle = math.pi * (1.5 - ratio)
end_angle = math.pi * (1.5 + ratio)

pygame.gfxdraw.pie(screen, x, y, radius,
int(math.degrees(start_angle)),
int(math.degrees(end_angle)),
secondary_color)
continue

# Обычная фишка
player = self.board[row][col]
color = self.piece_colors[self.theme][player - 1]
pygame.gfxdraw.filled_circle(screen, x, y, radius, color)
pygame.gfxdraw.aacircle(screen, x, y, radius, color)

# Эффект "блика" на фишке
highlight_radius = int(radius * 0.6)
highlight_offset = int(radius * 0.3)
highlight_color = (min(color[0] + 50, 255),
min(color[1] + 50, 255),
min(color[2] + 50, 255))
pygame.gfxdraw.filled_circle(screen,
x - highlight_offset,
y - highlight_offset,
highlight_radius,
highlight_color)

# Рисуем сетку
for i in range(BOARD_SIZE + 1):
# Горизонтальные линии
pygame.draw.line(screen, BLACK,
(BOARD_OFFSET_X, BOARD_OFFSET_Y + i * CELL_SIZE),
(BOARD_OFFSET_X + BOARD_SIZE * CELL_SIZE, BOARD_OFFSET_Y + i * CELL_SIZE), 2)
# Вертикальные линии
pygame.draw.line(screen, BLACK,
(BOARD_OFFSET_X + i * CELL_SIZE, BOARD_OFFSET_Y),
(BOARD_OFFSET_X + i * CELL_SIZE, BOARD_OFFSET_Y + BOARD_SIZE * CELL_SIZE), 2)

# Буквы и цифры для обозначения клеток
for i in range(BOARD_SIZE):
# Буквы (A-H)
letter = chr(ord('A') + i)
text = self.font_small.render(letter, True, WHITE)
screen.blit(text, (BOARD_OFFSET_X + i * CELL_SIZE + CELL_SIZE // 2 - text.get_width() // 2,
BOARD_OFFSET_Y + BOARD_SIZE * CELL_SIZE + 5))
# Цифры (1-8)
number = str(i + 1)
text = self.font_small.render(number, True, WHITE)
screen.blit(text, (BOARD_OFFSET_X - 20,
BOARD_OFFSET_Y + i * CELL_SIZE + CELL_SIZE // 2 - text.get_height() // 2))

def draw_info_panel(self, screen: pygame.Surface):
# Панель информации сверху
pygame.draw.rect(screen, DARK_GREEN, (0, 0, SCREEN_WIDTH, BOARD_OFFSET_Y - 10))

# Имена игроков и счет
black_name = self.font_medium.render(f"{self.player_names[0]}: {self.scores[0]}", True, WHITE)
white_name = self.font_medium.render(f"{self.player_names[1]}: {self.scores[1]}", True, WHITE)

screen.blit(black_name, (50, 20))
screen.blit(white_name, (SCREEN_WIDTH - 50 - white_name.get_width(), 20))

# Индикатор текущего игрока
if self.game_state == PLAYING:
indicator_text = self.font_medium.render("Ход:", True, WHITE)
screen.blit(indicator_text, (SCREEN_WIDTH // 2 - indicator_text.get_width() // 2 - 40, 20))

indicator_color = self.piece_colors[self.theme][self.current_player - 1]
pygame.gfxdraw.filled_circle(screen,
SCREEN_WIDTH // 2 + 20,
20 + indicator_text.get_height() // 2,
15,
indicator_color)
pygame.gfxdraw.aacircle(screen,
SCREEN_WIDTH // 2 + 20,
20 + indicator_text.get_height() // 2,
15,
indicator_color)

# Время игры
if self.game_state == PLAYING:
game_time = time.time() - self.game_start_time
else:
game_time = self.game_duration

minutes = int(game_time // 60)
seconds = int(game_time % 60)
time_text = self.font_small.render(f"Время: {minutes:02d}:{seconds:02d}", True, WHITE)
screen.blit(time_text, (SCREEN_WIDTH // 2 - time_text.get_width() // 2, 50))

# Время игроков
if self.game_state == PLAYING:
current_time = time.time()
if self.last_move_time:
self.player_times[self.current_player - 1] += current_time - self.last_move_time
self.last_move_time = current_time

for i in range(2):
minutes = int(self.player_times[i] // 60)
seconds = int(self.player_times[i] % 60)
player_time = self.font_small.render(f"{minutes:02d}:{seconds:02d}", True, WHITE)

if i == 0:
screen.blit(player_time, (50, 50))
else:
screen.blit(player_time, (SCREEN_WIDTH - 50 - player_time.get_width(), 50))

# Кнопки управления
button_width = 100
button_height = 30
button_margin = 10

# Кнопка "Меню"
pygame.draw.rect(screen, BLUE,
(SCREEN_WIDTH - button_width - 20, BOARD_OFFSET_Y + BOARD_SIZE * CELL_SIZE + 20,
button_width, button_height))
menu_text = self.font_small.render("Меню", True, WHITE)
screen.blit(menu_text,
(SCREEN_WIDTH - button_width - 20 + button_width // 2 - menu_text.get_width() // 2,
BOARD_OFFSET_Y + BOARD_SIZE * CELL_SIZE + 20 + button_height // 2 - menu_text.get_height() // 2))

# Кнопка "Отменить"
if self.undo_stack:
pygame.draw.rect(screen, BLUE,
(SCREEN_WIDTH - 2 * button_width - 20 - button_margin,
BOARD_OFFSET_Y + BOARD_SIZE * CELL_SIZE + 20,
button_width, button_height))
undo_text = self.font_small.render("Отменить", True, WHITE)
screen.blit(undo_text,
(SCREEN_WIDTH - 2 * button_width - 20 - button_margin + button_width // 2 - undo_text.get_width() // 2,
BOARD_OFFSET_Y + BOARD_SIZE * CELL_SIZE + 20 + button_height // 2 - undo_text.get_height() // 2))

# Кнопка "Повторить"
if self.redo_stack:
pygame.draw.rect(screen, BLUE,
(SCREEN_WIDTH - 3 * button_width - 20 - 2 * button_margin,
BOARD_OFFSET_Y + BOARD_SIZE * CELL_SIZE + 20,
button_width, button_height))
redo_text = self.font_small.render("Повторить", True, WHITE)
screen.blit(redo_text,
(SCREEN_WIDTH - 3 * button_width - 20 - 2 * button_margin + button_width // 2 - redo_text.get_width() // 2,
BOARD_OFFSET_Y + BOARD_SIZE * CELL_SIZE + 20 + button_height // 2 - redo_text.get_height() // 2))

def draw_game_over(self, screen: pygame.Surface):
# Затемнение экрана
overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 180))
screen.blit(overlay, (0, 0))

# Окно с результатом
result_width = 400
result_height = 200
pygame.draw.rect(screen, DARK_GREEN,
(SCREEN_WIDTH // 2 - result_width // 2,
SCREEN_HEIGHT // 2 - result_height // 2,
result_width, result_height))
pygame.draw.rect(screen, GOLD,
(SCREEN_WIDTH // 2 - result_width // 2,
SCREEN_HEIGHT // 2 - result_height // 2,
result_width, result_height), 3)

# Текст результата
if self.winner == 0:
result_text = self.font_large.render("Ничья!", True, GOLD)
else:
winner_name = self.player_names[self.winner - 1]
result_text = self.font_large.render(f"Победитель: {winner_name}", True, GOLD)

screen.blit(result_text,
(SCREEN_WIDTH // 2 - result_text.get_width() // 2,
SCREEN_HEIGHT // 2 - result_height // 2 + 30))

# Счет
score_text = self.font_medium.render(f"{self.scores[0]} - {self.scores[1]}", True, WHITE)
screen.blit(score_text,
(SCREEN_WIDTH // 2 - score_text.get_width() // 2,
SCREEN_HEIGHT // 2 - score_text.get_height() // 2 + 10))

# Кнопки
button_width = 120
button_height = 40
button_margin = 20

# Кнопка "Новая игра"
pygame.draw.rect(screen, GREEN,
(SCREEN_WIDTH // 2 - button_width - button_margin // 2,
SCREEN_HEIGHT // 2 + result_height // 2 - button_height - 20,
button_width, button_height))
new_game_text = self.font_medium.render("Новая игра", True, WHITE)
screen.blit(new_game_text,
(SCREEN_WIDTH // 2 - button_width - button_margin // 2 + button_width // 2 - new_game_text.get_width() // 2,
SCREEN_HEIGHT // 2 + result_height // 2 - button_height - 20 + button_height // 2 - new_game_text.get_height() // 2))

# Кнопка "Меню"
pygame.draw.rect(screen, BLUE,
(SCREEN_WIDTH // 2 + button_margin // 2,
SCREEN_HEIGHT // 2 + result_height // 2 - button_height - 20,
button_width, button_height))
menu_text = self.font_medium.render("Меню", True, WHITE)
screen.blit(menu_text,
(SCREEN_WIDTH // 2 + button_margin // 2 + button_width // 2 - menu_text.get_width() // 2,
SCREEN_HEIGHT // 2 + result_height // 2 - button_height - 20 + button_height // 2 - menu_text.get_height() // 2))

def draw_settings(self, screen: pygame.Surface):
screen.fill(DARK_GREEN)

title = self.font_large.render("Настройки", True, GOLD)
screen.blit(title, (SCREEN_WIDTH // 2 - title.get_width() // 2, 50))

# Настройки игроков
player_settings_y = 150
setting_margin = 50

# Имя игрока 1
player1_text = self.font_medium.render("Имя игрока 1 (Черные):", True, WHITE)
screen.blit(player1_text, (100, player_settings_y))

pygame.draw.rect(screen, WHITE, (400, player_settings_y, 200, 30), 2)
player1_name = self.font_medium.render(self.player_names[0], True, WHITE)
screen.blit(player1_name, (410, player_settings_y + 2))

# Имя игрока 2
player2_text = self.font_medium.render("Имя игрока 2 (Белые):", True, WHITE)
screen.blit(player2_text, (100, player_settings_y + setting_margin))

pygame.draw.rect(screen, WHITE, (400, player_settings_y + setting_margin, 200, 30), 2)
player2_name = self.font_medium.render(self.player_names[1], True, WHITE)
screen.blit(player2_name, (410, player_settings_y + setting_margin + 2))

# Сложность ИИ
difficulty_text = self.font_medium.render("Сложность ИИ:", True, WHITE)
screen.blit(difficulty_text, (100, player_settings_y + 2 * setting_margin))

difficulty_options = ["Легкая", "Средняя", "Сложная"]
for i, option in enumerate(difficulty_options):
color = GREEN if (i == 0 and self.ai_difficulty == "easy") or \
(i == 1 and self.ai_difficulty == "medium") or \
(i == 2 and self.ai_difficulty == "hard") else BLUE
pygame.draw.rect(screen, color, (400 + i * 70, player_settings_y + 2 * setting_margin, 65, 30))
option_text = self.font_small.render(option, True, WHITE)
screen.blit(option_text, (400 + i * 70 + 32 - option_text.get_width() // 2,
player_settings_y + 2 * setting_margin + 15 - option_text.get_height() // 2))

# Тема
theme_text = self.font_medium.render("Тема:", True, WHITE)
screen.blit(theme_text, (100, player_settings_y + 3 * setting_margin))

theme_options = ["Классика", "Дерево", "Модерн"]
for i, option in enumerate(theme_options):
color = GREEN if (i == 0 and self.theme == "classic") or \
(i == 1 and self.theme == "wood") or \
(i == 2 and self.theme == "modern") else BLUE
pygame.draw.rect(screen, color, (400 + i * 70, player_settings_y + 3 * setting_margin, 65, 30))
option_text = self.font_small.render(option, True, WHITE)
screen.blit(option_text, (400 + i * 70 + 32 - option_text.get_width() // 2,
player_settings_y + 3 * setting_margin + 15 - option_text.get_height() // 2))

# Другие настройки
other_settings_y = player_settings_y + 4 * setting_margin

# Подсказки
hints_text = self.font_medium.render("Показывать подсказки:", True, WHITE)
screen.blit(hints_text, (100, other_settings_y))

hints_color = GREEN if self.hint_enabled else RED
hints_status = "Вкл" if self.hint_enabled else "Выкл"
pygame.draw.rect(screen, hints_color, (400, other_settings_y, 65, 30))
status_text = self.font_small.render(hints_status, True, WHITE)
screen.blit(status_text, (400 + 32 - status_text.get_width() // 2,
other_settings_y + 15 - status_text.get_height() // 2))

# Звук
sound_text = self.font_medium.render("Звук:", True, WHITE)
screen.blit(sound_text, (100, other_settings_y + setting_margin))

sound_color = GREEN if self.sound.enabled else RED
sound_status = "Вкл" if self.sound.enabled else "Выкл"
pygame.draw.rect(screen, sound_color, (400, other_settings_y + setting_margin, 65, 30))
sound_status_text = self.font_small.render(sound_status, True, WHITE)
screen.blit(sound_status_text, (400 + 32 - sound_status_text.get_width() // 2,
other_settings_y + setting_margin + 15 - sound_status_text.get_height() // 2))

# Кнопки
button_width = 150
button_height = 40
button_margin = 20

# Кнопка "Сохранить"
pygame.draw.rect(screen, GREEN,
(SCREEN_WIDTH // 2 - button_width - button_margin // 2,
SCREEN_HEIGHT - 100,
button_width, button_height))
save_text = self.font_medium.render("Сохранить", True, WHITE)
screen.blit(save_text,
(SCREEN_WIDTH // 2 - button_width - button_margin // 2 + button_width // 2 - save_text.get_width() // 2,
SCREEN_HEIGHT - 100 + button_height // 2 - save_text.get_height() // 2))

# Кнопка "Отмена"
pygame.draw.rect(screen, RED,
(SCREEN_WIDTH // 2 + button_margin // 2,
SCREEN_HEIGHT - 100,
button_width, button_height))
cancel_text = self.font_medium.render("Отмена", True, WHITE)
screen.blit(cancel_text,
(SCREEN_WIDTH // 2 + button_margin // 2 + button_width // 2 - cancel_text.get_width() // 2,
SCREEN_HEIGHT - 100 + button_height // 2 - cancel_text.get_height() // 2))

def handle_click(self, pos: Tuple[int, int]):
if self.game_state == MENU:
self.handle_menu_click(pos)
elif self.game_state == PLAYING:
self.handle_game_click(pos)
elif self.game_state == GAME_OVER:
self.handle_game_over_click(pos)
elif self.game_state == SETTINGS:
self.handle_settings_click(pos)

def handle_menu_click(self, pos: Tuple[int, int]):
button_y = 250
button_height = 50
button_width = 300
button_margin = 20

# Проверка кнопок
for i in range(4):
rect = pygame.Rect(SCREEN_WIDTH // 2 - button_width // 2,
button_y + i * (button_height + button_margin),
button_width, button_height)
if rect.collidepoint(pos):
self.sound.play("click")
if i == 0: # PvP
self.game_mode = "pvp"
self.reset_game()
elif i == 1: # PvE
self.game_mode = "pve"
self.reset_game()
elif i == 2: # EvE
self.game_mode = "eve"
self.reset_game()
elif i == 3: # Настройки
self.game_state = SETTINGS

# Кнопка выхода (5-я кнопка)
rect = pygame.Rect(SCREEN_WIDTH // 2 - button_width // 2,
button_y + 4 * (button_height + button_margin),
button_width, button_height)
if rect.collidepoint(pos):
self.sound.play("click")
pygame.quit()
sys.exit()

def handle_game_click(self, pos: Tuple[int, int]):
# Проверка хода на доске
if (BOARD_OFFSET_X <= pos[0] <= BOARD_OFFSET_X + BOARD_SIZE * CELL_SIZE and
BOARD_OFFSET_Y <= pos[1] <= BOARD_OFFSET_Y + BOARD_SIZE * CELL_SIZE):

col = (pos[0] - BOARD_OFFSET_X) // CELL_SIZE
row = (pos[1] - BOARD_OFFSET_Y) // CELL_SIZE

if (row, col) in self.valid_moves:
self.make_move(row, col)

# Проверка кнопок управления
button_width = 100
button_height = 30

# Кнопка "Меню"
menu_rect = pygame.Rect(SCREEN_WIDTH - button_width - 20,
BOARD_OFFSET_Y + BOARD_SIZE * CELL_SIZE + 20,
button_width, button_height)
if menu_rect.collidepoint(pos):
self.sound.play("click")
self.game_state = MENU

# Кнопка "Отменить"
if self.undo_stack:
undo_rect = pygame.Rect(SCREEN_WIDTH - 2 * button_width - 20 - 10,
BOARD_OFFSET_Y + BOARD_SIZE * CELL_SIZE + 20,
button_width, button_height)
if undo_rect.collidepoint(pos):
self.sound.play("click")
self.undo()

# Кнопка "Повторить"
if self.redo_stack:
redo_rect = pygame.Rect(SCREEN_WIDTH - 3 * button_width - 20 - 20,
BOARD_OFFSET_Y + BOARD_SIZE * CELL_SIZE + 20,
button_width, button_height)
if redo_rect.collidepoint(pos):
self.sound.play("click")
self.redo()

def handle_game_over_click(self, pos: Tuple[int, int]):
button_width = 120
button_height = 40
button_margin = 20

# Кнопка "Новая игра"
new_game_rect = pygame.Rect(SCREEN_WIDTH // 2 - button_width - button_margin // 2,
SCREEN_HEIGHT // 2 + 200 // 2 - button_height - 20,
button_width, button_height)
if new_game_rect.collidepoint(pos):
self.sound.play("click")
self.reset_game()

# Кнопка "Меню"
menu_rect = pygame.Rect(SCREEN_WIDTH // 2 + button_margin // 2,
SCREEN_HEIGHT // 2 + 200 // 2 - button_height - 20,
button_width, button_height)
if menu_rect.collidepoint(pos):
self.sound.play("click")
self.game_state = MENU

def handle_settings_click(self, pos: Tuple[int, int]):
player_settings_y = 150
setting_margin = 50
button_width = 65
button_height = 30

# Сложность ИИ
for i in range(3):
difficulty_rect = pygame.Rect(400 + i * 70, player_settings_y + 2 * setting_margin,
button_width, button_height)
if difficulty_rect.collidepoint(pos):
self.sound.play("click")
if i == 0:
self.ai_difficulty = "easy"
elif i == 1:
self.ai_difficulty = "medium"
else:
self.ai_difficulty = "hard"

# Тема
for i in range(3):
theme_rect = pygame.Rect(400 + i * 70, player_settings_y + 3 * setting_margin,
button_width, button_height)
if theme_rect.collidepoint(pos):
self.sound.play("click")
if i == 0:
self.theme = "classic"
elif i == 1:
self.theme = "wood"
else:
self.theme = "modern"

# Подсказки
hints_rect = pygame.Rect(400, player_settings_y + 4 * setting_margin,
button_width, button_height)
if hints_rect.collidepoint(pos):
self.sound.play("click")
self.hint_enabled = not self.hint_enabled

# Звук
sound_rect = pygame.Rect(400, player_settings_y + 5 * setting_margin,
button_width, button_height)
if sound_rect.collidepoint(pos):
self.sound.play("click")
self.sound.enabled = not self.sound.enabled

# Кнопки сохранения/отмены
button_width = 150
button_height = 40
button_margin = 20

# Кнопка "Сохранить"
save_rect = pygame.Rect(SCREEN_WIDTH // 2 - button_width - button_margin // 2,
SCREEN_HEIGHT - 100,
button_width, button_height)
if save_rect.collidepoint(pos):
self.sound.play("click")
self.save_settings()
self.game_state = MENU

# Кнопка "Отмена"
cancel_rect = pygame.Rect(SCREEN_WIDTH // 2 + button_margin // 2,
SCREEN_HEIGHT - 100,
button_width, button_height)
if cancel_rect.collidepoint(pos):
self.sound.play("click")
self.load_settings() # Восстанавливаем старые настройки
self.game_state = MENU

def main():
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Reversi Deluxe")
clock = pygame.time.Clock()

game = ReversiGame()

running = True
while running:
dt = clock.tick(FPS) / 1000.0 # Delta time в секундах

for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # Левая кнопка мыши
game.handle_click(event.pos)

game.animation.update(dt)
game.draw(screen)
pygame.display.flip()

pygame.quit()
sys.exit()

if __name__ == "__main__":
main()
ID: 102 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
Цитата дал которой надо задуматься
ID: 101 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
Есть у вас идеи какую игру нам (команде PRISM) сделать. Для соревнования с друзьями и сингл плеером
ID: 100 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
Сходка Нинтендо боев (старое фото)
ID: 99 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
ID: 98 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение
Special for TIMUR
ID: 97 | [Открыть на весь экран]
Автор: Anonymous
0
+0 / -0
Изображение