我创建了一个蛇游戏并安装了 NEAT 算法,但存在问题

人工智能 神经网络 Python 整洁的
2021-10-31 11:10:44

下面是我的输入输出和适应度函数。蛇的学习速度很慢,而且似乎停滞不前,另外当蛇与食物碰撞时,它会从基因组中删除,这没有任何意义,因为碰撞中没有指定。任何投入将不胜感激

for x, s in enumerate(snakes):
        # inserting new snake head and deleting the tale for movement

        # inputs
        s.x = s.snake_head[0]
        s.y = s.snake_head[1]
        snakeheadBottomDis = win_h - s.y
        snakeheadRightDis = win_w - s.x
        snake_length = len(s.snake_position)
        snakefoodDistEuclidean = math.sqrt((s.x - food.x) ** 2 + (s.y - food.y) ** 2)
        snakefoodDisManhattan = abs(s.x - food.x) + abs(s.y - food.y)
        xdis = s.Xdis()
        ydis = s.Ydis()
        s.dis_list1.append(snakefoodDistEuclidean)
        s.dis_list2.append(snakefoodDisManhattan)
        s.dis_list3.append(s.Xdis())
        s.dis_list4.append(s.Ydis())
        s.hunger_list.append(s.hunger)
        #print('Euclidean: ', dis_list1[-1])
        #print('Manhattan: ', dis_list2[-1])
        #print('X distance from Wall: ', dis_list3[-1])
        #print('Y distance from Wall: ', dis_list4[-1])

        output = nets[snakes.index(s)].activate((s.hunger, s.x, s.y, food.x, food.y, snakeheadBottomDis,
                                                 snakeheadRightDis, snake_length, xdis,ydis,
                                                 snakefoodDisManhattan, snakefoodDistEuclidean,s.dis_list1[-1],s.dis_list1[-2],
                                                 s.dis_list2[-1],s.dis_list2[-2],s.dis_list3[-1],s.dis_list3[-2],
                                                 s.dis_list4[-1],s.dis_list4[-2],s.hunger_list[-1],s.hunger_list[-2]))


        #snake moving animation
        s.snake_position.insert(0, list(s.snake_head))
        s.snake_position.pop()
        s.hunger -= 1

        # Checking distance Euclidean and Manhattan current and last
        if s.dis_list1[-1] > s.dis_list1[-2]:
            ge[x].fitness -= 1

        if s.dis_list1[-1] < s.dis_list1[-2]:
            ge[x].fitness += 0.5

        if s.dis_list1[-1] > s.dis_list2[-2]:
            ge[x].fitness -= 1

        if s.dis_list1[-1] < s.dis_list2[-2]:
            ge[x].fitness += 0.5

        #checking hunger number and if its decreasing
        if s.hunger_list[-1] < s.hunger_list[-2]:
            ge[x].fitness -= 0.1

        # move right
        if output[0] >= 0 and output[1] < 0 and output[2] < 0 and output[
            3] < 0:
            #and s.x < win_w - s.width and s.y > 0 + s.height:
            # ge[x].fitness += 0.5
            s.move_right()

        # move left
        if output[1] >= 0 and output[0] < 0 and output[2] < 0 and output[
            3] < 0:
            #and s.x < 500 - s.width and s.y > 0 + s.height:
            #ge[x].fitness += 0.5
            s.move_left()

        # move down
        if output[2] >= 0 and output[1] < 0 and output[0] < 0 and output[
            3] < 0:
            #and s.x < 500 - s.width and s.y > 0 + s.height:
            # ge[x].fitness += 0.5
            s.move_down()

        # move up
        if output[3] >= 0 and output[1] < 0 and output[2] < 0 and output[
            3] < 0:
            #and s.x < 500 - s.width and s.y > 0 + s.height:
            # ge[x].fitness += 0.5
            s.move_up()

        #adding more fitness if axis aligns
        if s.snake_head[0] == food.x:
            ge[x].fitness += 0.1
        if s.snake_head[1] == food.x:
            ge[x].fitness += 0.1

        # checking the activation function tanh
        # print ('output 0: ', output[0])
        # print('output 1: ', output[1])
        # print ('output 2: ', output[1])
        # print ('output 3: ', output[1])

        # snake poping on other side of screen if screen limit reached
        if s.snake_head[0] >= win_w - s.width:
            s.snake_head[0] = 12
        if s.snake_head[0] <= 11 + s.width:
            s.snake_head[0] = win_w - s.width - 1
        if s.snake_head[1] >= win_h - s.height:
            s.snake_head[1] = s.height + 15
        if s.snake_head[1] <= 11 + s.height:
            s.snake_head[1] = win_h - s.height - 1

        head = s.snake_position[0]
        #s.x < 0 + s.width or s.x > win_w - s.width or s.y < 0 + s.height or \
                #s.y > win_h - s.height or

        #if run into self you die
        if head in s.snake_position[1:]:
            ge[x].fitness -= 10
            snakes.pop(x)
            nets.pop(x)
            ge.pop(x)

        #if hunger reaches 0 you die
        if s.hunger == 0:
            ge[x].fitness -= 5
            snakes.pop(x)
            nets.pop(x)
            ge.pop(x)

        #if snake collides with food award fitness
        if s.getRec().colliderect(food.getRec()):
            ge[x].fitness += 100
            s.hunger = 100
            score += 1
            s.snake_position.insert(0, list(s.snake_head))
            food.y = random.randint(0 + 24, 500 - 24)
            food.x = random.randint(0 + 24, 500 - 24)

    # print(s.hunger)
1个回答

首先,实现像 NEAT 一样好的遗传算法的关键是适应度。现在健身就是一切,它基本上告诉你的蛇会学到什么。如果你的健身功能不好,你的 AI 会瞄准错误的目标。当蛇与食物对齐时,您不应该健身,因为那不是您想要的。你真正想让你的蛇做的是吃食物。

So, I suggest you to try giving fitness only when your snake is eating food, and maybe remove some as time passes (because of hunger). Your fitness could even be just the time a snake survived, since to survive your snakes have to eat, and avoid touching themselves! Definitely try this: just giving fitness as time passes!

其次,你必须为你的 AI 提供良好的输入,以便他们有足够的环境信息来优化他们的策略。我建议您尝试与蛇的位置和方向相关的输入。蛇和食物的 X 和 Y 位置是不好的输入,因为它们与蛇无关,它们与游戏的起源有关。因此,蛇的位置每秒钟都在变化,这可能会导致一些分心。

The snake doesn't need to know his position, he just need to know the distance between him and the food, and the angle between the direction of the snake (him) and the food.

最后,您可以查看您的输出。但这是一个小问题,你绝对应该关注你的蛇的健康状况。但是,如果您想更深入,请尝试使用两个输出而不是四个输出:速度和转弯速度。这样,你的蛇就很容易直行。当一条蛇想要用左、右、上、下输出前进时,这要困难得多。