basketball 0.0.1 → 0.0.3
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 +9 -0
- data/lib/basketball/drafting/cli.rb +5 -0
- data/lib/basketball/drafting/engine.rb +10 -2
- data/lib/basketball/drafting/engine_serializer.rb +7 -1
- data/lib/basketball/drafting/front_office.rb +13 -19
- data/lib/basketball/drafting/pick_event.rb +2 -0
- data/lib/basketball/drafting/position.rb +8 -15
- data/lib/basketball/drafting/roster.rb +4 -2
- data/lib/basketball/drafting/team.rb +4 -4
- data/lib/basketball/drafting.rb +1 -17
- data/lib/basketball/entity.rb +31 -0
- data/lib/basketball/value_object.rb +53 -0
- data/lib/basketball/version.rb +1 -1
- data/lib/basketball.rb +6 -3
- metadata +4 -3
- data/lib/basketball/drafting/entity.rb +0 -33
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 29805ef216312c25dee77d7f7c2a82bf220287404e9e241d24e16dddfb895fcc
|
|
4
|
+
data.tar.gz: 3d8a0038acf62e4e1aa230299cc1b2d7d777596bc133b159b1e661639c75c76d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ae3baac2215dbfee6b9cf70a44b2bdf9257d7dade811c6a30bf37b22f840bd85621f6441d137e07f38b615210092d0cede011a2e9f4655aa1e05c6281411a856
|
|
7
|
+
data.tar.gz: 4bcb67de94178f2945376faa2cb57c5f5884d60b24479d73e12d1145c7c20c1b9f3dd547f321c578f39d43868fb2f8d158859020b14d7e436fbface8a89b2809
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
#### 0.0.3 - May 5th, 2023
|
|
2
|
+
|
|
3
|
+
* Drafting::Engine#sim! should return events
|
|
4
|
+
* Added Drafting::Engine#undrafted_player_search
|
|
5
|
+
|
|
6
|
+
#### 0.0.2 - May 4th, 2023
|
|
7
|
+
|
|
8
|
+
* Remove autoloading in favor of require statements.
|
|
9
|
+
|
|
1
10
|
#### 0.0.1 - May 4th, 2023
|
|
2
11
|
|
|
3
12
|
* Initial release with Drafting module only
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'roster'
|
|
4
|
+
|
|
3
5
|
module Basketball
|
|
4
6
|
module Drafting
|
|
5
7
|
class Engine
|
|
@@ -96,12 +98,13 @@ module Basketball
|
|
|
96
98
|
|
|
97
99
|
def sim!(times = nil)
|
|
98
100
|
counter = 0
|
|
101
|
+
events = []
|
|
99
102
|
|
|
100
103
|
until done? || (times && counter >= times)
|
|
101
104
|
team = current_team
|
|
102
105
|
|
|
103
106
|
player = team.pick(
|
|
104
|
-
|
|
107
|
+
undrafted_player_search:,
|
|
105
108
|
drafted_players: drafted_players(team),
|
|
106
109
|
round: current_round
|
|
107
110
|
)
|
|
@@ -120,9 +123,10 @@ module Basketball
|
|
|
120
123
|
yield(event) if block_given?
|
|
121
124
|
|
|
122
125
|
counter += 1
|
|
126
|
+
events << event
|
|
123
127
|
end
|
|
124
128
|
|
|
125
|
-
|
|
129
|
+
events
|
|
126
130
|
end
|
|
127
131
|
|
|
128
132
|
def pick!(player)
|
|
@@ -144,6 +148,10 @@ module Basketball
|
|
|
144
148
|
players - drafted_players
|
|
145
149
|
end
|
|
146
150
|
|
|
151
|
+
def undrafted_player_search
|
|
152
|
+
PlayerSearch.new(undrafted_players)
|
|
153
|
+
end
|
|
154
|
+
|
|
147
155
|
private
|
|
148
156
|
|
|
149
157
|
attr_reader :players_by_id, :teams_by_id
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'front_office'
|
|
4
|
+
require_relative 'player'
|
|
5
|
+
require_relative 'team'
|
|
6
|
+
require_relative 'pick_event'
|
|
7
|
+
require_relative 'sim_event'
|
|
8
|
+
|
|
3
9
|
module Basketball
|
|
4
10
|
module Drafting
|
|
5
11
|
class EngineSerializer
|
|
@@ -95,7 +101,7 @@ module Basketball
|
|
|
95
101
|
first_name: player.first_name,
|
|
96
102
|
last_name: player.last_name,
|
|
97
103
|
overall: player.overall,
|
|
98
|
-
position: player.position.
|
|
104
|
+
position: player.position.code
|
|
99
105
|
}
|
|
100
106
|
]
|
|
101
107
|
end
|
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
module Basketball
|
|
4
4
|
module Drafting
|
|
5
|
-
class FrontOffice
|
|
5
|
+
class FrontOffice < ValueObject
|
|
6
6
|
MAX_DEPTH = 3
|
|
7
7
|
MAX_FUZZ = 2
|
|
8
8
|
MAX_POSITIONS = 12
|
|
9
9
|
|
|
10
10
|
private_constant :MAX_DEPTH, :MAX_FUZZ, :MAX_POSITIONS
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
attr_reader_value :prioritized_positions, :fuzz, :depth
|
|
13
13
|
|
|
14
14
|
def initialize(prioritized_positions: [], fuzz: rand(0..MAX_FUZZ), depth: rand(0..MAX_DEPTH))
|
|
15
|
+
super()
|
|
16
|
+
|
|
15
17
|
@fuzz = fuzz.to_i
|
|
16
18
|
@depth = depth.to_i
|
|
17
19
|
@prioritized_positions = prioritized_positions
|
|
@@ -24,44 +26,36 @@ module Basketball
|
|
|
24
26
|
freeze
|
|
25
27
|
end
|
|
26
28
|
|
|
27
|
-
def
|
|
28
|
-
"#{prioritized_positions.map(&:to_s).join(',')} (F:#{fuzz} D:#{depth})"
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def pick(undrafted_players:, drafted_players:, round:)
|
|
29
|
+
def pick(undrafted_player_search:, drafted_players:, round:)
|
|
32
30
|
players = []
|
|
33
31
|
|
|
34
|
-
players = adaptive_search(
|
|
35
|
-
players = balanced_search(
|
|
36
|
-
players = top_players(
|
|
32
|
+
players = adaptive_search(undrafted_player_search:, drafted_players:) if depth >= round
|
|
33
|
+
players = balanced_search(undrafted_player_search:, drafted_players:) if players.empty?
|
|
34
|
+
players = top_players(undrafted_player_search:) if players.empty?
|
|
37
35
|
|
|
38
36
|
players[0..fuzz].sample
|
|
39
37
|
end
|
|
40
38
|
|
|
41
39
|
private
|
|
42
40
|
|
|
43
|
-
def adaptive_search(
|
|
44
|
-
search = PlayerSearch.new(undrafted_players)
|
|
45
|
-
|
|
41
|
+
def adaptive_search(undrafted_player_search:, drafted_players:)
|
|
46
42
|
drafted_positions = drafted_players.map(&:position)
|
|
47
43
|
|
|
48
|
-
|
|
44
|
+
undrafted_player_search.query(exclude_positions: drafted_positions)
|
|
49
45
|
end
|
|
50
46
|
|
|
51
|
-
def balanced_search(
|
|
52
|
-
search = PlayerSearch.new(undrafted_players)
|
|
53
|
-
|
|
47
|
+
def balanced_search(undrafted_player_search:, drafted_players:)
|
|
54
48
|
players = []
|
|
55
49
|
|
|
56
50
|
# Try to find best pick for exact desired position.
|
|
57
51
|
# If you cant find one, then move to the next desired position until the end of the queue
|
|
58
52
|
available_prioritized_positions(drafted_players:).each do |position|
|
|
59
|
-
players =
|
|
53
|
+
players = undrafted_player_search.query(position:)
|
|
60
54
|
|
|
61
55
|
break if players.any?
|
|
62
56
|
end
|
|
63
57
|
|
|
64
|
-
players = players.any? ? players :
|
|
58
|
+
players = players.any? ? players : undrafted_player_search.query
|
|
65
59
|
end
|
|
66
60
|
|
|
67
61
|
def all_random_positions
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Basketball
|
|
4
4
|
module Drafting
|
|
5
|
-
class Position
|
|
5
|
+
class Position < ValueObject
|
|
6
6
|
extend Forwardable
|
|
7
7
|
|
|
8
8
|
class << self
|
|
@@ -17,25 +17,18 @@ module Basketball
|
|
|
17
17
|
FRONT_COURT_VALUES = %w[PF C].to_set.freeze
|
|
18
18
|
ALL_VALUES = (BACK_COURT_VALUES.to_a + FRONT_COURT_VALUES.to_a).to_set.freeze
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
attr_reader_value :code
|
|
21
21
|
|
|
22
|
-
def_delegators :
|
|
22
|
+
def_delegators :code, :to_s
|
|
23
23
|
|
|
24
|
-
def initialize(
|
|
25
|
-
|
|
24
|
+
def initialize(code)
|
|
25
|
+
super()
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
@code = code.to_s.upcase
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
end
|
|
29
|
+
raise InvalidPositionError, "Unknown position code: #{@code}" unless ALL_VALUES.include?(@code)
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
value == other.value
|
|
34
|
-
end
|
|
35
|
-
alias eql? ==
|
|
36
|
-
|
|
37
|
-
def hash
|
|
38
|
-
value.hash
|
|
31
|
+
freeze
|
|
39
32
|
end
|
|
40
33
|
end
|
|
41
34
|
end
|
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
module Basketball
|
|
4
4
|
module Drafting
|
|
5
|
-
class Roster
|
|
5
|
+
class Roster < ValueObject
|
|
6
6
|
extend Forwardable
|
|
7
7
|
|
|
8
8
|
class WrongTeamEventError < StandardError; end
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
attr_reader_value :team, :events
|
|
11
11
|
|
|
12
12
|
def_delegators :team, :id
|
|
13
13
|
|
|
14
14
|
def initialize(team:, events: [])
|
|
15
|
+
super()
|
|
16
|
+
|
|
15
17
|
raise ArgumentError, 'team is required' unless team
|
|
16
18
|
|
|
17
19
|
other_teams_pick_event_ids = events.reject { |e| e.team == team }.map(&:id)
|
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
module Basketball
|
|
4
4
|
module Drafting
|
|
5
5
|
class Team < Entity
|
|
6
|
+
extend Forwardable
|
|
7
|
+
|
|
6
8
|
attr_reader :name, :front_office
|
|
7
9
|
|
|
10
|
+
def_delegators :front_office, :pick
|
|
11
|
+
|
|
8
12
|
def initialize(id:, name: '', front_office: FrontOffice.new)
|
|
9
13
|
super(id)
|
|
10
14
|
|
|
@@ -19,10 +23,6 @@ module Basketball
|
|
|
19
23
|
def to_s
|
|
20
24
|
"[#{super}] #{name}"
|
|
21
25
|
end
|
|
22
|
-
|
|
23
|
-
def pick(undrafted_players:, drafted_players:, round:)
|
|
24
|
-
front_office.pick(undrafted_players:, drafted_players:, round:)
|
|
25
|
-
end
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
end
|
data/lib/basketball/drafting.rb
CHANGED
|
@@ -1,19 +1,3 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
module Drafting
|
|
5
|
-
autoload(:CLI, './lib/basketball/drafting/cli.rb')
|
|
6
|
-
autoload(:Engine, './lib/basketball/drafting/engine.rb')
|
|
7
|
-
autoload(:EngineSerializer, './lib/basketball/drafting/engine_serializer.rb')
|
|
8
|
-
autoload(:Entity, './lib/basketball/drafting/entity.rb')
|
|
9
|
-
autoload(:Event, './lib/basketball/drafting/event.rb')
|
|
10
|
-
autoload(:FrontOffice, './lib/basketball/drafting/front_office.rb')
|
|
11
|
-
autoload(:PickEvent, './lib/basketball/drafting/pick_event.rb')
|
|
12
|
-
autoload(:Position, './lib/basketball/drafting/position.rb')
|
|
13
|
-
autoload(:Player, './lib/basketball/drafting/player.rb')
|
|
14
|
-
autoload(:PlayerSearch, './lib/basketball/drafting/player_search.rb')
|
|
15
|
-
autoload(:Roster, './lib/basketball/drafting/roster.rb')
|
|
16
|
-
autoload(:SimEvent, './lib/basketball/drafting/sim_event.rb')
|
|
17
|
-
autoload(:Team, './lib/basketball/drafting/team.rb')
|
|
18
|
-
end
|
|
19
|
-
end
|
|
3
|
+
require_relative 'drafting/cli'
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basketball
|
|
4
|
+
class Entity
|
|
5
|
+
extend Forwardable
|
|
6
|
+
include Comparable
|
|
7
|
+
|
|
8
|
+
attr_reader :id
|
|
9
|
+
|
|
10
|
+
def_delegators :id, :to_s
|
|
11
|
+
|
|
12
|
+
def initialize(id)
|
|
13
|
+
raise ArgumentError, 'id is required' if id.to_s.empty?
|
|
14
|
+
|
|
15
|
+
@id = id.to_s.upcase
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def <=>(other)
|
|
19
|
+
id <=> other.id
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def ==(other)
|
|
23
|
+
id == other.id
|
|
24
|
+
end
|
|
25
|
+
alias eql? ==
|
|
26
|
+
|
|
27
|
+
def hash
|
|
28
|
+
id.hash
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basketball
|
|
4
|
+
class ValueObject
|
|
5
|
+
include Comparable
|
|
6
|
+
|
|
7
|
+
# NOTE: This current implementation most likely does not work for deep inheritance trees.
|
|
8
|
+
class << self
|
|
9
|
+
def value_keys
|
|
10
|
+
@value_keys ||= []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def sorted_value_keys
|
|
14
|
+
value_keys.sort
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def attr_reader_value(*keys)
|
|
18
|
+
keys.each { |k| value_keys << k.to_sym }
|
|
19
|
+
|
|
20
|
+
attr_reader(*keys)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_s
|
|
25
|
+
to_h.map { |k, v| "#{k}: #{v}" }.join(', ')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_h
|
|
29
|
+
self.class.sorted_value_keys.to_h { |k| [k, send(k)] }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def [](key)
|
|
33
|
+
to_h[key]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def <=>(other)
|
|
37
|
+
all_sorted_values <=> other.all_sorted_values
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def ==(other)
|
|
41
|
+
to_h == other.to_h
|
|
42
|
+
end
|
|
43
|
+
alias eql? ==
|
|
44
|
+
|
|
45
|
+
def hash
|
|
46
|
+
all_sorted_values.map(&:hash).hash
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def all_sorted_values
|
|
50
|
+
self.class.sorted_value_keys.map { |k| self[k] }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
data/lib/basketball/version.rb
CHANGED
data/lib/basketball.rb
CHANGED
|
@@ -7,6 +7,9 @@ require 'json'
|
|
|
7
7
|
require 'securerandom'
|
|
8
8
|
require 'slop'
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
# Top-level
|
|
11
|
+
require_relative 'basketball/entity'
|
|
12
|
+
require_relative 'basketball/value_object'
|
|
13
|
+
|
|
14
|
+
# Submodules
|
|
15
|
+
require_relative 'basketball/drafting'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: basketball
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matthew Ruggio
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-05-
|
|
11
|
+
date: 2023-05-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faker
|
|
@@ -207,7 +207,6 @@ files:
|
|
|
207
207
|
- lib/basketball/drafting/cli.rb
|
|
208
208
|
- lib/basketball/drafting/engine.rb
|
|
209
209
|
- lib/basketball/drafting/engine_serializer.rb
|
|
210
|
-
- lib/basketball/drafting/entity.rb
|
|
211
210
|
- lib/basketball/drafting/event.rb
|
|
212
211
|
- lib/basketball/drafting/front_office.rb
|
|
213
212
|
- lib/basketball/drafting/pick_event.rb
|
|
@@ -217,6 +216,8 @@ files:
|
|
|
217
216
|
- lib/basketball/drafting/roster.rb
|
|
218
217
|
- lib/basketball/drafting/sim_event.rb
|
|
219
218
|
- lib/basketball/drafting/team.rb
|
|
219
|
+
- lib/basketball/entity.rb
|
|
220
|
+
- lib/basketball/value_object.rb
|
|
220
221
|
- lib/basketball/version.rb
|
|
221
222
|
homepage: https://github.com/mattruggio/basketball
|
|
222
223
|
licenses:
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Basketball
|
|
4
|
-
module Drafting
|
|
5
|
-
class Entity
|
|
6
|
-
extend Forwardable
|
|
7
|
-
include Comparable
|
|
8
|
-
|
|
9
|
-
attr_reader :id
|
|
10
|
-
|
|
11
|
-
def_delegators :id, :to_s
|
|
12
|
-
|
|
13
|
-
def initialize(id)
|
|
14
|
-
raise ArgumentError, 'id is required' if id.to_s.empty?
|
|
15
|
-
|
|
16
|
-
@id = id.to_s.upcase
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def <=>(other)
|
|
20
|
-
id <=> other.id
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def ==(other)
|
|
24
|
-
id == other.id
|
|
25
|
-
end
|
|
26
|
-
alias eql? ==
|
|
27
|
-
|
|
28
|
-
def hash
|
|
29
|
-
id.hash
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|