basketball 0.0.14 → 0.0.16
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 +3 -0
- data/README.md +4 -111
- data/basketball.gemspec +1 -9
- data/lib/basketball/app/coordinator_repository.rb +2 -6
- data/lib/basketball/app/league_repository.rb +92 -3
- data/lib/basketball/app/room_repository.rb +2 -1
- data/lib/basketball/app/standings_repository.rb +69 -0
- data/lib/basketball/app.rb +1 -7
- data/lib/basketball/org/league.rb +0 -2
- data/lib/basketball/season/coordinator.rb +10 -31
- data/lib/basketball/season/record.rb +12 -6
- data/lib/basketball/season/standings.rb +16 -5
- data/lib/basketball/version.rb +1 -1
- data/lib/basketball.rb +0 -1
- metadata +5 -27
- data/exe/basketball +0 -91
- data/exe/basketball-draft-room +0 -7
- data/exe/basketball-season-coordinator +0 -7
- data/lib/basketball/app/coordinator_cli.rb +0 -227
- data/lib/basketball/app/league_serializable.rb +0 -99
- data/lib/basketball/app/room_cli.rb +0 -216
metadata
CHANGED
@@ -1,39 +1,22 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: basketball
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.16
|
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-06-
|
12
|
-
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: slop
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '4.10'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '4.10'
|
11
|
+
date: 2023-06-12 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
27
13
|
description: " This library is meant to serve as the domain for a basketball league/season
|
28
14
|
simulator/turn-based game. It models core ideas such as: players, general managers,
|
29
15
|
draft strategy, drafting, season generation, season simultation, playoff generation,
|
30
16
|
playoff simulation, and more.\n"
|
31
17
|
email:
|
32
18
|
- mattruggio@icloud.com
|
33
|
-
executables:
|
34
|
-
- basketball
|
35
|
-
- basketball-season-coordinator
|
36
|
-
- basketball-draft-room
|
19
|
+
executables: []
|
37
20
|
extensions: []
|
38
21
|
extra_rdoc_files: []
|
39
22
|
files:
|
@@ -49,20 +32,15 @@ files:
|
|
49
32
|
- README.md
|
50
33
|
- Rakefile
|
51
34
|
- basketball.gemspec
|
52
|
-
- exe/basketball
|
53
|
-
- exe/basketball-draft-room
|
54
|
-
- exe/basketball-season-coordinator
|
55
35
|
- lib/basketball.rb
|
56
36
|
- lib/basketball/app.rb
|
57
|
-
- lib/basketball/app/coordinator_cli.rb
|
58
37
|
- lib/basketball/app/coordinator_repository.rb
|
59
38
|
- lib/basketball/app/document_repository.rb
|
60
39
|
- lib/basketball/app/file_store.rb
|
61
40
|
- lib/basketball/app/in_memory_store.rb
|
62
41
|
- lib/basketball/app/league_repository.rb
|
63
|
-
- lib/basketball/app/league_serializable.rb
|
64
|
-
- lib/basketball/app/room_cli.rb
|
65
42
|
- lib/basketball/app/room_repository.rb
|
43
|
+
- lib/basketball/app/standings_repository.rb
|
66
44
|
- lib/basketball/draft.rb
|
67
45
|
- lib/basketball/draft/assessment.rb
|
68
46
|
- lib/basketball/draft/event.rb
|
data/exe/basketball
DELETED
@@ -1,91 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require 'bundler/setup'
|
5
|
-
require 'basketball'
|
6
|
-
|
7
|
-
# This is an example integration script tying all the contexts together.
|
8
|
-
# This is definitely subject to change as this library gets extended further.
|
9
|
-
|
10
|
-
store = Basketball::App::FileStore.new
|
11
|
-
room_repository = Basketball::App::RoomRepository.new(store)
|
12
|
-
league_repository = Basketball::App::LeagueRepository.new(store)
|
13
|
-
coordinator_repository = Basketball::App::CoordinatorRepository.new(store)
|
14
|
-
scheduler = Basketball::Season::Scheduler.new
|
15
|
-
|
16
|
-
seed_path = ARGV[0].to_s.empty? ? File.join('spec', 'fixtures', 'seed.json') : ARGV[0]
|
17
|
-
output_dir = ARGV[1].to_s.empty? ? 'tmp' : ARGV[1]
|
18
|
-
seed = JSON.parse(File.read(seed_path), symbolize_names: true)
|
19
|
-
|
20
|
-
league_path = File.join(output_dir, '00-league.json')
|
21
|
-
|
22
|
-
File.write(league_path, seed[:league].to_json)
|
23
|
-
|
24
|
-
front_offices = seed.dig(:league, :conferences).flat_map do |c|
|
25
|
-
c[:divisions].flat_map do |d|
|
26
|
-
d[:teams].flat_map do |t|
|
27
|
-
{ id: t[:id] }
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
room = {
|
33
|
-
rounds: 12,
|
34
|
-
front_offices:,
|
35
|
-
players: seed[:players]
|
36
|
-
}
|
37
|
-
|
38
|
-
room_input_path = File.join(output_dir, '01-room-input.json')
|
39
|
-
|
40
|
-
File.write(room_input_path, room.to_json)
|
41
|
-
|
42
|
-
room = room_repository.load(room_input_path)
|
43
|
-
|
44
|
-
room.sim_rest!
|
45
|
-
|
46
|
-
room_output_path = File.join(output_dir, '02-room-output.json')
|
47
|
-
|
48
|
-
room_repository.save(room_output_path, room)
|
49
|
-
|
50
|
-
league = league_repository.load(league_path)
|
51
|
-
|
52
|
-
room.teams.each do |team|
|
53
|
-
team.players.each do |player|
|
54
|
-
league.sign!(team:, player:)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
scheduler_input_path = File.join(output_dir, '03-scheduler-input.json')
|
59
|
-
|
60
|
-
league_repository.save(scheduler_input_path, league)
|
61
|
-
|
62
|
-
calendar = scheduler.schedule(league:)
|
63
|
-
current_date = calendar.exhibition_start_date
|
64
|
-
coordinator = Basketball::Season::Coordinator.new(league:, calendar:, current_date:)
|
65
|
-
|
66
|
-
coordinator_input_path = File.join(output_dir, '04-coordinator-input.json')
|
67
|
-
|
68
|
-
coordinator_repository.save(coordinator_input_path, coordinator)
|
69
|
-
|
70
|
-
coordinator.sim_rest!
|
71
|
-
|
72
|
-
coordinator_output_path = File.join(output_dir, '05-coordinator-output.json')
|
73
|
-
|
74
|
-
coordinator_repository.save(coordinator_output_path, coordinator)
|
75
|
-
|
76
|
-
preseason_standings = Basketball::Season::Standings.new
|
77
|
-
season_standings = Basketball::Season::Standings.new
|
78
|
-
|
79
|
-
league.teams.each do |team|
|
80
|
-
preseason_standings.register!(team)
|
81
|
-
season_standings.register!(team)
|
82
|
-
end
|
83
|
-
|
84
|
-
coordinator.exhibition_results.each { |result| preseason_standings.accept!(result) }
|
85
|
-
coordinator.regular_results.each { |result| season_standings.accept!(result) }
|
86
|
-
|
87
|
-
puts 'Preseason Standings'
|
88
|
-
puts preseason_standings
|
89
|
-
puts '--------------------------------------------'
|
90
|
-
puts 'Season Standings'
|
91
|
-
puts season_standings
|
data/exe/basketball-draft-room
DELETED
@@ -1,227 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Basketball
|
4
|
-
module App
|
5
|
-
# Examples:
|
6
|
-
# exe/basketball-season-coordinator -o tmp/coordinator.json
|
7
|
-
# exe/basketball-season-coordinator -i tmp/coordinator.json -o tmp/coordinator2.json -d 1
|
8
|
-
# exe/basketball-season-coordinator -i tmp/coordinator2.json -e
|
9
|
-
# exe/basketball-season-coordinator -i tmp/coordinator2.json -o tmp/coordinator2.json -d 2
|
10
|
-
# exe/basketball-season-coordinator -i tmp/coordinator2.json -a
|
11
|
-
#
|
12
|
-
# exe/basketball-season-coordinator -o tmp/coordinator.json -ae
|
13
|
-
class CoordinatorCLI
|
14
|
-
attr_reader :opts, :io, :coordinator_repository
|
15
|
-
|
16
|
-
def initialize(
|
17
|
-
args:,
|
18
|
-
io: $stdout,
|
19
|
-
coordinator_repository: CoordinatorRepository.new(FileStore.new)
|
20
|
-
)
|
21
|
-
raise ArgumentError, 'coordinator_repository is required' unless coordinator_repository
|
22
|
-
raise ArgumentError, 'io is required' unless io
|
23
|
-
|
24
|
-
@io = io
|
25
|
-
@opts = slop_parse(args)
|
26
|
-
@coordinator_repository = coordinator_repository
|
27
|
-
|
28
|
-
if no_input? && no_output?
|
29
|
-
io.puts('Input and/or output paths are required.')
|
30
|
-
|
31
|
-
exit
|
32
|
-
end
|
33
|
-
|
34
|
-
freeze
|
35
|
-
end
|
36
|
-
|
37
|
-
def invoke!
|
38
|
-
coordinator = read
|
39
|
-
|
40
|
-
execute(coordinator)
|
41
|
-
output_status(coordinator)
|
42
|
-
write(coordinator)
|
43
|
-
events(coordinator)
|
44
|
-
|
45
|
-
self
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def output_status(coordinator)
|
51
|
-
io.puts
|
52
|
-
io.puts('Status')
|
53
|
-
|
54
|
-
if coordinator.done?
|
55
|
-
io.puts('Coordinator is complete!')
|
56
|
-
else
|
57
|
-
io.puts("#{coordinator.days_left} Remaining day(s) (#{coordinator.total_days} total)")
|
58
|
-
io.puts("Currently on: #{coordinator.current_date}")
|
59
|
-
io.puts("#{coordinator.exhibitions_left} Remaining exhibition (#{coordinator.total_exhibitions} total)")
|
60
|
-
io.puts("#{coordinator.regulars_left} Remaining season (#{coordinator.total_regulars} total)")
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def execute(coordinator)
|
65
|
-
event_count = 0
|
66
|
-
|
67
|
-
io.puts
|
68
|
-
io.puts('New Events')
|
69
|
-
|
70
|
-
days&.times do
|
71
|
-
coordinator.sim! do |event|
|
72
|
-
io.puts(event)
|
73
|
-
|
74
|
-
event_count += 1
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
if sim_all
|
79
|
-
coordinator.sim_rest! do |event|
|
80
|
-
io.puts(event)
|
81
|
-
|
82
|
-
event_count += 1
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
io.puts("Generated #{event_count} new event(s)")
|
87
|
-
|
88
|
-
nil
|
89
|
-
end
|
90
|
-
|
91
|
-
def days
|
92
|
-
opts[:days]
|
93
|
-
end
|
94
|
-
|
95
|
-
def sim_all
|
96
|
-
opts[:sim_all]
|
97
|
-
end
|
98
|
-
|
99
|
-
def write(coordinator)
|
100
|
-
path = output? ? output : input
|
101
|
-
|
102
|
-
coordinator_repository.save(path, coordinator)
|
103
|
-
|
104
|
-
path
|
105
|
-
end
|
106
|
-
|
107
|
-
def make_league
|
108
|
-
Org::League.new(
|
109
|
-
conferences: 2.times.map do |i|
|
110
|
-
conference_id = "C#{i}"
|
111
|
-
|
112
|
-
Org::Conference.new(
|
113
|
-
id: conference_id,
|
114
|
-
divisions: 3.times.map do |j|
|
115
|
-
division_id = "#{conference_id}-D#{j}"
|
116
|
-
|
117
|
-
Org::Division.new(
|
118
|
-
id: division_id,
|
119
|
-
teams: 5.times.map do |k|
|
120
|
-
team_id = "#{division_id}-T#{k}"
|
121
|
-
|
122
|
-
Org::Team.new(
|
123
|
-
id: team_id,
|
124
|
-
players: 12.times.map do |l|
|
125
|
-
player_id = "#{team_id}-P#{l}"
|
126
|
-
|
127
|
-
Org::Player.new(
|
128
|
-
id: player_id,
|
129
|
-
overall: rand(20..100),
|
130
|
-
position: Org::Position.random
|
131
|
-
)
|
132
|
-
end
|
133
|
-
)
|
134
|
-
end
|
135
|
-
)
|
136
|
-
end
|
137
|
-
)
|
138
|
-
end
|
139
|
-
)
|
140
|
-
end
|
141
|
-
|
142
|
-
def make_coordinator
|
143
|
-
league = make_league
|
144
|
-
year = Time.now.year
|
145
|
-
calendar = Season::Scheduler.new.schedule(league:, year:)
|
146
|
-
current_date = calendar.games.min_by(&:date).date
|
147
|
-
|
148
|
-
Season::Coordinator.new(
|
149
|
-
calendar:,
|
150
|
-
current_date:,
|
151
|
-
league:
|
152
|
-
)
|
153
|
-
end
|
154
|
-
|
155
|
-
def read
|
156
|
-
coordinator =
|
157
|
-
if input?
|
158
|
-
io.puts("Coordinator loaded from: #{input}")
|
159
|
-
|
160
|
-
coordinator_repository.load(input)
|
161
|
-
else
|
162
|
-
io.puts('Input path was not provided, generating fresh coordinator')
|
163
|
-
|
164
|
-
make_coordinator
|
165
|
-
end
|
166
|
-
|
167
|
-
io.puts("Current Date: #{coordinator.current_date}")
|
168
|
-
|
169
|
-
coordinator
|
170
|
-
end
|
171
|
-
|
172
|
-
def input
|
173
|
-
opts[:input]
|
174
|
-
end
|
175
|
-
|
176
|
-
def input?
|
177
|
-
!no_input?
|
178
|
-
end
|
179
|
-
|
180
|
-
def no_input?
|
181
|
-
input.to_s.empty?
|
182
|
-
end
|
183
|
-
|
184
|
-
def output
|
185
|
-
opts[:output]
|
186
|
-
end
|
187
|
-
|
188
|
-
def no_output?
|
189
|
-
output.to_s.empty?
|
190
|
-
end
|
191
|
-
|
192
|
-
def output?
|
193
|
-
!no_output?
|
194
|
-
end
|
195
|
-
|
196
|
-
def events(coordinator)
|
197
|
-
return unless opts[:events]
|
198
|
-
|
199
|
-
io.puts
|
200
|
-
io.puts('Event Log')
|
201
|
-
|
202
|
-
puts coordinator.results
|
203
|
-
end
|
204
|
-
|
205
|
-
def slop_parse(args)
|
206
|
-
Slop.parse(args) do |o|
|
207
|
-
o.banner = 'Usage: basketball-season-coordinator [options] ...'
|
208
|
-
|
209
|
-
input_description = <<~DESC
|
210
|
-
Path to load the Coordinator from. If omitted then a new coordinator will be created.
|
211
|
-
DESC
|
212
|
-
|
213
|
-
o.string '-i', '--input', input_description.chomp
|
214
|
-
o.string '-o', '--output', 'Path to save updated coordinator. If omitted then the input path will be used.'
|
215
|
-
o.integer '-d', '--days', 'Number of days to simulate'
|
216
|
-
o.bool '-a', '--sim-all', 'Simulate the rest of the coordinator', default: false
|
217
|
-
o.bool '-e', '--events', 'Output event log.', default: false
|
218
|
-
|
219
|
-
o.on '-h', '--help', 'Print out help, like this is doing right now.' do
|
220
|
-
io.puts(o)
|
221
|
-
exit
|
222
|
-
end
|
223
|
-
end.to_h
|
224
|
-
end
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
@@ -1,99 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Basketball
|
4
|
-
module App
|
5
|
-
# Provides methods to serialize/deserialize a League object
|
6
|
-
module LeagueSerializable
|
7
|
-
# Serialization
|
8
|
-
|
9
|
-
def serialize_league(league)
|
10
|
-
{
|
11
|
-
id: league.id,
|
12
|
-
conferences: serialize_conferences(league.conferences)
|
13
|
-
}
|
14
|
-
end
|
15
|
-
|
16
|
-
def serialize_conferences(conferences)
|
17
|
-
conferences.map do |conference|
|
18
|
-
{
|
19
|
-
id: conference.id,
|
20
|
-
divisions: serialize_divisions(conference.divisions)
|
21
|
-
}
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def serialize_divisions(divisions)
|
26
|
-
divisions.map do |division|
|
27
|
-
{
|
28
|
-
id: division.id,
|
29
|
-
teams: serialize_teams(division.teams)
|
30
|
-
}
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def serialize_teams(teams)
|
35
|
-
teams.map do |team|
|
36
|
-
{
|
37
|
-
id: team.id,
|
38
|
-
players: serialize_players(team.players)
|
39
|
-
}
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def serialize_players(players)
|
44
|
-
players.map do |player|
|
45
|
-
{
|
46
|
-
id: player.id,
|
47
|
-
overall: player.overall,
|
48
|
-
position: player.position&.code
|
49
|
-
}
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Deserialization
|
54
|
-
|
55
|
-
def deserialize_league(league_hash)
|
56
|
-
Org::League.new(
|
57
|
-
conferences: deserialize_conferences(league_hash[:conferences])
|
58
|
-
)
|
59
|
-
end
|
60
|
-
|
61
|
-
def deserialize_conferences(conference_hashes)
|
62
|
-
(conference_hashes || []).map do |conference_hash|
|
63
|
-
Org::Conference.new(
|
64
|
-
id: conference_hash[:id],
|
65
|
-
divisions: deserialize_divisions(conference_hash[:divisions])
|
66
|
-
)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def deserialize_divisions(division_hashes)
|
71
|
-
(division_hashes || []).map do |division_hash|
|
72
|
-
Org::Division.new(
|
73
|
-
id: division_hash[:id],
|
74
|
-
teams: deserialize_teams(division_hash[:teams])
|
75
|
-
)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def deserialize_teams(team_hashes)
|
80
|
-
(team_hashes || []).map do |team_hash|
|
81
|
-
Org::Team.new(
|
82
|
-
id: team_hash[:id],
|
83
|
-
players: deserialize_players(team_hash[:players])
|
84
|
-
)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def deserialize_players(player_hashes)
|
89
|
-
(player_hashes || []).map do |player_hash|
|
90
|
-
Org::Player.new(
|
91
|
-
id: player_hash[:id],
|
92
|
-
overall: player_hash[:overall],
|
93
|
-
position: Org::Position.new(player_hash[:position])
|
94
|
-
)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
@@ -1,216 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Basketball
|
4
|
-
module App
|
5
|
-
# Examples:
|
6
|
-
# exe/basketball-draft-room -o tmp/draft.json
|
7
|
-
# exe/basketball-draft-room -i tmp/draft.json -o tmp/draft-wip.json -s 26 -p P-5,P-10 -l 10
|
8
|
-
# exe/basketball-draft-room -i tmp/draft-wip.json -x 2
|
9
|
-
# exe/basketball-draft-room -i tmp/draft-wip.json -g -l 10
|
10
|
-
# exe/basketball-draft-room -i tmp/draft-wip.json -s 30 -l 10
|
11
|
-
# exe/basketball-draft-room -i tmp/draft-wip.json -ate
|
12
|
-
class RoomCLI
|
13
|
-
class PlayerNotFound < StandardError; end
|
14
|
-
|
15
|
-
attr_reader :opts,
|
16
|
-
:io,
|
17
|
-
:room_repository
|
18
|
-
|
19
|
-
def initialize(
|
20
|
-
args:,
|
21
|
-
io: $stdout,
|
22
|
-
room_repository: RoomRepository.new(FileStore.new)
|
23
|
-
)
|
24
|
-
@io = io
|
25
|
-
@opts = slop_parse(args)
|
26
|
-
@room_repository = room_repository
|
27
|
-
|
28
|
-
if opts[:input].to_s.empty? && opts[:output].to_s.empty?
|
29
|
-
io.puts('Input and/or output paths are required.')
|
30
|
-
|
31
|
-
exit
|
32
|
-
end
|
33
|
-
|
34
|
-
freeze
|
35
|
-
end
|
36
|
-
|
37
|
-
def invoke!
|
38
|
-
room = load_room
|
39
|
-
|
40
|
-
execute(room)
|
41
|
-
status(room)
|
42
|
-
write(room)
|
43
|
-
events(room)
|
44
|
-
teams(room)
|
45
|
-
query(room)
|
46
|
-
|
47
|
-
self
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def status(room)
|
53
|
-
io.puts
|
54
|
-
io.puts('Status')
|
55
|
-
|
56
|
-
if room.done?
|
57
|
-
io.puts('Draft is complete!')
|
58
|
-
else
|
59
|
-
round = room.round
|
60
|
-
round_pick = room.round_pick
|
61
|
-
front_office = room.front_office
|
62
|
-
|
63
|
-
io.puts("#{room.remaining_picks} Remaining pick(s)")
|
64
|
-
io.puts("Up Next: Round #{round} pick #{round_pick} for #{front_office}")
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def slop_parse(args)
|
69
|
-
Slop.parse(args) do |o|
|
70
|
-
o.banner = 'Usage: basketball-draft-room [options] ...'
|
71
|
-
|
72
|
-
o.string '-i', '--input', 'Path to load the Room from. If omitted then a new draft will be generated.'
|
73
|
-
o.string '-o', '--output', 'Path to write the room to (if omitted then input path will be used)'
|
74
|
-
o.integer '-s', '--simulate', 'Number of picks to simulate (default is 0).', default: 0
|
75
|
-
o.bool '-a', '--simulate-all', 'Simulate the rest of the draft', default: false
|
76
|
-
o.array '-p', '--picks', 'Comma-separated list of ordered player IDs to pick.', delimiter: ','
|
77
|
-
o.integer '-l', '--list', 'List the top rated available players (default is 0).', default: 0
|
78
|
-
o.bool '-t', '--teams', 'Output all teams and their picks', default: false
|
79
|
-
o.integer '-x', '--skip', 'Number of picks to skip (default is 0).', default: 0
|
80
|
-
o.bool '-e', '--events', 'Output event log.', default: false
|
81
|
-
|
82
|
-
o.on '-h', '--help', 'Print out help, like this is doing right now.' do
|
83
|
-
io.puts(o)
|
84
|
-
exit
|
85
|
-
end
|
86
|
-
end.to_h
|
87
|
-
end
|
88
|
-
|
89
|
-
def load_room
|
90
|
-
if opts[:input].to_s.empty?
|
91
|
-
io.puts('Input path was not provided, generating fresh front_offices and players')
|
92
|
-
|
93
|
-
generate_draft
|
94
|
-
else
|
95
|
-
io.puts("Draft loaded from: #{opts[:input]}")
|
96
|
-
|
97
|
-
read
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def generate_draft
|
102
|
-
front_offices = 30.times.map do |i|
|
103
|
-
Draft::FrontOffice.new(
|
104
|
-
id: "T-#{i + 1}"
|
105
|
-
)
|
106
|
-
end
|
107
|
-
|
108
|
-
players = 450.times.map do |i|
|
109
|
-
Org::Player.new(
|
110
|
-
id: "P-#{i + 1}",
|
111
|
-
overall: (20..100).to_a.sample,
|
112
|
-
position: Org::Position.random
|
113
|
-
)
|
114
|
-
end
|
115
|
-
|
116
|
-
Draft::Room.new(rounds: 12, players:, front_offices:)
|
117
|
-
end
|
118
|
-
|
119
|
-
def teams(room)
|
120
|
-
return unless opts[:teams]
|
121
|
-
|
122
|
-
io.puts
|
123
|
-
io.puts(room.teams)
|
124
|
-
end
|
125
|
-
|
126
|
-
def events(room)
|
127
|
-
return unless opts[:events]
|
128
|
-
|
129
|
-
io.puts
|
130
|
-
io.puts('Event Log')
|
131
|
-
|
132
|
-
puts room.events
|
133
|
-
end
|
134
|
-
|
135
|
-
def query(room)
|
136
|
-
list = opts[:list]
|
137
|
-
|
138
|
-
return if list <= 0
|
139
|
-
|
140
|
-
players = room.undrafted_players.sort_by(&:overall).reverse.take(opts[:list])
|
141
|
-
|
142
|
-
io.puts
|
143
|
-
io.puts("Top #{list} available players")
|
144
|
-
io.puts(players)
|
145
|
-
end
|
146
|
-
|
147
|
-
def read
|
148
|
-
room_repository.load(opts[:input])
|
149
|
-
end
|
150
|
-
|
151
|
-
# rubocop:disable Metrics/AbcSize
|
152
|
-
def execute(room)
|
153
|
-
event_count = 0
|
154
|
-
|
155
|
-
io.puts
|
156
|
-
io.puts('New Events')
|
157
|
-
|
158
|
-
(opts[:picks] || []).each do |id|
|
159
|
-
break if room.done?
|
160
|
-
|
161
|
-
player = room.players.find { |p| p.id == id.to_s.upcase }
|
162
|
-
|
163
|
-
raise PlayerNotFound, "player not found by id: #{id}" unless player
|
164
|
-
|
165
|
-
event = room.pick!(player)
|
166
|
-
|
167
|
-
io.puts(event)
|
168
|
-
|
169
|
-
event_count += 1
|
170
|
-
end
|
171
|
-
|
172
|
-
opts[:skip].times do
|
173
|
-
event = room.skip!
|
174
|
-
|
175
|
-
io.puts(event)
|
176
|
-
|
177
|
-
event_count += 1
|
178
|
-
end
|
179
|
-
|
180
|
-
opts[:simulate].times do
|
181
|
-
room.sim!
|
182
|
-
|
183
|
-
event_count += 1
|
184
|
-
end
|
185
|
-
|
186
|
-
if opts[:simulate_all]
|
187
|
-
room.sim_rest! do |event|
|
188
|
-
io.puts(event)
|
189
|
-
|
190
|
-
event_count += 1
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
io.puts("Generated #{event_count} new event(s)")
|
195
|
-
|
196
|
-
nil
|
197
|
-
end
|
198
|
-
# rubocop:enable Metrics/AbcSize
|
199
|
-
|
200
|
-
def output_default_to_input
|
201
|
-
opts[:output].to_s.empty? ? opts[:input] : opts[:output]
|
202
|
-
end
|
203
|
-
|
204
|
-
def write(room)
|
205
|
-
output = output_default_to_input
|
206
|
-
|
207
|
-
room_repository.save(output, room)
|
208
|
-
|
209
|
-
io.puts
|
210
|
-
io.puts("Draft written to: #{output}")
|
211
|
-
|
212
|
-
nil
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|