hlockey 1 → 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.
data/lib/data/season.rb DELETED
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Season
4
- NUMBER = 1
5
- START_TIME = Time.utc(2022, 7, 4, 17).localtime.freeze
6
- ELECTION = {
7
- 'Bribery': {
8
- 'Eat More RAM': 'Add an online interface to the league.',
9
- 'Weather': 'Move all the stadiums outdoors.',
10
- 'We Do A Little Losing': 'Recognize the losingest teams with an Underbracket.'
11
- },
12
- 'Treasure': {
13
- 'Vengence': 'All your team\'s stats are boosted by your team\'s losses * 0.005.',
14
- 'Dave': 'The worst stat on your team is set to 4.5.',
15
- 'Nice': 'Boost your worst player by 0.69 in every stat.',
16
- 'Convenient Math Error': 'Your team starts the next season with 5 wins.'
17
- },
18
- 'Coaching': {
19
- 'Player Swapping': 'Swap the positions of 2 players on your team.',
20
- 'Stat Swapping': 'Swap 2 stats of a player on your team.',
21
- 'Draft': 'Replace a player with a random new player.',
22
- 'Small Gamble': 'All your team\'s stats go up or down by 0.5 at random.',
23
- 'Big Gamble': 'All your team\'s stats go up or down by 1.0 at random.'
24
- }
25
- }.freeze
26
- ELECTION_FORM = 'https://forms.gle/saLp3ucxg2ERsY9L7'
27
- end
data/lib/game.rb DELETED
@@ -1,158 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative('./messages')
4
-
5
- class Game
6
- attr_reader(:home, :away, :stream, :in_progress)
7
-
8
- def initialize(home, away, prng)
9
- @home = home
10
- @away = away
11
- @prng = prng
12
- @stream = [Messages.StartOfGame(to_s)]
13
- @in_progress = true
14
- @score = { home: 0, away: 0 }
15
- @actions = 0
16
- @period = 1
17
- @face_off = true
18
- @team_with_puck = nil
19
- @puckless_team = nil
20
- @puck_holder = nil
21
- @shooting_chance = 0
22
- end
23
-
24
- def to_s
25
- "#{@home.emoji} #{@home.name} vs #{@away.name} #{@away.emoji}"
26
- end
27
-
28
- def update
29
- return unless @in_progress
30
-
31
- @stream << Messages.StartOfPeriod(@period) if @actions.zero?
32
- @actions += 1
33
-
34
- if @actions == 60
35
- @stream << Messages.EndOfPeriod(@period, @home.name, @away.name, *@score.values)
36
- @actions = 0
37
- @period += 1
38
- start_faceoff
39
-
40
- if @period > 3 && !(@score[:home] == @score[:away] && @period < 12)
41
- # Game is over
42
- @in_progress = false
43
-
44
- winner, loser = @score[:away] > @score[:home] ? [@away, @home] : [@home, @away]
45
-
46
- @stream << Messages.EndOfGame(winner.name)
47
- winner.wins += 1
48
- loser.losses += 1
49
- end
50
- return
51
- end
52
-
53
- if @face_off
54
- if @puck_holder.nil?
55
- # Pass opposite team to who wins the puck to switch_team_with_puck,
56
- # so @team_with_puck & @puckless_team are set to the correct values.
57
- switch_team_with_puck(if action_succeeds?(@home.roster[:center].stats[:offense],
58
- @away.roster[:center].stats[:offense])
59
- @away
60
- else
61
- @home
62
- end)
63
-
64
- @puck_holder = @team_with_puck.roster[:center]
65
- @stream << Messages.FaceOff(@puck_holder)
66
- else
67
- pass
68
- @face_off = false
69
- end
70
- return
71
- end
72
-
73
- case @prng.rand 5 + @shooting_chance
74
- when 0..4
75
- pass
76
- when 5..6 # Check
77
- defender = puckless_non_goalie
78
- @stream << Messages.Hit(@puck_holder, defender,
79
- try_take_puck(defender, 0, :defense))
80
- else # Shoot
81
- unless @shooting_chance < 5 &&
82
- try_block_shot(@puckless_team.roster[@prng.rand(2).zero? ? :ldef : :rdef]) ||
83
- try_block_shot(@puckless_team.roster[:goalie])
84
- @score[@team_with_puck == @home ? :home : :away] += 1
85
-
86
- @stream << Messages.Shoot(@puck_holder,
87
- nil, false,
88
- @home.name, @away.name,
89
- *@score.values)
90
-
91
- start_faceoff
92
- @actions = 59 if @period > 3 # Sudden death overtime
93
- end
94
- end
95
- end
96
-
97
- private
98
-
99
- def action_succeeds?(helping_stat, hindering_stat)
100
- @prng.rand(10) + helping_stat - hindering_stat > 4
101
- end
102
-
103
- def start_faceoff
104
- @shooting_chance = 0
105
- @face_off = true
106
- @puck_holder = nil
107
- end
108
-
109
- def switch_team_with_puck(team_with_puck = @team_with_puck)
110
- @team_with_puck, @puckless_team = if team_with_puck == @home
111
- [@away, @home]
112
- else
113
- [@home, @away]
114
- end
115
- @shooting_chance = 0
116
- end
117
-
118
- def pass
119
- sender = @puck_holder
120
- receiver = puckless_non_goalie(@team_with_puck)
121
- interceptor = puckless_non_goalie
122
-
123
- if !@face_off && try_take_puck(interceptor, 4) # Pass intercepted
124
- @stream << Messages.Pass(sender, receiver, interceptor)
125
- return
126
- end
127
-
128
- @stream << Messages.Pass(sender, receiver)
129
- @puck_holder = receiver
130
- @shooting_chance += 1
131
- end
132
-
133
- def try_take_puck(player, dis = 0, stat = :agility)
134
- return false unless action_succeeds?(player.stats[stat] - dis,
135
- @puck_holder.stats[stat])
136
-
137
- switch_team_with_puck
138
- @puck_holder = player
139
-
140
- true
141
- end
142
-
143
- def try_block_shot(blocker)
144
- return false unless action_succeeds?(blocker.stats[:defense],
145
- @puck_holder.stats[:offense])
146
-
147
- @shooting_chance += 1
148
- @stream << Messages.Shoot(@puck_holder, blocker, try_take_puck(blocker))
149
-
150
- true
151
- end
152
-
153
- def puckless_non_goalie(team = @puckless_team)
154
- team.roster.values.select do |p|
155
- p != team.roster[:goalie] and p != @puck_holder
156
- end.sample(random: @prng)
157
- end
158
- end
data/lib/league.rb DELETED
@@ -1,140 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require('yaml')
4
- require_relative('./game')
5
-
6
- class League
7
- attr_reader(:divisions, :day, :games_in_progress, :playoff_teams, :champion_team)
8
-
9
- class Team
10
- private_class_method(:new)
11
-
12
- attr_accessor(:wins, :losses)
13
- attr_reader(:name, :emoji, :roster)
14
-
15
- def to_s
16
- "#{@emoji} #{@name}"
17
- end
18
-
19
- def print_win_loss
20
- puts(" #{to_s.ljust 26} #{@wins}-#{@losses}")
21
- end
22
-
23
- def print_roster
24
- puts(to_s)
25
- @roster.each do |pos, player|
26
- puts(" #{pos.to_s.ljust(6)}: #{player}")
27
- player.stats.each { |stat, value| puts(" #{stat}: #{value.round 1}") }
28
- end
29
- end
30
-
31
- def self.sort(teams)
32
- teams.sort { |a, b| b.wins - b.losses <=> a.wins - a.losses }
33
- end
34
- end
35
-
36
- def initialize(season, start_time)
37
- # The YAML file is included with the program,
38
- # so this is as safe as anything else
39
- @divisions = YAML.unsafe_load_file(File.expand_path('data/divisions.yaml',
40
- File.dirname(__FILE__)))
41
-
42
- @day = 0
43
- @games_in_progress = []
44
- @games = []
45
- @champion_team = nil
46
- @last_update_time = start_time
47
- @passed_updates = 0
48
- @prng = Random.new(69_420 * season)
49
- @shuffled_teams = @divisions.values.reduce(:+).shuffle(random: @prng)
50
- @playoff_teams = nil
51
- @game_in_matchup = 3
52
- end
53
-
54
- def update_state
55
- return if @champion_team
56
-
57
- now = Time.at(Time.now.to_i)
58
- five_sec_intervals = (now - @last_update_time).div(5)
59
-
60
- return unless five_sec_intervals.positive?
61
-
62
- five_sec_intervals.times do |i|
63
- if ((i + @passed_updates) % 720).zero?
64
- new_games
65
- else
66
- update_games
67
- end
68
-
69
- break if @champion_team
70
- end
71
-
72
- @last_update_time = now
73
- @passed_updates += five_sec_intervals
74
- end
75
-
76
- private
77
-
78
- def new_games
79
- if @game_in_matchup != (@day > 38 ? 5 : 3)
80
- # New game in matchups
81
- @games.map! { |game| Game.new(game.away, game.home, @prng) }
82
- @game_in_matchup += 1
83
- return
84
- end
85
-
86
- # New matchups
87
- @games.clear
88
- @game_in_matchup = 1
89
- @day += 1
90
-
91
- case @day <=> 39
92
- when -1
93
- (@shuffled_teams.length / 2).times do |i|
94
- pair = [@shuffled_teams[i], @shuffled_teams[-i - 1]]
95
- @games << Game.new(*(@day > 19 ? pair : pair.reverse), @prng)
96
- end
97
-
98
- @shuffled_teams.insert 1, @shuffled_teams.pop
99
- when 0
100
- @playoff_teams = Team.sort(
101
- @divisions.values.map do |teams|
102
- Team.sort(teams).first(2)
103
- end.reduce(:+)
104
- ).map(&:clone)
105
-
106
- new_playoff_matchups
107
- when 1
108
- @playoff_teams = Team.sort(@playoff_teams).first(@playoff_teams.length / 2)
109
-
110
- if @playoff_teams.length == 1
111
- @champion_team = @playoff_teams[0]
112
- return
113
- end
114
-
115
- new_playoff_matchups
116
- end
117
- end
118
-
119
- def update_games
120
- @games_in_progress.each(&:update)
121
- @games_in_progress = @games.select(&:in_progress)
122
- end
123
-
124
- def new_playoff_matchups
125
- @playoff_teams.each do |team|
126
- team.wins = 0
127
- team.losses = 0
128
- end
129
-
130
- (0...@playoff_teams.length).step(2) do |i|
131
- @games << Game.new(*@playoff_teams[i, 2], @prng)
132
- end
133
- end
134
-
135
- class Player
136
- private_class_method(:new)
137
-
138
- attr_reader(:stats, :to_s)
139
- end
140
- end
data/lib/messages.rb DELETED
@@ -1,66 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Messages
4
- def initialize(event, fields, data)
5
- @event = event
6
- fields.zip(data) do |(f, d)|
7
- instance_variable_set("@#{f}", d)
8
- end
9
- end
10
-
11
- private_class_method(:new)
12
-
13
- class << self
14
- [
15
- %i[StartOfGame title],
16
- %i[EndOfGame winning_team],
17
- %i[StartOfPeriod period],
18
- %i[EndOfPeriod period home away home_score away_score],
19
- %i[FaceOff winning_player],
20
- %i[Hit puck_holder defender puck_taken],
21
- %i[Pass sender receiver interceptor],
22
- %i[Shoot shooter blocker puck_taken home away home_score away_score]
23
- ].each do |event, *fields|
24
- define_method event do |*data|
25
- new(event, fields, data)
26
- end
27
- end
28
- end
29
-
30
- def to_s
31
- case @event
32
- when :StartOfGame
33
- "#{@title}\nHocky!"
34
- when :EndOfGame
35
- "Game over.\n#{@winning_team} wins!"
36
- when :StartOfPeriod
37
- "Start#{of_period}"
38
- when :EndOfPeriod
39
- "End#{of_period}#{score}"
40
- when :FaceOff
41
- "#{@winning_player} wins the faceoff!"
42
- when :Hit
43
- "#{@defender} hits #{@puck_holder.to_s + takes}!"
44
- when :Pass
45
- "#{@sender} passes to #{@receiver}" +
46
- (@interceptor ? "... intercepted by #{@interceptor}!" : '.')
47
- when :Shoot
48
- "#{@shooter} takes a shot... " +
49
- (@blocker ? "#{@blocker} blocks the shot#{takes}!" : "and scores!#{score}")
50
- end
51
- end
52
-
53
- private
54
-
55
- def of_period
56
- " of period #{@period}."
57
- end
58
-
59
- def score
60
- "\n#{@home} #{@home_score}, #{@away} #{@away_score}"
61
- end
62
-
63
- def takes
64
- @puck_taken ? ' and takes the puck' : ''
65
- end
66
- end