basketball 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +9 -19
  3. data/CHANGELOG.md +1 -39
  4. data/README.md +72 -93
  5. data/basketball.gemspec +3 -6
  6. data/exe/{basketball-season-scheduling → basketball-coordinator} +1 -1
  7. data/exe/{basketball-draft → basketball-room} +1 -1
  8. data/lib/basketball/app/coordinator_cli.rb +243 -0
  9. data/lib/basketball/app/coordinator_repository.rb +191 -0
  10. data/lib/basketball/app/file_store.rb +22 -0
  11. data/lib/basketball/{draft/cli.rb → app/room_cli.rb} +53 -76
  12. data/lib/basketball/app/room_repository.rb +189 -0
  13. data/lib/basketball/app.rb +12 -0
  14. data/lib/basketball/draft/assessment.rb +31 -0
  15. data/lib/basketball/draft/event.rb +3 -2
  16. data/lib/basketball/draft/front_office.rb +35 -28
  17. data/lib/basketball/draft/{pick_event.rb → pick.rb} +13 -6
  18. data/lib/basketball/draft/room.rb +119 -119
  19. data/lib/basketball/draft/{player_search.rb → scout.rb} +4 -9
  20. data/lib/basketball/draft/skip.rb +12 -0
  21. data/lib/basketball/draft.rb +13 -6
  22. data/lib/basketball/entity.rb +10 -4
  23. data/lib/basketball/org/league.rb +73 -0
  24. data/lib/basketball/org/player.rb +26 -0
  25. data/lib/basketball/{draft → org}/position.rb +3 -2
  26. data/lib/basketball/org/team.rb +38 -0
  27. data/lib/basketball/org.rb +12 -0
  28. data/lib/basketball/season/arena.rb +112 -0
  29. data/lib/basketball/season/calendar.rb +41 -72
  30. data/lib/basketball/season/coordinator.rb +185 -126
  31. data/lib/basketball/season/{preseason_game.rb → exhibition.rb} +2 -1
  32. data/lib/basketball/season/game.rb +15 -10
  33. data/lib/basketball/season/matchup.rb +27 -0
  34. data/lib/basketball/season/opponent.rb +15 -0
  35. data/lib/basketball/season/{season_game.rb → regular.rb} +2 -1
  36. data/lib/basketball/season/result.rb +37 -0
  37. data/lib/basketball/season.rb +12 -13
  38. data/lib/basketball/value_object.rb +4 -1
  39. data/lib/basketball/version.rb +1 -1
  40. data/lib/basketball.rb +9 -4
  41. metadata +32 -44
  42. data/lib/basketball/draft/league.rb +0 -70
  43. data/lib/basketball/draft/player.rb +0 -43
  44. data/lib/basketball/draft/room_serializer.rb +0 -186
  45. data/lib/basketball/draft/roster.rb +0 -37
  46. data/lib/basketball/draft/sim_event.rb +0 -23
  47. data/lib/basketball/draft/skip_event.rb +0 -13
  48. data/lib/basketball/season/calendar_serializer.rb +0 -94
  49. data/lib/basketball/season/conference.rb +0 -57
  50. data/lib/basketball/season/division.rb +0 -43
  51. data/lib/basketball/season/league.rb +0 -114
  52. data/lib/basketball/season/league_serializer.rb +0 -99
  53. data/lib/basketball/season/scheduling_cli.rb +0 -198
  54. data/lib/basketball/season/team.rb +0 -21
