basketball 0.0.8 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +9 -19
  3. data/CHANGELOG.md +1 -39
  4. data/README.md +75 -93
  5. data/basketball.gemspec +3 -6
  6. data/exe/{basketball-season-scheduling → basketball-coordinator} +1 -1
  7. data/exe/{basketball-draft → basketball-room} +1 -1
  8. data/lib/basketball/app/coordinator_cli.rb +250 -0
  9. data/lib/basketball/app/coordinator_repository.rb +114 -0
  10. data/lib/basketball/app/document_repository.rb +67 -0
  11. data/lib/basketball/app/file_store.rb +38 -0
  12. data/lib/basketball/app/in_memory_store.rb +42 -0
  13. data/lib/basketball/app/league_repository.rb +20 -0
  14. data/lib/basketball/app/league_serializable.rb +54 -0
  15. data/lib/basketball/{draft/cli.rb → app/room_cli.rb} +74 -80
  16. data/lib/basketball/app/room_repository.rb +149 -0
  17. data/lib/basketball/app.rb +20 -0
  18. data/lib/basketball/draft/assessment.rb +31 -0
  19. data/lib/basketball/draft/event.rb +3 -2
  20. data/lib/basketball/draft/front_office.rb +35 -28
  21. data/lib/basketball/draft/{pick_event.rb → pick.rb} +13 -6
  22. data/lib/basketball/draft/room.rb +119 -119
  23. data/lib/basketball/draft/{player_search.rb → scout.rb} +4 -9
  24. data/lib/basketball/draft/skip.rb +12 -0
  25. data/lib/basketball/draft.rb +13 -6
  26. data/lib/basketball/entity.rb +19 -10
  27. data/lib/basketball/org/league.rb +68 -0
  28. data/lib/basketball/org/player.rb +26 -0
  29. data/lib/basketball/{draft → org}/position.rb +3 -2
  30. data/lib/basketball/org/team.rb +38 -0
  31. data/lib/basketball/org.rb +12 -0
  32. data/lib/basketball/season/arena.rb +113 -0
  33. data/lib/basketball/season/calendar.rb +41 -72
  34. data/lib/basketball/season/coordinator.rb +186 -128
  35. data/lib/basketball/season/{preseason_game.rb → exhibition.rb} +2 -1
  36. data/lib/basketball/season/game.rb +15 -10
  37. data/lib/basketball/season/matchup.rb +27 -0
  38. data/lib/basketball/season/opponent.rb +15 -0
  39. data/lib/basketball/season/{season_game.rb → regular.rb} +2 -1
  40. data/lib/basketball/season/result.rb +37 -0
  41. data/lib/basketball/season.rb +12 -13
  42. data/lib/basketball/value_object.rb +8 -27
  43. data/lib/basketball/value_object_dsl.rb +30 -0
  44. data/lib/basketball/version.rb +1 -1
  45. data/lib/basketball.rb +9 -4
  46. metadata +37 -44
  47. data/lib/basketball/draft/league.rb +0 -70
  48. data/lib/basketball/draft/player.rb +0 -43
  49. data/lib/basketball/draft/room_serializer.rb +0 -186
  50. data/lib/basketball/draft/roster.rb +0 -37
  51. data/lib/basketball/draft/sim_event.rb +0 -23
  52. data/lib/basketball/draft/skip_event.rb +0 -13
  53. data/lib/basketball/season/calendar_serializer.rb +0 -94
  54. data/lib/basketball/season/conference.rb +0 -57
  55. data/lib/basketball/season/division.rb +0 -43
  56. data/lib/basketball/season/league.rb +0 -114
  57. data/lib/basketball/season/league_serializer.rb +0 -99
  58. data/lib/basketball/season/scheduling_cli.rb +0 -198
  59. data/lib/basketball/season/team.rb +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c6417577ab066cf68ac376551774f538e5ba1d018139e2d2e99af4a607acf10e
4
- data.tar.gz: 2bf491b44bfb3591e411e105c33353f20044933662dc8f4a64999144f943bd3d
3
+ metadata.gz: dca22b3ec7251a012db2afed77f3bda87bd8b59bb59e6084fff80096efcb802a
4
+ data.tar.gz: 55973e68a7aece1571d926f21e5866e045322e1009b9a5139a959d5059e1b150
5
5
  SHA512:
