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
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Basketball
4
+ module App
5
+ # Knows how to flatten a Coordinator instance and rehydrate one from JSON and/or a Ruby hash.
6
+ class CoordinatorRepository
7
+ GAME_CLASSES = {
8
+ 'Exhibition' => Season::Exhibition,
9
+ 'Regular' => Season::Regular
10
+ }.freeze
11
+
12
+ private_constant :GAME_CLASSES
13
+
14
+ attr_reader :store
15
+
16
+ def initialize(store: FileStore.new)
17
+ super()
18
+
19
+ @store = store
20
+
21
+ freeze
22
+ end
23
+
24
+ def load(path)
25
+ contents = store.read(path)
26
+
27
+ deserialize(contents).tap do |coordinator|
28
+ coordinator.send('id=', path)
29
+ end
30
+ end
31
+
32
+ def save(path, coordinator)
33
+ contents = serialize(coordinator)
34
+
35
+ store.write(path, contents)
36
+
37
+ coordinator.send('id=', path)
38
+
39
+ coordinator
40
+ end
41
+
42
+ private
43
+
44
+ def deserialize(string)
45
+ hash = JSON.parse(string, symbolize_names: true)
46
+
47
+ from_h(hash)
48
+ end
49
+
50
+ def serialize(object)
51
+ to_h(object).to_json
52
+ end
53
+
54
+ def from_h(hash)
55
+ Season::Coordinator.new(
56
+ calendar: deserialize_calendar(hash[:calendar]),
57
+ current_date: Date.parse(hash[:current_date]),
58
+ results: deserialize_results(hash[:results]),
59
+ league: deserialize_league(hash[:league])
60
+ )
61
+ end
62
+
63
+ def to_h(coordinator)
64
+ {
65
+ calendar: serialize_calendar(coordinator.calendar),
66
+ current_date: coordinator.current_date.to_s,
67
+ results: serialize_results(coordinator.results),
68
+ league: serialize_league(coordinator.league)
69
+ }
70
+ end
71
+
72
+ # Serialization
73
+
74
+ def serialize_player(player)
75
+ {
76
+ id: player.id,
77
+ overall: player.overall,
78
+ position: player.position&.code
79
+ }
80
+ end
81
+
82
+ def serialize_games(games)
83
+ games.map { |game| serialize_game(game) }
84
+ end
85
+
86
+ def serialize_calendar(calendar)
87
+ {
88
+ preseason_start_date: calendar.preseason_start_date.to_s,
89
+ preseason_end_date: calendar.preseason_end_date.to_s,
90
+ season_start_date: calendar.season_start_date.to_s,
91
+ season_end_date: calendar.season_end_date.to_s,
92
+ games: serialize_games(calendar.games)
93
+ }
94
+ end
95
+
96
+ def serialize_game(game)
97
+ {
98
+ type: game.class.name.split('::').last,
99
+ date: game.date.to_s,
100
+ home_opponent: game.home_opponent.id,
101
+ away_opponent: game.away_opponent.id
102
+ }
103
+ end
104
+
105
+ def serialize_result(result)
106
+ {
107
+ game: serialize_game(result.game),
108
+ home_score: result.home_score,
109
+ away_score: result.away_score
110
+ }
111
+ end
112
+
113
+ def serialize_league(league)
114
+ {
115
+ teams: league.teams.map { |team| serialize_team(team) }
116
+ }
117
+ end
118
+
119
+ def serialize_team(team)
120
+ {
121
+ id: team.id,
122
+ players: team.players.map { |player| serialize_player(player) }
123
+ }
124
+ end
125
+
126
+ def serialize_results(results)
127
+ results.map do |result|
128
+ serialize_result(result)
129
+ end
130
+ end
131
+
132
+ # Deserialization
133
+
134
+ def deserialize_player(player_hash)
135
+ Org::Player.new(
136
+ id: player_hash[:id],
137
+ overall: player_hash[:overall],
138
+ position: Org::Position.new(player_hash[:position])
139
+ )
140
+ end
141
+
142
+ def deserialize_league(league_hash)
143
+ team_hashes = league_hash[:teams] || []
144
+
145
+ teams = team_hashes.map do |team_hash|
146
+ players = (team_hash[:players] || []).map { |player_hash| deserialize_player(player_hash) }
147
+
148
+ Org::Team.new(id: team_hash[:id], players:)
149
+ end
150
+
151
+ Org::League.new(teams:)
152
+ end
153
+
154
+ def deserialize_calendar(calendar_hash)
155
+ Season::Calendar.new(
156
+ preseason_start_date: Date.parse(calendar_hash[:preseason_start_date]),
157
+ preseason_end_date: Date.parse(calendar_hash[:preseason_end_date]),
158
+ season_start_date: Date.parse(calendar_hash[:season_start_date]),
159
+ season_end_date: Date.parse(calendar_hash[:season_end_date]),
160
+ games: deserialize_games(calendar_hash[:games])
161
+ )
162
+ end
163
+
164
+ def deserialize_games(game_hashes)
165
+ (game_hashes || []).map { |game_hash| deserialize_game(game_hash) }
166
+ end
167
+
168
+ def deserialize_game(game_hash)
169
+ GAME_CLASSES.fetch(game_hash[:type]).new(
170
+ date: Date.parse(game_hash[:date]),
171
+ home_opponent: Season::Opponent.new(id: game_hash[:home_opponent]),
172
+ away_opponent: Season::Opponent.new(id: game_hash[:away_opponent])
173
+ )
174
+ end
175
+
176
+ def deserialize_results(result_hashes)
177
+ (result_hashes || []).map do |result_hash|
178
+ deserialize_result(result_hash)
179
+ end
180
+ end
181
+
182
+ def deserialize_result(result_hash)
183
+ Season::Result.new(
184
+ game: deserialize_game(result_hash[:game]),
185
+ home_score: result_hash[:home_score],
186
+ away_score: result_hash[:away_score]
187
+ )
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Basketball
4
+ module App
5
+ # Knows how to read and write documents to disk.
6
+ class FileStore
7
+ def read(path)
8
+ File.read(path)
9
+ end
10
+
11
+ def write(path, contents)
12
+ dir = File.dirname(path)
13
+
14
+ FileUtils.mkdir_p(dir)
15
+
16
+ File.write(path, contents)
17
+
18
+ nil
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,30 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'room'
4
- require_relative 'room_serializer'
5
- require_relative 'player_search'
6
- require_relative 'position'
7
-
8
3
  module Basketball
