diff --git a/lib/wave_function_collapse/cell.rb b/lib/wave_function_collapse/cell.rb index e5b7a0f..50afe02 100644 --- a/lib/wave_function_collapse/cell.rb +++ b/lib/wave_function_collapse/cell.rb @@ -33,14 +33,15 @@ def collapse self.tiles = [@tiles.max_by { |t| rand**(1.0 / t.probability) }] end - def neighbors(grid) - return if grid.nil? - - @neighbors["#{@x},#{@y}"] ||= begin - up = grid[@x][@y + 1] if grid[@x] && @y < grid[0].length - 1 - down = grid[@x][@y - 1] if grid[@x] && @y.positive? - right = grid[@x + 1][@y] if @x < grid.length - 1 - left = grid[@x - 1][@y] if @x.positive? + def neighbors(model) + return if model.nil? + + @neighbors[model.width * y + x] ||= begin + up = model.cell_at(@x, @y + 1) if @y < model.height - 1 + down = model.cell_at(@x, @y - 1) if @y.positive? + right = model.cell_at(@x + 1, @y) if @x < model.width - 1 + left = model.cell_at(@x - 1, @y) if @x.positive? + {up: up, down: down, right: right, left: left} end end diff --git a/lib/wave_function_collapse/model.rb b/lib/wave_function_collapse/model.rb index 012efa6..76b3e2d 100644 --- a/lib/wave_function_collapse/model.rb +++ b/lib/wave_function_collapse/model.rb @@ -22,12 +22,16 @@ def initialize(tiles, width, height) @tiles = tiles @width = width.to_i @height = height.to_i - - @grid = Array.new(width) { |x| Array.new(height) { |y| Cell.new(x, y, @tiles.shuffle) } } - @uncollapsed_cells_grid = @grid.flatten.reject(&:collapsed) + @grid = [] + @height.times { |y| @width.times { |x| @grid << Cell.new(x, y, @tiles.shuffle) } } + @uncollapsed_cells_grid = @grid.reject(&:collapsed) @max_entropy = @tiles.length end + def cell_at(x, y) + @grid[@width * y + x] + end + def complete? @uncollapsed_cells_grid.empty? end @@ -79,18 +83,18 @@ def random_cell def generate_grid x = 0 result = [] - lx = @grid.length - while x < lx + + while x < @width rx = result[x] = [] y = 0 - pgx = @grid[x] - ly = pgx.length - while y < ly - rx[y] = pgx[y].tile + + while y < @height + rx[y] = cell_at(x, y).tile y += 1 end x += 1 end + result end @@ -110,7 +114,7 @@ def propagate(source_cell) end def evaluate_neighbor(source_cell, evaluation_direction) - neighbor_cell = source_cell.neighbors(@grid)[evaluation_direction] + neighbor_cell = source_cell.neighbors(self)[evaluation_direction] return if neighbor_cell.nil? || neighbor_cell.collapsed original_tile_count = neighbor_cell.tiles.length @@ -122,16 +126,19 @@ def evaluate_neighbor(source_cell, evaluation_direction) neighbor_tiles = neighbor_cell.tiles sci = 0 scil = source_tiles.length + while sci < scil source_tile = source_tiles[sci] sci += 1 source_edge_hash = source_tile.send(evaluation_direction) nci = 0 ncil = neighbor_tiles.length + while nci < ncil tile = neighbor_tiles[nci] nci += 1 next if new_tile_ids.has_key?(tile.tileid) + tile_edge_hash = tile.send(opposite_direction) if tile_edge_hash == source_edge_hash new_tile_ids[tile.tileid] = true @@ -139,6 +146,7 @@ def evaluate_neighbor(source_cell, evaluation_direction) end end end + neighbor_cell.tiles = new_tiles unless new_tiles.empty? @uncollapsed_cells_grid.delete(neighbor_cell) if neighbor_cell.collapsed diff --git a/lib/wave_function_collapse/window.rb b/lib/wave_function_collapse/window.rb index fb4eecf..5d3ba72 100644 --- a/lib/wave_function_collapse/window.rb +++ b/lib/wave_function_collapse/window.rb @@ -121,7 +121,7 @@ def draw_map column.reverse.each_with_index do |tile, y| inverted_y = (y - @model.height + 1).abs - entropy = @model.grid[x][inverted_y].entropy + entropy = @model.cell_at(x, inverted_y).entropy if entropy > 1 percent_entropy = (entropy.to_f / @model.max_entropy * 255).round diff --git a/test/test_model.rb b/test/test_model.rb index cbbecff..8d042a5 100644 --- a/test/test_model.rb +++ b/test/test_model.rb @@ -13,7 +13,7 @@ def test_initialize assert_equal 320, model.width assert_equal 240, model.height - assert_equal 320 * 240, model.grid.map(&:size).sum + assert_equal 320 * 240, model.grid.size assert_equal 3, model.max_entropy assert_equal 0, model.percent refute model.complete?