6
- metadata.gz: bbc69e448e39af4cb2a1df48d2e1fa729cc3eb85868b15eb8127aaac32ed57672c3c16cc1afa38cc147b2e9770e06bf89df9325a737ee1ea4f067afb253ced92
7
- data.tar.gz: 1b0046ce516d37e5d1b86f818213b2e0dd1197be910338bc380a653aecb9158bdb85f5647452f2889ebba4fe2dc7b02b85ce2df4d32bae814d7ea10563bb1204
6
+ metadata.gz: af6b695d1ad8bd581822ffe6fe61421c5839a51e880f0d143060656a8e916e11ff8ae4ae5293e9babb2d8f45646b643d30b7753c03141f8d0c321b4010eca14d
7
+ data.tar.gz: d0addd9247f2a3b945874d628eec04e44cb826db2578d493bd99cc242beb8e78041084bf3fbffa53b6a00f2a2b788abb8540894e1caf9db5b0031a01357d5bc1
data/.rubocop.yml CHANGED
@@ -6,36 +6,26 @@ AllCops:
6
6
  NewCops: enable
7
7
  Exclude:
8
8
  - bin/*
9
- - lib/basketball/draft/cli.rb
10
9
  - tmp/**/*
11
10
  - vendor/**/*
12
11
 
13
- Style/Documentation:
14
- Enabled: false
15
-
16
- Metrics/MethodLength:
17
- Max: 35
12
+ RSpec/MultipleMemoizedHelpers:
13
+ Max: 30
18
14
 
19
15
  RSpec/ExampleLength:
20
- Max: 20
16
+ Max: 25
21
17
 
22
- RSpec/MultipleMemoizedHelpers:
23
- Max: 10
18
+ RSpec/NestedGroups:
19
+ Max: 5
24
20
 
25
21
  Metrics/ParameterLists:
26
22
  Max: 6
27
23
 
28
- Metrics/AbcSize:
29
- Max: 25
30
-
31
24
  Metrics/ClassLength:
32
- Max: 200
25
+ Max: 300
33
26
 
34
- Metrics/BlockLength:
27
+ Metrics/MethodLength:
35
28
  Max: 30
36
29
 
