sashite-pcn 0.2.0 → 0.3.0
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/README.md +255 -382
- data/lib/sashite/pcn/game/meta.rb +170 -0
- data/lib/sashite/pcn/game/sides/player.rb +129 -0
- data/lib/sashite/pcn/game/sides.rb +96 -0
- data/lib/sashite/pcn/game.rb +275 -344
- data/lib/sashite/pcn.rb +35 -45
- metadata +18 -5
- data/lib/sashite/pcn/error.rb +0 -38
- data/lib/sashite/pcn/meta.rb +0 -275
- data/lib/sashite/pcn/player.rb +0 -186
- data/lib/sashite/pcn/sides.rb +0 -194
data/lib/sashite/pcn/sides.rb
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Sashite
|
|
4
|
-
module Pcn
|
|
5
|
-
# Immutable representation of player information for both sides.
|
|
6
|
-
#
|
|
7
|
-
# Contains player information for first and second player.
|
|
8
|
-
# At least one player must be defined when sides are present.
|
|
9
|
-
#
|
|
10
|
-
# @see https://sashite.dev/specs/pcn/1.0.0/
|
|
11
|
-
class Sides
|
|
12
|
-
# @return [Player, nil] First player information
|
|
13
|
-
attr_reader :first
|
|
14
|
-
|
|
15
|
-
# @return [Player, nil] Second player information
|
|
16
|
-
attr_reader :second
|
|
17
|
-
|
|
18
|
-
# Parse a sides hash into a Sides object.
|
|
19
|
-
#
|
|
20
|
-
# @param hash [Hash] Sides hash
|
|
21
|
-
# @return [Sides] Immutable sides object
|
|
22
|
-
# @raise [Error::Validation] If validation fails
|
|
23
|
-
#
|
|
24
|
-
# @example
|
|
25
|
-
# sides = Sides.parse({
|
|
26
|
-
# "first" => { "name" => "Alice", "elo" => 2800 },
|
|
27
|
-
# "second" => { "name" => "Bob", "elo" => 2750 }
|
|
28
|
-
# })
|
|
29
|
-
def self.parse(hash)
|
|
30
|
-
raise Error::Validation, "Sides must be a Hash, got #{hash.class}" unless hash.is_a?(::Hash)
|
|
31
|
-
|
|
32
|
-
first = parse_player(hash["first"], "first")
|
|
33
|
-
second = parse_player(hash["second"], "second")
|
|
34
|
-
|
|
35
|
-
new(first:, second:)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Validate a sides hash without raising exceptions.
|
|
39
|
-
#
|
|
40
|
-
# @param hash [Hash] Sides hash
|
|
41
|
-
# @return [Boolean] true if valid, false otherwise
|
|
42
|
-
#
|
|
43
|
-
# @example
|
|
44
|
-
# Sides.valid?({ "first" => { "name" => "Alice" } }) # => true
|
|
45
|
-
def self.valid?(hash)
|
|
46
|
-
parse(hash)
|
|
47
|
-
true
|
|
48
|
-
rescue Error
|
|
49
|
-
false
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# Create a new Sides.
|
|
53
|
-
#
|
|
54
|
-
# @param first [Player, Hash, nil] First player information
|
|
55
|
-
# @param second [Player, Hash, nil] Second player information
|
|
56
|
-
# @raise [Error::Validation] If validation fails
|
|
57
|
-
#
|
|
58
|
-
# @example
|
|
59
|
-
# sides = Sides.new(
|
|
60
|
-
# first: Player.new(name: "Alice", elo: 2800),
|
|
61
|
-
# second: Player.new(name: "Bob", elo: 2750)
|
|
62
|
-
# )
|
|
63
|
-
def initialize(first: nil, second: nil)
|
|
64
|
-
@first = normalize_player(first, "first")
|
|
65
|
-
@second = normalize_player(second, "second")
|
|
66
|
-
|
|
67
|
-
validate!
|
|
68
|
-
|
|
69
|
-
freeze
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# Check if the sides are valid.
|
|
73
|
-
#
|
|
74
|
-
# @return [Boolean] true if valid
|
|
75
|
-
def valid?
|
|
76
|
-
validate!
|
|
77
|
-
true
|
|
78
|
-
rescue Error
|
|
79
|
-
false
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# Check if both sides are empty.
|
|
83
|
-
#
|
|
84
|
-
# @return [Boolean] true if both players are nil
|
|
85
|
-
def empty?
|
|
86
|
-
first.nil? && second.nil?
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# Convert to hash representation.
|
|
90
|
-
#
|
|
91
|
-
# @return [Hash] Sides hash (excludes nil values)
|
|
92
|
-
#
|
|
93
|
-
# @example
|
|
94
|
-
# sides.to_h # => { "first" => {...}, "second" => {...} }
|
|
95
|
-
def to_h
|
|
96
|
-
hash = {}
|
|
97
|
-
|
|
98
|
-
hash["first"] = first.to_h unless first.nil?
|
|
99
|
-
hash["second"] = second.to_h unless second.nil?
|
|
100
|
-
|
|
101
|
-
hash
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# String representation.
|
|
105
|
-
#
|
|
106
|
-
# @return [String] Inspectable representation
|
|
107
|
-
def to_s
|
|
108
|
-
fields = []
|
|
109
|
-
fields << "first=#{first.name.inspect}" if first && first.name
|
|
110
|
-
fields << "second=#{second.name.inspect}" if second && second.name
|
|
111
|
-
|
|
112
|
-
"#<#{self.class} #{fields.join(' ')}>"
|
|
113
|
-
end
|
|
114
|
-
alias inspect to_s
|
|
115
|
-
|
|
116
|
-
# Equality comparison.
|
|
117
|
-
#
|
|
118
|
-
# @param other [Sides] Other sides
|
|
119
|
-
# @return [Boolean] true if equal
|
|
120
|
-
def ==(other)
|
|
121
|
-
other.is_a?(self.class) &&
|
|
122
|
-
other.first == first &&
|
|
123
|
-
other.second == second
|
|
124
|
-
end
|
|
125
|
-
alias eql? ==
|
|
126
|
-
|
|
127
|
-
# Hash code for equality.
|
|
128
|
-
#
|
|
129
|
-
# @return [Integer] Hash code
|
|
130
|
-
def hash
|
|
131
|
-
[self.class, first, second].hash
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
private
|
|
135
|
-
|
|
136
|
-
# Parse player field.
|
|
137
|
-
def self.parse_player(value, field_name)
|
|
138
|
-
return nil if value.nil?
|
|
139
|
-
|
|
140
|
-
Player.parse(value)
|
|
141
|
-
rescue Error => e
|
|
142
|
-
raise Error::Validation, "Invalid '#{field_name}' player: #{e.message}"
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
# Normalize player to Player object.
|
|
146
|
-
def normalize_player(value, field_name)
|
|
147
|
-
return nil if value.nil?
|
|
148
|
-
return value if value.is_a?(Player)
|
|
149
|
-
|
|
150
|
-
Player.parse(value)
|
|
151
|
-
rescue Error => e
|
|
152
|
-
raise Error::Validation, "Invalid '#{field_name}' player: #{e.message}"
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
# Validate all fields.
|
|
156
|
-
def validate!
|
|
157
|
-
validate_structure!
|
|
158
|
-
validate_first!
|
|
159
|
-
validate_second!
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
# Validate that at least one player is defined.
|
|
163
|
-
def validate_structure!
|
|
164
|
-
return unless first.nil? && second.nil?
|
|
165
|
-
|
|
166
|
-
raise Error::Validation, "Sides must have at least one player defined"
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
# Validate first player.
|
|
170
|
-
def validate_first!
|
|
171
|
-
return if first.nil?
|
|
172
|
-
|
|
173
|
-
raise Error::Validation, "Sides 'first' must be a Player object, got #{first.class}" unless first.is_a?(Player)
|
|
174
|
-
|
|
175
|
-
return if first.valid?
|
|
176
|
-
|
|
177
|
-
raise Error::Validation, "Sides 'first' player validation failed"
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
# Validate second player.
|
|
181
|
-
def validate_second!
|
|
182
|
-
return if second.nil?
|
|
183
|
-
|
|
184
|
-
unless second.is_a?(Player)
|
|
185
|
-
raise Error::Validation, "Sides 'second' must be a Player object, got #{second.class}"
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
return if second.valid?
|
|
189
|
-
|
|
190
|
-
raise Error::Validation, "Sides 'second' player validation failed"
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
end
|
|
194
|
-
end
|