basketball 0.0.14 → 0.0.15
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/README.md +1 -109
- data/basketball.gemspec +1 -9
- data/lib/basketball/app/coordinator_repository.rb +2 -6
- data/lib/basketball/app/league_repository.rb +91 -2
- data/lib/basketball/app/room_repository.rb +1 -0
- data/lib/basketball/app.rb +0 -7
- data/lib/basketball/org/league.rb +0 -2
- data/lib/basketball/season/coordinator.rb +10 -31
- data/lib/basketball/version.rb +1 -1
- data/lib/basketball.rb +0 -1
- metadata +4 -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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27530180da34588494d04824d1fe1e9a6bfd4e0d94adc98afde3f659b070759c
|
4
|
+
data.tar.gz: 4f8e961e2e8ac1bedd5d0869d5f5f8e0e2498cb24465ef0d4505f20d4219b7fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bbb24ef7d1f192e39dd3e0740d60210e47fcdc041e6b69ec8d9a2897a39514dca775439c8c2894f228afc6ef8ebedf2005a83ea7b8817d00247a69e5e0ae2177
|
7
|
+
data.tar.gz: 3c24e207c24e33c49baadb8bf13f8107a2bea9dc1d8bf6404601551635ef9a375f03f4b27da0b18118ef37eea55cda7d7e24b2572fd1649bc012d3a7081c9928
|
data/README.md
CHANGED
@@ -12,11 +12,8 @@ Element | Description
|
|
12
12
|
:------------ | :-----------
|
13
13
|
**Arena** | Determines exhibition and regular season game outcomes.
|
14
14
|
**Assessment** | When the Room needs to know who a Front Office wants to select, the Room will send the Front Office an Assessment. The Assessment is a report of where the team currently stands: players picked, players available, and round information.
|
15
|
-
**basketball-draft-room** | Command-line executable script showing an example of how to consume the draft room aggregate root.
|
16
|
-
**basketball-season-coordinator** | Command-line executable script showing an example of how to consume the season coordinator aggregate root.
|
17
15
|
**Calendar** | Stores important boundary dates (exhibition start, exhibition end, season start, and season end).
|
18
16
|
**Conference** | A collection of Divisions.
|
19
|
-
**Coordinator CLI** | Underlying Ruby class that powers the `basketball-season-coordinator` script. Basically a terminal wrapper over the Coordinator object.
|
20
17
|
**Coordinator Repository** | Understands how to save and load Coordinator objects from JSON files on disk.
|
21
18
|
**Coordinator** | Object which can take a League, Calendar, Games, and an Arena and provide an iterable interface to enumerate through days and simulate games as results.
|
22
19
|
**Detail** | Re-representation of a Result object but from a specific team's perspective.
|
@@ -25,7 +22,7 @@ Element | Description
|
|
25
22
|
**Exhibition** | Pre-season game which has no impact to team record.
|
26
23
|
**External Dependency** | Some outside system which this library or portions of this library are dependent on.
|
27
24
|
**File Store** | Implements a store that can interact with the underlying File System.
|
28
|
-
**File System** | Local operating system that
|
25
|
+
**File System** | Local operating system that repositories can use as their underlying persistence layer.
|
29
26
|
**Front Office** | Identifiable as a team, contains logic for how to auto-pick draft selections. Meant to be subclassed and extended to include more intricate player selection logic as the base will simply randomly select a player.
|
30
27
|
**Game** | Matches up a date with two teams (home and away) to represent a coordinatord match-up.
|
31
28
|
**League Repository** | Understands how to save and load League objects from JSON files on disk.
|
@@ -37,7 +34,6 @@ Element | Description
|
|
37
34
|
**Record** | Represents a team's overall record.
|
38
35
|
**Regular** | Game that counts towards regular season record.
|
39
36
|
**Result** | The outcome of a game (typically with a home and away score).
|
40
|
-
**Room CLI** | Underlying Ruby class that powers the `basketball-draft-room` script. Basically a terminal wrapper for the Room object.
|
41
37
|
**Room Repository** | Understands how to save and load Room objects from JSON files on disk.
|
42
38
|
**Room** | Main object responsible for providing an iterable interface capable of executing a draft, pick by pick.
|
43
39
|
**Scheduler** | Knows how to take a League and a year and generate a game-populated calendar.
|
@@ -72,70 +68,6 @@ The input for the main object `Basketball::Draft::Room` is an array of teams (`B
|
|
72
68
|
* **Basketball::Draft::Room#pick!(player)**: Pick an exact player for the current front office.
|
73
69
|
* **Basketball::Draft::Room#sim_rest!**: Simulate the rest of the picks.
|
74
70
|
|
75
|
-
#### Command Line Interface
|
76
|
-
|
77
|
-
This library ships with an example of how the Draft module could be used implemented as a command-line executable script. The script is file-based and will de-serialize into a Room object, execute operations, then serialize and write it back to disk.
|
78
|
-
|
79
|
-
###### Generate a Fresh Draft
|
80
|
-
|
81
|
-
```zsh
|
82
|
-
basketball-draft-room -o tmp/draft.json
|
83
|
-
```
|
84
|
-
|
85
|
-
###### N Top Available Players
|
86
|
-
|
87
|
-
```zsh
|
88
|
-
basketball-draft-room -i tmp/draft.json -t 10
|
89
|
-
```
|
90
|
-
|
91
|
-
###### N Top Available Players for a Position
|
92
|
-
|
93
|
-
```zsh
|
94
|
-
basketball-draft-room -i tmp/draft.json -t 10 -q PG
|
95
|
-
```
|
96
|
-
|
97
|
-
###### Output League
|
98
|
-
|
99
|
-
```zsh
|
100
|
-
basketball-draft-room -i tmp/draft.json -l
|
101
|
-
```
|
102
|
-
|
103
|
-
###### Output Event Log
|
104
|
-
|
105
|
-
```zsh
|
106
|
-
basketball-draft-room -i tmp/draft.json -e
|
107
|
-
```
|
108
|
-
|
109
|
-
###### Simulate N Picks
|
110
|
-
|
111
|
-
```zsh
|
112
|
-
basketball-draft-room -i tmp/draft.json -s 10
|
113
|
-
```
|
114
|
-
|
115
|
-
###### Skip N Picks
|
116
|
-
|
117
|
-
```zsh
|
118
|
-
basketball-draft-room -i tmp/draft.json -x 10
|
119
|
-
```
|
120
|
-
|
121
|
-
###### Pick Players
|
122
|
-
|
123
|
-
```zsh
|
124
|
-
basketball-draft-room -i tmp/draft.json -p P-100,P-200,P-300
|
125
|
-
```
|
126
|
-
|
127
|
-
###### Simulate the Rest of the Draft
|
128
|
-
|
129
|
-
```zsh
|
130
|
-
basketball-draft-room -i tmp/draft.json -a
|
131
|
-
```
|
132
|
-
|
133
|
-
###### Help Menu
|
134
|
-
|
135
|
-
```zsh
|
136
|
-
basketball-draft-room -h
|
137
|
-
```
|
138
|
-
|
139
71
|
### Season Module
|
140
72
|
|
141
73
|
The Season module knows how to execute a calendar of games for a League and generate results. The main object is the `Basketball::Season::Coordinator` class. Once instantiated there are four main methods:
|
@@ -143,46 +75,6 @@ The Season module knows how to execute a calendar of games for a League and gene
|
|
143
75
|
* **Basketball::Season::Coordinator#sim!**: Simulate the next day of games.
|
144
76
|
* **Basketball::Season::Coordinator#sim_rest!**: Simulate the rest of the games.
|
145
77
|
|
146
|
-
#### Command Line Interface
|
147
|
-
|
148
|
-
This library ships with an example of how the Season module could be used implemented as a command-line executable script. The script is file-based and will de-serialize into a Coordinator object, execute operations, then serialize and write it back to disk.
|
149
|
-
|
150
|
-
###### Generate Random coordinator
|
151
|
-
|
152
|
-
```zsh
|
153
|
-
exe/basketball-season-coordinator -o tmp/coordinator.json
|
154
|
-
```
|
155
|
-
|
156
|
-
###### Sim One Day and Save to New File
|
157
|
-
|
158
|
-
```zsh
|
159
|
-
exe/basketball-season-coordinator -i tmp/coordinator.json -o tmp/coordinator2.json -d 1
|
160
|
-
```
|
161
|
-
|
162
|
-
###### Output Event Log
|
163
|
-
|
164
|
-
```zsh
|
165
|
-
exe/basketball-season-coordinator -i tmp/coordinator.json -e
|
166
|
-
```
|
167
|
-
|
168
|
-
###### Sim Two Days and Save To Input File
|
169
|
-
|
170
|
-
```zsh
|
171
|
-
exe/basketball-season-coordinator -i tmp/coordinator.json -d 2
|
172
|
-
```
|
173
|
-
|
174
|
-
###### Sim Rest of Calendar
|
175
|
-
|
176
|
-
```zsh
|
177
|
-
exe/basketball-season-coordinator -i tmp/coordinator.json -a
|
178
|
-
```
|
179
|
-
|
180
|
-
###### Help Menu
|
181
|
-
|
182
|
-
```zsh
|
183
|
-
basketball-season-coordinator -h
|
184
|
-
```
|
185
|
-
|
186
78
|
## Contributing
|
187
79
|
|
188
80
|
### Development Environment Configuration
|
data/basketball.gemspec
CHANGED
@@ -15,13 +15,7 @@ Gem::Specification.new do |s|
|
|
15
15
|
s.email = ['mattruggio@icloud.com']
|
16
16
|
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(.github|bin|docs|spec)/}) }
|
17
17
|
s.bindir = 'exe'
|
18
|
-
|
19
|
-
s.executables = %w[
|
20
|
-
basketball
|
21
|
-
basketball-season-coordinator
|
22
|
-
basketball-draft-room
|
23
|
-
]
|
24
|
-
|
18
|
+
s.executables = %w[]
|
25
19
|
s.homepage = 'https://github.com/mattruggio/basketball'
|
26
20
|
s.license = 'MIT'
|
27
21
|
s.metadata = {
|
@@ -34,6 +28,4 @@ Gem::Specification.new do |s|
|
|
34
28
|
}
|
35
29
|
|
36
30
|
s.required_ruby_version = '>= 3.2.1'
|
37
|
-
|
38
|
-
s.add_dependency('slop', '~>4.10')
|
39
31
|
end
|
@@ -4,8 +4,6 @@ module Basketball
|
|
4
4
|
module App
|
5
5
|
# Knows how to flatten a Coordinator instance and rehydrate one from JSON and/or a Ruby hash.
|
6
6
|
class CoordinatorRepository < DocumentRepository
|
7
|
-
include LeagueSerializable
|
8
|
-
|
9
7
|
GAME_CLASSES = {
|
10
8
|
'Exhibition' => Season::Exhibition,
|
11
9
|
'Regular' => Season::Regular
|
@@ -19,8 +17,7 @@ module Basketball
|
|
19
17
|
Season::Coordinator.new(
|
20
18
|
calendar: deserialize_calendar(hash[:calendar]),
|
21
19
|
current_date: Date.parse(hash[:current_date]),
|
22
|
-
results: deserialize_results(hash[:results])
|
23
|
-
league: deserialize_league(hash[:league])
|
20
|
+
results: deserialize_results(hash[:results])
|
24
21
|
)
|
25
22
|
end
|
26
23
|
|
@@ -29,8 +26,7 @@ module Basketball
|
|
29
26
|
id: coordinator.id,
|
30
27
|
calendar: serialize_calendar(coordinator.calendar),
|
31
28
|
current_date: coordinator.current_date.to_s,
|
32
|
-
results: serialize_results(coordinator.results)
|
33
|
-
league: serialize_league(coordinator.league)
|
29
|
+
results: serialize_results(coordinator.results)
|
34
30
|
}
|
35
31
|
end
|
36
32
|
|
@@ -4,8 +4,6 @@ module Basketball
|
|
4
4
|
module App
|
5
5
|
# Knows how to flatten a League instance and rehydrate one from JSON and/or a Ruby hash.
|
6
6
|
class LeagueRepository < DocumentRepository
|
7
|
-
include LeagueSerializable
|
8
|
-
|
9
7
|
private
|
10
8
|
|
11
9
|
def from_h(hash)
|
@@ -15,6 +13,97 @@ module Basketball
|
|
15
13
|
def to_h(league)
|
16
14
|
serialize_league(league)
|
17
15
|
end
|
16
|
+
|
17
|
+
# Serialization
|
18
|
+
|
19
|
+
def serialize_league(league)
|
20
|
+
{
|
21
|
+
id: league.id,
|
22
|
+
conferences: serialize_conferences(league.conferences)
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def serialize_conferences(conferences)
|
27
|
+
conferences.map do |conference|
|
28
|
+
{
|
29
|
+
id: conference.id,
|
30
|
+
divisions: serialize_divisions(conference.divisions)
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def serialize_divisions(divisions)
|
36
|
+
divisions.map do |division|
|
37
|
+
{
|
38
|
+
id: division.id,
|
39
|
+
teams: serialize_teams(division.teams)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def serialize_teams(teams)
|
45
|
+
teams.map do |team|
|
46
|
+
{
|
47
|
+
id: team.id,
|
48
|
+
players: serialize_players(team.players)
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def serialize_players(players)
|
54
|
+
players.map do |player|
|
55
|
+
{
|
56
|
+
id: player.id,
|
57
|
+
overall: player.overall,
|
58
|
+
position: player.position&.code
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Deserialization
|
64
|
+
|
65
|
+
def deserialize_league(league_hash)
|
66
|
+
Org::League.new(
|
67
|
+
conferences: deserialize_conferences(league_hash[:conferences])
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
def deserialize_conferences(conference_hashes)
|
72
|
+
(conference_hashes || []).map do |conference_hash|
|
73
|
+
Org::Conference.new(
|
74
|
+
id: conference_hash[:id],
|
75
|
+
divisions: deserialize_divisions(conference_hash[:divisions])
|
76
|
+
)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def deserialize_divisions(division_hashes)
|
81
|
+
(division_hashes || []).map do |division_hash|
|
82
|
+
Org::Division.new(
|
83
|
+
id: division_hash[:id],
|
84
|
+
teams: deserialize_teams(division_hash[:teams])
|
85
|
+
)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def deserialize_teams(team_hashes)
|
90
|
+
(team_hashes || []).map do |team_hash|
|
91
|
+
Org::Team.new(
|
92
|
+
id: team_hash[:id],
|
93
|
+
players: deserialize_players(team_hash[:players])
|
94
|
+
)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def deserialize_players(player_hashes)
|
99
|
+
(player_hashes || []).map do |player_hash|
|
100
|
+
Org::Player.new(
|
101
|
+
id: player_hash[:id],
|
102
|
+
overall: player_hash[:overall],
|
103
|
+
position: Org::Position.new(player_hash[:position])
|
104
|
+
)
|
105
|
+
end
|
106
|
+
end
|
18
107
|
end
|
19
108
|
end
|
20
109
|
end
|
data/lib/basketball/app.rb
CHANGED
@@ -4,9 +4,6 @@
|
|
4
4
|
require_relative 'app/file_store'
|
5
5
|
require_relative 'app/in_memory_store'
|
6
6
|
|
7
|
-
# Serialization
|
8
|
-
require_relative 'app/league_serializable'
|
9
|
-
|
10
7
|
# Repositories / Common
|
11
8
|
require_relative 'app/document_repository'
|
12
9
|
|
@@ -14,7 +11,3 @@ require_relative 'app/document_repository'
|
|
14
11
|
require_relative 'app/coordinator_repository'
|
15
12
|
require_relative 'app/league_repository'
|
16
13
|
require_relative 'app/room_repository'
|
17
|
-
|
18
|
-
# Controllers
|
19
|
-
require_relative 'app/coordinator_cli'
|
20
|
-
require_relative 'app/room_cli'
|
@@ -11,14 +11,12 @@ module Basketball
|
|
11
11
|
class OutOfBoundsError < StandardError; end
|
12
12
|
class PlayedGamesError < StandardError; end
|
13
13
|
class UnknownGameError < StandardError; end
|
14
|
-
class UnknownTeamError < StandardError; end
|
15
14
|
class UnplayedGamesError < StandardError; end
|
16
15
|
|
17
16
|
attr_reader :calendar,
|
18
17
|
:current_date,
|
19
18
|
:arena,
|
20
|
-
:results
|
21
|
-
:league
|
19
|
+
:results
|
22
20
|
|
23
21
|
def_delegators :calendar,
|
24
22
|
:exhibition_start_date,
|
@@ -30,37 +28,29 @@ module Basketball
|
|
30
28
|
:regulars_for,
|
31
29
|
:games_for
|
32
30
|
|
33
|
-
def initialize(
|
34
|
-
calendar:,
|
35
|
-
current_date:,
|
36
|
-
results: [],
|
37
|
-
league: Org::League.new
|
38
|
-
)
|
31
|
+
def initialize(calendar:, current_date:, results: [])
|
39
32
|
super()
|
40
33
|
|
41
34
|
raise ArgumentError, 'calendar is required' unless calendar
|
42
35
|
raise ArgumentError, 'current_date is required' if current_date.to_s.empty?
|
43
|
-
raise ArgumentError, 'league is required' unless league
|
44
36
|
|
45
37
|
@calendar = calendar
|
46
38
|
@current_date = current_date
|
47
39
|
@arena = Arena.new
|
48
40
|
@results = []
|
49
|
-
@league = league
|
50
41
|
|
51
42
|
results.each { |result| replay!(result) }
|
52
43
|
|
53
44
|
assert_current_date
|
54
45
|
assert_all_past_dates_are_played
|
55
46
|
assert_all_future_dates_arent_played
|
56
|
-
assert_all_known_teams
|
57
47
|
end
|
58
48
|
|
59
|
-
def sim_rest!(&)
|
49
|
+
def sim_rest!(league, &)
|
60
50
|
events = []
|
61
51
|
|
62
52
|
while not_done?
|
63
|
-
new_events = sim!(&)
|
53
|
+
new_events = sim!(league, &)
|
64
54
|
|
65
55
|
events += new_events
|
66
56
|
end
|
@@ -78,15 +68,17 @@ module Basketball
|
|
78
68
|
raise OutOfBoundsError, "current date #{current_date} should be on or after #{exhibition_start_date}"
|
79
69
|
end
|
80
70
|
|
81
|
-
def sim!
|
71
|
+
def sim!(league)
|
72
|
+
raise ArgumentError, 'league is required' unless league
|
73
|
+
|
82
74
|
return [] if done?
|
83
75
|
|
84
76
|
events = []
|
85
77
|
games = games_for(date: current_date)
|
86
78
|
|
87
79
|
games.each do |game|
|
88
|
-
home_players = opponent_team(game.home_opponent).players
|
89
|
-
away_players = opponent_team(game.away_opponent).players
|
80
|
+
home_players = opponent_team(league, game.home_opponent).players
|
81
|
+
away_players = opponent_team(league, game.away_opponent).players
|
90
82
|
matchup = Matchup.new(game:, home_players:, away_players:)
|
91
83
|
event = arena.play(matchup)
|
92
84
|
|
@@ -140,7 +132,6 @@ module Basketball
|
|
140
132
|
|
141
133
|
def add!(game)
|
142
134
|
assert_today_or_in_future(game)
|
143
|
-
assert_known_teams(game)
|
144
135
|
|
145
136
|
calendar.add!(game)
|
146
137
|
|
@@ -165,7 +156,7 @@ module Basketball
|
|
165
156
|
|
166
157
|
attr_writer :arena
|
167
158
|
|
168
|
-
def opponent_team(opponent)
|
159
|
+
def opponent_team(league, opponent)
|
169
160
|
league.teams.find { |t| t == opponent }
|
170
161
|
end
|
171
162
|
|
@@ -191,14 +182,6 @@ module Basketball
|
|
191
182
|
raise OutOfBoundsError, "#{game.date} is on or before the current date (#{current_date})"
|
192
183
|
end
|
193
184
|
|
194
|
-
def assert_known_teams(game)
|
195
|
-
raise UnknownTeamError, "unknown opponent: #{game.home_opponent}" unless league.team?(game.home_opponent)
|
196
|
-
|
197
|
-
return if league.team?(game.away_opponent)
|
198
|
-
|
199
|
-
raise UnknownTeamError, "unknown opponent: #{game.away_opponent}"
|
200
|
-
end
|
201
|
-
|
202
185
|
def assert_all_past_dates_are_played
|
203
186
|
games_that_should_be_played = games.select { |game| game.date < current_date }
|
204
187
|
|
@@ -237,10 +220,6 @@ module Basketball
|
|
237
220
|
|
238
221
|
result
|
239
222
|
end
|
240
|
-
|
241
|
-
def assert_all_known_teams
|
242
|
-
calendar.games.each { |game| assert_known_teams(game) }
|
243
|
-
end
|
244
223
|
end
|
245
224
|
end
|
246
225
|
end
|
data/lib/basketball/version.rb
CHANGED
data/lib/basketball.rb
CHANGED
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.15
|
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,19 +32,13 @@ 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
|
66
43
|
- lib/basketball/draft.rb
|
67
44
|
- lib/basketball/draft/assessment.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
|