basketball 0.0.25 → 0.0.26

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e02bf31c8332d0d1010f8ad9ff18cb09ddd3f97e4a7cefcb14ddf11d38633d67
4
- data.tar.gz: 9c4b3b0e1771c0a4d22e8c83ba9040089fae019f3726c8cda55ddecbb3d69fa1
3
+ metadata.gz: 11631dcd181d791f3eb5d9ca7af6bbfab2527c1837302ac83d72ff77bd990345
4
+ data.tar.gz: 4f9a808e1579e83d7ca7c811e1e75a82af919f1b9c53d9f5f67c9a4d2e846db2
5
5
  SHA512:
6
- metadata.gz: 65a444b460b134eeceecea00213a0e4887dc635b7d012f402e09404e4d3e2dea44931810f413da167ae72ea6fb9e2b1533aea4691d3b5d99ba841709388f95e0
7
- data.tar.gz: b193b20e0ba49d4cf4686150cc7abef344a3289bcefdeb4bfc168e57e2eb8f1c6d776e3eafdc6a618096ea29e0ae9d3e94d96b3c78f341efc461efab6f746b16
6
+ metadata.gz: 4e52ca8ea4a738af4dd3548b4332e60cac35cef0469c3a9e6698d7936358f624ddb30a79de5bfb54a43425ec83a9a20a77e7ec4f94663d9c6e2064f41d33f7ba
7
+ data.tar.gz: b0b07ad92d1aacab9a0d5aaba9dea3713b12ae4f1deeb8bcf9b08fa3d95b6a857b0b4dd2237a8cb979e37aa651bd770c4413d324ea92875b7b004e3ffa85f6a8
@@ -7,12 +7,14 @@ module Basketball
7
7
  value_reader :date,
8
8
  :home,
9
9
  :opponent_score,
10
+ :opponent_type,
10
11
  :opponent,
11
12
  :score
12
13
 
13
14
  alias home? home
14
15
 
15
- def initialize(date:, home:, opponent:, opponent_score:, score:)
16
+ # rubocop:disable Metrics/CyclomaticComplexity
17
+ def initialize(date:, home:, opponent:, opponent_score:, score:, opponent_type:)
16
18
  super()
17
19
 
18
20
  raise ArgumentError, 'date is required' unless date
@@ -21,15 +23,30 @@ module Basketball
21
23
  raise ArgumentError, 'opponent_score is required' unless opponent_score
22
24
  raise ArgumentError, 'home is required' if home.nil?
23
25
  raise CannotTieError, 'scores cannot be equal' if score == opponent_score
26
+ raise ArgumentError, 'opponent_type is required' unless opponent_type
24
27
 
25
28
  @date = date
26
29
  @opponent = opponent
27
30
  @score = score
28
31
  @opponent_score = opponent_score
29
32
  @home = home
33
+ @opponent_type = OpponentType.parse(opponent_type)
30
34
 
31
35
  freeze
32
36
  end
37
+ # rubocop:enable Metrics/CyclomaticComplexity
38
+
39
+ def divisional?
40
+ opponent_type == INTRA_DIVISIONAL
41
+ end
42
+
43
+ def intra_conference?
44
+ opponent_type == INTRA_CONFERENCE
45
+ end
46
+
47
+ def inter_conterence?
48
+ opponent_type == INTER_CONFERENCE
49
+ end
33
50
 
34
51
  def win?
35
52
  score > opponent_score
@@ -40,7 +57,10 @@ module Basketball
40
57
  end
41
58
 
42
59
  def to_s
43
- "[#{date}] #{win? ? 'Win' : 'Loss'} #{home? ? 'vs' : 'at'} #{opponent} (#{score}-#{opponent_score})"
60
+ win_display = win? ? 'win' : 'loss'
61
+ vs_display = home? ? 'vs' : 'at'
62
+
63
+ "[#{date}] #{opponent_type} #{win_display} #{vs_display} #{opponent} (#{score}-#{opponent_score})"
44
64
  end
45
65
  end
46
66
  end
@@ -4,19 +4,21 @@ module Basketball
4
4
  module Season
5
5
  # Base class describing what all games have in common.
6
6
  class Game < ValueObject
7
- value_reader :date, :home_opponent, :away_opponent
7
+ value_reader :date, :home_opponent, :away_opponent, :opponent_type
8
8
 
9
- def initialize(date:, home_opponent:, away_opponent:)
9
+ def initialize(date:, home_opponent:, away_opponent:, opponent_type:)
10
10
  super()
11
11
 
12
12
  raise ArgumentError, 'date is required' unless date
13
13
  raise ArgumentError, 'home_opponent is required' unless home_opponent
14
14
  raise ArgumentError, 'away_opponent is required' unless away_opponent
15
15
  raise ArgumentError, 'teams cannot play themselves' if home_opponent == away_opponent
16
+ raise ArgumentError, 'opponent_type is required' unless opponent_type
16
17
 
17
18
  @date = date
18
19
  @home_opponent = home_opponent
19
20
  @away_opponent = away_opponent
21
+ @opponent_type = OpponentType.parse(opponent_type)
20
22
 
21
23
  freeze
22
24
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Basketball
4
+ module Season
5
+ # Describes the relationship between two teams.
6
+ module OpponentType
7
+ INTRA_DIVISIONAL = :intra_divisional
8
+ INTRA_CONFERENCE = :intra_conference
9
+ INTER_CONFERENCE = :inter_conference
10
+
11
+ class << self
12
+ def parse(value)
13
+ OpponentType.const_get(value.to_s.upcase.to_sym)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -52,26 +52,28 @@ module Basketball
52
52
  details_by_date.values
53
53
  end
54
54
 
