basketball 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +9 -19
  3. data/CHANGELOG.md +1 -39
  4. data/README.md +72 -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 +243 -0
  9. data/lib/basketball/app/coordinator_repository.rb +191 -0
  10. data/lib/basketball/app/file_store.rb +22 -0
  11. data/lib/basketball/{draft/cli.rb → app/room_cli.rb} +53 -76
  12. data/lib/basketball/app/room_repository.rb +189 -0
  13. data/lib/basketball/app.rb +12 -0
  14. data/lib/basketball/draft/assessment.rb +31 -0
  15. data/lib/basketball/draft/event.rb +3 -2
  16. data/lib/basketball/draft/front_office.rb +35 -28
  17. data/lib/basketball/draft/{pick_event.rb → pick.rb} +13 -6
  18. data/lib/basketball/draft/room.rb +119 -119
  19. data/lib/basketball/draft/{player_search.rb → scout.rb} +4 -9
  20. data/lib/basketball/draft/skip.rb +12 -0
  21. data/lib/basketball/draft.rb +13 -6
  22. data/lib/basketball/entity.rb +10 -4
  23. data/lib/basketball/org/league.rb +73 -0
  24. data/lib/basketball/org/player.rb +26 -0
  25. data/lib/basketball/{draft → org}/position.rb +3 -2
  26. data/lib/basketball/org/team.rb +38 -0
  27. data/lib/basketball/org.rb +12 -0
  28. data/lib/basketball/season/arena.rb +112 -0
  29. data/lib/basketball/season/calendar.rb +41 -72
  30. data/lib/basketball/season/coordinator.rb +185 -126
  31. data/lib/basketball/season/{preseason_game.rb → exhibition.rb} +2 -1
  32. data/lib/basketball/season/game.rb +15 -10
  33. data/lib/basketball/season/matchup.rb +27 -0
  34. data/lib/basketball/season/opponent.rb +15 -0
  35. data/lib/basketball/season/{season_game.rb → regular.rb} +2 -1
  36. data/lib/basketball/season/result.rb +37 -0
  37. data/lib/basketball/season.rb +12 -13
  38. data/lib/basketball/value_object.rb +4 -1
  39. data/lib/basketball/version.rb +1 -1
  40. data/lib/basketball.rb +9 -4
  41. metadata +32 -44
  42. data/lib/basketball/draft/league.rb +0 -70
  43. data/lib/basketball/draft/player.rb +0 -43
  44. data/lib/basketball/draft/room_serializer.rb +0 -186
  45. data/lib/basketball/draft/roster.rb +0 -37
  46. data/lib/basketball/draft/sim_event.rb +0 -23
  47. data/lib/basketball/draft/skip_event.rb +0 -13
  48. data/lib/basketball/season/calendar_serializer.rb +0 -94
  49. data/lib/basketball/season/conference.rb +0 -57
  50. data/lib/basketball/season/division.rb +0 -43
  51. data/lib/basketball/season/league.rb +0 -114
  52. data/lib/basketball/season/league_serializer.rb +0 -99
  53. data/lib/basketball/season/scheduling_cli.rb +0 -198
  54. 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: ab187320b9735e8bc6ace40a171cbc9fecd27058e78e5ee18ab1b663b6ea3d54
4
+ data.tar.gz: 6173d1bfdb1b531d54763d369f248944c532916e5fecac89698ac4f49a72e4d9
5
5
  SHA512:
6
- metadata.gz: bbc69e448e39af4cb2a1df48d2e1fa729cc3eb85868b15eb8127aaac32ed57672c3c16cc1afa38cc147b2e9770e06bf89df9325a737ee1ea4f067afb253ced92
7
- data.tar.gz: 1b0046ce516d37e5d1b86f818213b2e0dd1197be910338bc380a653aecb9158bdb85f5647452f2889ebba4fe2dc7b02b85ce2df4d32bae814d7ea10563bb1204
6
+ metadata.gz: df618bc45b196219e9f607a1842f5fda8513ea4dc7bce54756c98a327b87c9905bf41ded2c3dbf04cc70459d06ea4ab76864ff02713ecc2cf400e959cda081a6
7
+ data.tar.gz: 536c2f5fff03419da03604302743b6ec0fccde9957238a0ae4c71c8b560b1709e3460afbc18e0fc377f239c20f4fb82fbb5e2d184b45f60c05d974d4f8615894
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,45 @@
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 System** | Local operating system that the CLI will use for persistence.
24
+ **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.
25
+ **Game** | Matches up a date with two teams (home and away) to represent a coordinatord match-up.
26
+ **League** | Describes a league in terms of structure composed of teams and players.
27
+ **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.
28
+ **Org** | Bounded context (sub-module) dealing with overall organizational structure of a sports assocation.
29
+ **Pick** | Result event emitted when a player is automatically or manually selected.
30
+ **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.
31
+ **Regular** | Game that counts towards regular season record.
32
+ **Result** | The outcome of a game (typically with a home and away score).
33
+ **Room CLI** | Underlying Ruby class that powers the `basketball-room` script. Basically a terminal wrapper for the Room object.
34
+ **Room Repository** | Understands how to save and load Room objects from JSON files on disk.
35
+ **Room** | Main object responsible for providing an iterable interface capable of executing a draft, pick by pick.
36
+ **Scout** | Knows how to stack rank lists of players.
37
+ **Season** | Bounded context (sub-module) dealing with calendar and matchup generation.
38
+ **Skip** | Result event emitted when a front office decides to skip a round.
39
+ **Team Group** | Set of rosters that together form a cohesive league.
40
+ **Team** | Member of a league and signs players. Has games assigned and played.
41
+
42
+ ### Installation
12
43
 
