gthc 0.0.1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ed762c975444452f1ac856022506cfbefca548709194affc52b8bf229346839
4
- data.tar.gz: 989e1971a5d5a515b8554c3ad8021d428fb251ff478680c9c13857be45f98b33
3
+ metadata.gz: f4a4d5c17afbded52b98ab45a4790c0b40603c84bd4dfdda8b372a098d1350fa
4
+ data.tar.gz: d08051fe205d84b2619a56a42b3be1ca34e33dc7200d4d61e1e3d0c8c631999b
5
5
  SHA512:
6
- metadata.gz: 524ac3eef73252d447f3eefdabe24b7927a4d2d2f68311dad2ad0a84879fb159ac46da360de653d64d219ad792b686dac48e74f8cd236580ae11be02cfa3f195
7
- data.tar.gz: 93b2f74bfa3dc56a51ac61c81c394a23c2b06cbc4ba4a86ce39d9b4ccd1f3f501c15486fd8a6ae4122ff3c5372f92efff522c322181061f03dcdff3f0de124d1
6
+ metadata.gz: 70b7aebf6fda10145d3772ff72bd7aa11be6d2e97f4a59affb1ed1f1da43f161efcbd4fa835c5b4199361a8d4908f69061056fdedf869f7ba4602da58c744c85
7
+ data.tar.gz: f160ec0134082c62c56929558a6e2cd59c60d18106a389320bd4b422e43615aaa0c163293e7097f12e77e4d09392a53e74938f561d8296ce47c7d772aff46d3d
data/.gitignore CHANGED
@@ -12,3 +12,5 @@
12
12
 
13
13
  # generated file from building gem
14
14
  *.gem
