basketball 0.0.7 → 0.0.9
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 +4 -4
- data/.rubocop.yml +9 -19
- data/CHANGELOG.md +1 -31
- data/README.md +72 -91
- data/basketball.gemspec +3 -6
- data/exe/{basketball-schedule → basketball-coordinator} +1 -1
- data/exe/{basketball-draft → basketball-room} +1 -1
- data/lib/basketball/app/coordinator_cli.rb +243 -0
- data/lib/basketball/app/coordinator_repository.rb +191 -0
- data/lib/basketball/app/file_store.rb +22 -0
- data/lib/basketball/app/room_cli.rb +212 -0
- data/lib/basketball/app/room_repository.rb +189 -0
- data/lib/basketball/app.rb +12 -0
- data/lib/basketball/draft/assessment.rb +31 -0
- data/lib/basketball/{drafting → draft}/event.rb +4 -3
- data/lib/basketball/draft/front_office.rb +99 -0
- data/lib/basketball/draft/pick.rb +32 -0
- data/lib/basketball/draft/room.rb +221 -0
- data/lib/basketball/{drafting/player_search.rb → draft/scout.rb} +5 -10
- data/lib/basketball/draft/skip.rb +12 -0
- data/lib/basketball/draft.rb +16 -0
- data/lib/basketball/entity.rb +10 -4
- data/lib/basketball/org/league.rb +73 -0
- data/lib/basketball/org/player.rb +26 -0
- data/lib/basketball/{drafting → org}/position.rb +3 -2
- data/lib/basketball/org/team.rb +38 -0
- data/lib/basketball/org.rb +12 -0
- data/lib/basketball/season/arena.rb +112 -0
- data/lib/basketball/season/calendar.rb +90 -0
- data/lib/basketball/season/coordinator.rb +239 -0
- data/lib/basketball/{scheduling/preseason_game.rb → season/exhibition.rb} +3 -2
- data/lib/basketball/season/game.rb +37 -0
- data/lib/basketball/season/matchup.rb +27 -0
- data/lib/basketball/season/opponent.rb +15 -0
- data/lib/basketball/season/regular.rb +9 -0
- data/lib/basketball/season/result.rb +37 -0
- data/lib/basketball/season.rb +16 -0
- data/lib/basketball/value_object.rb +4 -1
- data/lib/basketball/version.rb +1 -1
- data/lib/basketball.rb +11 -6
- metadata +40 -52
- data/lib/basketball/drafting/cli.rb +0 -235
- data/lib/basketball/drafting/engine.rb +0 -221
- data/lib/basketball/drafting/engine_serializer.rb +0 -186
- data/lib/basketball/drafting/front_office.rb +0 -92
- data/lib/basketball/drafting/league.rb +0 -70
- data/lib/basketball/drafting/pick_event.rb +0 -25
- data/lib/basketball/drafting/player.rb +0 -43
- data/lib/basketball/drafting/roster.rb +0 -37
- data/lib/basketball/drafting/sim_event.rb +0 -23
- data/lib/basketball/drafting/skip_event.rb +0 -13
- data/lib/basketball/drafting.rb +0 -9
- data/lib/basketball/scheduling/calendar.rb +0 -121
- data/lib/basketball/scheduling/calendar_serializer.rb +0 -94
- data/lib/basketball/scheduling/cli.rb +0 -198
- data/lib/basketball/scheduling/conference.rb +0 -57
- data/lib/basketball/scheduling/coordinator.rb +0 -180
- data/lib/basketball/scheduling/division.rb +0 -43
- data/lib/basketball/scheduling/game.rb +0 -32
- data/lib/basketball/scheduling/league.rb +0 -114
- data/lib/basketball/scheduling/league_serializer.rb +0 -99
- data/lib/basketball/scheduling/season_game.rb +0 -8
- data/lib/basketball/scheduling/team.rb +0 -21
- data/lib/basketball/scheduling.rb +0 -17
@@ -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
|
@@ -0,0 +1,212 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Basketball
|
4
|
+
module App
|
5
|
+
# Examples:
|
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
|
15
|
+
class PlayerNotFound < StandardError; end
|
16
|
+
|
17
|
+
attr_reader :opts, :io, :repository
|
18
|
+
|
19
|
+
def initialize(args:, io: $stdout)
|
20
|
+
@io = io
|
21
|
+
@opts = slop_parse(args)
|
22
|
+
@repository = RoomRepository.new
|
23
|
+
|
24
|
+
if opts[:input].to_s.empty? && opts[:output].to_s.empty?
|
25
|
+
io.puts('Input and/or output paths are required.')
|
26
|
+
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
|
30
|
+
freeze
|
31
|
+
end
|
32
|
+
|
33
|
+
def invoke!
|
34
|
+
room = load_room
|
35
|
+
|
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
|
47
|
+
|
48
|
+
def status(room)
|
49
|
+
io.puts
|
50
|
+
io.puts('Status')
|
51
|
+
|
52
|
+
if room.done?
|
53
|
+
io.puts('Draft is complete!')
|
54
|
+
else
|
55
|
+
round = room.round
|
56
|
+
round_pick = room.round_pick
|
57
|
+
front_office = room.front_office
|
58
|
+
|
59
|
+
io.puts("#{room.remaining_picks} Remaining pick(s)")
|
60
|
+
io.puts("Up Next: Round #{round} pick #{round_pick} for #{front_office}")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def slop_parse(args)
|
65
|
+
Slop.parse(args) do |o|
|
66
|
+
o.banner = 'Usage: basketball-room [options] ...'
|
67
|
+
|
68
|
+
o.string '-i', '--input', 'Path to load the Room from. If omitted then a new draft will be generated.'
|
69
|
+
o.string '-o', '--output', 'Path to write the room to (if omitted then input path will be used)'
|
70
|
+
o.integer '-s', '--simulate', 'Number of picks to simulate (default is 0).', default: 0
|
71
|
+
o.bool '-a', '--simulate-all', 'Simulate the rest of the draft', default: false
|
72
|
+
o.array '-p', '--picks', 'Comma-separated list of ordered player IDs to pick.', delimiter: ','
|
73
|
+
o.integer '-t', '--top', 'Output the top rated available players (default is 0).', default: 0
|
74
|
+
o.bool '-l', '--league', 'Output all teams and their picks', default: false
|
75
|
+
o.integer '-x', '--skip', 'Number of picks to skip (default is 0).', default: 0
|
76
|
+
o.bool '-e', '--events', 'Output event log.', default: false
|
77
|
+
|
78
|
+
o.on '-h', '--help', 'Print out help, like this is doing right now.' do
|
79
|
+
io.puts(o)
|
80
|
+
exit
|
81
|
+
end
|
82
|
+
end.to_h
|
83
|
+
end
|
84
|
+
|
85
|
+
def load_room
|
86
|
+
if opts[:input].to_s.empty?
|
87
|
+
io.puts('Input path was not provided, generating fresh front_offices and players')
|
88
|
+
|
89
|
+
generate_draft
|
90
|
+
else
|
91
|
+
io.puts("Draft loaded from: #{opts[:input]}")
|
92
|
+
|
93
|
+
read
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def generate_draft
|
98
|
+
front_offices = 30.times.map do |i|
|
99
|
+
Draft::FrontOffice.new(
|
100
|
+
id: "T-#{i + 1}"
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
players = 450.times.map do |i|
|
105
|
+
Org::Player.new(
|
106
|
+
id: "P-#{i + 1}",
|
107
|
+
overall: (20..100).to_a.sample,
|
108
|
+
position: Org::Position.random
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
Draft::Room.new(rounds: 12, players:, front_offices:)
|
113
|
+
end
|
114
|
+
|
115
|
+
def league(room)
|
116
|
+
return unless opts[:league]
|
117
|
+
|
118
|
+
io.puts
|
119
|
+
io.puts(room.league)
|
120
|
+
end
|
121
|
+
|
122
|
+
def events(room)
|
123
|
+
return unless opts[:events]
|
124
|
+
|
125
|
+
io.puts
|
126
|
+
io.puts('Event Log')
|
127
|
+
|
128
|
+
puts room.events
|
129
|
+
end
|
130
|
+
|
131
|
+
def query(room)
|
132
|
+
top = opts[:top]
|
133
|
+
|
134
|
+
return if top <= 0
|
135
|
+
|
136
|
+
players = room.undrafted_players.sort_by(&:overall).reverse.take(opts[:top])
|
137
|
+
|
138
|
+
io.puts
|
139
|
+
io.puts("Top #{top} available players")
|
140
|
+
io.puts(players)
|
141
|
+
end
|
142
|
+
|
143
|
+
def read
|
144
|
+
repository.load(opts[:input])
|
145
|
+
end
|
146
|
+
|
147
|
+
# rubocop:disable Metrics/AbcSize
|
148
|
+
def execute(room)
|
149
|
+
event_count = 0
|
150
|
+
|
151
|
+
io.puts
|
152
|
+
io.puts('New Events')
|
153
|
+
|
154
|
+
(opts[:picks] || []).each do |id|
|
155
|
+
break if room.done?
|
156
|
+
|
157
|
+
player = room.players.find { |p| p.id == id.to_s.upcase }
|
158
|
+
|
159
|
+
raise PlayerNotFound, "player not found by id: #{id}" unless player
|
160
|
+
|
161
|
+
event = room.pick!(player)
|
162
|
+
|
163
|
+
io.puts(event)
|
164
|
+
|
165
|
+
event_count += 1
|
166
|
+
end
|
167
|
+
|
168
|
+
opts[:skip].times do
|
169
|
+
event = room.skip!
|
170
|
+
|
171
|
+
io.puts(event)
|
172
|
+
|
173
|
+
event_count += 1
|
174
|
+
end
|
175
|
+
|
176
|
+
opts[:simulate].times do
|
177
|
+
room.sim!
|
178
|
+
|
179
|
+
event_count += 1
|
180
|
+
end
|
181
|
+
|
182
|
+
if opts[:simulate_all]
|
183
|
+
room.sim_rest! do |event|
|
184
|
+
io.puts(event)
|
185
|
+
|
186
|
+
event_count += 1
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
io.puts("Generated #{event_count} new event(s)")
|
191
|
+
|
192
|
+
nil
|
193
|
+
end
|
194
|
+
# rubocop:enable Metrics/AbcSize
|
195
|
+
|
196
|
+
def output_default_to_input
|
197
|
+
opts[:output].to_s.empty? ? opts[:input] : opts[:output]
|
198
|
+
end
|
199
|
+
|
200
|
+
def write(room)
|
201
|
+
output = output_default_to_input
|
202
|
+
|
203
|
+
repository.save(output, room)
|
204
|
+
|
205
|
+
io.puts
|
206
|
+
io.puts("Draft written to: #{output}")
|
207
|
+
|
208
|
+
nil
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
@@ -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
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Basketball
|
4
|
-
module
|
4
|
+
module Draft
|
5
|
+
# Describes what all Room events have to have to be considered an "event".
|
5
6
|
class Event < ValueObject
|
6
|
-
|
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}
|
21
|
+
"[##{pick} R:#{round} P:#{round_pick}] #{front_office}"
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|