view ellers.rb @ 0:1eef88068f9f tip

initial commit of maze game source
author ferencd
date Sun, 15 Sep 2019 11:46:47 +0200
parents
children
line wrap: on
line source
#---
# Excerpted from "Mazes for Programmers",
# published by The Pragmatic Bookshelf.
# Copyrights apply to this code. It may not be used to create training material, 
# courses, books, articles, and the like. Contact us if you are in doubt.
# We make no guarantees that this code is fit for any purpose. 
# Visit http://www.pragmaticprogrammer.com/titles/jbmaze for more book information.
#---
class Ellers

  class RowState
    def initialize(starting_set=0)
      @cells_in_set = {}
      @set_for_cell = []
      @next_set = starting_set
    end

    def record(set, cell)
      @set_for_cell[cell.column] = set

      @cells_in_set[set] = [] if !@cells_in_set[set]
      @cells_in_set[set].push cell
    end

    def set_for(cell)
      if !@set_for_cell[cell.column]
        record(@next_set, cell)
        @next_set += 1
      end

      @set_for_cell[cell.column]
    end

    def merge(winner, loser)
      @cells_in_set[loser].each do |cell|
        @set_for_cell[cell.column] = winner
        @cells_in_set[winner].push cell
      end

      @cells_in_set.delete(loser)
    end

    def next
      RowState.new(@next_set)
    end

    def each_set
      @cells_in_set.each { |set, cells| yield set, cells }
      self
    end
  end

  def on(grid)
    row_state = RowState.new

    grid.each_row do |row|
      row.each do |cell| 
        next unless cell.west 

        set = row_state.set_for(cell) 
        prior_set = row_state.set_for(cell.west) 

        should_link = set != prior_set && 
                      (cell.south.nil? || rand(2) == 0)

        if should_link
          cell.link(cell.west)
          row_state.merge(prior_set, set) 
        end
      end

      if row[0].south 
        next_row = row_state.next 

        row_state.each_set do |_, list|
          list.shuffle.each_with_index do |cell, index| 
            if index == 0 || rand(3) == 0
              cell.link(cell.south) 
              next_row.record(row_state.set_for(cell), cell.south) 
            end
          end
        end

        row_state = next_row 
      end
    end
  end

end