basketball 0.0.14 → 0.0.16
Sign up to get free protection for your applications and to get access to all the features.
- 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
|