2
$\begingroup$

Below are my Inputs Outputs and fitness function. The snake is learning at a slow rate, and seems to be stagnant, additionally when the snake collides with the food, it gets deleted from the genome, which doesn't make any sense because that's not specified in the collision. Any input would be greatly appreciated

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)
$\endgroup$
0
$\begingroup$

Firstly, the key of implementing a good genetic algorithm like the NEAT one is fitness. Now fitness is everything, it tells basically what your snakes will learn. If you have a bad fitness function, your AIs will target the wrong goal. You shouldn't give fitness when a snake is aligning with food, because that's not what you want. What you really want your snake to do is eating food.

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!

Secondly, you have to give good inputs to your AIs, so that they have enough information about their environment to optimize their strategy. I suggest you to try inputs that are relative to your snake's position, and direction. X and Y position of the snake and the food are bad inputs, because they're not relative to the snake, they're relative to the origin of your game. So, every second the position of the snake is changing, and this could lead to some distraction.

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.

Lastly, you may review your outputs. But this is a minor problem, you should definitely focus on the fitness of your snakes. But, if you want to go deeper, try having two outputs instead of four: speed, and turning velocity. That way, it's easy for your snakes to go straight forward. When a snake wants to go forward with left, right, up, down outputs, it's way harder.

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.