class Grid
Attributes
Public Class Methods
Given a list of Point2D, will create a Grid
that contains all points.
By default the grid will be recentered using the 'bottomleft'-most point. Set :bounding_box to false to get coordinates transferred as is.
By default all cells for which points are found are marked with an 'x'. Set :char to another character or supply a block which receives the point and should return the character to use.
By default the empty cells are filled with spaces. Set :empty to something else to change this.
# File lib/cem/cruzzles.rb, line 334 def self.from_points(point_array, bounding_box=true, char='x', empty=' ', &block) min, max = Point2D.minmax(point_array) if !bounding_box min = Point2D.new(0,0) end result = Grid.new(max.x - min.x + 1, max.y - min.y + 1, empty) point_array.each { |p| result[p-min] = if block block.call(p) else char end } return result end
# File lib/cem/cruzzles.rb, line 276 def initialize(x, y, default=0, &block) @data = [] if block case block.arity when 0 y.times { row = [] x.times { row << block.call() } @data << row } when 2 y.times { |iy| row = [] x.times { |ix| row << block.call(iy, ix) } @data << row } else raise end else # if no block given y.times { row = [] x.times { row << default } @data << row } # @data = [[default] * x] * y end end
Public Instance Methods
# File lib/cem/cruzzles.rb, line 380 def [](y, x=nil) if x == nil # puts y.inspect if y.respond_to?(:x) && y.respond_to?(:y) return @data[y.y][y.x] end return @data[y] end if y.is_a? Range return @data[y].map { |row| row[x] } end return @data[y][x] end
Array
assignment to grid.
grid[y,x] = a # Store a in row y and column x grid[point2d] = a # Use point2d.y and point2d.x to store a
# File lib/cem/cruzzles.rb, line 401 def []=(y, x, assign=nil) if assign == nil if y.respond_to?(:x) && y.respond_to?(:y) return @data[y.y][y.x] = x end return @data[y] = x end return @data[y][x] = assign end
# File lib/cem/cruzzles.rb, line 459 def adja_index(x,y=nil) if y == nil if x.respond_to?(:x) && x.respond_to?(:y) y = x.y x = x.x else raise "Need Point2D with :x and :y or two parameters" end end result = [] if x > 0 if y > 0 result << Point2D.new(x-1,y-1) end result << Point2D.new(x-1,y) if y + 1 < @data.size result << Point2D.new(x-1, y+1) end end if y > 0 result << Point2D.new(x,y-1) end # result << Point2D.new(x,y) if y + 1 < @data.size result << Point2D.new(x, y+1) end if x + 1 < @data[0].size if y > 0 result << Point2D.new(x+1,y-1) end result << Point2D.new(x+1,y) if y + 1 < @data.size result << Point2D.new(x+1, y+1) end end return result end
# File lib/cem/cruzzles.rb, line 544 def each(&block) @data.each { |row| row.each { |cell| block.call(cell) } } end
# File lib/cem/cruzzles.rb, line 552 def each_with_index(&block) case block.arity when 2 @data.each_with_index { |l, y| l.each_with_index { |c, x| block.call(c, Point2D.new(x,y)) } } when 3 @data.each_with_index { |l, y| l.each_with_index { |c, x| block.call(c, y, x) } } else raise end end
Returns the underlying 2D array as a flattened array
# File lib/cem/cruzzles.rb, line 412 def flatten return @data.flatten end
# File lib/cem/cruzzles.rb, line 316 def initialize_copy(orig) super @data = Marshal.load(Marshal.dump(orig.data)) # Do custom initialization for self end
Maps each cell of the grid by the given block.
If block has…
- one parameter, passes the cell value - two parameters, passes the coordinates as a Point2D and the cell value - three parameteres, passes y, x and the cell value
If the block returns nil, the original value is kept.
# File lib/cem/cruzzles.rb, line 525 def map_a(&block) case block.arity when 1 @data.map { |row| row.map { |value| block.call(value) || value } } when 2 @data.each_with_index.map { |row, y| row.each_with_index.map { |value, x| block.call(Point2D.new(x, y), value) || value } } when 3 @data.each_with_index.map { |row, y| row.each_with_index.map { |value, x| block.call(y, x, value) || value} } else raise end end
# File lib/cem/cruzzles.rb, line 540 def map_a!(&block) @data = map_a(&block) end
Finds the top-left (min), bottom-right (max) coordinates of this Grid
using the given value 'null' as an indicator for an empty field.
# File lib/cem/cruzzles.rb, line 360 def minmax(null=nil) min = nil max = nil @data.each_with_index { |l, y| l.each_with_index { |c, x| if c != null if min == nil || max == nil min = max = Point2D.new(x,y) end min = Point2D.new([min.x, x].min, [min.y, y].min) max = Point2D.new([max.x, x].max, [min.y, y].max) end } } return min, max end
Returns the Point2Ds in the directions NSEW as an array (no diagonals, see adja_index
for this)
Will not return Point2Ds in case we are at the boundary of the Grid
# File lib/cem/cruzzles.rb, line 421 def nsew_index(x,y=nil) # puts "#{@data.size} x #{@data[0].size}" if y == nil if x.respond_to?(:x) && x.respond_to?(:y) y = x.y x = x.x else raise "Need Point2D with :x and :y or two parameters" end end result = [] if x > 0 result << Point2D.new(x-1,y) end if y > 0 result << Point2D.new(x,y-1) end if y + 1 < @data.size - 1 result << Point2D.new(x, y+1) end if x + 1 < @data[0].size - 1 result << Point2D.new(x+1,y) end return result end
# File lib/cem/cruzzles.rb, line 580 def printBoard(overlay = nil) result = "" @data.each_with_index { |l, y| l.each_with_index { |c, x| if overlay pos = Point2D.new(x,y) if overlay.has_key?(pos) result += overlay[pos] end next else result += c.to_s end } result += "\r\n" } return result end
Will remove all invalid indices from the array
# File lib/cem/cruzzles.rb, line 453 def select_valid(a) a.select { |p| (p.x >= 0) && (p.y >= 0) && (p.y <= @data.size-1) && (p.x <= @data[0].size-1) } end
# File lib/cem/cruzzles.rb, line 572 def sum(&block) sum = 0 each { |cell| sum += block.call(cell) } return sum end
returns a copy of the underlying 2D array, with linking to the content (rather than dup the content also)
# File lib/cem/cruzzles.rb, line 505 def to_a @data.map { |row| row.dup } end
# File lib/cem/cruzzles.rb, line 500 def to_s printBoard() end