hlockey 1 → 2

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.
@@ -0,0 +1,2 @@
1
+ :GitHub: https://github.com/Hlockey
2
+ :Discord: https://discord.gg/hQMRZyexUB
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('yaml')
4
+
5
+ module Hlockey
6
+ # Loads data for the current Hlockey season.
7
+ # +category+ can be 'league', 'election', 'information', or 'links'.
8
+ # If it is anything else, there will be an error.
9
+ def Hlockey.load_data(category)
10
+ # If this is only used on data included with the gem, it should be safe
11
+ YAML.unsafe_load_file(File.expand_path("data/#{category}.yaml", __dir__))
12
+ end
13
+ end
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('hlockey/messages')
4
+
5
+ module Hlockey
6
+ class Game
7
+ attr_reader(:home, :away, :stream, :score, :in_progress)
8
+
9
+ def initialize(home, away, prng)
10
+ @home = home
11
+ @away = away
12
+ @prng = prng
13
+ @stream = [Messages.StartOfGame]
14
+ @score = { home: 0, away: 0 }
15
+ @in_progress = true
16
+ @actions = 0
17
+ @period = 1
18
+ @face_off = true
19
+ @team_with_puck = nil
20
+ @puckless_team = nil
21
+ @puck_holder = nil
22
+ @shooting_chance = 0
23
+ end
24
+
25
+ def to_s
26
+ "#{@home} vs #{@away}"
27
+ end
28
+
29
+ def update
30
+ return unless @in_progress
31
+
32
+ @stream << Messages.StartOfPeriod(@period) if @actions.zero?
33
+ @actions += 1
34
+
35
+ if @actions == 60
36
+ @stream << Messages.EndOfPeriod(@period, @home, @away, *@score.values)
37
+ @actions = 0
38
+ @period += 1
39
+ start_faceoff
40
+
41
+ if @period > 3 && !(@score[:home] == @score[:away] && @period < 12)
42
+ # Game is over
43
+ @in_progress = false
44
+
45
+ winner, loser = @score[:away] > @score[:home] ?
46
+ [@away, @home] : [@home, @away]
47
+
48
+ @stream << Messages.EndOfGame(winner)
49
+ winner.wins += 1
50
+ loser.losses += 1
51
+ end
52
+ return
53
+ end
54
+
55
+ if @face_off
56
+ if @puck_holder.nil?
57
+ # Pass opposite team to who wins the puck to switch_team_with_puck,
58
+ # so @team_with_puck & @puckless_team are set to the correct values.
59
+ switch_team_with_puck(
60
+ action_succeeds?(@home.roster[:center].stats[:offense],
61
+ @away.roster[:center].stats[:offense]) ? @away : @home
62
+ )
63
+
64
+ @puck_holder = @team_with_puck.roster[:center]
65
+ @stream << Messages.FaceOff(@puck_holder, @team_with_puck)
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
+ check
78
+ else # Shoot
79
+ unless @shooting_chance < 5 &&
80
+ try_block_shot(@puckless_team.roster[@prng.rand(2).zero? ?
81
+ :ldef : :rdef]) ||
82
+ try_block_shot(@puckless_team.roster[:goalie])
83
+ @score[@team_with_puck == @home ? :home : :away] += 1
84
+
85
+ @stream << Messages.ShootScore(@puck_holder, @home, @away, *@score.values)
86
+
87
+ start_faceoff
88
+ @actions = 59 if @period > 3 # Sudden death overtime
89
+ end
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ def action_succeeds?(helping_stat, hindering_stat)
96
+ @prng.rand(10) + helping_stat - hindering_stat > 4
97
+ end
98
+
99
+ def start_faceoff
100
+ @shooting_chance = 0
101
+ @face_off = true
102
+ @puck_holder = nil
103
+ end
104
+
105
+ def switch_team_with_puck(team_with_puck = @team_with_puck)
106
+ @team_with_puck, @puckless_team = team_with_puck == @home ?
107
+ [@away, @home] : [@home, @away]
108
+ @shooting_chance = 0
109
+ end
110
+
111
+ def pass
112
+ sender = @puck_holder
113
+ receiver = puckless_non_goalie(@team_with_puck)
114
+ interceptor = puckless_non_goalie
115
+
116
+ if !@face_off && try_take_puck(interceptor, 4) # Pass intercepted
117
+ @stream << Messages.Pass(sender, receiver, interceptor, @team_with_puck)
118
+ return
119
+ end
120
+
121
+ @stream << Messages.Pass(sender, receiver)
122
+ @puck_holder = receiver
123
+ @shooting_chance += 1
124
+ end
125
+
126
+ def check
127
+ defender = puckless_non_goalie
128
+ @stream << Messages.Hit(@puck_holder, defender,
129
+ try_take_puck(defender, 0, :defense), @team_with_puck)
130
+ end
131
+
132
+ def try_take_puck(player, dis = 0, stat = :agility)
133
+ return false unless action_succeeds?(player.stats[stat] - dis,
134
+ @puck_holder.stats[stat])
135
+
136
+ switch_team_with_puck
137
+ @puck_holder = player
138
+
139
+ true
140
+ end
141
+
142
+ def try_block_shot(blocker)
143
+ return false unless action_succeeds?(blocker.stats[:defense],
144
+ @puck_holder.stats[:offense])
145
+
146
+ @shooting_chance += 1
147
+ @stream << Messages.ShootBlock(@puck_holder, blocker,
148
+ try_take_puck(blocker), @team_with_puck)
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
159
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('hlockey/data')
4
+ require('hlockey/game')
5
+ require('hlockey/team')
6
+ require('hlockey/version')
7
+
8
+ module Hlockey
9
+ class League
10
+ attr_reader(:start_time, :divisions, :teams, :day,
11
+ :games, :games_in_progress, :playoff_teams, :champion_team)
12
+
13
+ def initialize
14
+ @start_time, @divisions = Hlockey.load_data('league')
15
+ @start_time.localtime
16
+ @day = 0
17
+ @games_in_progress = []
18
+ @games = []
19
+ @champion_team = nil
20
+ @last_update_time = @start_time
21
+ @passed_updates = 0
22
+ @prng = Random.new(69_420 * VERSION.to_i)
23
+ @teams = @divisions.values.reduce(:+)
24
+ @shuffled_teams = teams.shuffle(random: @prng)
25
+ @playoff_teams = nil
26
+ @game_in_matchup = 3
27
+ end
28
+
29
+ def update_state
30
+ return if @champion_team
31
+
32
+ now = Time.at(Time.now.to_i)
33
+ five_sec_intervals = (now - @last_update_time).div(5)
34
+
35
+ return unless five_sec_intervals.positive?
36
+
37
+ five_sec_intervals.times do |i|
38
+ if ((i + @passed_updates) % 720).zero?
39
+ new_games
40
+ else
41
+ update_games
42
+ end
43
+
44
+ break if @champion_team
45
+ end
46
+
47
+ @last_update_time = now
48
+ @passed_updates += five_sec_intervals
49
+ end
50
+
51
+ private
52
+
53
+ def new_games
54
+ if @game_in_matchup != (@day > 38 ? 5 : 3)
55
+ # New game in matchups
56
+ @games.map! { |game| Game.new(game.away, game.home, @prng) }
57
+ @game_in_matchup += 1
58
+ return
59
+ end
60
+
61
+ # New matchups
62
+ @games.clear
63
+ @game_in_matchup = 1
64
+ @day += 1
65
+
66
+ case @day <=> 39
67
+ when -1
68
+ (@shuffled_teams.length / 2).times do |i|
69
+ pair = [@shuffled_teams[i], @shuffled_teams[-i - 1]]
70
+ @games << Game.new(*(@day > 19 ? pair : pair.reverse), @prng)
71
+ end
72
+
73
+ @shuffled_teams.insert 1, @shuffled_teams.pop
74
+ when 0
75
+ @playoff_teams = sort_teams_by_wins(
76
+ @divisions.values.map do |teams|
77
+ sort_teams_by_wins(teams).first(2)
78
+ end.reduce(:+)
79
+ ).map(&:clone)
80
+
81
+ new_playoff_matchups
82
+ when 1
83
+ @playoff_teams.select! { |team| team.wins > team.losses }
84
+
85
+ if @playoff_teams.length == 1
86
+ @champion_team = @playoff_teams[0]
87
+ return
88
+ end
89
+
90
+ new_playoff_matchups
91
+ end
92
+ end
93
+
94
+ def update_games
95
+ @games_in_progress.each(&:update)
96
+ @games_in_progress = @games.select(&:in_progress)
97
+ @divisions.transform_values!(&method(:sort_teams_by_wins))
98
+ end
99
+
100
+ def new_playoff_matchups
101
+ @playoff_teams.each do |team|
102
+ team.wins = 0
103
+ team.losses = 0
104
+ end
105
+
106
+ (@playoff_teams.length / 2).times do |i|
107
+ @games << Game.new(@playoff_teams[i], @playoff_teams[-i - 1], @prng)
108
+ end
109
+ end
110
+
111
+ def sort_teams_by_wins(teams)
112
+ teams.sort { |a, b| b.wins <=> a.wins }
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('hlockey/version')
4
+
5
+ module Hlockey
6
+ class Messages
7
+ private_class_method(:new)
8
+
9
+ def initialize(event, fields, data)
10
+ @event = event
11
+ fields.zip(data) do |(f, d)|
12
+ instance_variable_set("@#{f}", d)
13
+ end
14
+ end
15
+
16
+ class << self
17
+ # These are messages logged to game streams
18
+
19
+ [
20
+ %i[StartOfGame],
21
+ %i[EndOfGame winning_team],
22
+ %i[StartOfPeriod period],
23
+ %i[EndOfPeriod period home away home_score away_score],
24
+ %i[FaceOff winning_player new_puck_team],
25
+ %i[Hit puck_holder defender puck_taken new_puck_team],
26
+ %i[Pass sender receiver interceptor new_puck_team],
27
+ %i[ShootScore shooter home away home_score away_score],
28
+ %i[ShootBlock shooter blocker puck_taken new_puck_team]
29
+ ].each do |event, *fields|
30
+ define_method(event) do |*data|
31
+ new(event, fields, data)
32
+ end
33
+ end
34
+
35
+ # These are messages used elsewhere
36
+
37
+ def SeasonDay(day)
38
+ "Season #{VERSION} day #{day}"
39
+ end
40
+
41
+ def SeasonStarts(time)
42
+ time.strftime("Season #{VERSION} starts at %H:%M, %A, %B %d (%Z).")
43
+ end
44
+
45
+ def SeasonChampion(team)
46
+ "Your season #{VERSION} champions are the #{team}!"
47
+ end
48
+
49
+ def NoGames
50
+ 'no games right now. it is the offseason. join the Hlockey Discord for updates'
51
+ end
52
+ end
53
+
54
+ def to_s
55
+ case @event
56
+ when :StartOfGame
57
+ 'Hocky!'
58
+ when :EndOfGame
59
+ "Game over.\n#{@winning_team} win!"
60
+ when :StartOfPeriod
61
+ "Start#{of_period}"
62
+ when :EndOfPeriod
63
+ "End#{of_period}#{score}"
64
+ when :FaceOff
65
+ "#{@winning_player} wins the faceoff!#{possession_change}"
66
+ when :Hit
67
+ "#{@defender} hits #{@puck_holder}#{takes}"
68
+ when :Pass
69
+ "#{@sender} passes to #{@receiver}." +
70
+ "#{"..\nIntercepted by #{@interceptor}!#{possession_change}" if @interceptor}"
71
+ when :ShootScore
72
+ "#{shot} and scores!#{score}"
73
+ when :ShootBlock
74
+ "#{shot}...\n#{@blocker} blocks the shot#{takes}"
75
+ end
76
+ end
77
+
78
+ private
79
+
80
+ def of_period
81
+ " of period #{@period}."
82
+ end
83
+
84
+ def score
85
+ "\n#{@home} #{@home_score}, #{@away} #{@away_score}"
86
+ end
87
+
88
+ def shot
89
+ "#{@shooter} takes a shot"
90
+ end
91
+
92
+ def takes
93
+ @puck_taken ? " and takes the puck!#{possession_change}" : '!'
94
+ end
95
+
96
+ def possession_change
97
+ "\n#{@new_puck_team} have possession."
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hlockey
4
+ # Created by League when data is loaded
5
+ class Team
6
+ private_class_method(:new)
7
+ attr_accessor(:wins, :losses, :roster)
8
+ attr_reader(:to_s, :emoji)
9
+
10
+ def w_l
11
+ "#{@wins}-#{@losses}"
12
+ end
13
+
14
+ # Created by League when data is loaded
15
+ class Player
16
+ attr_accessor(:stats, :to_s)
17
+ end
18
+ end
19
+
20
+ # Takes symbol from Team roster & converts it to full position name
21
+ def Hlockey.pos_name(pos)
22
+ case pos
23
+ when :lwing
24
+ 'Left wing'
25
+ when :rwing
26
+ 'Right wing'
27
+ when :ldef
28
+ 'Left defender'
29
+ when :rdef
30
+ 'Right defender'
31
+ else
32
+ pos.capitalize.to_s
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hlockey
4
+ VERSION = '2'
5
+ end
data/lib/hlockey.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('hlockey/league')
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hlockey
3
3
  version: !ruby/object:Gem::Version