13
44
  To install through Rubygems:
14
45
 
@@ -22,176 +53,124 @@ You can also add this to your Gemfile using:
22
53
  bundle add basketball
23
54
  ````
24
55
 
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.
56
+ ### Draft Module
40
57
 
41
- ## Draft Module
58
+ 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
59
 
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:
60
+ * **Basketball::Draft::Room#sim!**: Simulate the next pick.
61
+ * **Basketball::Draft::Room#skip!**: Skip the next pick.
62
+ * **Basketball::Draft::Room#pick!(player)**: Pick an exact player for the current front office.
63
+ * **Basketball::Draft::Room#sim_rest!**: Simulate the rest of the picks.
44
64
 
45
- ![Basketball Architecture - Draft](/docs/architecture/Basketball%20Architecture%20-%20Draft.png)
65
+ #### Command Line Interface
46
66
 
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.
67
+ 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
68
 
66
69
  ###### Generate a Fresh Draft
67
70
 
68
71
  ```zsh
69
- basketball-draft -o tmp/draft.json
72
+ basketball-room -o tmp/draft.json
70
73
  ```
71
74
 
72
75
  ###### N Top Available Players
73
76
 
74
77
  ```zsh
75
- basketball-draft -i tmp/draft.json -t 10
78
+ basketball-room -i tmp/draft.json -t 10
76
79
  ```
77
80
 
78
81
  ###### N Top Available Players for a Position
79
82
 
80
83
  ```zsh
81
- basketball-draft -i tmp/draft.json -t 10 -q PG
84
+ basketball-room -i tmp/draft.json -t 10 -q PG
82
85
  ```
83
86
 
84
- ###### Output Current Rosters
87
+ ###### Output League
85
88
 
86
89
  ```zsh
87
- basketball-draft -i tmp/draft.json -r
90
+ basketball-room -i tmp/draft.json -l
88
91
  ```
89
92
 
90
93
  ###### Output Event Log
91
94
 
92
95
  ```zsh
93
- basketball-draft -i tmp/draft.json -l
96
+ basketball-room -i tmp/draft.json -e
94
97
  ```
95
98
 
96
99
  ###### Simulate N Picks
97
100
 
98
101
  ```zsh
99
- basketball-draft -i tmp/draft.json -s 10
102
+ basketball-room -i tmp/draft.json -s 10
100
103
  ```
101
104
 
102
105
  ###### Skip N Picks
103
106
 
104
107
  ```zsh
105
- basketball-draft -i tmp/draft.json -x 10
108
+ basketball-room -i tmp/draft.json -x 10
106
109
  ```
107
110
 
108
111
  ###### Pick Players
109
112
 
110
113
  ```zsh
111
- basketball-draft -i tmp/draft.json -p P-100,P-200,P-300
114
+ basketball-room -i tmp/draft.json -p P-100,P-200,P-300
112
115
  ```
113
116
 
114
117
  ###### Simulate the Rest of the Draft
115
118
 
116
119
  ```zsh
117
- basketball-draft -i tmp/draft.json -a
120
+ basketball-room -i tmp/draft.json -a
118
121
  ```
119
122
 
120
123
  ###### Help Menu
121
124
 
122
125
  ```zsh
123
- basketball-draft -h
126
+ basketball-room -h
124
127
  ```
125
128
 
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
129
+ ### Season Module
148
130
 
149
- ###### Generate League
131
+ 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
132
 
