basketball 0.0.5 → 0.0.7

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.
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Basketball
4
+ module Scheduling
5
+ class Game < ValueObject
6
+ attr_reader_value :date, :home_team, :away_team
7
+
8
+ def initialize(date:, home_team:, away_team:)
9
+ super()
10
+
11
+ raise ArgumentError, 'date is required' unless date
12
+ raise ArgumentError, 'home_team is required' unless home_team
13
+ raise ArgumentError, 'away_team is required' unless away_team
14
+ raise ArgumentError, 'teams cannot play themselves' if home_team == away_team
15
+
16
+ @date = date
17
+ @home_team = home_team
18
+ @away_team = away_team
19
+
20
+ freeze
21
+ end
22
+
23
+ def teams
24
+ [home_team, away_team]
25
+ end
26
+
27
+ def to_s
28
+ "#{date} - #{away_team} at #{home_team}"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Basketball
4
+ module Scheduling
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
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Basketball
4
+ module Scheduling
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
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Basketball
4
+ module Scheduling
5
+ class PreseasonGame < Game
6
+ def to_s
7
+ "#{super} (preseason)"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Basketball
4
+ module Scheduling
5
+ class SeasonGame < Game
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Basketball
4
+ module Scheduling
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
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'scheduling/cli'
4
+
5
+ module Basketball
6
+ module Scheduling
7
+ class ConferenceAlreadyRegisteredError < StandardError; end
8
+ class DivisionAlreadyRegisteredError < StandardError; end
9
+ class TeamAlreadyRegisteredError < StandardError; end
10
+
11
+ class BadConferencesSizeError < StandardError; end
12
+ class BadDivisionsSizeError < StandardError; end
13
+ class BadTeamsSizeError < StandardError; end
14
+
15
+ class UnknownTeamError < StandardError; end
16
+ end
17
+ end
@@ -4,14 +4,23 @@ module Basketball
4
4
  class ValueObject
5
5
  include Comparable
6
6
 
7
- # NOTE: This current implementation most likely does not work for deep inheritance trees.
8
7
  class << self
9
- def value_keys
10
- @value_keys ||= []
8
+ def all_value_keys
9
+ @all_value_keys ||= ancestors.flat_map do |ancestor|
10
+ if ancestor < Basketball::ValueObject
11
+ ancestor.value_keys
12
+ else
13
+ []
14
+ end
15
+ end.uniq.sort
16
+ end
17
+
18
+ def all_sorted_value_keys
19
+ all_value_keys.sort
11
20
  end
12
21
 
13
- def sorted_value_keys
14
- value_keys.sort
22
+ def value_keys
23
+ @value_keys ||= []
15
24
  end
16
25
 
17
26
  def attr_reader_value(*keys)
@@ -26,7 +35,7 @@ module Basketball
26
35
  end
27
36
 
28
37
  def to_h
29
- self.class.sorted_value_keys.to_h { |k| [k, send(k)] }
38
+ self.class.all_sorted_value_keys.to_h { |k| [k, send(k)] }
30
39
  end
31
40
 
32
41
  def [](key)
@@ -47,7 +56,7 @@ module Basketball
47
56
  end
48
57
 
49
58
  def all_sorted_values
50
- self.class.sorted_value_keys.map { |k| self[k] }
59
+ self.class.all_sorted_value_keys.map { |k| self[k] }
51
60
  end
52
61
  end
53
62
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Basketball
4
- VERSION = '0.0.5'
4
+ VERSION = '0.0.7'
5
5
  end
data/lib/basketball.rb CHANGED
@@ -13,3 +13,4 @@ require_relative 'basketball/value_object'
13
13
 
14
14
  # Submodules
15
15
  require_relative 'basketball/drafting'
16
+ require_relative 'basketball/scheduling'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: basketball
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-05-06 00:00:00.000000000 Z
11
+ date: 2023-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faker
@@ -38,146 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '4.10'
41
- - !ruby/object:Gem::Dependency
42
- name: bundler-audit
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '0.9'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '0.9'
55
- - !ruby/object:Gem::Dependency
56
- name: guard-rspec
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '4.7'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '4.7'
69
- - !ruby/object:Gem::Dependency
70
- name: pry
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '0.14'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '0.14'
83
- - !ruby/object:Gem::Dependency
84
- name: rake
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '13.0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '13.0'
97
- - !ruby/object:Gem::Dependency
98
- name: rspec
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '3.12'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '3.12'
111
- - !ruby/object:Gem::Dependency
112
- name: rubocop
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: '1.49'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: '1.49'
125
- - !ruby/object:Gem::Dependency
126
- name: rubocop-rake
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: '0.6'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: '0.6'
139
- - !ruby/object:Gem::Dependency
140
- name: rubocop-rspec
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - "~>"
144
- - !ruby/object:Gem::Version
145
- version: '2.20'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - "~>"
151
- - !ruby/object:Gem::Version
152
- version: '2.20'
153
- - !ruby/object:Gem::Dependency
154
- name: simplecov
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - "~>"
158
- - !ruby/object:Gem::Version
159
- version: '0.22'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - "~>"
165
- - !ruby/object:Gem::Version
166
- version: '0.22'
167
- - !ruby/object:Gem::Dependency
168
- name: simplecov-console
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - "~>"
172
- - !ruby/object:Gem::Version
173
- version: '0.9'
174
- type: :development
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - "~>"
179
- - !ruby/object:Gem::Version
180
- version: '0.9'
181
41
  description: |2
182
42
  This library is meant to serve as the domain for a basketball league/season simulator/turn-based game.
183
43
  It models core ideas such as: players, general managers, draft strategy, drafting, season generation, season simultation,
@@ -186,6 +46,7 @@ email:
186
46
  - mattruggio@icloud.com
187
47
  executables:
188
48
  - basketball-draft
49
+ - basketball-schedule
189
50
  extensions: []
190
51
  extra_rdoc_files: []
191
52
  files:
@@ -202,6 +63,7 @@ files:
202
63
  - Rakefile
203
64
  - basketball.gemspec
204
65
  - exe/basketball-draft
66
+ - exe/basketball-schedule
205
67
  - lib/basketball.rb
206
68
  - lib/basketball/drafting.rb
207
69
  - lib/basketball/drafting/cli.rb
@@ -218,6 +80,19 @@ files:
218
80
  - lib/basketball/drafting/sim_event.rb
219
81
  - lib/basketball/drafting/skip_event.rb
220
82
  - lib/basketball/entity.rb
83
+ - lib/basketball/scheduling.rb
84
+ - lib/basketball/scheduling/calendar.rb
85
+ - lib/basketball/scheduling/calendar_serializer.rb
86
+ - lib/basketball/scheduling/cli.rb
87
+ - lib/basketball/scheduling/conference.rb
88
+ - lib/basketball/scheduling/coordinator.rb
89
+ - lib/basketball/scheduling/division.rb
90
+ - lib/basketball/scheduling/game.rb
91
+ - lib/basketball/scheduling/league.rb
92
+ - lib/basketball/scheduling/league_serializer.rb
93
+ - lib/basketball/scheduling/preseason_game.rb
94
+ - lib/basketball/scheduling/season_game.rb
95
+ - lib/basketball/scheduling/team.rb
221
96
  - lib/basketball/value_object.rb
222
97
  - lib/basketball/version.rb
223
98
  homepage: https://github.com/mattruggio/basketball