Skip to content

Commit f01150f

Browse files
authored
more improvements to the genetic algorithm
1 parent 9acd5b6 commit f01150f

5 files changed

Lines changed: 35 additions & 24 deletions

File tree

Classes/genetic.gd

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ extends Reference
44

55
# Adjustable parameters
66
const CROSSOVER_EXTENT = 0.5 # 1 (means only parent 1) to 0 (means only parent 1)
7-
const MAX_CROSSOVER_SPLITS: int = 2 # the max amount of splits a network can have
7+
const MAX_CROSSOVER_SPLITS: int = 1 # the max amount of splits a network can have
88

9-
const MUTATION_DEGREE = 0.5 # 1 (means full mutation) to 0 (no mutation)
10-
const PERCENTAGE_MUTATION = 0.9 # 0 to 1 (how much mutatated elements in next generation)
9+
const MUTATION_DEGREE = 0.1 # 1 (means full mutation) to 0 (no mutation)
10+
const PERCENTAGE_MUTATION = 0.5 # 0 to 1 (how much mutatated elements in next generation)
1111

1212
var current_generation: int = -1
1313
var players_per_generation: int = 50
@@ -64,6 +64,7 @@ func prepere_next_generation() -> Array:
6464
_last_winners_b = winner_2
6565

6666
var next_gen_networks = []
67+
var _added_biases = [] # to check if a network already exists
6768
for i in range(players_per_generation):
6869
var new_network: Network
6970
if i < 1: # keep 1 best from the last generation
@@ -72,8 +73,12 @@ func prepere_next_generation() -> Array:
7273
# Make a crossover
7374
new_network = _crossover(winner_1, winner_2)
7475
var can_mutate = randf()
75-
if can_mutate > PERCENTAGE_MUTATION: # If we need mutation not crossover
76+
if (
77+
(can_mutate < PERCENTAGE_MUTATION) # If we need mutation not crossover
78+
or (new_network.biases in _added_biases) # If we the crossover already exist
79+
):
7680
new_network = _mutate(winner_1)
81+
_added_biases.append(new_network.biases)
7782
next_gen_networks.append(new_network)
7883
return next_gen_networks
7984

@@ -83,6 +88,7 @@ func _crossover(parent_1: Network, parent_2: Network = null) -> Network:
8388
var new_network: Network = Network.new(parent_1.sizes)
8489
new_network.biases = parent_1.biases.duplicate(true)
8590
new_network.weights = parent_1.weights.duplicate(true)
91+
8692
_random.randomize()
8793
if parent_2 == null:
8894
return new_network
@@ -104,7 +110,7 @@ func _mutate(net: Network) -> Network:
104110
var new_network: Network = Network.new(net.sizes)
105111
for i in new_network.biases.size():
106112
var value = _random.randf()
107-
if value > MUTATION_DEGREE: # don't mutate this layer's biases/weights
113+
if value < MUTATION_DEGREE: # don't mutate this layer's biases/weights
108114
new_network.biases[i] = net.biases[i].duplicate(true)
109115
new_network.weights[i] = net.weights[i].duplicate(true)
110116
return new_network

Examples/FlappyTest/AI/FlappyBird.gd

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
extends KinematicBody2D
22

3-
var sizes = [2, 16, 4, 1] # nodes in the respective layers
3+
var sizes = [2, 10, 10, 10, 1] # nodes in the respective layers
44
var net: Network
55

66
var jump_vel = 250
@@ -11,6 +11,8 @@ var initial_time: float
1111

1212
var modulation: Color
1313

14+
var visualizer
15+
1416
func jump():
1517
$JumpRecoil.start()
1618
velocity.y = -jump_vel
@@ -46,17 +48,12 @@ func _process(_delta: float) -> void:
4648

4749
func _on_Area2D_area_entered(area: Area2D) -> void:
4850
if area.is_in_group("obstacle"):
49-
###### remove Visualizer #####
50-
var idx = get_index()
51-
var visualizer_container = AiMonitor.visualizer_popup.visualizer_container
52-
var visualizer: PanelContainer = visualizer_container.get_child(idx)
53-
if visualizer:
54-
visualizer.queue_free()
55-
##############################
5651
queue_free()
5752

5853

5954
func _exit_tree() -> void:
55+
########### remove Visualizer ############
56+
visualizer.queue_free()
6057
############ Grant a reward ###############
6158
net.reward = Time.get_ticks_msec() - initial_time
6259
# Add to the monitor

