Class: BLF::World

Inherits:
Object
  • Object
show all
Defined in:
lib/blf/world.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(args) ⇒ World

Returns a new instance of World.



9
10
11
12
13
14
15
# 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

Instance Attribute Details

#bl_stable_point_listObject (readonly)

Returns the value of attribute bl_stable_point_list.



7
8
9
# File 'lib/blf/world.rb', line 7

def bl_stable_point_list
  @bl_stable_point_list
end

#blocksObject (readonly)

Returns the value of attribute blocks.



7
8
9
# File 'lib/blf/world.rb', line 7

def blocks
  @blocks
end

#heightObject (readonly)

Returns the value of attribute height.



7
8
9
# File 'lib/blf/world.rb', line 7

def height
  @height
end

#imageObject (readonly)

Returns the value of attribute image.



7
8
9
# File 'lib/blf/world.rb', line 7

def image
  @image
end

#placed_blocksObject (readonly)

Returns the value of attribute placed_blocks.



7
8
9
# File 'lib/blf/world.rb', line 7

def placed_blocks
  @placed_blocks
end

#unplaced_blocksObject (readonly)

Returns the value of attribute unplaced_blocks.



7
8
9
# File 'lib/blf/world.rb', line 7

def unplaced_blocks
  @unplaced_blocks
end

#widthObject (readonly)

Returns the value of attribute width.



7
8
9
# File 'lib/blf/world.rb', line 7

def width
  @width
end

Instance Method Details

#add_bl_stable_point_candidates(new_block) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 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) ⇒ Object



17
18
19
# 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) ⇒ Object



21
22
23
# 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) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
# 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_allObject



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# 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) ⇒ Boolean

Returns:

  • (Boolean)


103
104
105
106
107
# 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

#drawObject



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# 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) ⇒ Boolean

Returns:

  • (Boolean)


89
90
91
92
93
94
95
96
97
98
99
100
101
# 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) ⇒ Boolean

Returns:

  • (Boolean)


79
80
81
82
83
84
85
86
87
# 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