grrrisu/Simulator

View on GitHub
lib/sim/matrix/base.rb

Summary

Maintainability
A
0 mins
Test Coverage
require 'json'

module Sim
  module Matrix
    class Base
      include Enumerable

      extend Forwardable
      def_delegators :@matrix, :to_s, :to_json, :flatten, :inspect

      attr_writer :matrix

      def initialize columns, rows = nil, default = nil
        rows = columns unless rows
        @matrix = Array.new(rows) { Array.new(columns){ default } }
      end

      def == other
        if other.instance_of? Sim::Matrix::Base
          fields == other.fields
        elsif other.instance_of? Array
          fields == other
        else
          super
        end
      end

      # size of matrix [x,y]
      def size
        [width, height]
      end

      def width
        @matrix.first.size
      end

      def height
        @matrix.size
      end

      def fields
        @matrix
      end

      def each_field
        @matrix.each do |row|
          row.each {|field| yield field}
        end
      end

      alias each each_field

      def each_field_with_index
        @matrix.each_with_index do |row, y|
          row.each_with_index {|field, x| yield field, x, y}
        end
      end

      def set_each_field
        @matrix.each_with_index do |row, y|
          row.each_with_index {|field, x| self[x,y] = yield}
        end
      end

      def set_each_field_with_index
        @matrix.each_with_index do |row, y|
          row.each_with_index {|field, x| self[x, y] = yield x, y}
        end
      end

      def slice x, y, width, height = nil
        height = width unless height
        height.times do |j|
          width.times do |i|
            yield self[x + i, y + j]
          end
        end
      end

      def slice_with_index x, y, width, height = nil
        height = width unless height
        height.times do |j|
          width.times do |i|
            yield self[x + i, y + j], x + i, y + j
          end
        end
      end

      def set_slice x, y, width, height = nil
        height = width unless height
        height.times do |j|
          width.times do |i|
            set_field(x + i, y + j, yield)
          end
        end
      end

      def set_slice_with_index x, y, width, height = nil
        height = width unless height
        height.times do |j|
          width.times do |i|
            set_field(x + i, y + j, yield(x + i, y + j))
          end
        end
      end

      def get_field x, y
        @matrix.fetch(y).fetch(x)
      rescue IndexError
        raise ArgumentError, "coordinates x:#{x}, y:#{y} out of matrix width:#{width}, height:#{height}"
      end
      # matrix[1,0] #=> value
      alias [] get_field

      def set_field x, y, value
        raise ArgumentError, "coordinates x:#{x}, y:#{y} out of matrix width:#{width}, height:#{height}" unless x < width && y < height
        @matrix[y][x] = value
      end
      # matrix[1,0] = value
      alias []= set_field

      def field_as_string x, y, property
        self[x,y].try(:[],property).to_s
      end

    end
  end
end