151
- ```zsh
152
- basketball-season-scheduling -o tmp/league.json
153
- ```
133
+ * **Basketball::Season::Coordinator#sim!**: Simulate the next day of games.
134
+ * **Basketball::Season::Coordinator#sim_rest!**: Simulate the rest of the games.
154
135
 
155
- ###### Generate Calendar From League
136
+ #### Command Line Interface
156
137
 
157
- ```zsh
158
- basketball-season-scheduling -i tmp/league.json -o tmp/calendar.json
159
- ```
138
+ 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
139
 
161
- ###### Generate Calendar From League For a Specific Year
140
+ ###### Generate Random coordinator
162
141
 
163
142
  ```zsh
164
- basketball-season-scheduling -i tmp/league.json -o tmp/calendar.json -y 2005
143
+ exe/basketball-coordinator -o tmp/coordinator.json
165
144
  ```
166
145
 
167
- ###### Output a Generated Calendar's Matchups
146
+ ###### Sim One Day and Save to New File
168
147
 
169
148
  ```zsh
170
- basketball-season-scheduling -c tmp/calendar.json
149
+ exe/basketball-coordinator -i tmp/coordinator.json -o tmp/coordinator2.json -d 1
171
150
  ```
172
151
 
173
- ###### Output a Generated Calendar's Matchups For a Specific Team
152
+ ###### Output Event Log
174
153
 
175
154
  ```zsh
176
- basketball-season-scheduling -c tmp/calendar.json -t C0-D0-T0
155
+ exe/basketball-coordinator -i tmp/coordinator.json -e
177
156
  ```
178
157
 
179
- ###### Output a Generated Calendar's Matchups For a Specific Date
158
+ ###### Sim Two Days and Save To Input File
180
159
 
181
160
  ```zsh
182
- basketball-season-scheduling -c tmp/calendar.json -d 2005-02-03
161
+ exe/basketball-coordinator -i tmp/coordinator.json -d 2
183
162
  ```
184
163
 
185
- ###### Output a Generated Calendar's Matchups For a Specific Team and Date
164
+ ###### Sim Rest of Calendar
186
165
 
187
166
  ```zsh
188
- basketball-season-scheduling -c tmp/calendar.json -d 2005-02-03 -t C0-D0-T0
167
+ exe/basketball-coordinator -i tmp/coordinator.json -a
189
168
  ```
190
169
 
191
170
  ###### Help Menu
192
171
 
193
172
  ```zsh
194
- basketball-season-scheduling -h
173
+ basketball-coordinator -h
195
174
  ```
196
175
 
