class Grid

Attributes

data[RW]

Public Class Methods

from_points(point_array, bounding_box=true, char='x', empty=' ', &block) click to toggle source

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
new(x, y, default=0, &block) click to toggle source
# 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

[](y, x=nil) click to toggle source
# 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
[]=(y, x, assign=nil) click to toggle source

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
adja_index(x,y=nil) click to toggle source
# 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
each(&block) click to toggle source
# File lib/cem/cruzzles.rb, line 544
def each(&block)
  @data.each { |row|
    row.each { |cell|
      block.call(cell)
    }
  }
end
each_with_index(&block) click to toggle source
# 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
flatten() click to toggle source

Returns the underlying 2D array as a flattened array

# File lib/cem/cruzzles.rb, line 412
def flatten
  return @data.flatten
end
initialize_copy(orig) click to toggle source
Calls superclass method
# 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
map_a(&block) click to toggle source

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
map_a!(&block) click to toggle source
# File lib/cem/cruzzles.rb, line 540
def map_a!(&block)
  @data = map_a(&block)
end
minmax(null=nil) click to toggle source

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
nsew_index(x,y=nil) click to toggle source

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
printBoard(overlay = nil) click to toggle source
# 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
select_valid(a) click to toggle source

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
sum(&block) click to toggle source
# File lib/cem/cruzzles.rb, line 572
def sum(&block)    
  sum = 0
  each { |cell|
    sum += block.call(cell)
  }
  return sum
end
to_a() click to toggle source

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
to_s() click to toggle source
# File lib/cem/cruzzles.rb, line 500
def to_s
  printBoard()
end