hlockey 2 → 4
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 +4 -4
- data/data/election.yaml +21 -0
- data/data/external/names.txt +19948 -0
- data/data/information.yaml +24 -0
- data/data/league.yaml +1526 -0
- data/data/links.yaml +3 -0
- data/data/previous_election_results.yaml +59 -0
- data/lib/hlockey/constants.rb +4 -0
- data/lib/hlockey/data.rb +17 -13
- data/lib/hlockey/game/actions.rb +27 -0
- data/lib/hlockey/game/fight.rb +99 -0
- data/lib/hlockey/game.rb +321 -159
- data/lib/hlockey/league.rb +254 -115
- data/lib/hlockey/message.rb +182 -0
- data/lib/hlockey/player.rb +73 -0
- data/lib/hlockey/team.rb +52 -35
- data/lib/hlockey/utils.rb +15 -0
- data/lib/hlockey/version.rb +3 -5
- data/lib/hlockey/weather.rb +168 -0
- data/lib/hlockey.rb +1 -3
- metadata +36 -16
- data/bin/hlockey +0 -104
- data/lib/hlockey/data/election.yaml +0 -16
- data/lib/hlockey/data/information.yaml +0 -12
- data/lib/hlockey/data/league.yaml +0 -846
- data/lib/hlockey/data/links.yaml +0 -2
- data/lib/hlockey/messages.rb +0 -100
data/lib/hlockey/team.rb
CHANGED
@@ -1,35 +1,52 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module Hlockey
|
4
|
-
# Created by League when data is loaded
|
5
|
-
class Team
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
1
|
+
require("hlockey/player")
|
2
|
+
|
3
|
+
module Hlockey
|
4
|
+
# Created by League when data is loaded
|
5
|
+
class Team
|
6
|
+
attr_accessor(:wins, :losses, :roster, :shadows, :status, :to_s)
|
7
|
+
attr_reader(:emoji, :color, :motto)
|
8
|
+
|
9
|
+
# random is only used if roster is nil
|
10
|
+
def initialize(name, color, emoji, roster: nil, shadows: nil, random: Random)
|
11
|
+
@to_s = name
|
12
|
+
@color = color
|
13
|
+
@emoji = emoji
|
14
|
+
@roster = if roster.nil?
|
15
|
+
%i[lwing center rwing ldef goalie rdef].each_with_object({}) do |pos, h|
|
16
|
+
h[pos] = Player.new(self, random)
|
17
|
+
end
|
18
|
+
else
|
19
|
+
roster
|
20
|
+
end
|
21
|
+
@shadows = shadows.nil? ? Array.new(6) { Player.new(random) } : shadows
|
22
|
+
@wins = 0
|
23
|
+
@losses = 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def w_l
|
27
|
+
"#{@wins}-#{@losses}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def worst_player_pos
|
31
|
+
@roster.transform_values { |p| p.stats.values.reduce(:+) }
|
32
|
+
.min_by { |_, v| v }
|
33
|
+
.first
|
34
|
+
end
|
35
|
+
|
36
|
+
# Takes symbol from Team roster & converts it to full position name
|
37
|
+
def self.pos_name(pos)
|
38
|
+
case pos
|
39
|
+
when :lwing
|
40
|
+
"Left wing"
|
41
|
+
when :rwing
|
42
|
+
"Right wing"
|
43
|
+
when :ldef
|
44
|
+
"Left defender"
|
45
|
+
when :rdef
|
46
|
+
"Right defender"
|
47
|
+
else
|
48
|
+
pos.capitalize.to_s
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Hlockey
|
2
|
+
module Utils
|
3
|
+
# Does a weighted random with a hash,
|
4
|
+
# where the keys are elements being randomly selected,
|
5
|
+
# and the values are the weights
|
6
|
+
# @param hash [Hash<Object => Integer>]
|
7
|
+
# @param prng [#rand]
|
8
|
+
# @return [Object]
|
9
|
+
def self.weighted_random(hash, prng)
|
10
|
+
cumulative_weights = []
|
11
|
+
hash.each_value { |v| cumulative_weights << v + (cumulative_weights.last or 0) }
|
12
|
+
hash.keys[cumulative_weights.index { |n| prng.rand(cumulative_weights.last) < n }]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/hlockey/version.rb
CHANGED
@@ -0,0 +1,168 @@
|
|
1
|
+
require("hlockey/game")
|
2
|
+
require("hlockey/message")
|
3
|
+
require("hlockey/player")
|
4
|
+
|
5
|
+
module Hlockey
|
6
|
+
class Weather
|
7
|
+
def initialize(game)
|
8
|
+
@game = game
|
9
|
+
@home = @game.home
|
10
|
+
@away = @game.away
|
11
|
+
@prng = @game.prng
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
self.class.to_s.split("::").last
|
16
|
+
end
|
17
|
+
|
18
|
+
def on_game_start() end
|
19
|
+
|
20
|
+
def on_game_end() end
|
21
|
+
|
22
|
+
def on_period_end() end
|
23
|
+
|
24
|
+
def on_action() end
|
25
|
+
|
26
|
+
def on_goal(scoring_team) end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# Swaps roster & shadows player, used for Chicken & Waves weather
|
31
|
+
# @param team_sym [:home, :away]
|
32
|
+
# @param pos [Symbol] position of player swapped out
|
33
|
+
# @param shadows_idx [Integer] index of shadows player swapped in
|
34
|
+
# @return [Array<Player>] the players that were swapped
|
35
|
+
def swap(team_sym, pos, shadows_idx)
|
36
|
+
team = @game.send(team_sym)
|
37
|
+
|
38
|
+
prev_player = team.roster[pos]
|
39
|
+
next_player = team.shadows[shadows_idx]
|
40
|
+
team.roster[pos] = next_player
|
41
|
+
team.shadows[shadows_idx] = prev_player
|
42
|
+
|
43
|
+
unless @game.fight.nil?
|
44
|
+
player_array = @game.fight.players[team_sym]
|
45
|
+
player_idx = player_array.index(prev_player)
|
46
|
+
|
47
|
+
player_array[player_idx] = next_player unless player_idx.nil?
|
48
|
+
end
|
49
|
+
|
50
|
+
[prev_player, next_player]
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [:home, :away]
|
54
|
+
def rand_team
|
55
|
+
@prng.rand(2).zero? ? :home : :away
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Audacity < Weather
|
60
|
+
def on_action
|
61
|
+
@game.shoot(audacity: true) if @prng.rand(Game::NON_OT_ACTIONS / 10).zero?
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class Chicken < Weather
|
66
|
+
def on_game_start
|
67
|
+
@chickened_out = { home: {}, away: {} }
|
68
|
+
end
|
69
|
+
|
70
|
+
def on_action
|
71
|
+
return unless @prng.rand(Game::NON_OT_ACTIONS / 5).zero?
|
72
|
+
|
73
|
+
team = rand_team
|
74
|
+
pos, shadows_idx = get_swap(team)
|
75
|
+
if pos.nil? || shadows_idx.nil?
|
76
|
+
team = team == :home ? :away : :home
|
77
|
+
pos, shadows_idx = get_swap(team)
|
78
|
+
return if pos.nil? || shadows_idx.nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
@chickened_out[team][pos] = shadows_idx
|
82
|
+
|
83
|
+
@game.stream << Message.ChickenedOut(*swap(team, pos, shadows_idx))
|
84
|
+
end
|
85
|
+
|
86
|
+
def on_game_end
|
87
|
+
@chickened_out.each do |team, swaps|
|
88
|
+
swaps.each { |pos, shadows_idx| swap(team, pos, shadows_idx) }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
# @param team_sym [:home, :away]
|
95
|
+
# @return [Array<Symbol, Integer>]
|
96
|
+
def get_swap(team_sym)
|
97
|
+
team = @game.send(team_sym)
|
98
|
+
|
99
|
+
[
|
100
|
+
(team.roster.keys - @chickened_out[team_sym].keys).sample(random: @prng),
|
101
|
+
(team.shadows.each_index.to_a - @chickened_out[team_sym].values)
|
102
|
+
.sample(random: @prng)
|
103
|
+
]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class Inclines < Weather
|
108
|
+
def on_game_start
|
109
|
+
make_incline
|
110
|
+
end
|
111
|
+
|
112
|
+
def on_goal(scoring_team)
|
113
|
+
return unless scoring_team == @favored_team
|
114
|
+
|
115
|
+
@game.score[scoring_team] += @prng.rand(0.1..0.5)
|
116
|
+
make_incline
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def make_incline
|
122
|
+
new_favored_team = rand_team
|
123
|
+
return unless new_favored_team != @favored_team
|
124
|
+
|
125
|
+
@favored_team = new_favored_team
|
126
|
+
@game.stream << Message.InclineFavors(@game.send(@favored_team))
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
class Stars < Weather
|
131
|
+
def on_period_end
|
132
|
+
team = %i[home away].find { |sym| @game.send(sym).to_s == "Sleepers" }
|
133
|
+
if team.nil?
|
134
|
+
return if @game.score[:home] == @game.score[:away]
|
135
|
+
|
136
|
+
team = @game.score.min_by { |_, v| v }.first
|
137
|
+
end
|
138
|
+
|
139
|
+
@game.score[team] += 0.5
|
140
|
+
@game.stream << Message.StarsAlign(@game.send(team))
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class Sunset < Weather
|
145
|
+
def on_game_start
|
146
|
+
@score_amt = { home: 0, away: 0 }
|
147
|
+
end
|
148
|
+
|
149
|
+
def on_goal(scoring_team)
|
150
|
+
@score_amt[scoring_team] += 1
|
151
|
+
@game.score[scoring_team] -= @score_amt[scoring_team] * 0.2
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class Waves < Weather
|
156
|
+
def on_action
|
157
|
+
return unless @prng.rand(Game::NON_OT_ACTIONS).zero?
|
158
|
+
|
159
|
+
team_sym = rand_team
|
160
|
+
team = @game.send(team_sym)
|
161
|
+
@game.stream << Message.WavesWashedAway(*swap(team_sym,
|
162
|
+
team.worst_player_pos,
|
163
|
+
@prng.rand(team.shadows.length)))
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
Weather::WEATHERS = [Audacity, Chicken, Inclines, Stars, Sunset, Waves].freeze
|
168
|
+
end
|
data/lib/hlockey.rb
CHANGED
metadata
CHANGED
@@ -1,39 +1,59 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hlockey
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '
|
4
|
+
version: '4'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lavender Perry
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
13
|
-
|
11
|
+
date: 2023-07-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: psych
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5'
|
27
|
+
description: Hlockey library.
|
14
28
|
email: endie2@protonmail.com
|
15
|
-
executables:
|
16
|
-
- hlockey
|
29
|
+
executables: []
|
17
30
|
extensions: []
|
18
31
|
extra_rdoc_files: []
|
19
32
|
files:
|
20
|
-
-
|
33
|
+
- data/election.yaml
|
34
|
+
- data/external/names.txt
|
35
|
+
- data/information.yaml
|
36
|
+
- data/league.yaml
|
37
|
+
- data/links.yaml
|
38
|
+
- data/previous_election_results.yaml
|
21
39
|
- lib/hlockey.rb
|
40
|
+
- lib/hlockey/constants.rb
|
22
41
|
- 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
42
|
- lib/hlockey/game.rb
|
43
|
+
- lib/hlockey/game/actions.rb
|
44
|
+
- lib/hlockey/game/fight.rb
|
28
45
|
- lib/hlockey/league.rb
|
29
|
-
- lib/hlockey/
|
46
|
+
- lib/hlockey/message.rb
|
47
|
+
- lib/hlockey/player.rb
|
30
48
|
- lib/hlockey/team.rb
|
49
|
+
- lib/hlockey/utils.rb
|
31
50
|
- lib/hlockey/version.rb
|
32
|
-
|
51
|
+
- lib/hlockey/weather.rb
|
52
|
+
homepage: https://github.com/Hlockey/lib
|
33
53
|
licenses:
|
34
54
|
- LicenseRef-LICENSE.md
|
35
55
|
metadata:
|
36
|
-
source_code_uri: https://github.com/Hlockey/
|
56
|
+
source_code_uri: https://github.com/Hlockey/lib
|
37
57
|
post_install_message:
|
38
58
|
rdoc_options: []
|
39
59
|
require_paths:
|
@@ -49,8 +69,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
69
|
- !ruby/object:Gem::Version
|
50
70
|
version: '0'
|
51
71
|
requirements: []
|
52
|
-
rubygems_version: 3.
|
72
|
+
rubygems_version: 3.4.10
|
53
73
|
signing_key:
|
54
74
|
specification_version: 4
|
55
|
-
summary: Hlockey season
|
75
|
+
summary: Hlockey season 4.
|
56
76
|
test_files: []
|
data/bin/hlockey
DELETED
@@ -1,104 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
# frozen_string_literal: true
|
4
|
-
|
5
|
-
require('hlockey')
|
6
|
-
|
7
|
-
def menu_input(default, *choices)
|
8
|
-
puts('Please enter a number...')
|
9
|
-
# Adding 1 to i when printing choices
|
10
|
-
# to avoid confusing a non-numerical input with the first choice
|
11
|
-
choices.each_with_index { |choice, i| puts("#{(i + 1).to_s.rjust(2)} - #{choice}") }
|
12
|
-
puts("anything else - #{default}")
|
13
|
-
|
14
|
-
# Subtract 1 here to undo adding 1 earlier
|
15
|
-
STDIN.gets.to_i - 1
|
16
|
-
end
|
17
|
-
|
18
|
-
# Each element from choices should implement to_s
|
19
|
-
def menu_input_elem(choices)
|
20
|
-
i = menu_input('Back', *choices)
|
21
|
-
choices[i] unless i.negative?
|
22
|
-
end
|
23
|
-
|
24
|
-
def emoji_team(team)
|
25
|
-
"#{team.emoji} #{team}"
|
26
|
-
end
|
27
|
-
|
28
|
-
puts('Please wait...')
|
29
|
-
|
30
|
-
PRINT_TEAM_W_L = Proc.new do |team|
|
31
|
-
puts(" #{emoji_team(team).ljust(26)} #{team.w_l}")
|
32
|
-
end
|
33
|
-
|
34
|
-
league = Hlockey::League.new
|
35
|
-
|
36
|
-
puts(Hlockey::Messages.SeasonStarts(league.start_time)) if Time.now < league.start_time
|
37
|
-
|
38
|
-
loop do
|
39
|
-
league.update_state
|
40
|
-
|
41
|
-
puts(Hlockey::Messages.SeasonDay(league.day))
|
42
|
-
|
43
|
-
case menu_input('Exit', 'Games', 'Standings', 'Team info', 'Election', 'Information')
|
44
|
-
when 0 # Games
|
45
|
-
if league.games.empty?
|
46
|
-
puts(Hlockey::Messages.NoGames)
|
47
|
-
next
|
48
|
-
end
|
49
|
-
|
50
|
-
game = menu_input_elem(league.games)
|
51
|
-
next if game.nil?
|
52
|
-
|
53
|
-
puts("#{game.home.emoji} #{game} #{game.away.emoji}")
|
54
|
-
loop do
|
55
|
-
league.update_state
|
56
|
-
|
57
|
-
game.stream.each(&method(:puts))
|
58
|
-
|
59
|
-
break unless game.in_progress
|
60
|
-
|
61
|
-
game.stream.clear
|
62
|
-
sleep(5)
|
63
|
-
end
|
64
|
-
when 1 # Standings
|
65
|
-
if league.champion_team
|
66
|
-
puts(Hlockey::Messages.SeasonChampion(league.champion_team))
|
67
|
-
elsif league.playoff_teams
|
68
|
-
puts('Playoffs')
|
69
|
-
league.playoff_teams.each(&PRINT_TEAM_W_L)
|
70
|
-
end
|
71
|
-
|
72
|
-
league.divisions.each do |name, teams|
|
73
|
-
puts(name)
|
74
|
-
teams.each(&PRINT_TEAM_W_L)
|
75
|
-
end
|
76
|
-
when 2 # Team info
|
77
|
-
team = menu_input_elem(league.teams)
|
78
|
-
next if team.nil?
|
79
|
-
|
80
|
-
puts(emoji_team(team))
|
81
|
-
team.roster.each do |pos, player|
|
82
|
-
puts(" #{Hlockey.pos_name(pos)}:\n #{player}")
|
83
|
-
player.stats.each { |stat, value| puts(" #{stat}: #{value.round(1)}") }
|
84
|
-
end
|
85
|
-
puts(" wins: #{team.wins}")
|
86
|
-
puts(" losses: #{team.losses}")
|
87
|
-
when 3 # Election
|
88
|
-
election = Hlockey.load_data('election')
|
89
|
-
election.each do |category, options|
|
90
|
-
puts(category)
|
91
|
-
options.each { |name, description| puts(" #{name}: #{description}") }
|
92
|
-
end
|
93
|
-
puts('Go to the website (https://hlockey.herokuapp.com) to vote.')
|
94
|
-
when 4 # Information
|
95
|
-
Hlockey.load_data('information').each do |title, info|
|
96
|
-
puts(title)
|
97
|
-
info.each_line { |l| puts(" #{l}") }
|
98
|
-
end
|
99
|
-
puts('Links')
|
100
|
-
Hlockey.load_data('links').each { |site, link| puts(" #{site}: #{link}") }
|
101
|
-
else
|
102
|
-
exit
|
103
|
-
end
|
104
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
---
|
2
|
-
:Bribery:
|
3
|
-
:Flavor Text: Give each team a motto.
|
4
|
-
:Weather: Move all the stadiums outdoors.
|
5
|
-
:We Do A Little Losing: Recognize the losingest teams with an Underbracket.
|
6
|
-
:Treasure:
|
7
|
-
:Vengabus: All your team's stats are boosted by your team's losses * 0.005.
|
8
|
-
:Dave: The worst stat on your team is set to 4.5.
|
9
|
-
:Nice: Boost your worst player by 0.69 in every stat.
|
10
|
-
:Convenient Math Error: Your team starts the next season with 5 wins.
|
11
|
-
:Coaching:
|
12
|
-
:Please Block Shots: Move your team's best defensive player to goalie.
|
13
|
-
:Please Win Faceoffs: Move your team's player best offensive player to center.
|
14
|
-
:Draft: Replace your team's worst player with a random new player.
|
15
|
-
:Small Gamble: All your team's stats go up or down by 0.5 at random.
|
16
|
-
:Big Gamble: All your team's stats go up or down by 1.0 at random.
|
@@ -1,12 +0,0 @@
|
|
1
|
-
---
|
2
|
-
:Format: |-
|
3
|
-
Hlockey has 3 game long regular season matchups, & 5 game long postseason matchups.
|
4
|
-
The regular season is round robin format.
|
5
|
-
Teams play 2 regular season matchups against each other.
|
6
|
-
Playoffs are single-elimination tournaments.
|
7
|
-
The top 2 teams of each division qualify for playoffs.
|
8
|
-
Playoffs are perfectly seeded (best team plays worst team, etc).
|
9
|
-
:Relation to Blaseball: |-
|
10
|
-
Both Hlockey and Blaseball are splorts, therefore they have some similarities.
|
11
|
-
Breaks will usually be scheduled when Blaseball is more active.
|
12
|
-
Hlockey is inspired by Blaseball, & would most likely not exist without it.
|