hlockey 1 → 2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []