Скачиваний:
4
Добавлен:
03.06.2024
Размер:
15.87 Кб
Скачать
import pygame
import sys, os
from numpy import sign
# Задание ширины окна и числа рядов
WIDTH = 800
ROWS = 8

def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

icon = pygame.image.load(resource_path('checkers.ico'))
# Задание изображений шашек
BLACK= pygame.image.load(resource_path('black.png'))
WHITE= pygame.image.load(resource_path('white.png'))
BLACKKING = pygame.image.load(resource_path('blackKing.png'))
WHITEKING = pygame.image.load(resource_path('whiteKing.png'))

DEFAULT_IMAGE_SIZE = (100,100)
BLACK= pygame.transform.scale(BLACK, DEFAULT_IMAGE_SIZE)
WHITE= pygame.transform.scale(WHITE, DEFAULT_IMAGE_SIZE)
BLACKKING = pygame.transform.scale(BLACKKING, DEFAULT_IMAGE_SIZE)
WHITEKING = pygame.transform.scale(WHITEKING, DEFAULT_IMAGE_SIZE)

# Задание цветов
Colour_WHITE = (255,255,255)
Colour_BLACK = (105, 105, 105)
Colour_BLUE = (52, 152, 219)
Colour_GREEN = (46, 204, 113)

# Инициализация игры и создание окна
pygame.init()
WIN = pygame.display.set_mode((WIDTH,WIDTH))
pygame.display.set_icon(icon)
pygame.display.set_caption('Шашки')

move_sound = pygame.mixer.Sound(resource_path("push.mp3"))
eat_sound = pygame.mixer.Sound(resource_path("roll.mp3"))

# Класс клетка
class Node: 
    def __init__(self, row, col, width):
        self.row = row
        self.col = col
        self.x = int(row * width)
        self.y = int(col * width)
        self.colour = Colour_WHITE
        self.piece = None
    # Отрисовка клетки
    def draw(self, WIN):
        pygame.draw.rect(WIN, self.colour, (self.x, self.y, WIDTH / ROWS, WIDTH / ROWS))
        if self.piece:
            WIN.blit(self.piece.image, (self.x, self.y))

# Обновление отображения
def update_display(win, grid, rows, width):
    for row in grid:
        for spot in row:
            spot.draw(win)
    draw_grid(win, rows, width)
    pygame.display.update()

# Создание поля
def make_grid(rows, width):
    grid = []
    gap = width// rows
    count = 0
    for i in range(rows):
        grid.append([])
        for j in range(rows):
            node = Node(j,i, gap)
            if abs(i-j) % 2 == 0:
                node.colour=Colour_BLACK
            if (abs(i+j)%2==0) and (i<3):
                node.piece = Piece('B')
            elif(abs(i+j)%2==0) and i>4:
                node.piece=Piece('W')
            count+=1
            grid[i].append(node)
    return grid

# Отрисовка поля
def draw_grid(win, rows, width):
    gap = width // ROWS
    for i in range(rows):
        pygame.draw.line(win, Colour_BLACK, (0, i * gap), (width, i * gap))
        for j in range(rows):
            pygame.draw.line(win, Colour_BLACK, (j * gap, 0), (j * gap, width))

# Класс шашка
class Piece: 
    def __init__(self, team):
        self.team=team
        self.image= BLACK if self.team=='B' else WHITE
        self.type=None
    # Отрисовка шашки
    def draw(self, x, y):  
        WIN.blit(self.image, (x,y))

# Получение клетки
def getNode(grid, rows, width):
    # Ширина клетки (ширину окна разделить на количество рядов)
    gap = width//rows 
     # Получение координат клика мыши
    RowX,RowY = pygame.mouse.get_pos()
    # Вычисление ряда и столбца (Целочисленное деление координаты клика на ширину клетки)
    Row = RowX//gap 
    Col = RowY//gap
    return (Col,Row)

# Обновить цвета
def resetColours(grid, node):
    positions = generatePotentialMoves(node, grid)
    positions.append(node)

    # Закрашивание клеток
    for colouredNodes in positions:
        nodeX, nodeY = colouredNodes
        grid[nodeX][nodeY].colour = Colour_BLACK if abs(nodeX - nodeY) % 2 == 0 else Colour_WHITE

# Подсветка возможных ходов
def HighlightpotentialMoves(piecePosition, grid):
    positions = generatePotentialMoves(piecePosition, grid)
    for position in positions:
        Column,Row = position
        grid[Column][Row].colour=Colour_GREEN

# Определение команды противника
def opposite(team):
    return "B" if team=="W" else "W"

