chicago_charter_bus_rental 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4e0a07ce1b40771854f1854487248d57f90ef29eb960f2f04d07206a70656edb
4
+ data.tar.gz: cd9e21fc56df3f49e4bb461546cdbe4c88e9866450b33381782cf9606202ece3
5
+ SHA512:
6
+ metadata.gz: 849e94120dbb847b5379745ee4ac0a43b242422546b5dda6c0cb80718f1533e4eafa187a151a61c4e65f95de61b82174306e9360d642cfec264a67284885fc5b
7
+ data.tar.gz: b3c0c1bba1ee7b1c5d4a34ccadb953f54725bf1d35ddeacd1b34321c52e1aebc093aadfdf1a8b6f5da2d8f377b69ceefc96e638350318936af8e4c78a203d7d6
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Chicago Super Coach
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # chicago_charter_bus_rental
2
+
3
+ Group charter planning helpers for the [Chicago Charter Bus Rental](https://chicagosupercoachbus.com/) fleet: work out how many vehicles a headcount needs and how many seats are left over.
4
+
5
+ Seat counts are the top of the ranges published for each vehicle class: SuperCoach 57 (50-57), Coach Bus 44 (39-44), Small Coach Bus 28 (22-28), Executive Sprinter Van 15 (13-15), Party Bus 45 and Trolley 30.
6
+
7
+ ```ruby
8
+ require "chicago_charter_bus_rental"
9
+
10
+ headcount = ChicagoCharterBusRental.headcount_with_buffer(80) # 84, +5% for late additions
11
+ plan = ChicagoCharterBusRental.recommend_fleet(headcount)
12
+ puts plan.summary
13
+ # 1 x SuperCoach (50-57 seats) + 1 x Small Coach Bus (22-28 seats)
14
+ # = 85 seats for 84 passengers, 1 spare
15
+
16
+ ChicagoCharterBusRental.vehicles_needed(headcount, ChicagoCharterBusRental::SUPER_COACH) # 2
17
+ ```
18
+
19
+ - `recommend_fleet(passengers, vehicles: STANDARD)` returns the fewest vehicles that seat everyone and, among those, the fewest spare seats. Pass `vehicles: ChicagoCharterBusRental::ALL` to include the party bus and trolley.
20
+ - `vehicles_needed(passengers, vehicle)` is the simple round-up for one class.
21
+ - `headcount_with_buffer(confirmed, percent: 5)` adds a rounded-up safety margin.
22
+
23
+ A headcount below 1 raises `ArgumentError`.
24
+
25
+ ## Scope
26
+
27
+ A planning aid, not a quote, booking or availability statement. Confirm vehicles, prices and dates with the provider.
28
+
29
+ ## Development
30
+
31
+ ```
32
+ ruby test/chicago_charter_bus_rental_test.rb
33
+ gem build chicago_charter_bus_rental.gemspec
34
+ ```
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Group charter planning helpers for Chicago Charter Bus Rental: how many
4
+ # vehicles does a headcount need, and how many seats are left over?
5
+ #
6
+ # Seat counts are the top of the ranges on the published fleet page. They are
7
+ # a planning aid only, not a quote, a booking or a statement of availability.
8
+ module ChicagoCharterBusRental
9
+ VERSION = "1.0.0"
10
+ TITLE = "Chicago Charter Bus Rental"
11
+ HOMEPAGE = "https://chicagosupercoachbus.com/"
12
+ MAX_PLAN_PASSENGERS = 5000
13
+
14
+ # A vehicle class in the Chicago charter fleet.
15
+ Vehicle = Struct.new(:key, :label, :min_seats, :max_seats) do
16
+ # Seat range as text, e.g. "39-44", or "45" for a single number.
17
+ def seat_range
18
+ min_seats == max_seats ? max_seats.to_s : "#{min_seats}-#{max_seats}"
19
+ end
20
+ end
21
+
22
+ SUPER_COACH = Vehicle.new(:super_coach, "SuperCoach", 50, 57).freeze
23
+ COACH = Vehicle.new(:coach, "Coach Bus", 39, 44).freeze
24
+ SMALL_COACH = Vehicle.new(:small_coach, "Small Coach Bus", 22, 28).freeze
25
+ SPRINTER_VAN = Vehicle.new(:sprinter_van, "Executive Sprinter Van", 13, 15).freeze
26
+ PARTY_BUS = Vehicle.new(:party_bus, "Party Bus", 45, 45).freeze
27
+ TROLLEY = Vehicle.new(:trolley, "Trolley", 30, 30).freeze
28
+
29
+ # Standard coaches used by default, largest first.
30
+ STANDARD = [SUPER_COACH, COACH, SMALL_COACH, SPRINTER_VAN].freeze
31
+ # Every class, including the party bus and trolley.
32
+ ALL = [SUPER_COACH, PARTY_BUS, COACH, TROLLEY, SMALL_COACH, SPRINTER_VAN].freeze
33
+
34
+ # One line of a plan: +count+ vehicles of one class.
35
+ FleetLine = Struct.new(:vehicle, :count) do
36
+ def seats
37
+ vehicle.max_seats * count
38
+ end
39
+
40
+ def to_s
41
+ "#{count} x #{vehicle.label} (#{vehicle.seat_range} seats)"
42
+ end
43
+ end
44
+
45
+ # The vehicles recommended for a headcount.
46
+ FleetPlan = Struct.new(:passengers, :lines) do
47
+ def vehicle_count
48
+ lines.sum(&:count)
49
+ end
50
+
51
+ def total_seats
52
+ lines.sum(&:seats)
53
+ end
54
+
55
+ def spare_seats
56
+ total_seats - passengers
57
+ end
58
+
59
+ def summary
60
+ "#{lines.join(' + ')} = #{total_seats} seats for #{passengers} passengers, #{spare_seats} spare"
61
+ end
62
+
63
+ alias_method :to_s, :summary
64
+ end
65
+
66
+ module_function
67
+
68
+ def homepage
69
+ HOMEPAGE
70
+ end
71
+
72
+ # Vehicles of one class needed for +passengers+.
73
+ def vehicles_needed(passengers, vehicle)
74
+ check_passengers(passengers)
75
+ (passengers + vehicle.max_seats - 1) / vehicle.max_seats
76
+ end
77
+
78
+ # Headcount to plan for after adding +percent+ (default 5) for late
79
+ # additions, rounded up.
80
+ def headcount_with_buffer(confirmed, percent: 5)
81
+ check_passengers(confirmed)
82
+ raise ArgumentError, "percent must not be negative" if percent.negative?
83
+
84
+ (confirmed * (100 + percent) + 99) / 100
85
+ end
86
+
87
+ # Fewest vehicles that seat +passengers+, and among those the fewest spare
88
+ # seats. Uses the standard coaches unless +vehicles+ is given.
89
+ def recommend_fleet(passengers, vehicles: STANDARD)
90
+ check_passengers(passengers)
91
+ if passengers > MAX_PLAN_PASSENGERS
92
+ raise ArgumentError, "passengers must be at most #{MAX_PLAN_PASSENGERS}"
93
+ end
94
+ raise ArgumentError, "vehicles must not be empty" if vehicles.empty?
95
+
96
+ options = vehicles.sort_by { |v| -v.max_seats }
97
+ limit = passengers + options.first.max_seats - 1
98
+ unreachable = 1 << 30
99
+ fewest = Array.new(limit + 1, unreachable)
100
+ pick = Array.new(limit + 1)
101
+ fewest[0] = 0
102
+ (1..limit).each do |s|
103
+ options.each do |v|
104
+ from = s - v.max_seats
105
+ next unless from >= 0 && fewest[from] + 1 < fewest[s]
106
+
107
+ fewest[s] = fewest[from] + 1
108
+ pick[s] = v
109
+ end
110
+ end
111
+
112
+ best = nil
113
+ (passengers..limit).each do |s|
114
+ next if fewest[s] == unreachable
115
+
116
+ best = s if best.nil? || fewest[s] < fewest[best]
117
+ end
118
+
119
+ counts = Hash.new(0)
120
+ s = best
121
+ while s.positive?
122
+ counts[pick[s]] += 1
123
+ s -= pick[s].max_seats
124
+ end
125
+ lines = options.select { |v| counts.key?(v) }.map { |v| FleetLine.new(v, counts[v]) }
126
+ FleetPlan.new(passengers, lines)
127
+ end
128
+
129
+ def check_passengers(passengers)
130
+ raise ArgumentError, "passengers must be at least 1" if passengers < 1
131
+ end
132
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chicago_charter_bus_rental
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - nbkdevs
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: Recommends the fewest vehicles for a Chicago group charter headcount
13
+ using the Chicago Charter Bus Rental fleet seat sizes, with spare-seat counts and
14
+ a late-additions headcount buffer. Library only, no dependencies.
15
+ email: info@chicagosupercoach.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - LICENSE
21
+ - README.md
22
+ - lib/chicago_charter_bus_rental.rb
23
+ homepage: https://chicagosupercoachbus.com/
24
+ licenses:
25
+ - MIT
26
+ metadata:
27
+ homepage_uri: https://chicagosupercoachbus.com/
28
+ source_code_uri: https://github.com/nbkdevs/chicago-super/tree/main/publish/chicago-charter-bus-rental/rubygems
29
+ bug_tracker_uri: https://github.com/nbkdevs/chicago-super/issues
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '2.7'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubygems_version: 4.0.20
45
+ specification_version: 4
46
+ summary: 'Chicago group charter planner: how many vehicles does a headcount need?'
47
+ test_files: []