def reset(self): """ Reset the spaceship """ self.dead = False self.pos = Vector2(d.SCREEN_SIZE / 2, d.SCREEN_SIZE / 2) self.velocity = Vector2() self.angular_vel = 0 self.rotation = 0
def get_wall_collision(self): """ Find intersection point with the wall """ self.inters = None # Check collision with inner wall for i in range(len(d.WALL_IN)): if self.inters == None: j = 0 if len(d.WALL_IN) - 1 == i else i + 1 w_p1 = d.WALL_I_EXT[i] w_p2 = d.WALL_I_EXT[j] p1 = Vector2(w_p1[0], w_p1[1]) p2 = Vector2(w_p2[0], w_p2[1]) s = Algs.get_segment_inters( p1, p2, self.pos, self.pos + self.dir * d.SENSOR_LENGTH) self.inters = s # Check collision with outer wall for i in range(len(d.WALL_O_EXT) - 1): if self.inters == None: if i == len(d.WALL_IN) - 1: j = 0 else: j = i + 1 w_p1 = d.WALL_O_EXT[i] w_p2 = d.WALL_O_EXT[j] p1 = Vector2(w_p1[0], w_p1[1]) p2 = Vector2(w_p2[0], w_p2[1]) s = Algs.get_segment_inters( p1, p2, self.pos, self.pos + self.dir * d.SENSOR_LENGTH) self.inters = s
def __init__(self, neural_net): self.pos = Vector2(d.SCREEN_SIZE / 2, d.SCREEN_SIZE / 2) self.points = [Vector2()] * 3 # Shape points of the player (triangle) self.dir = Vector2(0, -1) # Direction in which the ship moves self.rotation = 0 # Rotation of the ship (radians) self.dead = False # Inputs fed to the neural network: # If sensor mode: the length of each sensor # Else: the distance vectors to the closest asteroids self.inputs = [] * d.INPUT_COUNT if d.sensor_mode: # Configure the ship's sensors self.sensors = [] self.setup_sensors() else: # Indices of the asteroids closest to the player # of 'data.asteroids' list self.ast_idx = [0] * d.CLOSEST_AST_COUNT self.neural_net = neural_net self.start_time = pg.time.get_ticks() self.speed = d.SPEED self.color = d.NEON_BLUE
def spawn(self, edge): """ Spawn the asteroid at the given edge """ s = d.SCREEN_SIZE rd = random.uniform(0, s) # Get the position if edge == 1: self.pos.x = rd self.pos.y = 0 self.dir = Vector2(0, 1) elif edge == 2: self.pos.x = s self.pos.y = rd self.dir = Vector2(-1, 0) elif edge == 3: self.pos.x = rd self.pos.y = s self.dir = Vector2(0, -1) else: self.pos.x = 0 self.pos.y = rd self.dir = Vector2(1, 0) # Choose random direction (towards the center direction) self.dir.rotate(random.uniform(-math.pi/2, math.pi/2), Vector2())
def __init__(self, angle): self.angle = angle self.dir = Vector2() self.pos = Vector2() self.end_pos = Vector2() self.car_dir = Vector2() self.inters = None self.length = d.SENSOR_LENGTH
def __init__(self, angle): self.angle = angle # In degrees self.dir = Vector2() self.pos = Vector2() # Start position (= Ship position) self.end_pos = Vector2() # End of the sensor self.ship_dir = Vector2() self.inters = None # Intersection point self.dist = d.SENSOR_LENGTH # Length of the sensor
def __init__(self, spawn_edge): self.dir = Vector2(0, 1) self.pos = Vector2() self.rad = random.randint(d.AST_MIN_SIZE, d.AST_MAX_SIZE) self.speed = random.uniform(d.AST_MIN_SPD, d.AST_MAX_SPD) self.dead = False self.color = d.WHITE self.spawn(spawn_edge)
def check_checkpoint_col(self): """ Check whether the car collects a checkpoint """ # First point of the first active checkpoint p1 = Vector2(d.active_checkp[0][0][0], d.active_checkp[0][0][1]) # Second point of the first active checkpoint p2 = Vector2(d.active_checkp[0][1][0], d.active_checkp[0][1][1]) if self.check_col(p1, p2): # Check for collision with the checkpoint d.active_checkp.pop(0) d.best_car = self if len(d.active_checkp) == 0: self.restart_simulation()
def __init__(self, net=None): self.position = Vector2(d.START_POSITION[0], d.START_POSITION[1]) self.rotation = 0 self.direction = Vector2(1, 0) self.direction_normal = Vector2(0, 1) self.frame = [Vector2()] * 4 self.sensors = [ Sensor((180 / (d.SENSOR_COUNT - 1)) * i - 90) for i in range(d.SENSOR_COUNT) ] self.dead = False self.turn = 0.5 if net == None: self.neural_net = NeuralNetWork(d.SENSOR_COUNT, d.HIDDEN_LAYERS, 1) else: self.neural_net = net
def forward_prop(self, inputs): """ Calculate output from given inputs through the neural network """ layers = [inputs] for i in range(len(self.h_layers)+1): # Calculate the input * weights + bias z = np.dot(layers[i], self.weights[i]) + self.biases[i] # Apply activation function out = [] if d.sensor_mode: # Outputs are numbers for j in range(len(z)): o = sigmoid(clamp(-20, 20, z[j])) out.append(o) else: # Output are vectors for j in range(len(z)): sigm_x = sigmoid(clamp(-20, 20, z[j].x)) sigm_y = sigmoid(clamp(-20, 20, z[j].y)) out.append(Vector2(sigm_x, sigm_y)) layers.append(out) # Return the output final_output = layers[len(layers)-1][0] # Last layer only has 1 output neuron return final_output
def check_wall_col(self): """ Check whether the car collides with a wall """ # Check collision with inner wall for i in range(len(d.WALL_I_EXT) - 1): w_p1 = d.WALL_I_EXT[i] w_p2 = d.WALL_I_EXT[i + 1] p1 = Vector2(w_p1[0], w_p1[1]) p2 = Vector2(w_p2[0], w_p2[1]) if self.check_col(p1, p2): self.die() # Check collision with outer wall for i in range(len(d.WALL_O_EXT) - 1): w_p1 = d.WALL_O_EXT[i] w_p2 = d.WALL_O_EXT[i + 1] p1 = Vector2(w_p1[0], w_p1[1]) p2 = Vector2(w_p2[0], w_p2[1]) if self.check_col(p1, p2): self.die()
def setup_biases(self): """ Set every bias to random value between -1 and 1 """ # There is a bias for every hidden layer and for the input layer self.biases = [] for _ in range(len(self.h_layers) + 1): rd = random.uniform(-1, 1) # Floats as inputs --> bias must be number as well if d.sensor_mode: self.biases.append(rd) # Vectors as inputs --> bias must be vector as well else: self.biases.append(Vector2(rd, rd))
def turn(self, out): """ Control the spaceship's direction through neural network output or key input """ if not d.solo: if d.sensor_mode: angle = out - 0.5 angle *= d.TURN_SPEED self.rotation -= angle self.dir.rotate(-angle, Vector2()) else: # x and y are between (0, 1) --> (-0.5, 0.5) out.x -= 0.5 out.y -= 0.5 out = out.normalized() # Turn the spaceship by changing its direction r = self.dir + out self.dir = (self.dir + r.normalized() * d.TURN_SPEED).normalized() else: angle = out - 0.5 angle *= 0.2 self.rotation -= angle self.dir.rotate(-angle, Vector2())
def update_inputs(self): """ Update the ship's inputs used for the neural network """ self.inputs = [] if d.sensor_mode: # Inputs are the distances of the sensors for sensor in self.sensors: input = sensor.dist / d.SENSOR_LENGTH # Scale the inputs between 0 and 1 self.inputs.append(input) else: # Inputs are the distance vectors of the closest asteroids for index in self.ast_idx: a_p = d.asteroids[index].pos - self.pos n = a_p.normalized() dist = [] d1 = a_p # Find all the possible distances to the spaceship for the current asteroid # For example when the player is far right and the asteroid far left, # the player is still close to the asteroid (through the screen) dist.append(d1 - n * (d.asteroids[index].rad + d.PLAYER_H)) dist.append((d1 - Vector2(d.SCREEN_SIZE, 0)) - n * (d.asteroids[index].rad + d.PLAYER_H)) dist.append((d1 + Vector2(d.SCREEN_SIZE, 0)) - n * (d.asteroids[index].rad + d.PLAYER_H)) dist.append((d1 - Vector2(0, d.SCREEN_SIZE)) - n * (d.asteroids[index].rad + d.PLAYER_H)) dist.append((d1 + Vector2(0, d.SCREEN_SIZE)) - n * (d.asteroids[index].rad + d.PLAYER_H)) dist.append((d1 - Vector2(d.SCREEN_SIZE, d.SCREEN_SIZE)) - n * (d.asteroids[index].rad + d.PLAYER_H)) dist.append((d1 + Vector2(d.SCREEN_SIZE, d.SCREEN_SIZE)) - n * (d.asteroids[index].rad + d.PLAYER_H)) dist.append((d1 - Vector2(-d.SCREEN_SIZE, d.SCREEN_SIZE)) - n * (d.asteroids[index].rad + d.PLAYER_H)) dist.append((d1 + Vector2(-d.SCREEN_SIZE, d.SCREEN_SIZE)) - n * (d.asteroids[index].rad + d.PLAYER_H)) # Take the smallest distance m = Algs.v2_min(dist) m.x = m.x m.y = m.y self.inputs.append(m)
def mutate(net, strong): """ Mutate a neural network\n Parameters: \n \tnet = the neural net to mutate \tstrong = whether or not the mutation should be strong""" b = net.biases w = net.weights """ weights """ w_new = net.weights for _ in range(d.MUTATED_WEIGHTS_COUNT): # Find a random weight layer_i = random.randint(0, len(w) - 1) input_i = random.randint(0, len(w[layer_i]) - 1) weigth_i = random.randint(0, len(w[layer_i][input_i]) - 1) _w = w[layer_i][input_i][weigth_i] # How strong should the weight be mutated if (strong): mut_strength = d.MUTATION_STRENGTH_HIGH else: mut_strength = d.MUTATION_STRENGTH_LOW # Mutate the weight (weights are always clamped between -1 and 1) rd = random.uniform(-mut_strength, mut_strength) w_new[layer_i][input_i][weigth_i] = clamp(-1, 1, _w + rd * _w) net.weights = w_new """ biases """ # Find a random bias index = random.randint(0, len(b) - 1) # How strong should the bias be mutated rd = random.uniform(-mut_strength, mut_strength) # Mutate the bias if d.sensor_mode: # Bias is a number b[index] += rd else: # Bias is a vector b[index] += Vector2(rd, rd) net.biases = b return net