Class: Grid

Inherits:
Object
  • Object
show all
Defined in:
lib/cem/cruzzles.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(x, y, default = 0, &block) ⇒ Grid

Returns a new instance of Grid.



276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# 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

Instance Attribute Details

#dataObject

Returns access to the underlying 2D array. Caution: This is not a duplicate. Use to_a for this.



511
512
513
# File 'lib/cem/cruzzles.rb', line 511

def data
  @data
end

Class Method Details

.from_points(point_array, bounding_box = true, char = 'x', empty = ' ', &block) ⇒ Object

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.



334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# 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

Instance Method Details

#[](y, x = nil) ⇒ Object



380
381
382
383
384
385
386
387
388
389
390
391
392
393
# 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) ⇒ Object

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


401
402
403
404
405
406
407
408
409
# 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) ⇒ Object



459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
# 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) ⇒ Object



544
545
546
547
548
549
550
# File 'lib/cem/cruzzles.rb', line 544

def each(&block)
  @data.each { |row|
    row.each { |cell|
      block.call(cell)
    }
  }
end

#each_with_index(&block) ⇒ Object



552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
# 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

#flattenObject

Returns the underlying 2D array as a flattened array



412
413
414
# File 'lib/cem/cruzzles.rb', line 412

def flatten
  return @data.flatten
end

#initialize_copy(orig) ⇒ Object



316
317
318
319
320
321
# 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) ⇒ Object

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.



525
526
527
528
529
530
531
532
533
534
535
536
537
538
# 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) ⇒ Object



540
541
542
# File 'lib/cem/cruzzles.rb', line 540

def map_a!(&block)
  @data = map_a(&block)
end

#minmax(null = nil) ⇒ Object

Finds the top-left (min), bottom-right (max) coordinates of this Grid using the given value ‘null’ as an indicator for an empty field.



360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
# 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) ⇒ Object

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



421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
# 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) ⇒ Object



580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
# 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) ⇒ Object

Will remove all invalid indices from the array



453
454
455
456
457
# 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) ⇒ Object



572
573
574
575
576
577
578
# File 'lib/cem/cruzzles.rb', line 572

def sum(&block)    
  sum = 0
  each { |cell|
    sum += block.call(cell)
  }
  return sum
end

#to_aObject

returns a copy of the underlying 2D array, with linking to the content (rather than dup the content also)



505
506
507
# File 'lib/cem/cruzzles.rb', line 505

def to_a
  @data.map { |row| row.dup }
end

#to_sObject



500
501
502
# File 'lib/cem/cruzzles.rb', line 500

def to_s
  printBoard()
end