15
+
16
+ *dconf*
@@ -0,0 +1,35 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ gthc (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.3)
10
+ rake (10.5.0)
11
+ rspec (3.8.0)
12
+ rspec-core (~> 3.8.0)
13
+ rspec-expectations (~> 3.8.0)
14
+ rspec-mocks (~> 3.8.0)
15
+ rspec-core (3.8.2)
16
+ rspec-support (~> 3.8.0)
17
+ rspec-expectations (3.8.4)
18
+ diff-lcs (>= 1.2.0, < 2.0)
19
+ rspec-support (~> 3.8.0)
20
+ rspec-mocks (3.8.1)
21
+ diff-lcs (>= 1.2.0, < 2.0)
22
+ rspec-support (~> 3.8.0)
23
+ rspec-support (3.8.2)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ bundler (~> 2.0)
30
+ gthc!
31
+ rake (~> 10.0)
32
+ rspec (~> 3.0)
33
+
34
+ BUNDLED WITH
35
+ 2.0.2
data/README.md CHANGED
@@ -1,8 +1,4 @@
1
- # Gthc
2
-
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/gthc`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
1
+ # GTHC
6
2
 
7
3
  ## Installation
8
4
 
@@ -40,4 +36,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
40
36
 
41
37
  ## Code of Conduct
42
38
 
43
- Everyone interacting in the Gthc project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/gthc/blob/master/CODE_OF_CONDUCT.md).
39
+ Everyone interacting in the GTHC project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/gthc/blob/master/CODE_OF_CONDUCT.md).
@@ -2,6 +2,7 @@ require "gthc/version"
2
2
  require "gthc/olson"
3
3
 
4
4
  module GTHC
5
+ include Olson
5
6
  class Error < StandardError; end
6
7
  # Your code goes here...
7
8
  end
@@ -0,0 +1,12 @@
1
+ require "gthc/olson/algorithm"
2
+
3
+ module GTHC
4
+ module Olson
5
+ extend Algorithm
6
+
7
+ def self.driver(peopleList, scheduleGrid)
8
+ # Algorithm
9
+ schedule(peopleList, scheduleGrid)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,148 @@
1
+ require "gthc/olson/helpers"
2
+ require "gthc/olson/weight"
3
+
4
+ module Algorithm
5
+
6
+ include Helpers
7
+ extend Weight
8
+
9
+ # Central document for creating schedule.
10
+ def schedule(people, scheduleGrid)
11
+ scheduleLength = scheduleGrid[0].length
12
+
13
+ # Remove all availability slots that are already filled in the schedule.
14
+ slots, graveyard, people = removeFilledSlots(people, scheduleGrid)
15
+
16
+ # Remove all availability slots that are already filled in the schedule.
17
+ while slots.length > 0
18
+
19
+ # Weight Reset - set all weights to 1.
20
+ slots = Weight.weightReset(slots)
21
+
22
+ # Weight Balance - prioritize people with fewer scheduled shifts.
23
+ people, slots = Weight.weightBalance(people, slots)
24
+
25
+ # Weight Contiguous - prioritize people to stay in the tent more time at once.
26
+ slots, scheduleGrid, graveyard = Weight.weightContiguous(slots, scheduleGrid, graveyard)
27
+
28
+ # Weight Tough Time - prioritize time slots with few people available.
29
+ slots = Weight.weightToughTime(slots, scheduleLength)
30
+
31
+ # Sort by Weights
32
+ slots.sort_by { |a| -a.weight }
33
+
34
+ # Update people, spreadsheet, and remove slots.
35
+ people, slots, graveyard, scheduleGrid = Weight.weightPick(people, slots, graveyard, scheduleGrid)
36
+
37
+ end
38
+
39
+ return processData(people, scheduleGrid)
40
+
41
+ end
42
+
43
+
44
+ # Remove all availability slots that are already filled in the schedule.
45
+ def removeFilledSlots(people, scheduleGrid)
46
+
47
+ # Reset Slots Array.
48
+ slots = Array.new
49
+ # Set up graveyard (Rows that are completely scheduled will go here).
50
+ graveyard = Array.new(scheduleGrid[0].length, 0)
51
+ # Set up counterArray (Going to count how scheduled a row is).
52
+ counterArray = Array.new(scheduleGrid[0].length, 0)
53
+
54
+ # Count number of scheduled tenters during a specific time.
55
+ scheduleGrid.each do | currentPerson |
56
+ counter = 0
57
+ while counter < currentPerson.length
58
+ if currentPerson[counter].status == "Scheduled"
59
+ counterArray[counter] = counterArray[counter] + 1
60
+ end
61
+ counter = counter + 1
62
+ end
63
+ end
64
+
65
+ # Iterate through every slot.
66
+ i = 0
67
+ while i < scheduleGrid.length
68
+
69
+ currentPerson = scheduleGrid[i]
70
+ counter = 0
71
+
72
+ while counter < scheduleGrid[i].length
73
+
74
+ # Determine how many people are needed.
75
+ isNight = currentPerson[counter].isNight
76
+ phase = currentPerson[counter].phase
77
+ peopleNeeded = Helpers.calculatePeopleNeeded(isNight, phase)
78
+ numPeople = counterArray[counter]
79
+
80
+ # Only add in slot if necessary.
81
+ if numPeople < peopleNeeded && currentPerson[counter].status == "Available"
82
+ slots.push(currentPerson[counter])
83
+ end
84
+
85
+ # Update graveyard
86
+ if numPeople >= peopleNeeded
87
+ graveyard[counter] = 1
88
+ end
89
+
90
+ # Update person freedom
91
+ # if numPeople >= peopleNeeded && currentPerson[counter].status == "Available"
92
+ # if isNight
93
+ # people[i].nightFree -= 1
94
+ # else
95
+ # people[i].dayFree -= 1
96
+ # end
97
+ # end
98
+
99
+ counter = counter + 1
100
+
101
+ end
102
+
103
+ i = i + 1
104
+
105
+ end
106
+
107
+ return slots, graveyard, people
108
+
109
+ end
110
+
111
+ def processData(people, scheduleGrid)
112
+ # compress data from 2d grid with a single-deminsion of
113
+ # all of the scheduled slots
114
+ combinedGrid = []
115
+
116
+ # iterating through every unique slot, and
117
+ # checking for any people that are scheduled on that slot as well
118
+ for slotIndex in 0...scheduleGrid[0].length
119
+ slotData = scheduleGrid[0][slotIndex].to_hash
120
+ slot = {
121
+ "startDate": slotData["startDate"],
122
+ "endDate": slotData["endDate"],
123
+ "isNight": slotData["isNight"],
124
+ "phase": slotData["phase"],
125
+ }
126
+ slot[:ids] = Array.new
127
+
128
+ # checking every person at that slot for status
129
+ for personIndex in 0...people.length
130
+ person = people[personIndex]
131
+ if scheduleGrid[personIndex][slotIndex].status == "Scheduled"
132
+ slot[:ids].push(person.id)
133
+ end
134
+ end
135
+
136
+ combinedGrid.push(slot)
137
+ end
138
+
139
+ # prints amount of people needed in a slot based on time and phase
140
+ combinedGrid.each do | slot |
141
+ peopleNeeded = Helpers.calculatePeopleNeeded slot[:isNight], slot[:phase]
142
+ peopleLeft = peopleNeeded - slot[:ids].length
143
+ slot["peopleLeft"] = peopleLeft
144
+ end
145
+
146
+ combinedGrid
147
+ end
148
+ end
@@ -0,0 +1,26 @@
1
+ module Helpers
2
+ def self.calculatePeopleNeeded(nightBoolean, phase)
3
+ if phase == "Black"
4
+ if nightBoolean
5
+ return 10
6
+ else
7
+ return 2
8
+ end
9
+ end
10
+ if phase == "Blue"
11
+ if nightBoolean
12
+ return 6
13
+ else
14
+ return 1
15
+ end
16
+ end
17
+ if phase == "White"
18
+ if nightBoolean
19
+ return 2
20
+ else
21
+ return 1
22
+ end
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,235 @@
1
+ require "gthc/olson/helpers"
2
+
3
+ module Weight
4
+ include Helpers
5
+
6
+ # Weight Reset - set all weights to 1.
7
+ def self.weightReset(slots)
8
+ slots.each do | currentSlot |
9
+ currentSlot.weight = 1;
10
+ end
11
+ slots
12
+ end
13
+
14
+ # Weight Balance - prioritize people with fewer scheduled shifts
15
+ def self.weightBalance(people, slots)
16
+
17
+ slots.each do | currentSlot |
18
+
19
+ # Establish variables.
20
+ currentPersonID = currentSlot.personID
21
+ dayScheduled = people[currentPersonID].dayScheduled
22
+ nightScheduled = people[currentPersonID].nightScheduled
23
+ night = currentSlot.isNight;
24
+
25
+ nightMulti = 0;
26
+ dayMulti = 0;
27
+
28
+ # Set multipliers.
29
+ if nightScheduled != 0
30
+ nightMulti = 1.0 / nightScheduled
31
+ else
32
+ nightMulti = 1.5
33
+ end
34
+
35
+ if dayScheduled != 0
36
+ dayMulti = (1.0/(dayScheduled+nightScheduled*4*2))
37
+ else
38
+ dayMulti = 1.5
39
+ end
40
+
41
+ #Adjust weights with multipliers.
42
+ if night
43
+ currentSlot.weight = currentSlot.weight * nightMulti
44
+ else
45
+ currentSlot.weight = currentSlot.weight * dayMulti
46
+ end
47
+
48
+ end
49
+ return people, slots
50
+ end
51
+
52
+ def self.gridLimits(row, rowLength)
53
+ return row - 1 < 0,
54
+ row + 1 > rowLength - 1
55
+ end
56
+
57
+ # Weight Contiguous - prioritize people to stay in the tent more time at once.
58
+ def self.weightContiguous(slots, scheduleGrid, graveyard)
59
+
60
+ i = 0
61
+ while i < slots.length
62
+ # Establish Variables
63
+ currentRow = slots[i].row
64
+ currentCol = slots[i].col
65
+
66
+ aboveRow = currentRow-1
67
+ belowRow = currentRow+1
68
+
69
+ # grab all slots under the same col as the inspected slot in order
70
+ # to get the slots above and below
71
+ allSlots = scheduleGrid[currentCol]
72
+ slotsLength = allSlots.length
73
+
74
+ # find what to skip
75
+ skipAboveRow, skipBelowRow = gridLimits(currentRow, slotsLength)
76
+
77
+ currentIsNight = slots[i].isNight
78
+ aboveIsNight = !skipAboveRow && allSlots[aboveRow].isNight
79
+ belowIsNight = !skipBelowRow && allSlots[belowRow].isNight
80
+
81
+ aboveTent = !skipAboveRow && allSlots[aboveRow].status == "Scheduled"
82
+ belowTent = !skipBelowRow && allSlots[belowRow].status == "Scheduled"
83
+ aboveSome = !skipAboveRow && allSlots[aboveRow].status == "Somewhat"
84
+ belowSome = !skipBelowRow && allSlots[belowRow].status == "Somewhat"
85
+ aboveFree = !skipAboveRow && allSlots[aboveRow].status == "Available"
86
+ belowFree = !skipBelowRow && allSlots[belowRow].status == "Available"
87
+
88
+ multi = 1
89
+
90
+ # Both are scheduled.
91
+ if aboveTent && belowTent
92
+ multi = 100
93
+ end
94
+
95
+ # Both are not free
96
+ if !belowTent && !belowFree && !aboveSome && !belowSome && !aboveTent && !aboveFree
97
+ if slots[i].weight > 0
98
+ multi = -1
99
+ end
100
+ end
101
+
102
+ # Above is scheduled, below is free.
103
+ if aboveTent && !belowTent && belowFree
104
+ multi = 3.25
105
+ end
106
+
107
+ # Below is scheduled, above is free.
108
+ if belowTent && !aboveTent && aboveFree
109
+ multi = 3.25
110
+ end
111
+
112
+ # Above is scheduled, below is not free.
113
+ if aboveTent && !belowTent && !belowFree
114
+ multi = 3
115
+ end
116
+
117
+ # Below is scheduled, above is not free.
118
+ if belowTent && !aboveTent && !aboveFree
119
+ multi = 3
120
+ end
121
+
122
+ # Both are free
123
+ if belowFree && aboveFree
124
+ multi = 2.75
125
+ end
126
+
127
+ # Above is free, below is not free
128
+ if aboveFree && !belowTent && !belowFree
129
+ multi = 1
130
+ end
131
+
132
+ # Below is free, above is not free
133
+ if(belowFree && !aboveTent && !aboveFree)
134
+ multi = 1
135
+ end
136
+
137
+ # Night Multi
138
+ if aboveIsNight || belowIsNight || currentIsNight
139
+ multi *= 1.25
140
+ end
141
+
142
+ # Occurance of Somewhat Available
143
+ if aboveSome || belowSome
144
+ multi *= 0.5
145
+ end
146
+
147
+ slots[i].weight = slots[i].weight*multi
148
+ i += 1
149
+
150
+ end
151
+
152
+ return slots, scheduleGrid, graveyard
153
+ end
154
+
155
+ # Weight Tough Time - prioritize time slots with few people available. */
156
+ def self.weightToughTime(slots, scheduleLength)
157
+
158
+ # Set up counterArray (Rows that are filled).
159
+ counterArray = Array.new(scheduleLength + 1, 0)
160
+
161
+ # Fill counterArray.
162
+ slots.each do | currentSlot |
163
+ currentRow = currentSlot.row
164
+ counterArray[currentRow] = counterArray[currentRow] + 1
165
+ end
166
+
167
+ # Update Weights.
168
+ slots.each do | currentSlot |
169
+ currentRow = currentSlot.row
170
+ currentPhase = currentSlot.phase
171
+ nightBoolean = currentSlot.isNight
172
+ peopleNeeded = Helpers.calculatePeopleNeeded(nightBoolean, currentPhase)
173
+ numFreePeople = counterArray[currentRow]
174
+ currentSlot.weight = currentSlot.weight*(12/numFreePeople)*peopleNeeded
175
+ end
176
+
177
+ return slots
178
+ end
179
+
180
+ # Update people, spreadsheet, and remove slots.
181
+ def self.weightPick(people, slots, graveyard, scheduleGrid)
182
+
183
+ # Remove winner from list.
184
+ winner = slots.shift;
185
+
186
+ # Update person information.
187
+ currentPersonID = winner.personID;
188
+ currentTime = winner.isNight;
189
+
190
+ if currentTime
191
+ people[currentPersonID].nightScheduled += 1
192
+ people[currentPersonID].nightFree -= 1
193
+ else
194
+ people[currentPersonID].dayScheduled += 1
195
+ people[currentPersonID].dayFree -= 1
196
+ end
197
+
198
+ # Establish Variables
199
+ currentRow = winner.row
200
+ currentCol = winner.col
201
+ tentCounter = 0
202
+
203
+ # Update Data
204
+ scheduleGrid[currentCol][currentRow].status = "Scheduled";
205
+
206
+ # Count number of scheduled tenters during winner slot.
207
+ i = 0
208
+ while i < scheduleGrid.length
209
+ if scheduleGrid[i][currentRow].status == "Scheduled"
210
+ tentCounter = tentCounter + 1
211
+ end
212
+ i += 1
213
+ end
214
+
215
+ # Determine how many people are needed.
216
+ peopleNeeded = Helpers.calculatePeopleNeeded(currentTime, winner.phase)
217
+
218
+ # Update Slots and Graveyard
219
+ if tentCounter >= peopleNeeded
220
+ graveyard[currentRow] = 1
221
+ j = 0
222
+ tempSlots = []
223
+ while j < slots.length
224
+ tempRow = slots[j].row
225
+ if tempRow != currentRow
226
+ tempSlots.push slots[j]
227
+ end
228
+ j += 1
229
+ end
230
+ slots = tempSlots
231
+ end
232
+
233
+ return people, slots, graveyard, scheduleGrid
234
+ end
235
+ end
@@ -1,3 +1,3 @@
1
1
  module GTHC
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gthc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aman Ibrahim
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2019-08-21 00:00:00.000000000 Z
12
+ date: 2019-12-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -66,6 +66,7 @@ files:
66
66
  - ".travis.yml"
67
67
  - CODE_OF_CONDUCT.md
68
68
  - Gemfile
69
+ - Gemfile.lock
69
70
  - LICENSE.txt
70
71
  - README.md
71
72
  - Rakefile
@@ -73,6 +74,10 @@ files:
73
74
  - bin/setup
74
75
  - gthc.gemspec
75
76
  - lib/gthc.rb
77
+ - lib/gthc/olson.rb
78
+ - lib/gthc/olson/algorithm.rb
79
+ - lib/gthc/olson/helpers.rb
80
+ - lib/gthc/olson/weight.rb
76
81
  - lib/gthc/version.rb
77
82
  homepage: https://www.gthc.io/
78
83
  licenses:
@@ -95,7 +100,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
95
100
  - !ruby/object:Gem::Version
96
101
  version: '0'
97
102
  requirements: []
98
- rubygems_version: 3.0.3
103
+ rubyforge_project:
104
+ rubygems_version: 2.7.7
99
105
  signing_key:
100
106
  specification_version: 4
101
107
  summary: GTHC Ruby Gem