@@ -1,114 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Basketball
4
- module Season
5
- class League
6
- class UnknownTeamError < StandardError; end
7
-
8
- class << self
9
- def generate_random; end
10
- end
11
-
12
- CONFERENCES_SIZE = 2
13
-
14
- attr_reader :conferences
15
-
16
- def initialize(conferences: [])
17
- @conferences = []
18
-
19
- conferences.each { |c| register_conference!(c) }
20
-
21
- if conferences.length != CONFERENCES_SIZE
22
- raise BadConferencesSizeError, "there has to be #{CONFERENCES_SIZE} conferences"
23
- end
24
-
25
- freeze
26
- end
27
-
28
- def to_s
29
- (['League'] + conferences.map(&:to_s)).join("\n")
30
- end
31
-
32
- def divisions
33
- conferences.flat_map(&:divisions)
34
- end
35
-
36
- def conference?(conference)
37
- conferences.include?(conference)
38
- end
39
-
40
- def division?(division)
41
- divisions.include?(division)
42
- end
43
-
44
- def team?(team)
45
- teams.include?(team)
46
- end
47
-
48
- def teams
49
- conferences.flat_map do |conference|
50
- conference.divisions.flat_map(&:teams)
51
- end
52
- end
53
-
54
- def conference_for(team)
55
- conferences.find { |c| c.divisions.find { |d| d.teams.include?(team) } }
56
- end
57
-
58
- def division_for(team)
59
- conference_for(team)&.divisions&.find { |d| d.teams.include?(team) }
60
- end
61
-
62
- # Same conference, same division
63
- def division_opponents_for(team)
64
- division = division_for(team)
65
-
66
- return nil unless division
67
-
68
- division.teams - [team]
69
- end
70
-
71
- # Same conference, different division
72
- def cross_division_opponents_for(team)
73
- conference = conference_for(team)
74
- division = division_for(team)
75
-
76
- return nil unless conference && division
77
-
78
- other_divisions = conference.divisions - [division]
79
-
80
- other_divisions.flat_map(&:teams)
81
- end
82
-
83
- # Different conference
84
- def cross_conference_opponents_for(team)
85
- conference = conference_for(team)
86
-
87
- return nil unless conference
88
-
89
- other_conferences = conferences - [conference]
90
-
91
- other_conferences.flat_map { |c| c.divisions.flat_map(&:teams) }
92
- end
93
-
94
- private
95
-
96
- def register_conference!(conference)
97
- raise ArgumentError, 'conference is required' unless conference
98
- raise ConferenceAlreadyRegisteredError, "#{conference} already registered" if conference?(conference)
99
-
100
- conference.divisions.each do |division|
101
- raise DivisionAlreadyRegisteredError, "#{division} already registered" if division?(division)
102
-
103
- division.teams.each do |team|
104
- raise TeamAlreadyRegisteredError, "#{team} already registered" if team?(team)
105
- end
106
- end
107
-
108
- conferences << conference
109
-
110
- self
111
- end
112
- end
113
- end
114
- end
@@ -1,99 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Basketball
4
- module Season
5
- class LeagueSerializer
6
- def to_hash(league)
7
- {
8
- 'conferences' => serialize_conferences(league.conferences)
9
- }
10
- end
11
-
12
- def from_hash(json)
13
- conferences = deserialize_conferences(json['conferences'])
14
-
15
- League.new(conferences:)
16
- end
17
-
18
- def deserialize(string)
19
- json = JSON.parse(string)
20
-
21
- from_hash(json)
22
- end
23
-
24
- def serialize(league)
25
- to_hash(league).to_json
26
- end
27
-
28
- private
29
-
30
- ## Deserialization
31
-
32
- def deserialize_conferences(conferences)
33
- (conferences || []).map do |conference_id, conference_hash|
34
- Conference.new(
35
- id: conference_id,
36
- name: conference_hash['name'],
37
- divisions: deserialize_divisions(conference_hash['divisions'])
38
- )
39
- end
40
- end
41
-
42
- def deserialize_divisions(divisions)
43
- (divisions || []).map do |division_id, division_hash|
44
- Division.new(
45
- id: division_id,
46
- name: division_hash['name'],
47
- teams: deserialize_teams(division_hash['teams'])
48
- )
49
- end
50
- end
51
-
52
- def deserialize_teams(teams)
53
- (teams || []).map do |team_id, team_hash|
54
- Team.new(
55
- id: team_id,
56
- name: team_hash['name']
57
- )
58
- end
59
- end
60
-
61
- ## Serialization
62
-
63
- def serialize_conferences(conferences)
64
- conferences.to_h do |conference|
65
- [
66
- conference.id,
67
- {
68
- 'name' => conference.name,
69
- 'divisions' => serialize_divisions(conference.divisions)
70
- }
71
- ]
72
- end
73
- end
74
-
75
- def serialize_divisions(divisions)
76
- divisions.to_h do |division|
77
- [
78
- division.id,
79
- {
80
- 'name' => division.name,
81
- 'teams' => serialize_teams(division.teams)
82
- }
83
- ]
84
- end
85
- end
86
-
87
- def serialize_teams(teams)
88
- teams.to_h do |team|
89
- [
90
- team.id,
91
- {
92
- 'name' => team.name
93
- }
94
- ]
95
- end
96
- end
97
- end
98
- end
99
- end
@@ -1,198 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'calendar_serializer'
4
- require_relative 'conference'
5
- require_relative 'coordinator'
6
- require_relative 'division'
7
- require_relative 'league'
8
- require_relative 'league_serializer'
9
- require_relative 'team'
10
-
11
- module Basketball
12
- module Season
13
- # Examples:
14
- # exe/basketball-season-scheduling -o tmp/league.json
15
- # exe/basketball-season-scheduling -i tmp/league.json -o tmp/calendar.json
16
- # exe/basketball-season-scheduling -i tmp/league.json -o tmp/calendar.json -y 2005
17
- # exe/basketball-season-scheduling -c tmp/calendar.json
18
- # exe/basketball-season-scheduling -c tmp/calendar.json -t C0-D0-T0
19
- # exe/basketball-season-scheduling -c tmp/calendar.json -d 2005-02-03
20
- # exe/basketball-season-scheduling -c tmp/calendar.json -d 2005-02-03 -t C0-D0-T0
21
- class SchedulingCLI
22
- attr_reader :opts,
23
- :league_serializer,
24
- :calendar_serializer,
25
- :io,
26
- :coordinator
27
-
28
- def initialize(args:, io: $stdout)
29
- @io = io
30
- @opts = slop_parse(args)
31
- @league_serializer = LeagueSerializer.new
32
- @calendar_serializer = CalendarSerializer.new
33
- @coordinator = Coordinator.new
34
-
35
- freeze
36
- end
37
-
38
- def invoke!
39
- if output?
40
- out_dir = File.dirname(output)
41
- FileUtils.mkdir_p(out_dir)
42
- end
43
-
44
- if output? && no_input?
45
- execute_with_no_input
46
- elsif output?
47
- execute_with_input
48
- end
49
-
50
- output_cal_query if cal
51
-
52
- self
53
- end
54
-
55
- private
56
-
57
- def output_cal_query
58
- contents = File.read(cal)
59
- calendar = calendar_serializer.deserialize(contents)
60
- team_instance = team ? calendar.team(team) : nil
61
- games = calendar.games_for(date:, team: team_instance).sort_by(&:date)
62
- pre_counter = 1
63
- counter = 1
64
-
65
- io.puts("Games for [team: #{team}, date: #{date}]")
66
- games.each do |game|
67
- if game.is_a?(PreseasonGame)
68
- io.puts("##{pre_counter} - #{game}")
69
- pre_counter += 1
70
- else
71
- io.puts("##{counter} - #{game}")
72
- counter += 1
73
- end
74
- end
75
- end
76
-
77
- def execute_with_input
78
- io.puts("Loading league from: #{input}")
79
-
80
- contents = File.read(input)
81
- league = league_serializer.deserialize(contents)
82
-
83
- io.puts("Generating calendar for the year #{year}...")
84
-
85
- calendar = coordinator.schedule(league:, year:)
86
- contents = calendar_serializer.serialize(calendar)
87
-
88
- File.write(output, contents)
89
-
90
- io.puts("Calendar written to: #{output}")
91
- end
92
-
93
- def execute_with_no_input
94
- league = generate_league
95
- contents = league_serializer.serialize(league)
96
-
97
- File.write(output, contents)
98
-
99
- io.puts("League written to: #{output}")
100
- end
101
-
102
- def cal
103
- opts[:cal].to_s.empty? ? nil : opts[:cal]
104
- end
105
-
106
- def team
107
- opts[:team].to_s.empty? ? nil : opts[:team]
108
- end
109
-
110
- def date
111
- opts[:date].to_s.empty? ? nil : Date.parse(opts[:date])
112
- end
113
-
114
- def year
115
- opts[:year].to_s.empty? ? Date.today.year : opts[:year]
116
- end
117
-
118
- def no_input?
119
- input.to_s.empty?
120
- end
121
-
122
- def input
123
- opts[:input]
124
- end
125
-
126
- def output?
127
- !output.to_s.empty?
128
- end
129
-
130
- def output
131
- opts[:output]
132
- end
133
-
134
- def generate_conferences
135
- 2.times.map do |i|
136
- id = "C#{i}"
137
-
138
- Conference.new(
139
- id:,
140
- name: Faker::Esport.league,
141
- divisions: generate_divisions("#{id}-")
142
- )
143
- end
144
- end
145
-
146
- def generate_divisions(id_prefix)
147
- 3.times.map do |j|
148
- id = "#{id_prefix}D#{j}"
149
-
150
- Division.new(
151
- id:,
152
- name: Faker::Address.community,
153
- teams: generate_teams("#{id}-")
154
- )
155
- end
156
- end
157
-
158
- def generate_teams(id_prefix)
159
- 5.times.map do |k|
160
- Team.new(
161
- id: "#{id_prefix}T#{k}",
162
- name: Faker::Team.name
163
- )
164
- end
165
- end
166
-
167
- def generate_league
168
- League.new(conferences: generate_conferences)
169
- end
170
-
171
- def slop_parse(args)
172
- Slop.parse(args) do |o|
173
- o.banner = 'Usage: basketball-schedule [options] ...'
174
-
175
- output_description = <<~DESC
176
- If input path is omitted then a new league will be written to this path.
177
- If an input path is specified then a Calendar will be written to the output path.
178
- DESC
179
-
180
- # League and Calendar Generation Interface
181
- o.string '-i', '--input', 'Path to load the League from. If omitted then a new league will be generated.'
182
- o.string '-o', '--output', output_description
183
- o.integer '-y', '--year', 'Year to use to generate a calendar for (defaults to current year).'
184
-
185
- # Calendar Query Interface
186
- o.string '-c', '--cal', 'Path to load a Calendar from. If omitted then no matchups will be outputted.'
187
- o.string '-d', '--date', 'Filter matchups to just the date specified (requires --cal option).'
188
- o.string '-t', '--team', 'Filter matchups to just the team ID specified (requires --cal option).'
189
-
190
- o.on '-h', '--help', 'Print out help, like this is doing right now.' do
191
- io.puts(o)
192
- exit
193
- end
194
- end.to_h
195
- end
196
- end
197
- end
198
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Basketball
4
- module Season
5
- class Team < Entity
6
- attr_reader :name
7
-
8
- def initialize(id:, name: '')
9
- super(id)
10
-
11
- @name = name.to_s
12
-
13
- freeze
14
- end
15
-
16
- def to_s
17
- "[#{super}] #{name}"
18
- end
19
- end
20
- end
21
- end