Клон игры Nibbles AI сталкивается с барьерами - PullRequest
0 голосов
/ 20 октября 2018

Я сделал простую игру, похожую на Nibbles / Snake, в Python, используя pygame.Идея игры состоит в том, чтобы есть кусочки пищи, где ваша змея растет дольше с каждым кусочком.Я создал компьютерного противника, чтобы соревноваться с игроком.Я новичок в Python, объектно-ориентированное программирование, и я впервые пытался использовать любой вид ИИ для видеоигр.

Сначала кажется, что ИИ работает прилично, но всегда сталкивается с конфликтом.с чем-то, в конце концов, даже когда это не захвачено.Столкновение должно быть зарегистрировано каждый раз, когда передний / головной сегмент любого игрока сталкивается с самим собой (в том числе, если он поворачивается обратно сам), противником или границей поля.

Логика противника находится в Противникеметод класса "set_direction".Он должен попытаться пройти кратчайший путь к своей целевой еде, обходя любые препятствия, которые встречаются на пути.Есть ли какой-то недостаток в логике, которую я пропускаю?Я не уверен, будет ли этот вопрос слишком широким или нет.Если так, дайте мне знать, и я постараюсь быть более конкретным.

import pygame
from random import randint

BOARD_SIZE_WIDTH = 25
BOARD_SIZE_HEIGHT = 25

# This will determine the size of the objects drawn on the board.
# Must be equal to resolution
BOARD_SPACE_SIZE = 20

DISPLAY_RESOLUTION_WIDTH = BOARD_SIZE_WIDTH * BOARD_SPACE_SIZE
DISPLAY_RESOLUTION_HEIGHT = BOARD_SIZE_HEIGHT * BOARD_SPACE_SIZE

PLAYER1_START_X = 10
PLAYER1_START_Y = 12

OPPONENT_ON = True

OPPONENT_START_X = 14
OPPONENT_START_Y = 12

# This will determine how long the opponent takes to acquire a new food target.
# Raising it will give the player more time to respond to new food appearing.
OPPONENT_TURNS_TO_WAIT = 1

COBRA_START_DIRECTION = "Up"
# Number of milliseconds between player movements.
MOVEMENT_DELAY = 100

SEGMENT_SIZE = 20

# Define the objects that can occupy board spaces.
EMPTY_SPACE = 0
COBRA1_SPACE = 1
COBRA2_SPACE = 2
FOOD_SPACE = 3

RED = (0xFF, 0x00, 0x00)
YELLOW = (0xFF, 0xFF, 0x00)
BLUE = (0x00, 0x00, 0xFF)
BLACK = (0x00, 0x00, 0x00)

class Food(object):
    def __init__(self, posX, posY, index):
        self.posX = posX
        self.posY = posY
        self.index = index

class Board(object):
    foodOnBoard = False
    amountOfFood = 0

    def __init__(self, width, height, spaceSize):
        self.width = width
        self.height = height
        self.spaceSize = spaceSize
        self.spaces = [[0 for y in range(0, BOARD_SIZE_HEIGHT)] for x in range(0, BOARD_SIZE_WIDTH)]
        self.foodList = []

    def create_food(self):
        while self.foodOnBoard == False:
            x = randint(0, BOARD_SIZE_WIDTH - 1)
            y = randint(0, BOARD_SIZE_HEIGHT - 1)
            if self.spaces[x][y] == EMPTY_SPACE:
                self.spaces[x][y] = FOOD_SPACE
                self.amountOfFood += 1
                foodIndex = self.amountOfFood - 1
                self.foodList.append(Food(x, y, foodIndex))
                self.foodOnBoard = True

    def draw_board(self, screen):
        for y in range(0, BOARD_SIZE_HEIGHT):
            for x in range(0, BOARD_SIZE_WIDTH):
                drawX = x * BOARD_SPACE_SIZE
                drawY = y * BOARD_SPACE_SIZE

                space_object = self.spaces[x][y]

                if space_object == COBRA1_SPACE:
                    color = RED
                elif space_object == COBRA2_SPACE:
                    color = BLUE
                elif space_object == FOOD_SPACE:
                    color = YELLOW
                elif space_object == EMPTY_SPACE:
                    color = BLACK

                pygame.draw.rect(screen, color, pygame.Rect(drawX, drawY, BOARD_SPACE_SIZE, BOARD_SPACE_SIZE))

class Cobra(object):
    segmentsToAdd = 1
    sizeOfSegments = SEGMENT_SIZE

    def __init__(self, posX, posY, direction, spaceType):
        self.posX = posX
        self.posY = posY
        self.direction = direction
        self.spaceType = spaceType
        self.segments = []
        collision = False

    class Segment(object):
        def __init__(self, posX, posY):
            self.posX = posX
            self.posY = posY

    def add_segment(self, segment):
        self.segments.append(segment)

    def move(self):
        if self.direction == "Up":
            self.posY -= 1
        if self.direction == "Down":
            self.posY += 1
        if self.direction == "Left":
            self.posX -= 1
        if self.direction == "Right":
            self.posX += 1

