basketball 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eade2dd71d031c05eaf7e5fa792056d9ee6621f6168c6cbd288e5106f0fe4c3a
4
- data.tar.gz: 66b92eb67dd64d84288dc5869b2076753d043311e22d903d4d8e5468ea90f7f6
3
+ metadata.gz: 29805ef216312c25dee77d7f7c2a82bf220287404e9e241d24e16dddfb895fcc
4
+ data.tar.gz: 3d8a0038acf62e4e1aa230299cc1b2d7d777596bc133b159b1e661639c75c76d
5
5
  SHA512:
6
- metadata.gz: 72a89afec17d978e79dd979a50188c62c19532a77143312a79f387a182cab5988a7e90399be60f019ce3a5d6639f5eb0ddc3f14ca896e5f3c3496488be3427de
7
- data.tar.gz: 4f04e99ddd1e64ad893395264c5753b975f4c46b741324d53bd125c1f2a8daa2079c44e2a85fd52bf6dd24d7b09fcf29c5f9266db4c67da19e8f952884de8a72
6
+ metadata.gz: ae3baac2215dbfee6b9cf70a44b2bdf9257d7dade811c6a30bf37b22f840bd85621f6441d137e07f38b615210092d0cede011a2e9f4655aa1e05c6281411a856
7
+ data.tar.gz: 4bcb67de94178f2945376faa2cb57c5f5884d60b24479d73e12d1145c7c20c1b9f3dd547f321c578f39d43868fb2f8d158859020b14d7e436fbface8a89b2809
data/CHANGELOG.md CHANGED
@@ -1,4 +1,9 @@
1
- #### 0.0.1 - May 4th, 2023
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
2
7
 
3
8
  * Remove autoloading in favor of require statements.
4
9
 
@@ -98,12 +98,13 @@ module Basketball
98
98
 
99
99
  def sim!(times = nil)
100
100
  counter = 0
101
+ events = []
101
102
 
102
103
  until done? || (times && counter >= times)
103
104
  team = current_team
104
105
 
105
106
  player = team.pick(
106
- undrafted_players:,
107
+ undrafted_player_search:,
107
108
  drafted_players: drafted_players(team),
108
109
  round: current_round
109
110
  )
@@ -122,9 +123,10 @@ module Basketball
122
123
  yield(event) if block_given?
123
124
 
124
125
  counter += 1
126
+ events << event
125
127
  end
126
128
 
127
- self
129
+ events
128
130
  end
129
131
 
130
132
  def pick!(player)
@@ -146,6 +148,10 @@ module Basketball
146
148
  players - drafted_players
147
149
  end
148
150
 
151
+ def undrafted_player_search
152
+ PlayerSearch.new(undrafted_players)
153
+ end
154
+
149
155
  private
150
156
 
151
157
  attr_reader :players_by_id, :teams_by_id
@@ -101,7 +101,7 @@ module Basketball
101
101
  first_name: player.first_name,
102
102
  last_name: player.last_name,
103
103
  overall: player.overall,
104
- position: player.position.value
104
+ position: player.position.code
105
105
  }
106
106
  ]
107
107
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'entity'
4
-
5
3
  module Basketball
6
4
  module Drafting
7
5
  class Event < Entity
@@ -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
- attr_reader :prioritized_positions, :fuzz, :depth
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 to_s
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(undrafted_players:, drafted_players:) if depth >= round
35
- players = balanced_search(undrafted_players:, drafted_players:) if players.empty?
36
- players = top_players(undrafted_players:) if players.empty?
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(undrafted_players:, drafted_players:)
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
- search.query(exclude_positions: drafted_positions)
44
+ undrafted_player_search.query(exclude_positions: drafted_positions)
49
45
  end
50
46
 
51
- def balanced_search(undrafted_players:, drafted_players:)
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 = search.query(position:)
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 : search.query
58
+ players = players.any? ? players : undrafted_player_search.query
65
59
  end
66
60
 
67
61
  def all_random_positions
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'entity'
4
-
5
3
  module Basketball
6
4
  module Drafting
7
5
  class Player < Entity
@@ -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
- attr_reader :value
20
+ attr_reader_value :code
21
21
 
22
- def_delegators :value, :to_s
22
+ def_delegators :code, :to_s
23
23
 
24
- def initialize(value)
25
- @value = value.to_s.upcase
24
+ def initialize(code)
25
+ super()
26
26
 
27
- raise InvalidPositionError, "Unknown position value: #{@value}" unless ALL_VALUES.include?(@value)
27
+ @code = code.to_s.upcase
28
28
 
29
- freeze
30
- end
29
+ raise InvalidPositionError, "Unknown position code: #{@code}" unless ALL_VALUES.include?(@code)
31
30
 
32
- def ==(other)
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
- attr_reader :team, :events
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)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'event'
4
-
5
3
  module Basketball
6
4
  module Drafting
7
5
  class SimEvent < Event
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'entity'
4
-
5
3
  module Basketball
6
4
  module Drafting
7
5
  class Team < Entity
6
+ extend Forwardable
7
+
8
8
  attr_reader :name, :front_office
9
9
 
10
+ def_delegators :front_office, :pick
11
+
10
12
  def initialize(id:, name: '', front_office: FrontOffice.new)
11
13
  super(id)
12
14
 
@@ -21,10 +23,6 @@ module Basketball
21
23
  def to_s
22
24
  "[#{super}] #{name}"
23
25
  end
24
-
25
- def pick(undrafted_players:, drafted_players:, round:)
26
- front_office.pick(undrafted_players:, drafted_players:, round:)
27
- end
28
26
  end
29
27
  end
30
28
  end
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Basketball
4
- VERSION = '0.0.2'
4
+ VERSION = '0.0.3'
5
5
  end
data/lib/basketball.rb CHANGED
@@ -7,4 +7,9 @@ require 'json'
7
7
  require 'securerandom'
8
8
  require 'slop'
9
9
 
10
+ # Top-level
11
+ require_relative 'basketball/entity'
12
+ require_relative 'basketball/value_object'
13
+
14
+ # Submodules
10
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.2
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-04 00:00:00.000000000 Z
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