# Генерация возможных ходов
def generatePotentialMoves(nodePosition, grid):
    checker = lambda x,y: x+y>=0 and x+y<8
    positions = []
    column, row = nodePosition

    if grid[column][row].piece:
        # Задаём дальность хода для обычной шашки и для дамки
        vector_range=2 
        if grid[column][row].piece.type=='KING':
            vector_range=8

        # Векторы для ударных ходов    
        vectors = [[1, -1], [1, 1],[-1, -1], [-1, 1]]    
        # Ударные ходы
        for vector in vectors:
            count_obstacle=0 
            columnVector, rowVector = vector
            for i in range (1, vector_range):
                # Проверка, что шашка не окажется за границами поля
                if checker(columnVector*i,column) and checker(rowVector*i,row):
                    # Проверка, что на пути встречено 0 шашек
                    if count_obstacle==0:
                        # Проверка, что на векторе стоит шашка
                        if grid[column + columnVector*i][row+rowVector*i].piece:
                            count_obstacle+=1
                            # Проверка, что на векторе стоит вражеская шашка 
                            if grid[column + columnVector*i][row+rowVector*i].piece.team==opposite(grid[column][row].piece.team):
                                # Проверка, что шашка не окажется за границами поля после ударного хода
                                if checker((columnVector*(i + 1)), column) and checker((rowVector*(i + 1)), row):
                                    # Проверка, что за вражеской шашкой пусто
                                    if not grid[(columnVector*(i + 1)) + column][(rowVector*(i + 1)) + row].piece: 
                                        # Занесение хода в массив
                                        positions.append((columnVector*(i + 1) + column, rowVector*(i + 1) + row ))
                                    # Если за шашкой есть еще одна мы прибавляем к счетчику встреченных шашек
                                    elif grid[(columnVector*(i + 1)) + column][(rowVector*(i + 1)) + row].piece:
                                        count_obstacle+=1
                            # Если на векторе стоит дружественная шашка, переходим на следующий вектор
                            else:
                                break
                    # Если уже встречена шашка и активная шашка - дамка, проверям ходы за встреченной шашкой
                    elif grid[column][row].piece.type=='KING' and count_obstacle==1:
                            # Проверка, что на векторе пусто
                            if not grid[column + columnVector*i][row+rowVector*i].piece:
                                positions.append((column + columnVector*i,row+rowVector*i))
                            elif grid[column + columnVector*i][row+rowVector*i].piece:
                                count_obstacle+=1
                    
        # Выход из функции если есть ударный ход
        if len(positions)!=0:
            return positions 
        
        # Тихие ходы
        else:
            # Присвоение векторов для тихого хода, если шашка не является дамкой
            if not grid[column][row].piece.type=='KING':
                vectors = [[1, -1], [1, 1]] if grid[column][row].piece.team == "B" else [[-1, -1], [-1, 1]]                 
            for vector in vectors:
                columnVector, rowVector = vector
                for i in range (1, vector_range):
                    # Проверка, что шашка не окажется за границами поля
                    if checker(columnVector*i,column) and checker(rowVector*i,row):
                        # Проверка, что на месте хода нет шашки
                        if not grid[(column+columnVector*i)][(row+rowVector*i)].piece:
                            positions.append((column + columnVector*i, row + rowVector*i))
                        # Если на пути вектора встречается шашка, происходит переход на следующий вектор
                        else:
                            break
    # Выход из функции                        
    return positions

# Управление подсветкой
def highlight(ClickedNode, Grid, OldHighlight):
    Column,Row = ClickedNode
    Grid[Column][Row].colour=Colour_BLUE
    if OldHighlight:
        resetColours(Grid, OldHighlight)
    HighlightpotentialMoves(ClickedNode, Grid)
    return (Column,Row)