37
- Metrics/CyclomaticComplexity:
38
- Max: 9
39
-
40
- Metrics/PerceivedComplexity:
41
- Max: 9
30
+ Metrics/AbcSize:
31
+ Max: 25
data/CHANGELOG.md CHANGED
@@ -1,39 +1 @@
1
-
2
- #### 0.0.8 - May 15th, 2023
3
-
4
- * Renamed Drafting to Draft to match bounded context word form.
5
- * Renamed Drafting::Engine to Draft::Room for better language.
6
- * Renamed Scheduling to Season to include more things other than scheduling.
7
- * Issued README warning for 0.0.X releases not having stable APIs.
8
-
9
- #### 0.0.7 - May 14th, 2023
10
-
11
- * Added #to_hash and #from_hash serializer methods to allow larger consumer json constructions more directly.
12
- * Opt for string keys during serialization/deserialization.
13
-
14
- #### 0.0.6 - May 11th, 2023
15
-
16
- * Added Season module that can generate full schedules for entire league.
17
- * Draft::Event does not have identity anymore (no current tangible benefit).
18
-
19
- #### 0.0.5 - May 5th, 2023
20
-
21
- * Remove the notion of Team in favor of a flat front office.
22
- #### 0.0.4 - May 5th, 2023
23
-
24
- * Add ability to skip draft picks using `Basketball::Draft::Room#skip!`
25
- * Add ability to output event full draft event log using CLI: `basketball-draft -i tmp/draft-wip.json -l`
26
- * Add ability to skip draft picks using CLI: `basketball-draft -i tmp/draft-wip.json -x 1`
27
-
28
- #### 0.0.3 - May 5th, 2023
29
-
30
- * `Draft::Room#sim!` should return events
31
- * Added `Draft::Room#undrafted_player_search`
32
-
33
- #### 0.0.2 - May 4th, 2023
34
-
35
- * Remove autoloading in favor of require statements.
36
-
37
- #### 0.0.1 - May 4th, 2023
38
-
39
- * Initial release with Draft module only
1
+ Will not be kept track of until stable version 1.0.0
data/README.md CHANGED
@@ -1,14 +1,48 @@
1
- # :basketball: Basketball
1
+ # Basketball
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/basketball.svg)](https://badge.fury.io/rb/basketball) [![CI](https://github.com/mattruggio/basketball/actions/workflows/ci.yaml/badge.svg)](https://github.com/mattruggio/basketball/actions/workflows/ci.yaml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
4
 
5
- :warning: **Note:** This is currently in the early phases of initial development. Consider all 0.0.X releases as having unstable APIs between versions. A formal 0.1 minor release will be eventually releases which will honor [Semver](https://semver.org/).
6
-
7
- #### Basketball League Game Room
5
+ :warning: **Note:** This is currently in the early phases of initial development. Consider all < 1 releases as having unstable APIs between versions. A formal 1.0.0 major release will be eventually released which will honor [Semver](https://semver.org/).
8
6
 
9
7
  This library is meant to serve as the domain for a basketball league/season simulator/turn-based game. It models core ideas such as: players, general managers, draft strategy, drafting, season generation, season simultation, playoff generation, playoff simulation, and more.
10
8
 
11
- ## Installation
9
+ ![Architecture](/docs/architecture.png)
10
+
11
+ Element | Description
12
+ :------------ | :-----------
13
+ **Arena** | Determines exhibition and regular season game outcomes.
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-room** | Command-line executable script illustrating an example of how to subclass and consume the drafting module.
16
+ **Calendar** | Stores important boundary dates (preseason start, preseason end, season start, and season end).
17
+ **Coordinator CLI** | Underlying Ruby class that powers the `basketball-coordinator` script. Basically a terminal wrapper over the Coordinator object.
18
+ **Coordinator Repository** | Understands how to save and load Coordinator objects from JSON files on disk.
19
+ **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.
20
+ **Draft** | Bounded context (sub-module) dealing with running a round-robin player draft for teams.
21
+ **Exhibition** | Pre-season game which has no impact to team record.
22
+ **External Dependency** | Some outside system which this library or portions of this library are dependent on.
23
+ **File Store** | Implements a store that can interact with the underlying File System.
24
+ **File System** | Local operating system that the CLI will use for persistence.
25
+ **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.
26
+ **Game** | Matches up a date with two teams (home and away) to represent a coordinatord match-up.
27
+ **League Repository** | Understands how to save and load League objects from JSON files on disk.
28
+ **League** | Describes a league in terms of structure composed of teams and players.
29
+ **Match** | When the Coordinator needs an Arena instance to select a game winner, it will send the Arena a Match. A match is Game but also includes the active roster (players) for both teams that will participate in the game.
30
+ **Org** | Bounded context (sub-module) dealing with overall organizational structure of a sports assocation.
31
+ **Pick** | Result event emitted when a player is automatically or manually selected.
32
+ **Player** | Identitiable as a person able to be drafted. Meant to be subclassed and extended to include more intricate descriptions of a specific sport player, such as abilities, ratings, and statistics. Right now it has none of these types of traits and it meant to only serve as the base with only an overall attribute.
33
+ **Regular** | Game that counts towards regular season record.
34
+ **Result** | The outcome of a game (typically with a home and away score).
35
+ **Room CLI** | Underlying Ruby class that powers the `basketball-room` script. Basically a terminal wrapper for the Room object.
36
+ **Room Repository** | Understands how to save and load Room objects from JSON files on disk.
37
+ **Room** | Main object responsible for providing an iterable interface capable of executing a draft, pick by pick.
38
+ **Scout** | Knows how to stack rank lists of players.
39
+ **Season** | Bounded context (sub-module) dealing with calendar and matchup generation.
40
+ **Skip** | Result event emitted when a front office decides to skip a round.
41
+ **Store** | Interface for the underlying Repository persistence layer. While a Document Repository is mainly responsible for serialization/de-serialization, the store actually knows how to read/write the data.
42
+ **Team Group** | Set of rosters that together form a cohesive league.
43
+ **Team** | Member of a league and signs players. Has games assigned and played.
44
+
45
+ ### Installation
12
46
 
13
47
  To install through Rubygems:
14
48
 
@@ -22,176 +56,124 @@ You can also add this to your Gemfile using:
22
56
  bundle add basketball
23
57
  ````
24
58
 
25
- Install executable scripts:
26
-
27
- ````
28
- bundle binstubs basketball
29
- ````
30
-
31
- ## Sub-Modules
32
-
33
- This library is broken down into several bounded contexts that can be consumed either via its Ruby API's or CLI through provided executable scripts:
34
-
35
- ![Basketball Architecture - Overview](/docs/architecture/Basketball%20Architecture%20-%20Overview.png)
36
-
37
- #### Command Line Interfaces
38
-
39
- Each module is meant to be interfaced with using its Ruby API by consuming applications. Each module also ships with a CLI script (backed by a module service) which a user can interact with to emulate different portions of the league management process. Technically speaking, the CLI provides an example application built on top of the each individual core module. Each module section below should contain with it example CLI calls.
59
+ ### Draft Module
40
60
 
41
- ## Draft Module
61
+ The input for the main object `Basketball::Draft::Room` is an array of teams (`Basketball::Draft::FrontOffice`) and players (`Basketball::Org::Players`). Once instantiated there are four main methods:
42
62
 
43
- The draft module is responsible for providing a turn-based iterator allowing the consumer to either manually pick or simulate picks. Here is a cartoon showing the major components:
63
+ * **Basketball::Draft::Room#sim!**: Simulate the next pick.
64
+ * **Basketball::Draft::Room#skip!**: Skip the next pick.
65
+ * **Basketball::Draft::Room#pick!(player)**: Pick an exact player for the current front office.
66
+ * **Basketball::Draft::Room#sim_rest!**: Simulate the rest of the picks.
44
67
 
45
- ![Basketball Architecture - Draft](/docs/architecture/Basketball%20Architecture%20-%20Draft.png)
68
+ #### Command Line Interface
46
69
 
47
- Element | Description
48
- :------------ | :-----------
49
- **Draft** | Bounded context (sub-module) dealing with executing an asynchronous draft.
50
- **Room** | Aggregate root responsible for providing an iterable interface capable of executing a draft, pick by pick.
51
- **Event** | Represents one cycle execution result from the Room.
52
- **External Ruby App** | An example consumer for the Draft context.
53
- **Front Office** | Identifiable as a team, contains configuration for how to auto-pick draft selections.
54
- **League** | Set of rosters that together form a cohesive league.
55
- **Pick Event** | Result event emitted when a player is manually selected.
56
- **Player** | Identitiable as a person able to be drafted.
57
- **Position** | Value object based on position code: PG, SG, SF, PF, and C.
58
- **Roster** | Identifiable as a team, set of players that make up a single team.
59
- **Sim Event** | Result event emitted when a player is automatically selected by a front office.
60
- **Skip Event** | Result event emitted when a front office decides to skip a round.
61
-
62
- #### The Draft CLI
63
-
64
- The draft module's main object: `Basketball::Draft::Room` is a stateful iterator. Each time a CLI command is executed, it's results will be re-saved to disk so the output file can then be used as the next command's input file to string together commands.
70
+ 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.
65
71
 
66
72
  ###### Generate a Fresh Draft
67
73
 
68
74
  ```zsh
69
- basketball-draft -o tmp/draft.json
75
+ basketball-room -o tmp/draft.json
70
76
  ```
71
77
 
72
78
  ###### N Top Available Players
73
79
 
74
80
  ```zsh
75
- basketball-draft -i tmp/draft.json -t 10
81
+ basketball-room -i tmp/draft.json -t 10
76
82
  ```
77
83
 
78
84
  ###### N Top Available Players for a Position
79
85
 
80
86
  ```zsh
81
- basketball-draft -i tmp/draft.json -t 10 -q PG
87
+ basketball-room -i tmp/draft.json -t 10 -q PG
82
88
  ```
83
89
 
84
- ###### Output Current Rosters
90
+ ###### Output League
85
91
 
86
92
  ```zsh
87
- basketball-draft -i tmp/draft.json -r
93
+ basketball-room -i tmp/draft.json -l
88
94
  ```
89
95
 
90
96
  ###### Output Event Log
91
97
 
92
98
  ```zsh
93
- basketball-draft -i tmp/draft.json -l
99
+ basketball-room -i tmp/draft.json -e
94
100
  ```
95
101
 
96
102
  ###### Simulate N Picks
97
103
 
98
104
  ```zsh
99
- basketball-draft -i tmp/draft.json -s 10
105
+ basketball-room -i tmp/draft.json -s 10
100
106
  ```
101
107
 
102
108
  ###### Skip N Picks
103
109
 
104
110
  ```zsh
105
- basketball-draft -i tmp/draft.json -x 10
111
+ basketball-room -i tmp/draft.json -x 10
106
112
  ```
107
113
 
108
114
  ###### Pick Players
109
115
 
110
116
  ```zsh
111
- basketball-draft -i tmp/draft.json -p P-100,P-200,P-300
117
+ basketball-room -i tmp/draft.json -p P-100,P-200,P-300
112
118
  ```
113
119
 
114
120
  ###### Simulate the Rest of the Draft
115
121
 
116
122
  ```zsh
117
- basketball-draft -i tmp/draft.json -a
123
+ basketball-room -i tmp/draft.json -a
118
124
  ```
119
125
 
120
126
  ###### Help Menu
121
127
 
122
128
  ```zsh
123
- basketball-draft -h
129
+ basketball-room -h
124
130
  ```
125
131
 
126
- ## Season Module
127
-
128
- The Season module is meant to take a League (conferences/divisions/teams) and turn it into a Calendar. This Calendar creation is atomic - the full calendar will be generated completely all in one call. Here is a cartoon showing the major components:
129
-
130
- ![Basketball Architecture - Season](/docs/architecture/Basketball%20Architecture%20-%20Season.png)
131
-
132
- Element | Description
133
- :------------ | :-----------
134
- **Away Team** | Team object designated as the away team for a Game.
135
- **Calendar Serializer** | Understands how to serialize and deserialize a Calendar object.
136
- **Calendar** | Hold a calendar for a year season. Pass in a year and the Calendar will know how to mark important boundary dates (preseason start, preseason end, season start, and season end) and it knows how to ensure Calendar correctness regarding dates.
137
- **Conference** | Describes a conference in terms of structure; composed of an array of divisions (there can only 3).
138
- **Coordinator** | Service which can generate a Calendar from a League.
139
- **Division** | Describes a division in terms of structure; composed of an array of teams (there can only 5).
140
- **Game** | Matches up a date with two teams (home and away) to represent a scheduled matchup.
141
- **Home Team** | Team object designated as the home team for a Game.
142
- **League Serializer** | Understands how to serialize and deserialize a League object.
143
- **League** | Describes a league in terms of structure; composed of an array conferences (there can only be 2).
144
- **Season** | Bounded context (sub-module) dealing with calendar and matchup generation.
145
- **Team** | Identified by an ID and described by a name: represents a basketball team that can be scheduled.
146
-
147
- #### The Season CLI
132
+ ### Season Module
148
133
 
149
- ###### Generate League
134
+ 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:
150
135
 
151
- ```zsh
152
- basketball-season-scheduling -o tmp/league.json
153
- ```
136
+ * **Basketball::Season::Coordinator#sim!**: Simulate the next day of games.
137
+ * **Basketball::Season::Coordinator#sim_rest!**: Simulate the rest of the games.
154
138
 
155
- ###### Generate Calendar From League
139
+ #### Command Line Interface
156
140
 
157
- ```zsh
158
- basketball-season-scheduling -i tmp/league.json -o tmp/calendar.json
159
- ```
141
+ 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.
160
142
 
161
- ###### Generate Calendar From League For a Specific Year
143
+ ###### Generate Random coordinator
162
144
 
163
145
  ```zsh
164
- basketball-season-scheduling -i tmp/league.json -o tmp/calendar.json -y 2005
146
+ exe/basketball-coordinator -o tmp/coordinator.json
165
147
  ```
166
148
 
167
- ###### Output a Generated Calendar's Matchups
149
+ ###### Sim One Day and Save to New File
168
150
 
169
151
  ```zsh
170
- basketball-season-scheduling -c tmp/calendar.json
152
+ exe/basketball-coordinator -i tmp/coordinator.json -o tmp/coordinator2.json -d 1
171
153
  ```
172
154
 
173
- ###### Output a Generated Calendar's Matchups For a Specific Team
155
+ ###### Output Event Log
174
156
 
175
157
  ```zsh
176
- basketball-season-scheduling -c tmp/calendar.json -t C0-D0-T0
158
+ exe/basketball-coordinator -i tmp/coordinator.json -e
177
159
  ```
178
160
 
179
- ###### Output a Generated Calendar's Matchups For a Specific Date
161
+ ###### Sim Two Days and Save To Input File
180
162
 
181
163
  ```zsh
182
- basketball-season-scheduling -c tmp/calendar.json -d 2005-02-03
164
+ exe/basketball-coordinator -i tmp/coordinator.json -d 2
183
165
  ```
184
166
 
185
- ###### Output a Generated Calendar's Matchups For a Specific Team and Date
167
+ ###### Sim Rest of Calendar
186
168
 
187
169
  ```zsh
188
- basketball-season-scheduling -c tmp/calendar.json -d 2005-02-03 -t C0-D0-T0
170
+ exe/basketball-coordinator -i tmp/coordinator.json -a
189
171
  ```
190
172
 
191
173
  ###### Help Menu
192
174
 
193
175
  ```zsh
194
- basketball-season-scheduling -h
176
+ basketball-coordinator -h
195
177
  ```
196
178
 
197
179
  ## Contributing
data/basketball.gemspec CHANGED
@@ -5,19 +5,17 @@ require './lib/basketball/version'
5
5
  Gem::Specification.new do |s|
6
6
  s.name = 'basketball'
7
7
  s.version = Basketball::VERSION
8
- s.summary = 'Basketball League Game Room'
8
+ s.summary = 'Basketball Simulation Domain Model'
9
9
 
10
10
  s.description = <<-DESC
11
- This library is meant to serve as the domain for a basketball league/season simulator/turn-based game.
12
- It models core ideas such as: players, general managers, draft strategy, drafting, season generation, season simultation,
13
- playoff generation, playoff simulation, and more.
11
+ This library is meant to serve as the domain for a basketball league/season simulator/turn-based game. It models core ideas such as: players, general managers, draft strategy, drafting, season generation, season simultation, playoff generation, playoff simulation, and more.
14
12
  DESC
15
13
 
16
14
  s.authors = ['Matthew Ruggio']
17
15
  s.email = ['mattruggio@icloud.com']
18
16
  s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(.github|bin|docs|spec)/}) }