9
- module Draft
4
+ module App
10
5
  # Examples:
11
- # exe/basketball-draft -o tmp/draft.json
12
- # exe/basketball-draft -i tmp/draft.json -o tmp/draft-wip.json -s 26 -p P-5,P-10 -t 10 -q PG
13
- # exe/basketball-draft -i tmp/draft-wip.json -x 2
14
- # exe/basketball-draft -i tmp/draft-wip.json -r -t 10
15
- # exe/basketball-draft -i tmp/draft-wip.json -t 10 -q SG
16
- # exe/basketball-draft -i tmp/draft-wip.json -s 30 -t 10
17
- # exe/basketball-draft -i tmp/draft-wip.json -a -r
18
- # exe/basketball-draft -i tmp/draft-wip.json -l
19
- class CLI
6
+ # exe/basketball-room -o tmp/draft.json
7
+ # exe/basketball-room -i tmp/draft.json -o tmp/draft-wip.json -s 26 -p P-5,P-10 -t 10
8
+ # exe/basketball-room -i tmp/draft-wip.json -x 2
9
+ # exe/basketball-room -i tmp/draft-wip.json -g -t 10
10
+ # exe/basketball-room -i tmp/draft-wip.json -s 30 -t 10
11
+ # exe/basketball-room -i tmp/draft-wip.json -ale
12
+ #
13
+ # exe/basketball-room -o tmp/draft-wip.json -ale
14
+ class RoomCLI
20
15
  class PlayerNotFound < StandardError; end
21
16
 
22
- attr_reader :opts, :serializer, :io
17
+ attr_reader :opts, :io, :repository
23
18
 
24
19
  def initialize(args:, io: $stdout)
25
20
  @io = io
26
- @serializer = RoomSerializer.new
27
21
  @opts = slop_parse(args)
22
+ @repository = RoomRepository.new
28
23
 
29
24
  if opts[:input].to_s.empty? && opts[:output].to_s.empty?
30
25
  io.puts('Input and/or output paths are required.')
@@ -39,49 +34,46 @@ module Basketball
39
34
  room = load_room
40
35
 
41
36
  execute(room)
37
+ status(room)
38
+ write(room)
39
+ events(room)
40
+ league(room)
41
+ query(room)
42
+
43
+ self
44
+ end
45
+
46
+ private
42
47
 
48
+ def status(room)
43
49
  io.puts
44
50
  io.puts('Status')
45
51
 
46
52
  if room.done?
47
53
  io.puts('Draft is complete!')
48
54
  else
