2

i have this simple game where there is a ball bouncing on the screen and the player can move left and right of the screen and shoot an arrow up to pop the ball, every time the player hits a ball, the ball bursts and splits into two smaller balls until they reach a minimum size and disappear. I am trying to solve this game with a genetic algorithm based on the python neat library and on this tutorial on flappy bird https://www.youtube.com/watch?v=MMxFDaIOHsE&list=PLzMcBGfZo4-lwGZWXz5Qgta_YNX3_vLS2, so I have a configuration file in which I have to specify how many input nodes must be in the network, I had thought to give as input the player's x coordinate, the distance between the player's x-coordinate and the ball's x-coordinate and the distance between the player's y-coordinate and the ball's y-coordinate.

My problem is that at the beginning of the game I have only one ball but after a few moves I could have more balls in the screen so I should have a greater number of input nodes,the more balls there are on the screen the more input coordinates I have to provide to the network.

So how to set the number of input nodes in a variable way?enter image description here

config-feedforward.txt file

"""
# network parameters
num_hidden              = 0
num_inputs              = 3 #this needs to be variable
num_outputs             = 3
"""

python file

    for index,player in enumerate(game.players):
        balls_array_x = []
        balls_array_y = []

        for ball in game.balls:
            balls_array_x.append(ball.x)
            balls_array_x.append(ball.y)




        output = np.argmax(nets[index].activate(("there may be a number of variable arguments here")))


        #other...

final code

for index,player in enumerate(game.players):
    balls_array_x = []
    balls_array_y = []

    for ball in game.balls:
        balls_array_x.append(ball.x)
        balls_array_y.append(ball.y)

  
    distance_list = []
    player_x = player.x
    player_y = player.y
    
    i = 0

    while i < len(balls_array_x):
        dist = math.sqrt((balls_array_x[i] - player_x) ** 2 + (balls_array_y[i] - player_y) ** 2)
        distance_list.append(dist)
        i+=1

    i = 0

    if len(distance_list) > 0:
        nearest_ball = min(distance_list)

        output = np.argmax(nets[index].activate((player.x,player.y,nearest_ball)))

1 Answer 1

3

This is a good question and as far as I can tell from a quick Google search hasn't been addressed for simple ML algorithms like NEAT.

Traditionally resizing methods of Deep NN (padding, cropping, RNNs, middle-layers, etc) can obviously not be applied here since NEAT explicitly encodes each single neuron and connection.

I am also not aware of any general method/trick to make the input size mutable for the traditional NEAT algorithm and frankly don't think there is one. Though I can think of a couple of changes to the algorithm that would make this possible, but that's of no help to you I suppose.


In my opinion you therefore have 3 options:

  • You increase the input size to the maximum number of balls the algorithm should track and set the x-diff/y-diff value of non-existent balls to an otherwise impossible number (e.g. -1). If balls come into existence you actually set the values for those x-diff/y-diff input neurons and set them to -1 again when they are gone. Then you let NEAT figure it out. Also worth thinking about concatenating 2 separate NEAT NNs, with the first NN having 2 inputs, 1 output and the second NN having 1 (player pos) + x (max number of balls) inputs and 2 outputs (left, right). The first NN produces an output for each ball position (and is identical for each ball) and the second NN takes the first NNs output and turns it into an action. Also: The maximum number of balls doesn't have to be the maximum number of displayable balls, but can also be limited to 10 and only considering the 10 closest balls.

  • You only consider 1 ball for each action side (making your input 1 + 2*2). This could be the consideration of the lowest ball on each side or the closest ball on each side. Such preprocessing can make such simple NN tasks however quite easy to solve. Maybe you can add inertia into your test environment and thereby add a non-linearity that makes it not so straightforward to always teleport/hurry to the lowest ball.

  • You input the whole observation space into NEAT (or a uniformly downsampled fraction), e.g. the whole game at whatever resolution is lowest but still sensible. I know that this observation space is huge, but NEAT works quite well in handling such spaces.


I know that this is not the variable input size option of NEAT that you might have hoped for, but I don't know about any such general option/trick without changing the underlying NEAT algorithm significantly.

However, I am very happy to be corrected if someone knows a better option!

Sign up to request clarification or add additional context in comments.

1 Comment

thank you very much for your clarifications and explanations, also I thought it was not possible to declare a variable number of input nodes so in the end I decided to calculate the distance from the player to each ball, take the minimum distance and declare as input nodes the player's coordinates and the distance to the nearest ball. If it helps someone I put the code in the question

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.