class Opponent(Cobra):
    turnsToWait = OPPONENT_TURNS_TO_WAIT

    def __init__(self, posX, posY, direction, spaceType):
        # This will hold the currently targeted piece of food's location.
        self.target = Food(-1, -1, -1)
        self.posX = posX
        self.posY = posY
        self.direction = direction
        self.spaceType = spaceType
        self.segments = []
        collision = False

    def get_food_target(self, board):
        if board.foodOnBoard == True:
            prevDistance = -1
            distance = -1

            for food in board.foodList:
                # Determine the food's distance from the current position.
                distance = abs(food.posX - self.posX) + abs(food.posY - self.posY)

                if prevDistance == -1:
                    self.target = food
                elif prevDistance > distance:
                    self.target = food

                prevDistance = distance

            #print (self.target.posX, self.target.posY)

    def check_target(self, board):
        # See if the currently targeted piece of food is gone.
        # A negative value will indicate that a target is not set.
        if board.spaces[self.target.posX][self.target.posY] != FOOD_SPACE:
            self.target = Food(-1, -1, -1)

    def set_direction(self, board):
        # Check if the target food is closer horizontally or vertically.
        horizontalDistance = abs(self.posX - self.target.posX)
        verticalDistance = abs(self.posY - self.target.posY)

        if horizontalDistance > verticalDistance:

            # If the target food is to the left.
            if self.posX > self.target.posX:
                # Make sure the opponent isn't about to run into a barrier.
                if board.spaces[self.posX - 1][self.posY] != COBRA1_SPACE and\
                   board.spaces[self.posX - 1][self.posY] != COBRA2_SPACE:
                    # If the opponent would turn back on itself, it needs to move up or down before going left.
                    if self.direction == "Right":
                        if self.posY > self.target.posY:
                            self.direction = "Up"
                        else:
                            self.direction = "Down"
                    else:
                        self.direction = "Left"
                # If there is an obstacle, look for an empty spot to move to.
                else:
                    if board.spaces[self.posX][self.posY - 1] == EMPTY_SPACE\
                    and self.posY > self.target.posY:
                        self.direction = "Up"
                    elif board.spaces[self.posX][self.posY + 1] == EMPTY_SPACE\
                    and self.posY <= self.target.posY:
                        self.direction = "Down"
                    elif board.spaces[self.posX - 1][self.posY] == EMPTY_SPACE:
                        self.direction = "Right"

            # If the target food is to the right.
            else:
                # Make sure the opponent isn't about to run into a barrier.
                if board.spaces[self.posX + 1][self.posY] != COBRA1_SPACE and\
                   board.spaces[self.posX + 1][self.posY] != COBRA2_SPACE:
                    # If the opponent would turn back on itself, it needs to move up or down before going right.
                    if self.direction == "Left":
                        if self.posY > self.target.posY:
                            self.direction = "Up"
                        else:
                            self.direction = "Down"
                    else:
                        self.direction = "Right"
                # If there is an obstacle, look for an empty spot to move to.
                else:
                    if board.spaces[self.posX][self.posY - 1] == EMPTY_SPACE\
                    and self.posY > self.target.posY:
                        self.direction = "Up"
                    elif board.spaces[self.posX][self.posY + 1] == EMPTY_SPACE\
                    and self.posY <= self.target.posY:
                        self.direction = "Down"
                    elif board.spaces[self.posX - 1][self.posY] == EMPTY_SPACE:
                        self.direction = "Left"
        else:

            # If the target food is up.
            if self.posY > self.target.posY:
                # Make sure the opponent isn't about to run into itself or the player.
                if board.spaces[self.posX][self.posY - 1] != COBRA1_SPACE and\
                   board.spaces[self.posX][self.posY - 1] != COBRA2_SPACE:
                    # If the opponent would turn back on itself, it needs to move left or right before going up.
                    if self.direction == "Down":
                        if self.posX > self.target.posX:
                            self.direction = "Left"
                        else:
                            self.direction = "Right"
                    else:
                        self.direction = "Up"
                # If there is an obstacle, look for an empty spot to move to.
                else:
                    if board.spaces[self.posX - 1][self.posY] == EMPTY_SPACE\
                    and self.posX > self.target.posX:
                        self.direction = "Left"
                    elif board.spaces[self.posX + 1][self.posY] == EMPTY_SPACE\
                    and self.posX <= self.target.posX:
                        self.direction = "Right"
                    elif board.spaces[self.posX][self.posY + 1] == EMPTY_SPACE:
                        self.direction = "Down"

            # If the target food is down.
            else:
                # Make sure the opponent isn't about to run into a barrier.
                if board.spaces[self.posX][self.posY + 1] != COBRA1_SPACE and\
                   board.spaces[self.posX][self.posY + 1] != COBRA2_SPACE:
                    # If the opponent would turn back on itself, it needs to move left or right before going down.
                    if self.direction == "Up":
                        if self.posX > self.target.posX:
                            self.direction = "Left"
                        else:
                            self.direction = "Right"
                    else:
                        self.direction = "Down"        
                # If there is an obstacle, look for an empty spot to move to.
                else:
                    if board.spaces[self.posX - 1][self.posY] == EMPTY_SPACE\
                    and self.posX > self.target.posX:
                        self.direction = "Left"
                    elif board.spaces[self.posX + 1][self.posY] == EMPTY_SPACE\
                    and self.posX <= self.target.posX:
                        self.direction = "Right"
                    elif board.spaces[self.posX][self.posY - 1] == EMPTY_SPACE:
                        self.direction = "Up"