19
17
  s.bindir = 'exe'
20
- s.executables = %w[basketball-draft basketball-season-scheduling]
18
+ s.executables = %w[basketball-coordinator basketball-room]
21
19
  s.homepage = 'https://github.com/mattruggio/basketball'
22
20
  s.license = 'MIT'
23
21
  s.metadata = {
@@ -31,6 +29,5 @@ Gem::Specification.new do |s|
31
29
 
32
30
  s.required_ruby_version = '>= 3.2.1'
33
31
 
34
- s.add_dependency('faker', '~>3.2')
35
32
  s.add_dependency('slop', '~>4.10')
36
33
  end
@@ -4,4 +4,4 @@
4
4
  require 'bundler/setup'
5
5
  require 'basketball'
6
6
 
7
- Basketball::Season::SchedulingCLI.new(args: ARGV).invoke!
7
+ Basketball::App::CoordinatorCLI.new(args: ARGV).invoke!
@@ -4,4 +4,4 @@
4
4
  require 'bundler/setup'
5
5
  require 'basketball'
6
6
 
7
- Basketball::Draft::CLI.new(args: ARGV).invoke!
7
+ Basketball::App::RoomCLI.new(args: ARGV).invoke!
@@ -0,0 +1,250 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Basketball
4
+ module App
5
+ # Examples:
6
+ # exe/basketball-coordinator -o tmp/coordinator.json
7
+ # exe/basketball-coordinator -i tmp/coordinator.json -o tmp/coordinator2.json -d 1
8
+ # exe/basketball-coordinator -i tmp/coordinator2.json -e
9
+ # exe/basketball-coordinator -i tmp/coordinator2.json -o tmp/coordinator2.json -d 2
10
+ # exe/basketball-coordinator -i tmp/coordinator2.json -a
11
+ #
12
+ # exe/basketball-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 preseason (#{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(team_count: 2, players_per_team_count: 4)
108
+ Org::League.new.tap do |league|
109
+ team_count.times do |i|
110
+ team = Org::Team.new(id: "T-#{i}")
111
+
112
+ players_per_team_count.times do |j|
113
+ player = Org::Player.new(
114
+ id: "T-#{i}-P-#{j}",
115
+ overall: rand(20..100),
116
+ position: Org::Position.random
117
+ )
118
+
119
+ team.sign!(player)
120
+ end
121
+
122
+ league.register!(team)
123
+ end
124
+ end
125
+ end
126
+
127
+ def make_calendar(league:)
128
+ preseason_start_date = Date.new(2000, 1, 1)
129
+ season_start_date = Date.new(2000, 1, 11)
130
+
131
+ exhibitions = make_games(
132
+ start_date: preseason_start_date,
133
+ count: 10,
134
+ league:,
135
+ game_class: Season::Exhibition
136
+ )
137
+
138
+ regulars = make_games(
139
+ start_date: season_start_date,
140
+ count: 10,
141
+ league:,
142
+ game_class: Season::Regular
143
+ )
144
+
145
+ Season::Calendar.new(
146
+ preseason_start_date:,
147
+ preseason_end_date: Date.new(2000, 1, 10),
148
+ season_start_date:,
149
+ season_end_date: Date.new(2000, 1, 20),
150
+ games: exhibitions + regulars
151
+ )
152
+ end
153
+
154
+ def make_games(start_date:, count:, league:, game_class:)
155
+ count.times.map do |i|
156
+ home_team, away_team = league.teams.sample(2)
157
+
158
+ game_class.new(
159
+ date: start_date + i,
160
+ home_opponent: Season::Opponent.new(id: home_team.id),
161
+ away_opponent: Season::Opponent.new(id: away_team.id)
162
+ )
163
+ end
164
+ end
165
+
166
+ def make_coordinator
167
+ league = make_league
168
+ current_date = Date.new(2000, 1, 1)
169
+ calendar = make_calendar(league:)
170
+
171
+ Season::Coordinator.new(
172
+ calendar:,
173
+ current_date:,
174
+ league:
175
+ )
176
+ end
177
+
178
+ def read
179
+ coordinator =
180
+ if input?
181
+ io.puts("Coordinator loaded from: #{input}")
182
+
183
+ coordinator_repository.load(input)
184
+ else
185
+ io.puts('Input path was not provided, generating fresh coordinator')
186
+
187
+ make_coordinator
188
+ end
189
+
190
+ io.puts("Current Date: #{coordinator.current_date}")
191
+
192
+ coordinator
193
+ end
194
+
195
+ def input
196
+ opts[:input]
197
+ end
198
+
199
+ def input?
200
+ !no_input?
201
+ end
202
+
203
+ def no_input?
204
+ input.to_s.empty?
205
+ end
206
+
207
+ def output
208
+ opts[:output]
209
+ end
210
+
211
+ def no_output?
212
+ output.to_s.empty?
213
+ end
214
+
215
+ def output?
216
+ !no_output?
217
+ end
218
+
219
+ def events(coordinator)
220
+ return unless opts[:events]
221
+
222
+ io.puts
223
+ io.puts('Event Log')
224
+
225
+ puts coordinator.results
226
+ end
227
+
228
+ def slop_parse(args)
229
+ Slop.parse(args) do |o|
230
+ o.banner = 'Usage: basketball-coordinator [options] ...'
231
+
232
+ input_description = <<~DESC
233
+ Path to load the Coordinator from. If omitted then a new coordinator will be created.
234
+ DESC
235
+
236
+ o.string '-i', '--input', input_description.chomp
237
+ o.string '-o', '--output', 'Path to save updated coordinator. If omitted then the input path will be used.'
238
+ o.integer '-d', '--days', 'Number of days to simulate'
239
+ o.bool '-a', '--sim-all', 'Simulate the rest of the coordinator', default: false
240
+ o.bool '-e', '--events', 'Output event log.', default: false
241
+
242
+ o.on '-h', '--help', 'Print out help, like this is doing right now.' do
243
+ io.puts(o)
244
+ exit
245
+ end
246
+ end.to_h
247
+ end
248
+ end
249
+ end
250
+ end