49
- current_round = room.current_round
50
- current_round_pick = room.current_round_pick
51
- current_front_office = room.current_front_office
55
+ round = room.round
56
+ round_pick = room.round_pick
57
+ front_office = room.front_office
52
58
 
53
59
  io.puts("#{room.remaining_picks} Remaining pick(s)")
54
- io.puts("Up Next: Round #{current_round} pick #{current_round_pick} for #{current_front_office}")
60
+ io.puts("Up Next: Round #{round} pick #{round_pick} for #{front_office}")
55
61
  end
56
-
57
- write(room)
58
-
59
- log(room)
60
-
61
- league(room)
62
-
63
- query(room)
64
-
65
- self
66
62
  end
67
63
 
68
- private
69
-
70
64
  def slop_parse(args)
71
65
  Slop.parse(args) do |o|
72
- o.banner = 'Usage: basketball-draft [options] ...'
66
+ o.banner = 'Usage: basketball-room [options] ...'
73
67
 
74
- o.string '-i', '--input',
75
- 'Path to load the room from. If omitted then a new draft will be generated.'
68
+ o.string '-i', '--input', 'Path to load the Room from. If omitted then a new draft will be generated.'
76
69
  o.string '-o', '--output', 'Path to write the room to (if omitted then input path will be used)'
77
70
  o.integer '-s', '--simulate', 'Number of picks to simulate (default is 0).', default: 0
78
71
  o.bool '-a', '--simulate-all', 'Simulate the rest of the draft', default: false
79
72
  o.array '-p', '--picks', 'Comma-separated list of ordered player IDs to pick.', delimiter: ','
80
73
  o.integer '-t', '--top', 'Output the top rated available players (default is 0).', default: 0
81
- o.string '-q', '--query', "Filter TOP by position: #{Position::ALL_VALUES.join(', ')}."
82
- o.bool '-r', '--rosters', 'Output all front_office rosters.', default: false
74
+ o.bool '-l', '--league', 'Output all teams and their picks', default: false
83
75
  o.integer '-x', '--skip', 'Number of picks to skip (default is 0).', default: 0
84
- o.bool '-l', '--log', 'Output event log.', default: false
76
+ o.bool '-e', '--events', 'Output event log.', default: false
85
77
 
86
78
  o.on '-h', '--help', 'Print out help, like this is doing right now.' do
87
79
  io.puts(o)
@@ -104,33 +96,31 @@ module Basketball
104
96
 
105
97
  def generate_draft
106
98
  front_offices = 30.times.map do |i|
