basketball 0.0.6 → 0.0.8
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/CHANGELOG.md +20 -7
- data/Gemfile +11 -0
- data/README.md +49 -41
- data/basketball.gemspec +2 -13
- data/exe/basketball-draft +1 -1
- data/exe/{basketball-schedule → basketball-season-scheduling} +1 -1
- data/lib/basketball/{drafting → draft}/cli.rb +34 -34
- data/lib/basketball/{drafting → draft}/event.rb +1 -1
- data/lib/basketball/{drafting → draft}/front_office.rb +1 -1
- data/lib/basketball/{drafting → draft}/league.rb +1 -1
- data/lib/basketball/{drafting → draft}/pick_event.rb +1 -1
- data/lib/basketball/{drafting → draft}/player.rb +1 -1
- data/lib/basketball/{drafting → draft}/player_search.rb +1 -1
- data/lib/basketball/{drafting → draft}/position.rb +1 -1
- data/lib/basketball/{drafting/engine.rb → draft/room.rb} +2 -2
- data/lib/basketball/draft/room_serializer.rb +186 -0
- data/lib/basketball/{drafting → draft}/roster.rb +1 -1
- data/lib/basketball/{drafting → draft}/sim_event.rb +1 -1
- data/lib/basketball/{drafting → draft}/skip_event.rb +1 -1
- data/lib/basketball/{drafting.rb → draft.rb} +2 -2
- data/lib/basketball/{scheduling → season}/calendar.rb +1 -1
- data/lib/basketball/{scheduling → season}/calendar_serializer.rb +31 -21
- data/lib/basketball/{scheduling → season}/conference.rb +1 -1
- data/lib/basketball/{scheduling → season}/coordinator.rb +2 -2
- data/lib/basketball/{scheduling → season}/division.rb +1 -1
- data/lib/basketball/{scheduling → season}/game.rb +1 -1
- data/lib/basketball/{scheduling → season}/league.rb +1 -1
- data/lib/basketball/{scheduling → season}/league_serializer.rb +26 -17
- data/lib/basketball/{scheduling → season}/preseason_game.rb +1 -1
- data/lib/basketball/{scheduling/cli.rb → season/scheduling_cli.rb} +9 -9
- data/lib/basketball/{scheduling → season}/season_game.rb +1 -1
- data/lib/basketball/{scheduling → season}/team.rb +1 -1
- data/lib/basketball/{scheduling.rb → season.rb} +2 -2
- data/lib/basketball/version.rb +1 -1
- data/lib/basketball.rb +2 -2
- metadata +32 -172
- data/lib/basketball/drafting/engine_serializer.rb +0 -174
@@ -0,0 +1,186 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'front_office'
|
4
|
+
require_relative 'player'
|
5
|
+
require_relative 'pick_event'
|
6
|
+
require_relative 'sim_event'
|
7
|
+
require_relative 'skip_event'
|
8
|
+
|
9
|
+
module Basketball
|
10
|
+
module Draft
|
11
|
+
class RoomSerializer
|
12
|
+
EVENT_CLASSES = {
|
13
|
+
'PickEvent' => PickEvent,
|
14
|
+
'SimEvent' => SimEvent,
|
15
|
+
'SkipEvent' => SkipEvent
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
private_constant :EVENT_CLASSES
|
19
|
+
|
20
|
+
def to_hash(room)
|
21
|
+
{
|
22
|
+
'info' => serialize_info(room),
|
23
|
+
'room' => serialize_room(room),
|
24
|
+
'league' => serialize_league(room)
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def from_hash(json)
|
29
|
+
front_offices = deserialize_front_offices(json)
|
30
|
+
players = deserialize_players(json)
|
31
|
+
events = deserialize_events(json, players, front_offices)
|
32
|
+
|
33
|
+
room_opts = {
|
34
|
+
players:,
|
35
|
+
front_offices:,
|
36
|
+
events:
|
37
|
+
}
|
38
|
+
|
39
|
+
room_opts[:rounds] = json.dig('room', 'rounds') if json.dig('room', 'rounds')
|
40
|
+
|
41
|
+
Room.new(**room_opts)
|
42
|
+
end
|
43
|
+
|
44
|
+
def deserialize(string)
|
45
|
+
json = JSON.parse(string)
|
46
|
+
|
47
|
+
from_hash(json)
|
48
|
+
end
|
49
|
+
|
50
|
+
def serialize(room)
|
51
|
+
to_hash(room).to_json
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def serialize_room(room)
|
57
|
+
{
|
58
|
+
'rounds' => room.rounds,
|
59
|
+
'front_offices' => serialize_front_offices(room),
|
60
|
+
'players' => serialize_players(room),
|
61
|
+
'events' => serialize_events(room.events)
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def serialize_info(room)
|
66
|
+
{
|
67
|
+
'total_picks' => room.total_picks,
|
68
|
+
'current_round' => room.current_round,
|
69
|
+
'current_round_pick' => room.current_round_pick,
|
70
|
+
'current_front_office' => room.current_front_office&.id,
|
71
|
+
'current_pick' => room.current_pick,
|
72
|
+
'remaining_picks' => room.remaining_picks,
|
73
|
+
'done' => room.done?
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
def serialize_league(room)
|
78
|
+
league = room.to_league
|
79
|
+
|
80
|
+
rosters = league.rosters.to_h do |roster|
|
81
|
+
[
|
82
|
+
roster.id,
|
83
|
+
{
|
84
|
+
'players' => roster.players.map(&:id)
|
85
|
+
}
|
86
|
+
]
|
87
|
+
end
|
88
|
+
|
89
|
+
{
|
90
|
+
'free_agents' => league.free_agents.map(&:id),
|
91
|
+
'rosters' => rosters
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
def serialize_front_offices(room)
|
96
|
+
room.front_offices.to_h do |front_office|
|
97
|
+
[
|
98
|
+
front_office.id,
|
99
|
+
{
|
100
|
+
'name' => front_office.name,
|
101
|
+
'fuzz' => front_office.fuzz,
|
102
|
+
'depth' => front_office.depth,
|
103
|
+
'prioritized_positions' => front_office.prioritized_positions.map(&:code)
|
104
|
+
}
|
105
|
+
]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def serialize_players(room)
|
110
|
+
room.players.to_h do |player|
|
111
|
+
[
|
112
|
+
player.id,
|
113
|
+
{
|
114
|
+
'first_name' => player.first_name,
|
115
|
+
'last_name' => player.last_name,
|
116
|
+
'overall' => player.overall,
|
117
|
+
'position' => player.position.code
|
118
|
+
}
|
119
|
+
]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def serialize_events(events)
|
124
|
+
events.map do |event|
|
125
|
+
{
|
126
|
+
'type' => event.class.name.split('::').last,
|
127
|
+
'front_office' => event.front_office.id,
|
128
|
+
'pick' => event.pick,
|
129
|
+
'round' => event.round,
|
130
|
+
'round_pick' => event.round_pick
|
131
|
+
}.tap do |hash|
|
132
|
+
hash['player'] = event.player.id if event.respond_to?(:player)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def deserialize_front_offices(json)
|
138
|
+
(json.dig('room', 'front_offices') || []).map do |id, front_office_hash|
|
139
|
+
prioritized_positions = (front_office_hash['prioritized_positions'] || []).map do |v|
|
140
|
+
Position.new(v)
|
141
|
+
end
|
142
|
+
|
143
|
+
front_office_opts = {
|
144
|
+
id:,
|
145
|
+
name: front_office_hash['name'],
|
146
|
+
prioritized_positions:,
|
147
|
+
fuzz: front_office_hash['fuzz'],
|
148
|
+
depth: front_office_hash['depth']
|
149
|
+
}
|
150
|
+
|
151
|
+
FrontOffice.new(**front_office_opts)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def deserialize_players(json)
|
156
|
+
(json.dig('room', 'players') || []).map do |id, player_hash|
|
157
|
+
player_opts = {
|
158
|
+
id:,
|
159
|
+
first_name: player_hash['first_name'],
|
160
|
+
last_name: player_hash['last_name'],
|
161
|
+
overall: player_hash['overall'],
|
162
|
+
position: Position.new(player_hash['position'])
|
163
|
+
}
|
164
|
+
|
165
|
+
Player.new(**player_opts)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def deserialize_events(json, players, front_offices)
|
170
|
+
(json.dig('room', 'events') || []).map do |event_hash|
|
171
|
+
event_opts = event_hash.slice('pick', 'round', 'round_pick').merge(
|
172
|
+
front_office: front_offices.find { |t| t.id == event_hash['front_office'] }
|
173
|
+
)
|
174
|
+
|
175
|
+
class_constant = EVENT_CLASSES.fetch(event_hash['type'])
|
176
|
+
|
177
|
+
if [PickEvent, SimEvent].include?(class_constant)
|
178
|
+
event_opts[:player] = players.find { |p| p.id == event_hash['player'] }
|
179
|
+
end
|
180
|
+
|
181
|
+
class_constant.new(**event_opts)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -5,28 +5,38 @@ require_relative 'preseason_game'
|
|
5
5
|
require_relative 'season_game'
|
6
6
|
|
7
7
|
module Basketball
|
8
|
-
module
|
8
|
+
module Season
|
9
9
|
class CalendarSerializer
|
10
10
|
GAME_CLASSES = {
|
11
11
|
'PreseasonGame' => PreseasonGame,
|
12
12
|
'SeasonGame' => SeasonGame
|
13
13
|
}.freeze
|
14
14
|
|
15
|
-
def
|
16
|
-
|
15
|
+
def to_hash(calendar)
|
16
|
+
teams = calendar.games.flat_map(&:teams).uniq
|
17
17
|
|
18
|
+
{
|
19
|
+
'year' => calendar.preseason_start_date.year,
|
20
|
+
'teams' => serialize_teams(teams),
|
21
|
+
'games' => serialize_games(calendar.games)
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def from_hash(json)
|
18
26
|
Calendar.new(
|
19
|
-
year: json[
|
27
|
+
year: json['year'].to_i,
|
20
28
|
games: deserialize_games(json)
|
21
29
|
)
|
22
30
|
end
|
23
31
|
|
32
|
+
def deserialize(string)
|
33
|
+
json = JSON.parse(string)
|
34
|
+
|
35
|
+
from_hash(json)
|
36
|
+
end
|
37
|
+
|
24
38
|
def serialize(calendar)
|
25
|
-
|
26
|
-
year: calendar.preseason_start_date.year,
|
27
|
-
teams: serialize_teams(calendar.games.flat_map(&:teams).uniq),
|
28
|
-
games: serialize_games(calendar.games)
|
29
|
-
}.to_json
|
39
|
+
to_hash(calendar).to_json
|
30
40
|
end
|
31
41
|
|
32
42
|
private
|
@@ -34,20 +44,20 @@ module Basketball
|
|
34
44
|
## Deserialization
|
35
45
|
|
36
46
|
def deserialize_games(json)
|
37
|
-
teams = deserialize_teams(json[
|
47
|
+
teams = deserialize_teams(json['teams'])
|
38
48
|
|
39
|
-
(json[
|
40
|
-
GAME_CLASSES.fetch(game_hash[
|
41
|
-
date: Date.parse(game_hash[
|
42
|
-
home_team: teams.fetch(game_hash[
|
43
|
-
away_team: teams.fetch(game_hash[
|
49
|
+
(json['games'] || []).map do |game_hash|
|
50
|
+
GAME_CLASSES.fetch(game_hash['type']).new(
|
51
|
+
date: Date.parse(game_hash['date']),
|
52
|
+
home_team: teams.fetch(game_hash['home_team']),
|
53
|
+
away_team: teams.fetch(game_hash['away_team'])
|
44
54
|
)
|
45
55
|
end
|
46
56
|
end
|
47
57
|
|
48
58
|
def deserialize_teams(teams)
|
49
59
|
(teams || []).to_h do |id, team_hash|
|
50
|
-
team = Team.new(id:, name: team_hash[
|
60
|
+
team = Team.new(id:, name: team_hash['name'])
|
51
61
|
|
52
62
|
[
|
53
63
|
team.id,
|
@@ -63,7 +73,7 @@ module Basketball
|
|
63
73
|
[
|
64
74
|
team.id,
|
65
75
|
{
|
66
|
-
name
|
76
|
+
'name' => team.name
|
67
77
|
}
|
68
78
|
]
|
69
79
|
end
|
@@ -72,10 +82,10 @@ module Basketball
|
|
72
82
|
def serialize_games(games)
|
73
83
|
games.sort_by(&:date).map do |game|
|
74
84
|
{
|
75
|
-
type
|
76
|
-
date
|
77
|
-
home_team
|
78
|
-
away_team
|
85
|
+
'type' => game.class.name.split('::').last,
|
86
|
+
'date' => game.date.to_s,
|
87
|
+
'home_team' => game.home_team.id,
|
88
|
+
'away_team' => game.away_team.id
|
79
89
|
}
|
80
90
|
end
|
81
91
|
end
|
@@ -3,12 +3,12 @@
|
|
3
3
|
require_relative 'calendar'
|
4
4
|
|
5
5
|
module Basketball
|
6
|
-
module
|
6
|
+
module Season
|
7
7
|
# This is the service class responsible for actually picking out free dates ane pairing up teams to
|
8
8
|
# play each other. This is a reasonable naive first pass at some underlying match-making algorithms
|
9
9
|
# but could definitely use some help with the complexity/runtime/etc.
|
10
10
|
class Coordinator
|
11
|
-
MIN_PRESEASON_GAMES_PER_TEAM =
|
11
|
+
MIN_PRESEASON_GAMES_PER_TEAM = 3
|
12
12
|
MAX_PRESEASON_GAMES_PER_TEAM = 6
|
13
13
|
|
14
14
|
private_constant :MIN_PRESEASON_GAMES_PER_TEAM,
|
@@ -1,19 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Basketball
|
4
|
-
module
|
4
|
+
module Season
|
5
5
|
class LeagueSerializer
|
6
|
-
def
|
7
|
-
|
8
|
-
|
6
|
+
def to_hash(league)
|
7
|
+
{
|
8
|
+
'conferences' => serialize_conferences(league.conferences)
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
def from_hash(json)
|
13
|
+
conferences = deserialize_conferences(json['conferences'])
|
9
14
|
|
10
15
|
League.new(conferences:)
|
11
16
|
end
|
12
17
|
|
18
|
+
def deserialize(string)
|
19
|
+
json = JSON.parse(string)
|
20
|
+
|
21
|
+
from_hash(json)
|
22
|
+
end
|
23
|
+
|
13
24
|
def serialize(league)
|
14
|
-
|
15
|
-
conferences: serialize_conferences(league.conferences)
|
16
|
-
}.to_json
|
25
|
+
to_hash(league).to_json
|
17
26
|
end
|
18
27
|
|
19
28
|
private
|
@@ -24,8 +33,8 @@ module Basketball
|
|
24
33
|
(conferences || []).map do |conference_id, conference_hash|
|
25
34
|
Conference.new(
|
26
35
|
id: conference_id,
|
27
|
-
name: conference_hash[
|
28
|
-
divisions: deserialize_divisions(conference_hash[
|
36
|
+
name: conference_hash['name'],
|
37
|
+
divisions: deserialize_divisions(conference_hash['divisions'])
|
29
38
|
)
|
30
39
|
end
|
31
40
|
end
|
@@ -34,8 +43,8 @@ module Basketball
|
|
34
43
|
(divisions || []).map do |division_id, division_hash|
|
35
44
|
Division.new(
|
36
45
|
id: division_id,
|
37
|
-
name: division_hash[
|
38
|
-
teams: deserialize_teams(division_hash[
|
46
|
+
name: division_hash['name'],
|
47
|
+
teams: deserialize_teams(division_hash['teams'])
|
39
48
|
)
|
40
49
|
end
|
41
50
|
end
|
@@ -44,7 +53,7 @@ module Basketball
|
|
44
53
|
(teams || []).map do |team_id, team_hash|
|
45
54
|
Team.new(
|
46
55
|
id: team_id,
|
47
|
-
name: team_hash[
|
56
|
+
name: team_hash['name']
|
48
57
|
)
|
49
58
|
end
|
50
59
|
end
|
@@ -56,8 +65,8 @@ module Basketball
|
|
56
65
|
[
|
57
66
|
conference.id,
|
58
67
|
{
|
59
|
-
name
|
60
|
-
divisions
|
68
|
+
'name' => conference.name,
|
69
|
+
'divisions' => serialize_divisions(conference.divisions)
|
61
70
|
}
|
62
71
|
]
|
63
72
|
end
|
@@ -68,8 +77,8 @@ module Basketball
|
|
68
77
|
[
|
69
78
|
division.id,
|
70
79
|
{
|
71
|
-
name
|
72
|
-
teams
|
80
|
+
'name' => division.name,
|
81
|
+
'teams' => serialize_teams(division.teams)
|
73
82
|
}
|
74
83
|
]
|
75
84
|
end
|
@@ -80,7 +89,7 @@ module Basketball
|
|
80
89
|
[
|
81
90
|
team.id,
|
82
91
|
{
|
83
|
-
name
|
92
|
+
'name' => team.name
|
84
93
|
}
|
85
94
|
]
|
86
95
|
end
|
@@ -9,16 +9,16 @@ require_relative 'league_serializer'
|
|
9
9
|
require_relative 'team'
|
10
10
|
|
11
11
|
module Basketball
|
12
|
-
module
|
12
|
+
module Season
|
13
13
|
# Examples:
|
14
|
-
# exe/basketball-
|
15
|
-
# exe/basketball-
|
16
|
-
# exe/basketball-
|
17
|
-
# exe/basketball-
|
18
|
-
# exe/basketball-
|
19
|
-
# exe/basketball-
|
20
|
-
# exe/basketball-
|
21
|
-
class
|
14
|
+
# exe/basketball-season-scheduling -o tmp/league.json
|
15
|
+
# exe/basketball-season-scheduling -i tmp/league.json -o tmp/calendar.json
|
16
|
+
# exe/basketball-season-scheduling -i tmp/league.json -o tmp/calendar.json -y 2005
|
17
|
+
# exe/basketball-season-scheduling -c tmp/calendar.json
|
18
|
+
# exe/basketball-season-scheduling -c tmp/calendar.json -t C0-D0-T0
|
19
|
+
# exe/basketball-season-scheduling -c tmp/calendar.json -d 2005-02-03
|
20
|
+
# exe/basketball-season-scheduling -c tmp/calendar.json -d 2005-02-03 -t C0-D0-T0
|
21
|
+
class SchedulingCLI
|
22
22
|
attr_reader :opts,
|
23
23
|
:league_serializer,
|
24
24
|
:calendar_serializer,
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'season/scheduling_cli'
|
4
4
|
|
5
5
|
module Basketball
|
6
|
-
module
|
6
|
+
module Season
|
7
7
|
class ConferenceAlreadyRegisteredError < StandardError; end
|
8
8
|
class DivisionAlreadyRegisteredError < StandardError; end
|
9
9
|
class TeamAlreadyRegisteredError < StandardError; end
|
data/lib/basketball/version.rb
CHANGED
data/lib/basketball.rb
CHANGED
@@ -12,5 +12,5 @@ require_relative 'basketball/entity'
|
|
12
12
|
require_relative 'basketball/value_object'
|
13
13
|
|
14
14
|
# Submodules
|
15
|
-
require_relative 'basketball/
|
16
|
-
require_relative 'basketball/
|
15
|
+
require_relative 'basketball/draft'
|
16
|
+
require_relative 'basketball/season'
|