55
- def win_percentage
55
+ def win_percentage(opponent_type = nil)
56
+ game_count = game_count(opponent_type)
57
+
56
58
  return 0 unless game_count.positive?
57
59
 
58
- (win_count.to_f / game_count).round(3)
60
+ (win_count(opponent_type).to_f / game_count).round(3)
59
61
  end
60
62
 
61
- def win_percentage_display
62
- format('%.3f', win_percentage)
63
+ def win_percentage_display(opponent_type = nil)
64
+ format('%.3f', win_percentage(opponent_type))
63
65
  end
64
66
 
65
- def game_count
66
- details.length
67
+ def game_count(opponent_type)
68
+ details_for(opponent_type).length
67
69
  end
68
70
 
69
- def win_count
70
- details.count(&:win?)
71
+ def win_count(opponent_type = nil)
72
+ details_for(opponent_type).count(&:win?)
71
73
  end
72
74
 
73
- def loss_count
74
- details.count(&:loss?)
75
+ def loss_count(opponent_type = nil)
76
+ details_for(opponent_type).count(&:loss?)
75
77
  end
76
78
 
77
79
  def to_s
@@ -93,6 +95,10 @@ module Basketball
93
95
  private
94
96
 
95
97
  attr_reader :details_by_date
98
+
99
+ def details_for(opponent_type = nil)
100
+ details.select { |d| opponent_type.nil? || d.opponent_type == opponent_type }
101
+ end
96
102
  end
97
103
  end
98
104
  end
@@ -160,16 +160,19 @@ module Basketball
160
160
  matchups = matchup_plan(league)
161
161
 
162
162
  matchups.each do |(team1, team2), count|
163
- candidates = calendar.available_regular_matchup_dates(team1, team2)
164
- dates = candidates.sample(count)
165
- games = balanced_games(dates, team1, team2)
163
+ determine_opponent_type(league, team1, team2)
164
+ candidates = calendar.available_regular_matchup_dates(team1, team2)
165
+ dates = candidates.sample(count)
166
+ games = balanced_games(dates, team1, team2, league)
166
167
 
167
168
  games.each { |game| calendar.add!(game) }
168
169
  end
169
170
  end
170
171
 
171
- def balanced_games(dates, team1, team2)
172
+ def balanced_games(dates, team1, team2, league)
172
173
  dates.map.with_index(1) do |date, index|
174
+ opponent_type = determine_opponent_type(league, team1, team2)
175
+
173
176
  home_opponent, away_opponent =
174
177
  if index.even?
175
178
  [Opponent.from(team1), Opponent.from(team2)]
@@ -177,7 +180,7 @@ module Basketball
177
180
  [Opponent.from(team2), Opponent.from(team1)]
178
181
  end
179
182
 
180
- Regular.new(date:, home_opponent:, away_opponent:)
183
+ Regular.new(date:, home_opponent:, away_opponent:, opponent_type:)
181
184
  end
182
185
  end
183
186
 
@@ -198,8 +201,9 @@ module Basketball
198
201
 
199
202
  next if candidates.empty?
200
203
 
201
- date = candidates.sample
202
- game = random_exhibition_game(date, team, other_team)
204
+ opponent_type = determine_opponent_type(league, team, other_team)
205
+ date = candidates.sample
206
+ game = random_exhibition_game(date, team, other_team, opponent_type)
203
207
 
204
208
  calendar.add!(game)
205
209
 
@@ -208,7 +212,17 @@ module Basketball
208
212
  end
209
213
  end
210
214
 
211
- def random_exhibition_game(date, team1, team2)
215
+ def determine_opponent_type(league, team1, team2)
216
+ if league.division_for(team1) == league.division_for(team2)
217
+ OpponentType::INTRA_DIVISIONAL
218
+ elsif league.conference_for(team1) == league.conference_for(team2)
219
+ OpponentType::INTRA_CONFERENCE
220
+ else
221
+ OpponentType::INTER_CONFERENCE
222
+ end
223
+ end
224
+
225
+ def random_exhibition_game(date, team1, team2, opponent_type)
212
226
  home_opponent, away_opponent =
213
227
  if rand(1..2) == 1
214
228
  [Opponent.from(team1), Opponent.from(team2)]
@@ -216,7 +230,7 @@ module Basketball
216
230
  [Opponent.from(team2), Opponent.from(team1)]
217
231
  end
218
232
 
219
- Exhibition.new(date:, home_opponent:, away_opponent:)
233
+ Exhibition.new(date:, home_opponent:, away_opponent:, opponent_type:)
220
234
  end
221
235
  end
222
236
  end
@@ -6,6 +6,7 @@ require_relative 'season/calendar'
6
6
  require_relative 'season/game'
7
7
  require_relative 'season/matchup'
8
8
  require_relative 'season/opponent'
9
+ require_relative 'season/opponent_type'
9
10
  require_relative 'season/result'
10
11
 
11
12
  # League Common
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Basketball
4
- VERSION = '0.0.25'
4
+ VERSION = '0.0.26'
5
5
  end
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.25
4
+ version: 0.0.26
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-06-30 00:00:00.000000000 Z
11
+ date: 2023-07-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: " This library is meant to serve as the domain for a basketball league/season
14
14
  simulator/turn-based game. It models core ideas such as: players, general managers,
@@ -62,6 +62,7 @@ files:
62
62
  - lib/basketball/season/league.rb
63
63
  - lib/basketball/season/matchup.rb
64
64
  - lib/basketball/season/opponent.rb
65
+ - lib/basketball/season/opponent_type.rb
65
66
  - lib/basketball/season/player.rb
66
67
  - lib/basketball/season/position.rb
67
68
  - lib/basketball/season/record.rb