def check_collision(board, cobra):
    if (cobra.posX < 0) or (cobra.posY < 0) or (cobra.posX > BOARD_SIZE_WIDTH - 1)\
    or (cobra.posY > BOARD_SIZE_HEIGHT - 1) or (board.spaces[cobra.posX][cobra.posY] == COBRA1_SPACE)\
    or (board.spaces[cobra.posX][cobra.posY] == COBRA2_SPACE):
        collision = True
    else:
        collision = False

    return collision

def update_segments(board, cobra):
    posX = cobra.posX
    posY = cobra.posY

    if board.spaces[posX][posY] == FOOD_SPACE:
        for i in range(0, cobra.segmentsToAdd):
            cobra.add_segment(cobra.Segment(posX, posY))
        # Defaults to first piece of food for now.  May have more than once piece on board at a time in the future.
        del board.foodList[0]
        board.amountOfFood -= 1
        if board.amountOfFood == 0:
            board.foodOnBoard = False

    for seg in cobra.segments:
        prevPosX = seg.posX
        prevPosY = seg.posY
        board.spaces[prevPosX][prevPosY] = EMPTY_SPACE
        seg.posX = posX
        seg.posY = posY
        board.spaces[seg.posX][seg.posY] = cobra.spaceType
        posX = prevPosX
        posY = prevPosY

def main():
    # Set board size, cobra starting position, create first cobra segment, and initialize display
    board1 = Board(BOARD_SIZE_WIDTH, BOARD_SIZE_HEIGHT, BOARD_SPACE_SIZE)
    cobra1 = Cobra(PLAYER1_START_X, PLAYER1_START_Y, COBRA_START_DIRECTION, COBRA1_SPACE)
    cobra2 = Opponent(OPPONENT_START_X, OPPONENT_START_Y, COBRA_START_DIRECTION, COBRA2_SPACE)
    cobra1.add_segment(Cobra.Segment(cobra1.posX, cobra1.posY))
    if OPPONENT_ON == True:
        cobra2.add_segment(Opponent.Segment(cobra2.posX, cobra2.posY))

    pygame.init()

    screen = pygame.display.set_mode((DISPLAY_RESOLUTION_WIDTH, DISPLAY_RESOLUTION_HEIGHT))

    gameRunning = True
    paused = False

    while gameRunning == True:

        events = pygame.event.get()
        for event in events:
            if event.type == pygame.QUIT:
                pygame.quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP:
                    cobra1.direction = "Up"
                if event.key == pygame.K_DOWN:
                    cobra1.direction = "Down"
                if event.key == pygame.K_LEFT:
                    cobra1.direction = "Left"
                if event.key == pygame.K_RIGHT:
                    cobra1.direction = "Right"
                if event.key == pygame.K_w:
                    cobra2.direction = "Up"
                if event.key == pygame.K_s:
                    cobra2.direction = "Down"
                if event.key == pygame.K_a:
                    cobra2.direction = "Left"
                if event.key == pygame.K_d:
                    cobra2.direction = "Right"
                if event.key == pygame.K_ESCAPE:
                    pygame.quit()
                if event.key == pygame.K_SPACE:
                    if not paused:
                        paused = True
                    else:
                        paused = False

        if not paused:
            update_segments(board1, cobra1)
            if OPPONENT_ON == True:
                update_segments(board1, cobra2)
            board1.draw_board(screen)
            pygame.display.update()

            if not board1.foodOnBoard:
                board1.create_food()

            cobra1.move()

            if OPPONENT_ON == True:
                cobra2.check_target(board1)
                if cobra2.target.index == -1 and board1.foodOnBoard == True:
                    if cobra2.turnsToWait == 0:
                        cobra2.get_food_target(board1)
                        cobra2.turnsToWait = OPPONENT_TURNS_TO_WAIT
                    else:
                        cobra2.turnsToWait -= 1
                cobra2.set_direction(board1)

                cobra2.move()
                cobra2.collision = check_collision(board1, cobra2)

            cobra1.collision = check_collision(board1, cobra1)

            if cobra1.collision == True or cobra2.collision == True:
                gameRunning = False

            pygame.time.wait(MOVEMENT_DELAY)

main()
...