197
176
  ## 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,243 @@
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, :repository
15
+
16
+ def initialize(args:, io: $stdout)
17
+ @io = io
18
+ @opts = slop_parse(args)
19
+ @repository = CoordinatorRepository.new
20
+
21
+ if no_input? && no_output?
22
+ io.puts('Input and/or output paths are required.')
23
+
24
+ exit
25
+ end
26
+
27
+ freeze
28
+ end
29
+
30
+ def invoke!
31
+ coordinator = read
32
+
33
+ execute(coordinator)
34
+ output_status(coordinator)
35
+ write(coordinator)
36
+ events(coordinator)
37
+
38
+ self
39
+ end
40
+
41
+ private
42
+
43
+ def output_status(coordinator)
44
+ io.puts
45
+ io.puts('Status')
46
+
47
+ if coordinator.done?
48
+ io.puts('Coordinator is complete!')
49
+ else
50
+ io.puts("#{coordinator.days_left} Remaining day(s) (#{coordinator.total_days} total)")
51
+ io.puts("Currently on: #{coordinator.current_date}")
52
+ io.puts("#{coordinator.exhibitions_left} Remaining preseason (#{coordinator.total_exhibitions} total)")
53
+ io.puts("#{coordinator.regulars_left} Remaining season (#{coordinator.total_regulars} total)")
54
+ end
55
+ end
56
+
57
+ def execute(coordinator)
58
+ event_count = 0
59
+
60
+ io.puts
61
+ io.puts('New Events')
62
+
63
+ days&.times do
64
+ coordinator.sim! do |event|
65
+ io.puts(event)
66
+
67
+ event_count += 1
68
+ end
69
+ end
70
+
71
+ if sim_all
72
+ coordinator.sim_rest! do |event|
73
+ io.puts(event)
74
+
75
+ event_count += 1
76
+ end
77
+ end
78
+
79
+ io.puts("Generated #{event_count} new event(s)")
80
+
81
+ nil
82
+ end
83
+
84
+ def days
85
+ opts[:days]
86
+ end
87
+
88
+ def sim_all
89
+ opts[:sim_all]
90
+ end
91
+
92
+ def write(coordinator)
93
+ path = output? ? output : input
94
+
95
+ repository.save(path, coordinator)
96
+
97
+ path
98
+ end
99
+
100
+ def make_league(team_count: 2, players_per_team_count: 4)
101
+ Org::League.new.tap do |league|
102
+ team_count.times do |i|
103
+ team = Org::Team.new(id: "T-#{i}")
104
+
105
+ players_per_team_count.times do |j|
106
+ player = Org::Player.new(
107
+ id: "T-#{i}-P-#{j}",
108
+ overall: rand(20..100),
109
+ position: Org::Position.random
110
+ )
111
+
112
+ team.sign!(player)
113
+ end
114
+
115
+ league.register!(team)
116
+ end
117
+ end
118
+ end
119
+
120
+ def make_calendar(league:)
121
+ preseason_start_date = Date.new(2000, 1, 1)
122
+ season_start_date = Date.new(2000, 1, 11)
123
+
124
+ exhibitions = make_games(
125
+ start_date: preseason_start_date,
126
+ count: 10,
127
+ league:,
128
+ game_class: Season::Exhibition
129
+ )
130
+
131
+ regulars = make_games(
132
+ start_date: season_start_date,
133
+ count: 10,
134
+ league:,
135
+ game_class: Season::Regular
136
+ )
137
+
138
+ Season::Calendar.new(
139
+ preseason_start_date:,
140
+ preseason_end_date: Date.new(2000, 1, 10),
141
+ season_start_date:,
142
+ season_end_date: Date.new(2000, 1, 20),
143
+ games: exhibitions + regulars
144
+ )
145
+ end
146
+
147
+ def make_games(start_date:, count:, league:, game_class:)
148
+ count.times.map do |i|
149
+ home_team, away_team = league.teams.sample(2)
150
+
151
+ game_class.new(
152
+ date: start_date + i,
153
+ home_opponent: Season::Opponent.new(id: home_team.id),
154
+ away_opponent: Season::Opponent.new(id: away_team.id)
155
+ )
156
+ end
157
+ end
158
+
159
+ def make_coordinator
160
+ league = make_league
161
+ current_date = Date.new(2000, 1, 1)
162
+ calendar = make_calendar(league:)
163
+
164
+ Season::Coordinator.new(
165
+ calendar:,
166
+ current_date:,
167
+ league:
168
+ )
169
+ end
170
+
171
+ def read
172
+ coordinator =
173
+ if input?
174
+ io.puts("Coordinator loaded from: #{input}")
175
+
176
+ repository.load(input)
177
+ else
178
+ io.puts('Input path was not provided, generating fresh coordinator')
179
+
180
+ make_coordinator
181
+ end
182
+
183
+ io.puts("Current Date: #{coordinator.current_date}")
184
+
185
+ coordinator
186
+ end
187
+
188
+ def input
189
+ opts[:input]
190
+ end
191
+
192
+ def input?
193
+ !no_input?
194
+ end
195
+
196
+ def no_input?
197
+ input.to_s.empty?
198
+ end
199
+
200
+ def output
201
+ opts[:output]
202
+ end
203
+
204
+ def no_output?
205
+ output.to_s.empty?
206
+ end
207
+
208
+ def output?
209
+ !no_output?
210
+ end
211
+
212
+ def events(coordinator)
213
+ return unless opts[:events]
214
+
215
+ io.puts
216
+ io.puts('Event Log')
217
+
218
+ puts coordinator.results
219
+ end
220
+
221
+ def slop_parse(args)
222
+ Slop.parse(args) do |o|
223
+ o.banner = 'Usage: basketball-coordinator [options] ...'
224
+
225
+ input_description = <<~DESC
226
+ Path to load the Coordinator from. If omitted then a new coordinator will be created.
227
+ DESC
228
+
229
+ o.string '-i', '--input', input_description.chomp
230
+ o.string '-o', '--output', 'Path to save updated coordinator. If omitted then the input path will be used.'
231
+ o.integer '-d', '--days', 'Number of days to simulate'
232
+ o.bool '-a', '--sim-all', 'Simulate the rest of the coordinator', default: false
233
+ o.bool '-e', '--events', 'Output event log.', default: false
234
+
235
+ o.on '-h', '--help', 'Print out help, like this is doing right now.' do
236
+ io.puts(o)
237
+ exit
238
+ end
239
+ end.to_h
240
+ end
241
+ end
242
+ end
243
+ end