gthc 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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