4
- version: '1'
4
+ version: '2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lavender Perry
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-03 00:00:00.000000000 Z
11
+ date: 2022-08-08 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: Hockey sports sim.
13
+ description: Hlockey library and console application.
14
14
  email: endie2@protonmail.com
15
15
  executables:
16
16
  - hlockey
@@ -18,16 +18,22 @@ extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
20
  - bin/hlockey
21
- - lib/data/divisions.yaml
22
- - lib/data/season.rb
23
- - lib/game.rb
24
- - lib/league.rb
25
- - lib/messages.rb
26
- homepage: https://github.com/Lavender-Perry/hlockey
21
+ - lib/hlockey.rb
22
+ - lib/hlockey/data.rb
23
+ - lib/hlockey/data/election.yaml
24
+ - lib/hlockey/data/information.yaml
25
+ - lib/hlockey/data/league.yaml
26
+ - lib/hlockey/data/links.yaml
27
+ - lib/hlockey/game.rb
28
+ - lib/hlockey/league.rb
29
+ - lib/hlockey/messages.rb
30
+ - lib/hlockey/team.rb
31
+ - lib/hlockey/version.rb
32
+ homepage: https://hlockey.herokuapp.com
27
33
  licenses:
28
34
  - LicenseRef-LICENSE.md
29
35
  metadata:
30
- source_code_uri: https://github.com/Lavender-Perry/hlockey
36
+ source_code_uri: https://github.com/Hlockey/hlockey
31
37
  post_install_message:
32
38
  rdoc_options: []
33
39
  require_paths:
@@ -46,5 +52,5 @@ requirements: []
46
52
  rubygems_version: 3.3.7
47
53
  signing_key:
48
54
  specification_version: 4
49
- summary: Hlockey season 1.
55
+ summary: Hlockey season 2.
50
56
  test_files: []