Answers.Body: <p>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.</p>
  
  <p><code>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!</code></p>
  
  <p>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.</p>
  
  <p><code>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.</code></p>
  
  <p>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.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-04-04T02:30:51.477Z
Answers.LastActivityDate: 2020-04-04T02:30:51.477Z
Answers.UserDisplayName: Dara Kong
Body: <p>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</p>
  
  <pre><code>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] &gt; s.dis_list1[-2]:
              ge[x].fitness -= 1
  
          if s.dis_list1[-1] &lt; s.dis_list1[-2]:
              ge[x].fitness += 0.5
  
          if s.dis_list1[-1] &gt; s.dis_list2[-2]:
              ge[x].fitness -= 1
  
          if s.dis_list1[-1] &lt; s.dis_list2[-2]:
              ge[x].fitness += 0.5
  
          #checking hunger number and if its decreasing
          if s.hunger_list[-1] &lt; s.hunger_list[-2]:
              ge[x].fitness -= 0.1
  
          # move right
          if output[0] &gt;= 0 and output[1] &lt; 0 and output[2] &lt; 0 and output[
              3] &lt; 0:
              #and s.x &lt; win_w - s.width and s.y &gt; 0 + s.height:
              # ge[x].fitness += 0.5
              s.move_right()
  
          # move left
          if output[1] &gt;= 0 and output[0] &lt; 0 and output[2] &lt; 0 and output[
              3] &lt; 0:
              #and s.x &lt; 500 - s.width and s.y &gt; 0 + s.height:
              #ge[x].fitness += 0.5
              s.move_left()
  
          # move down
          if output[2] &gt;= 0 and output[1] &lt; 0 and output[0] &lt; 0 and output[
              3] &lt; 0:
              #and s.x &lt; 500 - s.width and s.y &gt; 0 + s.height:
              # ge[x].fitness += 0.5
              s.move_down()
  
          # move up
          if output[3] &gt;= 0 and output[1] &lt; 0 and output[2] &lt; 0 and output[
              3] &lt; 0:
              #and s.x &lt; 500 - s.width and s.y &gt; 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] &gt;= win_w - s.width:
              s.snake_head[0] = 12
          if s.snake_head[0] &lt;= 11 + s.width:
              s.snake_head[0] = win_w - s.width - 1
          if s.snake_head[1] &gt;= win_h - s.height:
              s.snake_head[1] = s.height + 15
          if s.snake_head[1] &lt;= 11 + s.height:
              s.snake_head[1] = win_h - s.height - 1
  
          head = s.snake_position[0]
          #s.x &lt; 0 + s.width or s.x &gt; win_w - s.width or s.y &lt; 0 + s.height or \
                  #s.y &gt; 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)
  </code></pre>
  
Tags: <neural-networks><python><neat>
Title: I created a snake game and fitted the NEAT algorithm and there's issues
UserDisplayName: Vnix7
ThreadText: # I created a snake game and fitted the NEAT algorithm and there's issues
  
  (Asked by: username_0 on 2020-03-12)
  
  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)
  
  **Tags:** neural-networks, python, neat
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2020-04-04. Score: 1
  
  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.
  
  
  ---
  
  