seat_selector 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 660dbba0c80ddff35e3ecffff39d389ec5482380708579cae4f31fa4b7e95cd5
4
+ data.tar.gz: 16f95312509d2ab32b94bc29b3dbe347107fd3534e8ca312a892e3475050fa3c
5
+ SHA512:
6
+ metadata.gz: ac5ba4d66ab5f3c1b0ab0ee28a4b3a82b2f9b2ab10100929026882ffcfb5e7c344cf2a8733663e97cbd441c21dc3e4669d1b8401f0063015bad721fca8c6c42d
7
+ data.tar.gz: 99fffe2a6012f39d88813a5eef11e6151918c6c3d1c5983e29b973585a4113e33043454a4b3ac64a03b165d7f1c8ce8eee663c04af6349c406965e08f82fa21d
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # Seat Selector
2
+ A simple Ruby gem example.
3
+
4
+ Given a JSON input representing the available seats at a public venue, 'seat_selector' finds the best available seat(s) (meaning closest to front row, center-stage). If more than one seat is requested, 'seat_selector' finds the best available group of adjacent seats (within the same row).
5
+
6
+ ## Installation
7
+ To install:
8
+ ```
9
+ $ gem install seat_selector
10
+ ```
11
+ ## Usage
12
+
13
+ ```ruby
14
+ require 'seat_selector'
15
+ # Pass your JSON-formatted data to SeatSelector.
16
+ # You'll get back an array of the best available group of adjacent seats,
17
+ # or an empty array if no such group is available.
18
+ # See ./spec/fixtures/valid_data.json for examples of the supported format.
19
+ finder = SeatSelector.parse(json_str)
20
+
21
+ # request a single seat
22
+ seats = finder.get_best_seats(1)
23
+ # => [ <SeatSelector::Seat> ]
24
+
25
+ # request multiple seats
26
+ seats = finder.get_best_seats(3)
27
+ ```
28
+
data/bin/seat_selector ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/seat_selector'
@@ -0,0 +1,19 @@
1
+ module SeatSelector
2
+ class AlphaConverter
3
+ # A -> 1; C -> 3; AA -> 27; AAA -> 703
4
+ def self.to_i(alpha_str)
5
+ alpha_str.each_char.inject(0) do |sum, c|
6
+ (sum * 26) + self.letter_values[c.downcase]
7
+ end
8
+ end
9
+
10
+ def self.letter_values
11
+ @@letter_values ||= begin
12
+ ("a".."z").each_with_object({}).with_index do |(chr, value_map), i|
13
+ value_map[chr] = i + 1
14
+ end
15
+ end
16
+ end
17
+ private_class_method :letter_values
18
+ end
19
+ end
@@ -0,0 +1,66 @@
1
+ module SeatSelector
2
+ class Finder
3
+ attr_reader :seats
4
+
5
+ def initialize(venue)
6
+ @seats = venue.available_seats
7
+ set_distance!(venue.total_columns)
8
+ end
9
+
10
+ def get_best_seats(seats_needed = 1)
11
+ return [] if seats_needed < 1
12
+ best_seat = nil
13
+ best_distance = nil
14
+ @seats.each do |r, seats_in_row| # skip rows with no open seats
15
+ # search the current row
16
+ seats_in_row.each do |c, seat|
17
+ if seats_needed == 1
18
+ if best_seat.nil? || best_seat.distance > seat.distance
19
+ best_seat = seat
20
+ best_distance = seat.distance
21
+ end
22
+ else
23
+ # check rightward from current seat
24
+ valid_group = (c + 1).upto(c + seats_needed - 1).all?{|i| seats_in_row.key?(i) }
25
+ if valid_group
26
+ distance = (c).upto(c + seats_needed - 1).inject(0) do |sum, i|
27
+ sum + seats_in_row[i].distance
28
+ end
29
+ if best_seat.nil? || best_distance > distance
30
+ best_seat = seat
31
+ best_distance = distance
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ return [] if best_seat.nil?
39
+
40
+ if seats_needed > 1
41
+ seats_needed.times.map {|i| @seats[best_seat.row][best_seat.column + i] }
42
+ else
43
+ [best_seat]
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def set_distance!(total_columns)
50
+ median_column = median(total_columns)
51
+
52
+ @seats.each_value do |seats_in_row|
53
+ seats_in_row.each_value {|seat| seat.set_distance!(median_column) }
54
+ end
55
+ end
56
+
57
+ # get median of contiguous integer range 1 to max
58
+ def median(max)
59
+ if max.even?
60
+ max / 2
61
+ else
62
+ (max + 1) / 2
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,31 @@
1
+ require 'json'
2
+
3
+ module SeatSelector
4
+ class Parser
5
+ class UnprocessableEntity < StandardError
6
+ end
7
+
8
+ def self.parse(json_str)
9
+ begin
10
+ obj = JSON.parse(json_str)
11
+ seats = build_available_seats(obj.fetch("seats").values)
12
+ layout = obj.fetch("venue").fetch("layout")
13
+ rows = layout.fetch("rows")
14
+ columns = layout.fetch("columns")
15
+
16
+ venue = Venue.new(seats, rows, columns)
17
+ Finder.new(venue)
18
+
19
+ rescue StandardError
20
+ raise UnprocessableEntity
21
+ end
22
+ end
23
+
24
+ def self.build_available_seats(seats_args)
25
+ seats_args.map { |args| Seat.new(args) }
26
+ end
27
+ private_class_method :build_available_seats
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,24 @@
1
+ module SeatSelector
2
+ class Seat
3
+ attr_reader :row, :column, :id, :distance
4
+
5
+ def initialize(params, converter = AlphaConverter)
6
+ @row = converter.to_i(params.fetch("row"))
7
+ @column = params.fetch("column")
8
+ @id = params.fetch("id")
9
+ @is_available = (params.fetch("status") == "AVAILABLE")
10
+ end
11
+
12
+ def to_s
13
+ @id.to_s.upcase
14
+ end
15
+
16
+ def available?
17
+ @is_available
18
+ end
19
+
20
+ def set_distance!(median_column)
21
+ @distance = (@row - 1).abs + (@column - median_column).abs
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ module SeatSelector
2
+ class Venue
3
+ attr_reader :total_rows, :total_columns, :available_seats
4
+
5
+ def initialize(all_seats, total_rows, total_columns)
6
+ @total_rows = total_rows
7
+ @total_columns = total_columns
8
+ @available_seats = build_available_seats(all_seats)
9
+ end
10
+
11
+ private
12
+
13
+ def build_available_seats(all_seats)
14
+ all_seats.each_with_object({}) do |s, seats|
15
+ if s.available?
16
+ seats[s.row] ||= {}
17
+ seats[s.row][s.column] = s
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module SeatSelector
2
+ VERSION = '0.1.1'.freeze
3
+ end
@@ -0,0 +1,8 @@
1
+ Dir[File.dirname(__FILE__) + '/seat_selector/*.rb'].each { |file| require file }
2
+
3
+ module SeatSelector
4
+
5
+ def self.parse(json_str)
6
+ Parser.parse(json_str)
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: seat_selector
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Steve Lovell
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-08-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.10'
27
+ description: A simple practice app demonstrating how to make a gem.
28
+ email:
29
+ - sjlovell34@gmail.com
30
+ executables:
31
+ - seat_selector
32
+ extensions: []
33
+ extra_rdoc_files:
34
+ - README.md
35
+ files:
36
+ - Gemfile
37
+ - README.md
38
+ - bin/seat_selector
39
+ - lib/seat_selector.rb
40
+ - lib/seat_selector/alpha_converter.rb
41
+ - lib/seat_selector/finder.rb
42
+ - lib/seat_selector/parser.rb
43
+ - lib/seat_selector/seat.rb
44
+ - lib/seat_selector/venue.rb
45
+ - lib/seat_selector/version.rb
46
+ homepage: https://github.com/stephenjlovell/seat_selector
47
+ licenses:
48
+ - MIT
49
+ metadata: {}
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 2.7.3
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubygems_version: 3.1.6
66
+ signing_key:
67
+ specification_version: 4
68
+ summary: Finds the best seat(s) at a given venue.
69
+ test_files: []