107
- FrontOffice.new(
108
- id: "T-#{i + 1}", name: Faker::Team.name
99
+ Draft::FrontOffice.new(
100
+ id: "T-#{i + 1}"
109
101
  )
110
102
  end
111
103
 
112
104
  players = 450.times.map do |i|
113
- Player.new(
105
+ Org::Player.new(
114
106
  id: "P-#{i + 1}",
115
- first_name: Faker::Name.first_name,
116
- last_name: Faker::Name.last_name,
117
- position: Position.random,
118
- overall: (0..100).to_a.sample
107
+ overall: (20..100).to_a.sample,
108
+ position: Org::Position.random
119
109
  )
120
110
  end
121
111
 
122
- Room.new(players:, front_offices:)
112
+ Draft::Room.new(rounds: 12, players:, front_offices:)
123
113
  end
124
114
 
125
115
  def league(room)
126
- return unless opts[:rosters]
116
+ return unless opts[:league]
127
117
 
128
118
  io.puts
129
- io.puts(room.to_league)
119
+ io.puts(room.league)
130
120
  end
131
121
 
132
- def log(room)
133
- return unless opts[:log]
122
+ def events(room)
123
+ return unless opts[:events]
134
124
 
135
125
  io.puts
136
126
  io.puts('Event Log')
@@ -138,32 +128,20 @@ module Basketball
138
128
  puts room.events
139
129
  end
140
130
 
141
- # rubocop:disable Metrics/AbcSize
142
131
  def query(room)
143
132
  top = opts[:top]
144
133
 
145
134
  return if top <= 0
146
135
 
147
- search = PlayerSearch.new(room.undrafted_players)
148
- position = opts[:query].to_s.empty? ? nil : Position.new(opts[:query])
149
- players = search.query(position:).take(opts[:top])
136
+ players = room.undrafted_players.sort_by(&:overall).reverse.take(opts[:top])
150
137
 
151
138
  io.puts
152
- io.print("Top #{top} available players")
153
-
154
- if position
155
- io.puts(" for #{position} position:")
156
- else
157
- io.puts(' for all positions:')
158
- end
159
-
139
+ io.puts("Top #{top} available players")
160
140
  io.puts(players)
161
141
  end
162
- # rubocop:enable Metrics/AbcSize
163
142
 
164
143
  def read
165
- contents = File.read(opts[:input])
166
- serializer.deserialize(contents)
144
+ repository.load(opts[:input])
167
145
  end
168
146
 
169
147
  # rubocop:disable Metrics/AbcSize
@@ -195,14 +173,14 @@ module Basketball
195
173
  event_count += 1
196
174
  end
197
175
 
198
- room.sim!(opts[:simulate]) do |event|
199
- io.puts(event)
176
+ opts[:simulate].times do
177
+ room.sim!
200
178
 
201
179
  event_count += 1
202
180
  end
203
181
 
204
182
  if opts[:simulate_all]
205
- room.sim! do |event|
183
+ room.sim_rest! do |event|
206
184
  io.puts(event)
207
185
 
208
186
  event_count += 1
@@ -215,15 +193,14 @@ module Basketball
215
193
  end
216
194
  # rubocop:enable Metrics/AbcSize
217
195
 
218
- def write(room)
219
- output = opts[:output].to_s.empty? ? opts[:input] : opts[:output]
220
-
221
- contents = serializer.serialize(room)
222
- out_dir = File.dirname(output)
196
+ def output_default_to_input
197
+ opts[:output].to_s.empty? ? opts[:input] : opts[:output]
198
+ end
223
199
 
224
- FileUtils.mkdir_p(out_dir)
200
+ def write(room)
201
+ output = output_default_to_input
225
202
 
226
- File.write(output, contents)
203
+ repository.save(output, room)
227
204
 
228
205
  io.puts
229
206
  io.puts("Draft written to: #{output}")
@@ -0,0 +1,189 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Basketball
4
+ module App
5
+ # Can load and save Room objects to JSON files.
6
+ class RoomRepository
7
+ PICK_EVENT = 'Pick'
8
+ SKIP_EVENT = 'Skip'
9
+
10
+ private_constant :PICK_EVENT, :SKIP_EVENT
11
+
12
+ attr_reader :store
13
+
14
+ def initialize(store: FileStore.new)
15
+ super()
16
+
17
+ @store = store
18
+
19
+ freeze
20
+ end
21
+
22
+ def load(path)
23
+ contents = store.read(path)
24
+
25
+ room = deserialize(contents)
26
+
27
+ room.send('id=', path)
28
+
29
+ room
30
+ end
31
+
32
+ def save(path, room)
33
+ contents = serialize(room)
34
+
35
+ store.write(path, contents)
36
+
37
+ room.send('id=', path)
38
+
39
+ room
40
+ end
41
+
42
+ private
43
+
44
+ def deserialize(string)
45
+ hash = JSON.parse(string, symbolize_names: true)
46
+
47
+ from_h(hash)
48
+ end
49
+
50
+ def serialize(object)
51
+ to_h(object).to_json
52
+ end
53
+
54
+ def from_h(hash)
55
+ front_offices = deserialize_front_offices(hash[:front_offices])
56
+ players = deserialize_players(hash[:players])
57
+ events = deserialize_events(hash[:events], players:, front_offices:)
58
+
59
+ Draft::Room.new(
60
+ rounds: hash[:rounds],
61
+ front_offices:,
62
+ players:,
63
+ events:
64
+ )
65
+ end
66
+
67
+ def to_h(room)
68
+ {
69
+ rounds: room.rounds,
70
+ front_offices: room.front_offices.map { |fo| serialize_front_office(fo) },
71
+ players: room.players.map { |p| serialize_player(p) },
72
+ events: serialize_events(room.events)
73
+ }
74
+ end
75
+
76
+ # Serialization
77
+
78
+ def serialize_player(player)
79
+ {
80
+ id: player.id,
81
+ overall: player.overall,
82
+ position: player.position&.code
83
+ }
84
+ end
85
+
86
+ def serialize_front_office(front_office)
87
+ {
88
+ id: front_office.id,
89
+ risk_level: front_office.risk_level
90
+ }
91
+ end
92
+
93
+ def serialize_events(events)
94
+ events.map do |event|
95
+ case event
96
+ when Draft::Pick
97
+ serialize_pick(event)
98
+ when Draft::Skip
99
+ serialize_skip(event)
100
+ end
101
+ end
102
+ end
103
+
104
+ def serialize_pick(event)
105
+ {
106
+ type: PICK_EVENT,
107
+ front_office: event.front_office.id,
108
+ pick: event.pick,
109
+ round: event.round,
110
+ round_pick: event.round_pick,
111
+ auto: event.auto,
112
+ player: event.player.id
113
+ }
114
+ end
115
+
116
+ def serialize_skip(event)
117
+ {
118
+ type: SKIP_EVENT,
119
+ front_office: event.front_office.id,
120
+ pick: event.pick,
121
+ round: event.round,
122
+ round_pick: event.round_pick
123
+ }
124
+ end
125
+
126
+ # Deserialization
127
+
128
+ def deserialize_player(player_hash)
129
+ Org::Player.new(
130
+ id: player_hash[:id],
131
+ overall: player_hash[:overall],
132
+ position: Org::Position.new(player_hash[:position])
133
+ )
134
+ end
135
+
136
+ def deserialize_front_office(hash)
137
+ Draft::FrontOffice.new(
138
+ id: hash[:id],
139
+ risk_level: hash[:risk_level]
140
+ )
141
+ end
142
+
143
+ def deserialize_front_offices(hashes)
144
+ (hashes || []).map { |fo| deserialize_front_office(fo) }
145
+ end
146
+
147
+ def deserialize_players(hashes)
148
+ (hashes || []).map { |hash| deserialize_player(hash) }
149
+ end
150
+
151
+ def deserialize_pick(hash, players:, front_office:)
152
+ player_id = hash[:player]
153
+ player = players.find { |p| p.id == player_id }
154
+
155
+ Draft::Pick.new(
156
+ front_office:,
157
+ pick: hash[:pick],
158
+ round: hash[:round],
159
+ round_pick: hash[:round_pick],
160
+ player:,
161
+ auto: hash[:auto]
162
+ )
163
+ end
164
+
165
+ def deserialize_skip(hash, front_office:)
166
+ Draft::Skip.new(
167
+ front_office:,
168
+ pick: hash[:pick],
169
+ round: hash[:round],
170
+ round_pick: hash[:round_pick]
171
+ )
172
+ end
173
+
174
+ def deserialize_events(hashes, players:, front_offices:)
175
+ (hashes || []).map do |hash|
176
+ front_office_id = hash[:front_office]
177
+ front_office = front_offices.find { |fo| fo.id == front_office_id }
178
+
179
+ case hash[:type]
180
+ when PICK_EVENT
181
+ deserialize_pick(hash, players:, front_office:)
182
+ when SKIP_EVENT
183
+ deserialize_skip(hash, front_office:)
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Services
4
+ require_relative 'app/file_store'
5
+
6
+ # Repositories
7
+ require_relative 'app/coordinator_repository'
8
+ require_relative 'app/room_repository'
9
+
10
+ # Controllers
11
+ require_relative 'app/coordinator_cli'
12
+ require_relative 'app/room_cli'
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Basketball
4
+ module Draft
5
+ # An assessment is given to a front office when it needs the front office to make a pick.
6
+ # This is essentially just a data-transfer object to get information to a front office to make a pick.
7
+ class Assessment
8
+ attr_reader :drafted_players,
9
+ :pick,
10
+ :round_pick,
11
+ :round,
12
+ :undrafted_players
13
+
14
+ def initialize(
15
+ drafted_players:,
16
+ pick:,
17
+ round_pick:,
18
+ round:,
19
+ undrafted_players:
20
+ )
21
+ @drafted_players = drafted_players
22
+ @pick = pick
23
+ @round = round
24
+ @round_pick = round_pick
25
+ @undrafted_players = undrafted_players
26
+
27
+ freeze
28
+ end
29
+ end
30
+ end
31
+ end
@@ -2,8 +2,9 @@
2
2
 
3
3
  module Basketball
4
4
  module Draft
5
+ # Describes what all Room events have to have to be considered an "event".
5
6
  class Event < ValueObject
6
- attr_reader_value :pick, :round, :round_pick, :front_office
7
+ value_reader :pick, :round, :round_pick, :front_office
7
8
 
8
9
  def initialize(front_office:, pick:, round:, round_pick:)
9
10
  super()
@@ -17,7 +18,7 @@ module Basketball
17
18
  end
18
19
 
19
20
  def to_s
20
- "##{pick} overall (R#{round}:P#{round_pick}) by #{front_office}"
21
+ "[##{pick} R:#{round} P:#{round_pick}] #{front_office}"
21
22
  end
22
23
  end
23
24
  end