# Управление ходами
def move(grid, piecePosition, newPosition):
    resetColours(grid, piecePosition)
    newColumn, newRow = newPosition
    oldColumn, oldRow = piecePosition

    # Перемещение шашки
    piece = grid[oldColumn][oldRow].piece
    grid[newColumn][newRow].piece=piece
    grid[oldColumn][oldRow].piece = None

    # Обнуление превращения и статуса "съел"
    transform=False
    ate=False

    # Превращение в дамку
    if not grid[newColumn][newRow].piece.type=='KING':
        if newColumn==7 and grid[newColumn][newRow].piece.team=='B':
            grid[newColumn][newRow].piece.type='KING'
            grid[newColumn][newRow].piece.image=BLACKKING
            # Передача хода
            transform=True
        if newColumn==0 and  grid[newColumn][newRow].piece.team=='W':
            grid[newColumn][newRow].piece.type='KING'
            grid[newColumn][newRow].piece.image=WHITEKING
            # Передача хода
            transform=True
    
    # Ударный ход
    if abs(newColumn-oldColumn)>=2 or abs(newRow-oldRow)>=2:
        # Удаление съеденной шашки
        for i,j in zip(range(abs(newColumn-oldColumn)),range(abs(newRow-oldRow))):
            if grid[oldColumn+i*(sign(newColumn-oldColumn))][oldRow+j*sign(newRow-oldRow)].piece:
                grid[oldColumn+i*(sign(newColumn-oldColumn))][oldRow+j*sign(newRow-oldRow)].piece = None
                ate=True
                # Запуск звука ударного хода
                pygame.mixer.Sound.play(eat_sound)
                break
            
        # Передача хода если было превращение в дамку
        if transform:
            return opposite(grid[newColumn][newRow].piece.team)
        
        # Дальность повторного хода для обычной шашки и для дамки
        eat_limit=2
        if grid[newColumn][newRow].piece.type=='KING':
            eat_limit=7

        # Проверка на возможность еще одного ударного хода
        if ate:        
            for i in range(1, eat_limit):
                # Проверка что на возможном пути есть вражеская шашка и за ней пусто
                # В случае возможности еще одного ударного хода, ход не передается
                try:
                    if ((0<=newColumn+i+1<=7 and 0<=newRow+i+1<=7) and grid[newColumn+i][newRow+i].piece and grid[newColumn+i][newRow+i].piece.team==opposite(grid[newColumn][newRow].piece.team) and grid[newColumn+i+1][newRow+i+1].piece == None):
                        return grid[newColumn][newRow].piece.team
                except:
                    pass
                try:
                    if ((0<=newColumn-i-1<=7 and 0<=newRow+i+1<=7) and grid[newColumn-i][newRow+i].piece and grid[newColumn-i][newRow+i].piece.team==opposite(grid[newColumn][newRow].piece.team) and grid[newColumn-i-1][newRow+i+1].piece == None):
                        return grid[newColumn][newRow].piece.team
                except:
                    pass
                try:
                    if ((0<=newColumn-i-1<=7 and 0<=newRow-i-1<=7) and grid[newColumn-i][newRow-i].piece and grid[newColumn-i][newRow-i].piece.team==opposite(grid[newColumn][newRow].piece.team) and grid[newColumn-i-1][newRow-i-1].piece == None):
                        return grid[newColumn][newRow].piece.team
                except:
                    pass
                try:
                    if ((0<=newColumn+i+1<=7 and 0<=newRow-i-1<=7) and grid[newColumn+i][newRow-i].piece and grid[newColumn+i][newRow-i].piece.team==opposite(grid[newColumn][newRow].piece.team) and grid[newColumn+i+1][newRow-i-1].piece == None):
                        return grid[newColumn][newRow].piece.team
                except:
                    pass

    # Передача хода
    return opposite(grid[newColumn][newRow].piece.team)

def main(WIDTH, ROWS):
    grid = make_grid(ROWS, WIDTH)
    highlightedPiece = None
    currMove = 'W'

    while True:
        if currMove=='W':
            pygame.display.set_caption('Шашки Ход Белых')
        else:
            pygame.display.set_caption('Шашки Ход Чёрных')

        for event in pygame.event.get():
            if event.type== pygame.QUIT:
                print('EXIT SUCCESSFUL')
                pygame.quit()
                sys.exit()
              
            if event.type == pygame.MOUSEBUTTONDOWN:
                
                clickedNode = getNode(grid, ROWS, WIDTH)
                ClickedPositionColumn, ClickedPositionRow = clickedNode
                if grid[ClickedPositionColumn][ClickedPositionRow].colour == Colour_GREEN:
                    if highlightedPiece:
                        pieceColumn, pieceRow = highlightedPiece
                    if currMove == grid[pieceColumn][pieceRow].piece.team:
                        resetColours(grid, highlightedPiece)
                        currMove=move(grid, highlightedPiece, clickedNode)
                        # Запуск звука перемещения
                        pygame.mixer.Sound.play(move_sound)

                elif highlightedPiece == clickedNode:
                    pass
                else:
                    if grid[ClickedPositionColumn][ClickedPositionRow].piece:
                        if currMove == grid[ClickedPositionColumn][ClickedPositionRow].piece.team:
                            highlightedPiece = highlight(clickedNode, grid, highlightedPiece)
        update_display(WIN, grid,ROWS,WIDTH)

main(WIDTH, ROWS)
Соседние файлы в папке Килимник Курсовая