Browse Source

Added detection of stalled evolutions

master
Ryan Reed 1 year ago
parent
commit
b7d46e2567
2 changed files with 78 additions and 5 deletions
  1. +62
    -5
      world.gd
  2. +16
    -0
      world.tscn

+ 62
- 5
world.gd View File

@ -27,25 +27,37 @@ enum CellStates {
@onready var generation_cell_size_y: LineEdit = $UI/WorldGeneration/VBoxContainer/CellSize/Input_y @onready var generation_cell_size_y: LineEdit = $UI/WorldGeneration/VBoxContainer/CellSize/Input_y
@onready var start_paused_button: CheckBox = $UI/WorldGeneration/VBoxContainer/FinalRow/StartPausedButton @onready var start_paused_button: CheckBox = $UI/WorldGeneration/VBoxContainer/FinalRow/StartPausedButton
@onready var messages_label: Label = $UI/Messages/Label
## Other ## Other
@onready var camera: Camera2D = $Camera2D @onready var camera: Camera2D = $Camera2D
@onready var generation_timer: Timer = $GenerationTimer @onready var generation_timer: Timer = $GenerationTimer
@export var world_seed: int
@export var cell_size: Vector2 = Vector2(16, 16)
@export var cell_texture: Texture2D
@export var world_size: Vector2 = Vector2(32, 32)
@export var world_seed: int ## The seed utilized for generation of the world
@export var cell_size: Vector2 = Vector2(16, 16) ## Size of each cell image
@export var cell_texture: Texture2D ## Testure for each cell
@export var world_size: Vector2 = Vector2(32, 32) ## The size of the world
@export var zoom_increment: Vector2 = Vector2(0.1, 0.1) @export var zoom_increment: Vector2 = Vector2(0.1, 0.1)
var cell_instance var cell_instance
var evolution_is_stalled: bool = false
var generation: int = 1 var generation: int = 1
var is_paused: int = false
var is_paused: bool = false
var total_living: int = 0 var total_living: int = 0
var cell_ids: Array = [] # Store cell RIDs var cell_ids: Array = [] # Store cell RIDs
var cell_states: Array = [] var cell_states: Array = []
var previous_generation_hashes: Array = [] # Store the generation related to the hashes
var previous_generation_count: int = 10 # Number of generations to check for evolution stalling
# Number of collisions to consider evolution stalled
# The higher the number, the less likely to catch oscillators
# Consider the previous_generation_count as this may need to increase for larger counts
# 4 Collisions out of 10 previous_generation_count seems reasonable although it may not be quite enough
var collision_count_limit: int = 4
func _ready() -> void: func _ready() -> void:
update_generation_ui() update_generation_ui()
@ -97,6 +109,7 @@ func start_conway() -> void:
generate_world() generate_world()
generation = 1 generation = 1
evolution_is_stalled = false
debug_world_seed.text = "World Seeed: %s" % world_seed debug_world_seed.text = "World Seeed: %s" % world_seed
debug_generation_counter.text = "Generation: %s" % generation debug_generation_counter.text = "Generation: %s" % generation
debug_living_cells_counter.text = "Living Cells: %s" % total_living debug_living_cells_counter.text = "Living Cells: %s" % total_living
@ -147,8 +160,32 @@ func count_living_neighbors(pos: Vector2) -> int:
count += 1 count += 1
return count return count
func end_world_generation() -> void:
# Determine which generation first stalled
var current_world_hash: int = cell_states.hash()
var colliding = previous_generation_hashes.filter(func(gen): return gen.hash == current_world_hash)
var stalled_generation = colliding[0].generation
messages_label.text = "Detected Stalled Evolution Starting at Generation %s" % stalled_generation
messages_label.visible = true
evolution_is_stalled = true
## Get the number of previous generation results that collide with the current hash
func get_colliding_hash_count(input_hash: int) -> int:
var count = 0
for gen in previous_generation_hashes:
count += int(gen.hash == input_hash)
return count
## Loop through world to generate cell states, hide/show cells depending on state ## Loop through world to generate cell states, hide/show cells depending on state
func process_generation() -> void: func process_generation() -> void:
if evolution_is_stalled: return
update_previous_generation_hashes()
if previous_generation_hashes[previous_generation_hashes.size()-1].collisions >= collision_count_limit:
return end_world_generation()
generation += 1 generation += 1
total_living = 0 total_living = 0
@ -167,6 +204,23 @@ func process_generation() -> void:
cell_states = new_states cell_states = new_states
## Update the previous run hash and generation ids
## We only store the last `previous_generation_count` number of results
func update_previous_generation_hashes() -> void:
if previous_generation_hashes.size() < previous_generation_count:
previous_generation_hashes.resize(previous_generation_count)
previous_generation_hashes.fill({"generation": 0, "hash": 0, "collisions": 0})
# Remove the oldest generation information
previous_generation_hashes.remove_at(0)
var generation_hash := cell_states.hash()
previous_generation_hashes.append({
"generation": generation,
"hash": generation_hash,
"collisions": get_colliding_hash_count(generation_hash),
})
## Toggle Pause UI and Start/Stop Generation Timer ## Toggle Pause UI and Start/Stop Generation Timer
func toggle_pause() -> void: func toggle_pause() -> void:
is_paused = !is_paused is_paused = !is_paused
@ -217,6 +271,8 @@ func generate_world() -> void:
cell_states[x][y] = is_alive cell_states[x][y] = is_alive
cell_ids[x][y] = create_cell(Vector2(x, y), bool(is_alive)) cell_ids[x][y] = create_cell(Vector2(x, y), bool(is_alive))
update_previous_generation_hashes()
func _on_generation_timer_timeout() -> void: func _on_generation_timer_timeout() -> void:
process_generation() process_generation()
@ -240,6 +296,7 @@ func _on_run_button_pressed() -> void:
debug_ui.visible = true debug_ui.visible = true
generation_ui.visible = false generation_ui.visible = false
background_ui.visible = false background_ui.visible = false
messages_label.visible = false
seed(world_seed) seed(world_seed)
start_conway() start_conway()


+ 16
- 0
world.tscn View File

@ -196,6 +196,22 @@ layout_direction = 3
layout_mode = 2 layout_mode = 2
text = "Quit" text = "Quit"
[node name="Messages" type="MarginContainer" parent="UI"]
anchors_preset = 7
anchor_left = 0.5
anchor_top = 1.0
anchor_right = 0.5
anchor_bottom = 1.0
offset_left = -20.0
offset_top = -40.0
offset_right = 20.0
grow_horizontal = 2
grow_vertical = 0
[node name="Label" type="Label" parent="UI/Messages"]
visible = false
layout_mode = 2
[connection signal="timeout" from="GenerationTimer" to="." method="_on_generation_timer_timeout"] [connection signal="timeout" from="GenerationTimer" to="." method="_on_generation_timer_timeout"]
[connection signal="pressed" from="UI/WorldGeneration/VBoxContainer/Seed/Generate" to="." method="_on_world_seed_generate_pressed"] [connection signal="pressed" from="UI/WorldGeneration/VBoxContainer/Seed/Generate" to="." method="_on_world_seed_generate_pressed"]
[connection signal="toggled" from="UI/WorldGeneration/VBoxContainer/FinalRow/StartPausedButton" to="." method="_on_start_paused_button_toggled"] [connection signal="toggled" from="UI/WorldGeneration/VBoxContainer/FinalRow/StartPausedButton" to="." method="_on_start_paused_button_toggled"]


Loading…
Cancel
Save