Module: Algorithm

Extended by:
Weight
Includes:
Helpers
Included in:
GTHC::Olson
Defined in:
lib/gthc/olson/algorithm.rb

Instance Method Summary collapse

Methods included from Weight

gridLimits, weightBalance, weightContiguous, weightPick, weightReset, weightToughTime

Methods included from Helpers

calculatePeopleNeeded

Instance Method Details

#isConnectedSlot(slot1, slot2) ⇒ Object



176
177
178
# File 'lib/gthc/olson/algorithm.rb', line 176

def isConnectedSlot(slot1, slot2)
  slot1[:ids] == slot2[:ids] and slot1[:phase] == slot2[:phase]
end

#processData(people, scheduleGrid) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/gthc/olson/algorithm.rb', line 113

def processData(people, scheduleGrid)
  # compress data from 2d grid with a single-deminsion of
  # all of the scheduled slots
  combinedGrid = []

  # iterating through every unique slot, and
  # checking for any people that are scheduled on that slot as well
  for slotIndex in 0...scheduleGrid[0].length
    slotData = scheduleGrid[0][slotIndex].to_hash
    slot = {
      "startDate": slotData["startDate"],
      "endDate": slotData["endDate"],
      "isNight": slotData["isNight"],
      "phase": slotData["phase"],
    }
    slot[:ids] = Array.new

    # checking every person at that slot for status
    for personIndex in 0...people.length
      person = people[personIndex]
      if scheduleGrid[personIndex][slotIndex].status == "Scheduled"
        slot[:ids].push(person.id)
      end
    end

    combinedGrid.push(slot)
  end

  # prints amount of people needed in a slot based on time and phase
  combinedGrid.each do | slot |
    peopleNeeded = Helpers.calculatePeopleNeeded slot[:isNight], slot[:phase]
    peopleLeft = peopleNeeded - slot[:ids].length
    slot[:peopleLeft] = peopleLeft
  end

  return combinedGrid, simplifyGrid(combinedGrid)
end

#removeFilledSlots(people, scheduleGrid) ⇒ Object

Remove all availability slots that are already filled in the schedule.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/gthc/olson/algorithm.rb', line 46

def removeFilledSlots(people, scheduleGrid)

  # Reset Slots Array.
  slots = Array.new
  # Set up graveyard (Rows that are completely scheduled will go here).
  graveyard = Array.new(scheduleGrid[0].length, 0)
  # Set up counterArray (Going to count how scheduled a row is).
  counterArray = Array.new(scheduleGrid[0].length, 0)

  # Count number of scheduled tenters during a specific time.
  scheduleGrid.each do | currentPerson |
    counter = 0
    while counter < currentPerson.length
      if currentPerson[counter].status == "Scheduled"
        counterArray[counter] = counterArray[counter] + 1
      end
      counter = counter + 1
    end
  end

  # Iterate through every slot.
  i = 0
  while i < scheduleGrid.length

    currentPerson = scheduleGrid[i]
    counter = 0

    while counter < scheduleGrid[i].length

      # Determine how many people are needed.
      isNight = currentPerson[counter].isNight
      phase = currentPerson[counter].phase
      peopleNeeded = Helpers.calculatePeopleNeeded(isNight, phase)
      numPeople = counterArray[counter]

      addToSlot = currentPerson[counter].status == "Available" || currentPerson[counter].status == "Somewhat"
      # Only add in slot if necessary.
      if numPeople < peopleNeeded && addToSlot
        slots.push(currentPerson[counter])
      end

      # Update graveyard
      if numPeople >= peopleNeeded
        graveyard[counter] = 1
      end

      # Update person freedom
      # if numPeople >= peopleNeeded  && currentPerson[counter].status == "Available"
      #   if isNight
      #     people[i].nightFree -= 1
      #   else
      #     people[i].dayFree -= 1
      #   end
      # end

      counter = counter + 1

    end

    i = i + 1

  end

  return slots, graveyard, people

end

#schedule(people, scheduleGrid) ⇒ Object

Central document for creating schedule.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/gthc/olson/algorithm.rb', line 10

def schedule(people, scheduleGrid)
  scheduleLength = scheduleGrid[0].length

  # Remove all availability slots that are already filled in the schedule.
  slots, graveyard, people = removeFilledSlots(people, scheduleGrid)

  # Remove all availability slots that are already filled in the schedule.
  while slots.length > 0

    # Weight Reset - set all weights to 1.
    slots = Weight.weightReset(slots)

    # Weight Balance - prioritize people with fewer scheduled shifts.
    people, slots = Weight.weightBalance(people, slots)

    # Weight Contiguous - prioritize people to stay in the tent more time at once.
    slots, scheduleGrid = Weight.weightContiguous(slots, scheduleGrid)

    # Weight Tough Time - prioritize time slots with few people available.
    slots = Weight.weightToughTime(slots, scheduleLength)

    # Sort by Weights
    slots.sort! { |a, b|  b.weight <=> a.weight }
    # pp slots

    # Update people, spreadsheet, and remove slots.
    people, slots, graveyard, scheduleGrid = Weight.weightPick(people, slots, graveyard, scheduleGrid)

  end

  return processData(people, scheduleGrid)

end

#simplifyGrid(combinedGrid) ⇒ Object



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/gthc/olson/algorithm.rb', line 151

def simplifyGrid(combinedGrid)
  simplifiedGrid = []
  currentSlot = {}
  building = false
  combinedGrid.each_with_index do |slot, index|
    if building
      #if a slot has already started building
      if isConnectedSlot(currentSlot, slot)
        currentSlot[:endDate] = slot[:endDate]
        #if any of the slots are night, all are marked as night
        currentSlot[:isNight] = true if slot[:isNight]
      else
        simplifiedGrid.push currentSlot
        currentSlot = slot
      end
    else
      # if are starting a new slot
      currentSlot = slot
      building = true
    end
    simplifiedGrid.push currentSlot if index == combinedGrid.length - 1
  end
  simplifiedGrid
end