Examples/FlappyTest/FlappyTest.gd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ func _ready() -> void:
2424

2525
var network_visualizer = preload("res://NetworkVisualizer/NetworkVisualizer.tscn").instance()
2626
AiMonitor.visualizer_popup.visualizer_container.add_child(network_visualizer)
27+
player.visualizer = network_visualizer
2728
network_visualizer.identifier.color = player.modulation
2829
network_visualizer.visualize_network(player.net)
2930

Examples/FlappyTest/obstacle/Obstacle.tscn

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ script = ExtResource( 1 )
1111

1212
[node name="Sprite" type="Sprite" parent="."]
1313
position = Vector2( 0, 79 )
14-
scale = Vector2( 2.765, 21.7812 )
14+
scale = Vector2( 0.641, 21.7812 )
1515
texture = ExtResource( 2 )
1616
centered = false
1717
__meta__ = {
@@ -26,7 +26,7 @@ shape = SubResource( 1 )
2626

2727
[node name="Sprite2" type="Sprite" parent="."]
2828
position = Vector2( 0, -1231 )
29-
scale = Vector2( 2.765, 18.0937 )
29+
scale = Vector2( 0.641, 18.0937 )
3030
texture = ExtResource( 2 )
3131
centered = false
3232
__meta__ = {

NetworkVisualizer/NetworkVisualizer.gd

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const LINE_COLOR_NEGATIVE = Color.blueviolet
77

88
const ACTIVATION_COLOR_POSITIVE = Color.white
99
const ACTIVATION_COLOR_INACTIVE = Color.black
10-
const ACTIVATION_COLOR_NEGATIVE = Color.blue
10+
const ACTIVATION_COLOR_NEGATIVE = Color.blue # would appear in 1st layer
1111

1212
var lines = []
1313

@@ -17,28 +17,32 @@ onready var identifier: ColorRect = $"%identifier"
1717

1818
func visualize_network(network: Network) -> void:
1919
# generate a framework
20+
var sep = 0
21+
for i in network.sizes:
22+
if i > sep:
23+
sep = i
24+
layer_container.set("custom_constants/separation", max(10, sep * 2))
2025
for x in network.sizes.size():
2126
var layer = _generate_layer()
2227
for _y in range(network.sizes[x]):
2328
_generate_node(layer)
2429
# now set weights
2530
yield(get_tree(), "idle_frame")
26-
lines = update_weights(network)
31+
update_weights(network)
2732
# warning-ignore:return_value_discarded
2833
network.connect("activation_changed", self, "_update_activations")
29-
update()
3034

3135

3236
func update_weights(network: Network):
33-
var lines_array = []
37+
lines.clear()
3438
for layer_number in network.weights.size():
3539
for current_node_idx in network.weights[layer_number].size():
3640
for prev_node_idx in network.weights[layer_number][current_node_idx].size():
3741
var from = get_activation_node(layer_number, prev_node_idx)
3842
var to = get_activation_node(layer_number + 1, current_node_idx)
3943
var weight = network.weights[layer_number][current_node_idx][prev_node_idx]
40-
lines_array.append([from, to, weight])
41-
return lines_array
44+
lines.append([from, to, weight])
45+
update()
4246

4347

4448
func get_activation_node(layer_idx, node_idx) -> TextureRect:
@@ -53,10 +57,13 @@ func _update_activations(layer_idx, activations: Array):
5357
var color = ACTIVATION_COLOR_POSITIVE
5458
if activation < 0:
5559
color = ACTIVATION_COLOR_NEGATIVE
56-
color.a = abs(activation)
57-
if activation == 0:
60+
if is_equal_approx(activation, 0):
5861
color = ACTIVATION_COLOR_INACTIVE
62+
else:
63+
color.a = abs(activation)
64+
5965
layer.get_child(node_idx).modulate = color
66+
update()
6067

6168

6269
func _generate_layer() -> Node:
@@ -79,4 +86,4 @@ func _draw() -> void:
7986
var color := LINE_COLOR_POSITIVE
8087
if line[2] < 0:
8188
color = LINE_COLOR_NEGATIVE
82-
draw_line(start, end, color, abs(line[2]) * SCALE)
89+
draw_line(start, end, color, abs(line[2]) * SCALE * 2)

0 commit comments

Comments
 (0)