basketball 0.0.7 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +9 -19
  3. data/CHANGELOG.md +1 -31
  4. data/README.md +72 -91
  5. data/basketball.gemspec +3 -6
  6. data/exe/{basketball-schedule → 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/app/room_cli.rb +212 -0
  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/{drafting → draft}/event.rb +4 -3
  16. data/lib/basketball/draft/front_office.rb +99 -0
  17. data/lib/basketball/draft/pick.rb +32 -0
  18. data/lib/basketball/draft/room.rb +221 -0
  19. data/lib/basketball/{drafting/player_search.rb → draft/scout.rb} +5 -10
  20. data/lib/basketball/draft/skip.rb +12 -0
  21. data/lib/basketball/draft.rb +16 -0
  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/{drafting → 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 +90 -0
  30. data/lib/basketball/season/coordinator.rb +239 -0
  31. data/lib/basketball/{scheduling/preseason_game.rb → season/exhibition.rb} +3 -2
  32. data/lib/basketball/season/game.rb +37 -0
  33. data/lib/basketball/season/matchup.rb +27 -0
  34. data/lib/basketball/season/opponent.rb +15 -0
  35. data/lib/basketball/season/regular.rb +9 -0
  36. data/lib/basketball/season/result.rb +37 -0
  37. data/lib/basketball/season.rb +16 -0
  38. data/lib/basketball/value_object.rb +4 -1
  39. data/lib/basketball/version.rb +1 -1
  40. data/lib/basketball.rb +11 -6
  41. metadata +40 -52
  42. data/lib/basketball/drafting/cli.rb +0 -235
  43. data/lib/basketball/drafting/engine.rb +0 -221
  44. data/lib/basketball/drafting/engine_serializer.rb +0 -186
  45. data/lib/basketball/drafting/front_office.rb +0 -92
  46. data/lib/basketball/drafting/league.rb +0 -70
  47. data/lib/basketball/drafting/pick_event.rb +0 -25
  48. data/lib/basketball/drafting/player.rb +0 -43
  49. data/lib/basketball/drafting/roster.rb +0 -37
  50. data/lib/basketball/drafting/sim_event.rb +0 -23
  51. data/lib/basketball/drafting/skip_event.rb +0 -13
  52. data/lib/basketball/drafting.rb +0 -9
  53. data/lib/basketball/scheduling/calendar.rb +0 -121
  54. data/lib/basketball/scheduling/calendar_serializer.rb +0 -94
  55. data/lib/basketball/scheduling/cli.rb +0 -198
  56. data/lib/basketball/scheduling/conference.rb +0 -57
  57. data/lib/basketball/scheduling/coordinator.rb +0 -180
  58. data/lib/basketball/scheduling/division.rb +0 -43
  59. data/lib/basketball/scheduling/game.rb +0 -32
  60. data/lib/basketball/scheduling/league.rb +0 -114
  61. data/lib/basketball/scheduling/league_serializer.rb +0 -99
  62. data/lib/basketball/scheduling/season_game.rb +0 -8
  63. data/lib/basketball/scheduling/team.rb +0 -21
  64. data/lib/basketball/scheduling.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 00ac0278bb2e786c5a68b3cc7ac8fd5d49005f9f9a01fad32501c75a00880dce
4
- data.tar.gz: 4b76f9d42a702a206c837346de20396c6948c9bcb071a4143610e8179ba93c64
3
+ metadata.gz: ab187320b9735e8bc6ace40a171cbc9fecd27058e78e5ee18ab1b663b6ea3d54
4
+ data.tar.gz: 6173d1bfdb1b531d54763d369f248944c532916e5fecac89698ac4f49a72e4d9
5
5
  SHA512:
6
- metadata.gz: 806f800744de18f81e590cd712adf83592e372b8f1b19c3b8f9a6e702c7fbc04981380ba784b63436f2cc34d5f80238c0fce53366eed8a2a8a63eb9b64cb69c4
7
- data.tar.gz: acffa65b0315e7d5ec6638cd92c217e9aa665787114935d0859a4b6b02cfb0c8afd6e66d7914de6b147d6878d83ca210b2d5f5bfbdeb748784f559300fe79d46
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,31 +1 @@
1
- #### 0.0.7 - May 14th, 2023
2
-
3
- * Added #to_hash and #from_hash serializer methods to allow larger consumer json constructions more directly.
4
- * Opt for string keys during serialization/deserialization.
5
-
6
- #### 0.0.6 - May 11th, 2023
7
-
8
- * Added Scheduling module that can generate full schedules for entire league.
9
- * Drafting::Event does not have identity anymore (no current tangible benefit).
10
-
11
- #### 0.0.5 - May 5th, 2023
12
-
13
- * Remove the notion of Team in favor of a flat front office.
14
- #### 0.0.4 - May 5th, 2023
15
-
16
- * Add ability to skip draft picks using `Basketball::Drafting::Engine#skip!`
17
- * Add ability to output event full drafting event log using CLI: `basketball-draft -i tmp/draft-wip.json -l`
18
- * Add ability to skip draft picks using CLI: `basketball-draft -i tmp/draft-wip.json -x 1`
19
-
20
- #### 0.0.3 - May 5th, 2023
21
-
22
- * `Drafting::Engine#sim!` should return events
23
- * Added `Drafting::Engine#undrafted_player_search`
24
-
25
- #### 0.0.2 - May 4th, 2023
26
-
27
- * Remove autoloading in favor of require statements.
28
-
29
- #### 0.0.1 - May 4th, 2023
30
-
31
- * Initial release with Drafting module only
1
+ Will not be kept track of until stable version 1.0.0
data/README.md CHANGED
@@ -1,12 +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
- #### Basketball League Game Engine
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/).
6
6
 
7
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.
8
8
 
9
- ## 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
10
43
 
11
44
  To install through Rubygems:
12
45
 
@@ -20,176 +53,124 @@ You can also add this to your Gemfile using:
20
53
  bundle add basketball
21
54
  ````
22
55
 
23
- Install executable scripts:
24
-
25
- ````
26
- bundle binstubs basketball
27
- ````
28
-
29
- ## Sub-Modules
30
-
31
- 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:
32
-
33
- ![Basketball Architecture - Overview](/docs/architecture/overview.png)
56
+ ### Draft Module
34
57
 
35
- #### Command Line Interfaces
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:
36
59
 
37
- 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.
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.
38
64
 
39
- ## Drafting Module
65
+ #### Command Line Interface
40
66
 
41
- The drafting 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:
42
-
43
- ![Basketball Architecture - Drafting](/docs/architecture/drafting.png)
44
-
45
- Element | Description
46
- :------------ | :-----------
47
- **Drafting** | Bounded context (sub-module) dealing with executing an asynchronous draft.
48
- **Engine** | Aggregate root responsible for providing an iterable interface capable of executing a draft, pick by pick.
49
- **Event** | Represents one cycle execution result from the Engine.
50
- **External Ruby App** | An example consumer for the Drafting context.
51
- **Front Office** | Identifiable as a team, contains configuration for how to auto-pick draft selections.
52
- **League** | Set of rosters that together form a cohesive league.
53
- **Pick Event** | Result event emitted when a player is manually selected.
54
- **Player** | Identitiable as a person able to be drafted.
55
- **Position** | Value object based on position code: PG, SG, SF, PF, and C.
56
- **Roster** | Identifiable as a team, set of players that make up a single team.
57
- **Sim Event** | Result event emitted when a player is automatically selected by a front office.
58
- **Skip Event** | Result event emitted when a front office decides to skip a round.
59
-
60
- #### The Drafting CLI
61
-
62
- The drafting module's main object: `Basketball::Drafting::Engine` 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.
63
68
 
64
69
  ###### Generate a Fresh Draft
65
70
 
66
71
  ```zsh
67
- basketball-draft -o tmp/draft.json
72
+ basketball-room -o tmp/draft.json
68
73
  ```
69
74
 
70
75
  ###### N Top Available Players
71
76
 
72
77
  ```zsh
73
- basketball-draft -i tmp/draft.json -t 10
78
+ basketball-room -i tmp/draft.json -t 10
74
79
  ```
75
80
 
76
81
  ###### N Top Available Players for a Position
77
82
 
78
83
  ```zsh
79
- basketball-draft -i tmp/draft.json -t 10 -q PG
84
+ basketball-room -i tmp/draft.json -t 10 -q PG
80
85
  ```
81
86
 
82
- ###### Output Current Rosters
87
+ ###### Output League
83
88
 
84
89
  ```zsh
85
- basketball-draft -i tmp/draft.json -r
90
+ basketball-room -i tmp/draft.json -l
86
91
  ```
87
92
 
88
93
  ###### Output Event Log
89
94
 
90
95
  ```zsh
91
- basketball-draft -i tmp/draft.json -l
96
+ basketball-room -i tmp/draft.json -e
92
97
  ```
93
98
 
94
99
  ###### Simulate N Picks
95
100
 
96
101
  ```zsh
97
- basketball-draft -i tmp/draft.json -s 10
102
+ basketball-room -i tmp/draft.json -s 10
98
103
  ```
99
104
 
100
105
  ###### Skip N Picks
101
106
 
102
107
  ```zsh
103
- basketball-draft -i tmp/draft.json -x 10
108
+ basketball-room -i tmp/draft.json -x 10
104
109
  ```
105
110
 
106
111
  ###### Pick Players
107
112
 
108
113
  ```zsh
109
- 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
110
115
  ```
111
116
 
112
117
  ###### Simulate the Rest of the Draft
113
118
 
114
119
  ```zsh
115
- basketball-draft -i tmp/draft.json -a
120
+ basketball-room -i tmp/draft.json -a
116
121
  ```
117
122
 
118
123
  ###### Help Menu
119
124
 
120
125
  ```zsh
121
- basketball-draft -h
126
+ basketball-room -h
122
127
  ```
123
128
 
124
- ## Scheduling Module
125
-
126
- The Scheduling 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:
127
-
128
- ![Basketball Architecture - Scheduling](/docs/architecture/scheduling.png)
129
-
130
- Element | Description
131
- :------------ | :-----------
132
- **Away Team** | Team object designated as the away team for a Game.
133
- **Calendar Serializer** | Understands how to serialize and deserialize a Calendar object.
134
- **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.
135
- **Conference** | Describes a conference in terms of structure; composed of an array of divisions (there can only 3).
136
- **Coordinator** | Service which can generate a Calendar from a League.
137
- **Division** | Describes a division in terms of structure; composed of an array of teams (there can only 5).
138
- **Game** | Matches up a date with two teams (home and away) to represent a scheduled matchup.
139
- **Home Team** | Team object designated as the home team for a Game.
140
- **League Serializer** | Understands how to serialize and deserialize a League object.
141
- **League** | Describes a league in terms of structure; composed of an array conferences (there can only be 2).
142
- **Scheduling** | Bounded context (sub-module) dealing with matchup and calendar generation.
143
- **Team** | Identified by an ID and described by a name: represents a basketball team that can be scheduled.
144
-
145
- #### The Scheduling CLI
129
+ ### Season Module
146
130
 
147
- ###### 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:
148
132
 
149
- ```zsh
150
- basketball-schedule -o tmp/league.json
151
- ```
133
+ * **Basketball::Season::Coordinator#sim!**: Simulate the next day of games.
134
+ * **Basketball::Season::Coordinator#sim_rest!**: Simulate the rest of the games.
152
135
 
153
- ###### Generate Calendar From League
136
+ #### Command Line Interface
154
137
 
155
- ```zsh
156
- basketball-schedule -i tmp/league.json -o tmp/calendar.json
157
- ```
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.
158
139
 
159
- ###### Generate Calendar From League For a Specific Year
140
+ ###### Generate Random coordinator
160
141
 
161
142
  ```zsh
162
- basketball-schedule -i tmp/league.json -o tmp/calendar.json -y 2005
143
+ exe/basketball-coordinator -o tmp/coordinator.json
163
144
  ```
164
145
 
165
- ###### Output a Generated Calendar's Matchups
146
+ ###### Sim One Day and Save to New File
166
147
 
167
148
  ```zsh
168
- basketball-schedule -c tmp/calendar.json
149
+ exe/basketball-coordinator -i tmp/coordinator.json -o tmp/coordinator2.json -d 1
169
150
  ```
170
151
 
171
- ###### Output a Generated Calendar's Matchups For a Specific Team
152
+ ###### Output Event Log
172
153
 
173
154
  ```zsh
174
- basketball-schedule -c tmp/calendar.json -t C0-D0-T0
155
+ exe/basketball-coordinator -i tmp/coordinator.json -e
175
156
  ```
176
157
 
177
- ###### Output a Generated Calendar's Matchups For a Specific Date
158
+ ###### Sim Two Days and Save To Input File
178
159
 
179
160
  ```zsh
180
- basketball-schedule -c tmp/calendar.json -d 2005-02-03
161
+ exe/basketball-coordinator -i tmp/coordinator.json -d 2
181
162
  ```
182
163
 
183
- ###### Output a Generated Calendar's Matchups For a Specific Team and Date
164
+ ###### Sim Rest of Calendar
184
165
 
185
166
  ```zsh
186
- basketball-schedule -c tmp/calendar.json -d 2005-02-03 -t C0-D0-T0
167
+ exe/basketball-coordinator -i tmp/coordinator.json -a
187
168
  ```
188
169
 
189
170
  ###### Help Menu
190
171
 
191
172
  ```zsh
192
- basketball-schedule -h
173
+ basketball-coordinator -h
193
174
  ```
194
175
 
195
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 Engine'
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-schedule]
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::Scheduling::CLI.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::Drafting::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