Completed
Pull Request — master (#145)
by
unknown
03:49 queued 01:57
created

SchedulesHelper.estimated_height()   A

Complexity

Conditions 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
1
module SchedulesHelper
2
3
  def pill_label(slot)
4
    slot.starts_at.in_time_zone.to_s(:usahhmm)
5
  end
6
7
  def session_columns_for_slot(slot, &block)
8
    if params[:stable_room_order].to_i == 1
9
      stable_room_order_session_columns_for_slot(slot, &block)
10
    else
11
      balanced_session_columns_for_slot(slot, &block)
12
    end
13
  end
14
15
  def stable_room_order_session_columns_for_slot(slot, &block)
16
    sessions = slot.sessions.sort_by { |s| session_sort_order(s) }
17
    split = (sessions.size+1) / 2
18
    yield sessions[0...split]
19
    yield sessions[split..-1]
20
  end
21
22
  ##
23
  # Attempt to divide these sessions into two roughly equal groups of roughly equal height.
24
  # (Without this, the fully expanded details grow very lopsided.)
25
  def balanced_session_columns_for_slot(slot, &block)
26
27
    unassigned = slot.sessions.sort_by { |s| -estimated_height(s) }
28
29
    columns = [[], []]
30
    heights = [0, 0]
31
    i = 0
32
    first = true
33
    until unassigned.empty?
34
      if unassigned.size == 1 && columns[0].size == columns[1].size  # odd number of sessions, so last one can go in either column
35
        i = if heights[0] < heights[1]
36
          0
37
        else
38
          1
39
        end
40
      end
41
42
      if first
43
        # Start by placing longest description
44
        session = unassigned.shift
45
        first = false
46
      else
47
        # Greedy algo: choose next session to try to keep heights as close as possible
48
        desired_height = heights[1-i] - heights[i]
49
        session = nil
50
        best_diff = 1 / 0.0
51
        unassigned.each do |candidate|  # O(n^2), so watch this one if we start assigning lots of sessions per slot!
52
          diff = (estimated_height(candidate) - desired_height).abs
53
          if diff < best_diff
54
            best_diff = diff
55
            session = candidate
56
          end
57
        end
58
        unassigned.delete(session)
59
      end
60
      break unless session
61
62
      columns[i] << session
63
      heights[i] += estimated_height(session)
64
      i = 1-i
65
    end
66
67
    # Now yield each column with session sorted by room size.
68
69
    columns.map! { |col| col.sort_by { |s| session_sort_order(s) } }
70
    unless columns[0].empty? || columns[1].empty?
71
      if columns[0].first.attendance_count < columns[1].first.attendance_count
72
        columns = [columns[1], columns[0]]
73
      end
74
    end
75
76
    columns.each(&block)
77
  end
78
79
private
80
81
  def session_sort_order(session)
82
    [-session.attendance_count, session.room&.name || ""]
0 ignored issues
show
Bug introduced by
The Ruby parser could not interpret the code. It reported: unexpected token error (Using Ruby 2.0 pa...meter, under `AllCops`).
Loading history...
Bug introduced by
The Ruby parser could not interpret the code. It reported: unexpected token tRBRACK (Using Ruby 2.0 ...meter, under `AllCops`).
Loading history...
83
  end
84
85
  def estimated_height(session)
86
    if session.instance_variable_get(:@estimated_height).blank?
87
      h = 0
88
      h += (session.title.length / 42 + 1) * 25
89
      h += (session.presenters.size / 5 + 1) * 20
90
      h += session.description.length / 4 + 17
91
      session.presenters.each { |presenter| h += (presenter.bio || '').length / 5 + 30}
92
      session.instance_variable_set(:@estimated_height, h)
93
    end
94
    session.instance_variable_get(:@estimated_height)
95
  end
96
97
end
98
0 ignored issues
show
Bug introduced by
The Ruby parser could not interpret the code. It reported: unexpected token $end (Using Ruby 2.0 par...meter, under `AllCops`).
Loading history...