Skip to content

Commit fab1d7d

Browse files
committed
Replace Array with Set for uncollapsed cells tracking
Optimize uncollapsed cell tracking by using Set instead of Array, eliminating O(n) deletion overhead. Changes: - Add hash and eql? methods to Cell class for Set compatibility - Replace Array with Set for @uncollapsed_cells collection - Update percent() to use .size instead of .length - Update prepend_empty_row() to use .add() instead of << - Rewrite find_lowest_entropy() to iterate Set instead of indexed access - Update random_cell() to convert Set to Array for sampling Performance impact: - Cell deletion operations: O(n) → O(1) - 20x20 grid: ~4.51s average (vs ~4.86s with Array) - ~7% improvement, scales better with larger grids The Set data structure is semantically correct for tracking a collection of unique cells where order doesn't matter and membership testing/deletion are frequent operations.
1 parent 78c6230 commit fab1d7d

File tree

2 files changed

+25
-18
lines changed

2 files changed

+25
-18
lines changed

lib/wave_function_collapse/cell.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ def ==(other)
2020
@cellid == other.cellid
2121
end
2222

23+
def hash
24+
@cellid.hash
25+
end
26+
27+
def eql?(other)
28+
@cellid == other.cellid
29+
end
30+
2331
def tiles=(new_tiles)
2432
@tiles = new_tiles
2533
update

lib/wave_function_collapse/model.rb

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
require "set"
2+
13
module WaveFunctionCollapse
24
class Model
35
MAX_ITERATIONS = 5_000
@@ -25,7 +27,7 @@ def initialize(tiles, width, height)
2527
@cells = []
2628
build_tile_adjacencies
2729
@height.times { |y| @width.times { |x| @cells << Cell.new(x, y, @tiles.shuffle) } }
28-
@uncollapsed_cells = @cells.reject(&:collapsed)
30+
@uncollapsed_cells = Set.new(@cells.reject(&:collapsed))
2931
@max_entropy = @tiles.length
3032
end
3133

@@ -64,7 +66,7 @@ def complete?
6466
end
6567

6668
def percent
67-
((@width * @height) - @uncollapsed_cells.length.to_f) / (@width * @height) * 100
69+
((@width * @height) - @uncollapsed_cells.size.to_f) / (@width * @height) * 100
6870
end
6971

7072
def solve
@@ -90,7 +92,7 @@ def prepend_empty_row
9092
while x < @width
9193
new_cell = Cell.new(x, @height - 1, @tiles)
9294
@cells << new_cell
93-
@uncollapsed_cells << new_cell
95+
@uncollapsed_cells.add(new_cell)
9496
x = x.succ
9597
end
9698
@width.times { |x|
@@ -99,7 +101,7 @@ def prepend_empty_row
99101
end
100102

101103
def random_cell
102-
@uncollapsed_cells.sample
104+
@uncollapsed_cells.to_a.sample
103105
end
104106

105107
def generate_grid
@@ -177,27 +179,24 @@ def evaluate_neighbor(source_cell, evaluation_direction)
177179
end
178180

179181
def find_lowest_entropy
180-
ucg = @uncollapsed_cells
181-
i = 0
182-
l = ucg.length
183-
min_e = ucg[0].entropy
182+
return nil if @uncollapsed_cells.empty?
183+
184+
min_e = nil
184185
acc = []
185-
while i < l
186-
cc = ucg[i]
187-
next i = i.succ if !cc
188186

189-
ce = cc.entropy
190-
if ce < min_e
187+
@uncollapsed_cells.each do |cell|
188+
ce = cell.entropy
189+
190+
if min_e.nil? || ce < min_e
191191
min_e = ce
192192
acc.clear
193-
acc << i
193+
acc << cell
194194
elsif ce == min_e
195-
acc << i
195+
acc << cell
196196
end
197-
198-
i = i.succ
199197
end
200-
ucg[acc.sample]
198+
199+
acc.sample
201200
end
202201
end
203202
end

0 commit comments

Comments
 (0)