class BLF::World

Attributes

bl_stable_point_list[R]
blocks[R]
height[R]
image[R]
placed_blocks[R]
unplaced_blocks[R]
width[R]

Public Class Methods

new(args) click to toggle source
# File lib/blf/world.rb, line 9
def initialize(args)
  @width = args[:width]
  @height = args[:height]
  @unplaced_blocks = []
  @placed_blocks = []
  @bl_stable_point_list = []
end

Public Instance Methods

add_bl_stable_point_candidates(new_block) click to toggle source
# File lib/blf/world.rb, line 25
def add_bl_stable_point_candidates(new_block)
  @bl_stable_point_list << { x: new_block.end_x, y: 0, width: 0, height: new_block.start_y }
  @bl_stable_point_list << { x: 0, y: new_block.end_y, width: new_block.start_x, height: 0 }

  @placed_blocks.each_with_index do |placed_block, index|
    if (placed_block.end_x <= new_block.start_x) && (placed_block.end_y > new_block.end_y)
      @bl_stable_point_list << { x: placed_block.end_x, y: new_block.end_y, width: new_block.start_x - placed_block.end_x, height: placed_block.start_y - new_block.end_y }

    elsif (new_block.end_x <= placed_block.start_x) && (new_block.end_y > placed_block.end_y)
      @bl_stable_point_list << { x: new_block.end_x, y: placed_block.end_y, width: placed_block.start_x - new_block.end_x, height: new_block.start_y - placed_block.end_y }

    elsif (new_block.end_x < placed_block.end_x) && (placed_block.end_y <= new_block.start_y)
      @bl_stable_point_list << { x: new_block.end_x, y: placed_block.end_y, width: placed_block.start_x - new_block.end_x, height: new_block.start_y - placed_block.end_y }

    elsif (placed_block.end_x < new_block.end_x) && (new_block.end_y <= placed_block.start_y)
      @bl_stable_point_list << { x: placed_block.end_x, y: new_block.end_y, width: new_block.start_x - placed_block.end_x, height: placed_block.start_y - new_block.end_x }

    end
  end
end
add_block(args) click to toggle source
# File lib/blf/world.rb, line 17
def add_block(args)
  @unplaced_blocks << Block.new(width: args[:width], height: args[:height], world: self)
end
add_block_with_location(args) click to toggle source
# File lib/blf/world.rb, line 21
def add_block_with_location(args)
  @placed_blocks << Block.new(start_x: args[:x], start_y: args[:y], width: args[:width], height: args[:height], world: self)
end
allocate(new_block) click to toggle source
# File lib/blf/world.rb, line 46
def allocate new_block
  @bl_stable_point_list.each do |point|
    if stable?(point, new_block) &&
       !overlapped?(start_x: point[:x], start_y: point[:y], width: new_block.width, height: new_block.height) &&
       !beyond_area?(start_x: point[:x], start_y: point[:y], width: new_block.width, height: new_block.height)

      new_block.start_x = point[:x]
      new_block.start_y = point[:y]
      @placed_blocks << new_block
      break
    end
  end
end
allocate_all() click to toggle source
# File lib/blf/world.rb, line 60
def allocate_all
  # 左上端をブロックの組み合わせごとに追加するのは無駄なので、ここで一回だけ追加する。
  @bl_stable_point_list << { x: 0, y: 0, width: 0, height: 0 }

  @placed_blocks.each do |block|
    add_bl_stable_point_candidates block
  end

  @unplaced_blocks.length.times do
    # BL候補点の配列の順番通りに配置を試すので、Bottom-Leftの規則に沿って、yが小さい順に並べ替える。
    @bl_stable_point_list.sort! {|a, b| a[:y] <=> b[:y] }

    block = @unplaced_blocks.shift
    allocate block
    add_bl_stable_point_candidates block
    self.draw
  end
end
beyond_area?(args) click to toggle source
# File lib/blf/world.rb, line 103
def beyond_area?(args)
  end_x = args[:start_x] + args[:width]
  end_y = args[:start_y] + args[:height]
  !(end_x <= self.width && end_y <= self.height)
end
draw() click to toggle source
# File lib/blf/world.rb, line 109
def draw
  @image = Image.new(@width, @height) do
   self.background_color = 'white'
  end

  @placed_blocks.each {|block| block.draw }

  @bl_stable_point_list.compact.each do |point|
    dr = Draw.new
    dr.fill = "black"
    dr.ellipse(point[:x], point[:y], 1, 1, 0, 360)
    dr.draw @image
  end

  @image.write("example.jpg")
end
overlapped?(args) click to toggle source
# File lib/blf/world.rb, line 89
def overlapped?(args)
  start_x = args[:start_x]
  start_y = args[:start_y]
  end_x = args[:start_x] + args[:width]
  end_y = args[:start_y] + args[:height]

  @placed_blocks.map do |block|
    block.start_x < end_x &&
    block.start_y < end_y &&
    start_x < block.end_x &&
    start_y < block.end_y
  end.any?
end
stable?(point, current_block) click to toggle source
# File lib/blf/world.rb, line 79
def stable?(point, current_block)
  if point[:width] <= 0
    current_block.height >= point[:height]
  elsif point[:height] <= 0
    current_block.width >= point[:width]
  else
    current_block.width >= point[:width] && current_block.height >= point[:height]
  end
end