import pygame
import sys
import copy
# Настройки окна и графики
WIDTH, HEIGHT = 600, 600
ROWS, COLS = 8, 8
SQ_SIZE = WIDTH // COLS
# Цвета
WHITE = (240, 240, 240)
DARK_SQ = (180, 180, 180)
GREEN = (46, 204, 113) # Игрок (Зеленые)
RED = (231, 76, 60) # ИИ (Красные)
BLUE = (52, 152, 219) # Выделение и подсказки
BLACK = (44, 62, 80)
pygame.init()
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Уголки: Игрок против ИИ')
# Инициализация доски (Игрок 1 в левом верхнем углу, ИИ 2 в правом нижнем)
def create_initial_board():
board = [[0 for _ in range(COLS)] for _ in range(ROWS)]
# База игрока 1 (верхний левый угол 3х3)
for r in range(3):
for c in range(3):
board[r][c] = 1
# База ИИ (нижний правый угол 3х3)
for r in range(5, 8):
for c in range(5, 8):
board[r][c] = 2
return board
board = create_initial_board()
selected_piece = None
turn = 1 # 1 - Игрок, 2 - ИИ
is_jumping = False # Флаг, находится ли игрок в процессе серии прыжков
# --- Логика ходов ---
def get_valid_moves(board, row, col, only_jumps=False):
"""Возвращает список доступных ходов (r, c) для фишки в точке (row, col)"""
moves = []
directions = [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (-1, 1), (1, -1), (1, 1)]
for dr, dc in directions:
# 1. Обычные шаги (только если не в серии прыжков)
if not only_jumps:
nr, nc = row + dr, col + dc
if 0 <= nr < ROWS and 0 <= nc < COLS and board[nr][nc] == 0:
moves.append((nr, nc))
# 2. Прыжки через фигуры
mid_r, mid_c = row + dr, col + dc
if 0 <= mid_r < ROWS and 0 <= mid_c < COLS and board[mid_r][mid_c] != 0:
end_r, end_c = row + 2*dr, col + 2*dc
if 0 <= end_r < ROWS and 0 <= end_c < COLS and board[end_r][end_c] == 0:
moves.append((end_r, end_c))
return moves
def get_all_valid_moves(board, player):
"""Генерирует все возможные ходы для игрока (нужно для ИИ)"""
all_moves = []
for r in range(ROWS):
for c in range(COLS):
if board[r][c] == player:
# Добавляем обычные ходы и одиночные прыжки
for nr, nc in get_valid_moves(board, r, c):
all_moves.append(((r, c), (nr, nc)))
return all_moves
# --- Искусственный интеллект (Минимакс + Альфа-Бета) ---
def evaluate_board(board):
"""Оценка позиции: чем ближе фишки к цели, тем больше очков"""
score = 0
for r in range(ROWS):
for c in range(COLS):
if board[r][c] == 2: # ИИ стремится в верхний левый угол (0,0)
score += (14 - (r + c))
elif board[r][c] == 1: # Игрок стремится в нижний правый угол (7,7)
score -= (r + c)
return score
def minimax(board, depth, alpha, beta, maximizing_player):
"""Алгоритм поиска лучшего хода для ИИ"""
if depth == 0:
return evaluate_board(board), None
if maximizing_player:
max_eval = -float('inf')
best_move = None
moves = get_all_valid_moves(board, 2)
if not moves:
return evaluate_board(board), None
for start, end in moves:
temp_board = copy.deepcopy(board)
temp_board[end[0]][end[1]] = 2
temp_board[start[0]][start[1]] = 0
# ИИ проверяет, можно ли сделать прыжок еще дальше (серия)
if abs(start[0] - end[0]) == 2 or abs(start[1] - end[1]) == 2:
next_jumps = get_valid_moves(temp_board, end[0], end[1], only_jumps=True)
if next_jumps: # Если есть куда прыгнуть дальше, ИИ симулирует лучший прыжок
for jr, jc in next_jumps:
jump_board = copy.deepcopy(temp_board)
jump_board[jr][jc] = 2
jump_board[end[0]][end[1]] = 0
eval_score, _ = minimax(jump_board, depth - 1, alpha, beta, False)
if eval_score > max_eval:
max_eval = eval_score
best_move = (start, (jr, jc))
continue
eval_score, _ = minimax(temp_board, depth - 1, alpha, beta, False)
if eval_score > max_eval:
max_eval = eval_score
best_move = (start, end)
alpha = max(alpha, eval_score)
if beta <= alpha:
break
return max_eval, best_move
else:
min_eval = float('inf')
best_move = None
moves = get_all_valid_moves(board, 1)
if not moves:
return evaluate_board(board), None
for start, end in moves:
temp_board = copy.deepcopy(board)
temp_board[end[0]][end[1]] = 1
temp_board[start[0]][start[1]] = 0
eval_score, _ = minimax(temp_board, depth - 1, alpha, beta, True)
if eval_score < min_eval:
min_eval = eval_score
best_move = (start, end)
beta = min(beta, eval_score)
if beta <= alpha:
break
return min_eval, best_move
# --- Отрисовка интерфейса ---
def draw_board(win, board, selected, valid_moves):
win.fill(WHITE)
# Сетка
for row in range(ROWS):
for col in range(COLS):
if (row + col) % 2 == 1:
pygame.draw.rect(win, DARK_SQ, (col*SQ_SIZE, row*SQ_SIZE, SQ_SIZE, SQ_SIZE))
else:
pygame.draw.rect(win, WHITE, (col*SQ_SIZE, row*SQ_SIZE, SQ_SIZE, SQ_SIZE))
# Фишки
piece = board[row][col]
if piece == 1:
pygame.draw.circle(win, GREEN, (col*SQ_SIZE + SQ_SIZE//2, row*SQ_SIZE + SQ_SIZE//2), SQ_SIZE//3)
elif piece == 2:
pygame.draw.circle(win, RED, (col*SQ_SIZE + SQ_SIZE//2, row*SQ_SIZE + SQ_SIZE//2), SQ_SIZE//3)
# Подсветка выбранной фишки
if selected:
r, c = selected
pygame.draw.circle(win, BLUE, (c*SQ_SIZE + SQ_SIZE//2, r*SQ_SIZE + SQ_SIZE//2), SQ_SIZE//3, 4)
# Подсветка возможных ходов
for r_move, c_move in valid_moves:
pygame.draw.circle(win, BLUE, (c_move*SQ_SIZE + SQ_SIZE//2, r_move*SQ_SIZE + SQ_SIZE//2), 8)
def check_winner(board):
# Условие победы: занять целевой угол 3х3 полностью
p1_win = all(board[r][c] == 1 for r in range(5, 8) for c in range(5, 8))
p2_win = all(board[r][c] == 2 for r in range(3) for c in range(3))
if p1_win: return 1
if p2_win: return 2
return 0
# --- Основной цикл ---
def main():
global board, selected_piece, turn, is_jumping
clock = pygame.time.Clock()
valid_moves = []
while True:
clock.tick(60)
# Ход Искусственного Интеллекта
if turn == 2:
pygame.time.delay(500) # Небольшая задержка для реалистичности ходов
_, move = minimax(board, 3, -float('inf'), float('inf'), True)
if move:
start, end = move
board[end[0]][end[1]] = 2
board[start[0]][start[1]] = 0
turn = 1
is_jumping = False
selected_piece = None
# Обработка событий игрока
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN and turn == 1:
# Нажатие на ПРОБЕЛ завершает серию прыжков игрока
if event.key == pygame.K_SPACE and is_jumping:
turn = 2
is_jumping = False
selected_piece = None
valid_moves = []
if event.type == pygame.MOUSEBUTTONDOWN and turn == 1:
pos = pygame.mouse.get_pos()
row, col = pos[1] // SQ_SIZE, pos[0] // SQ_SIZE
# Если кликнули на доступную для хода клетку
if (row, col) in valid_moves and selected_piece:
start_r, start_c = selected_piece
board[row][col] = 1
board[start_r][start_c] = 0
# Проверяем, был ли это прыжок (дистанция 2 клетки)
if abs(start_r - row) == 2 or abs(start_c - col) == 2:
selected_piece = (row, col)
valid_moves = get_valid_moves(board, row, col, only_jumps=True)
# Если прыгать дальше некуда, завершаем ход
if not valid_moves:
turn = 2
is_jumping = False
selected_piece = None
else:
is_jumping = True # Входим в режим серийных прыжков
else:
# Обычный шаг завершает ход сразу
turn = 2
is_jumping = False
selected_piece = None
valid_moves = []
# Если выбираем свою фишку (и мы не посреди серии прыжков)
elif board[row][col] == 1 and not is_jumping:
selected_piece = (row, col)
valid_moves = get_valid_moves(board, row, col)
# Отрисовка интерфейса
draw_board(WIN, board, selected_piece, valid_moves)
# Проверка финала
winner = check_winner(board)
if winner != 0:
print(f"Игра окончена! Победил Игрок {winner}")
pygame.time.delay(3000)
break
pygame.display.update()
if __name__ == '__main__':
main()
Комментариев нет:
Отправить комментарий