sashite-epin 2.0.0 → 2.1.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 +192 -426
- data/lib/sashite/epin.rb +268 -191
- metadata +6 -11
- data/lib/sashite/epin/identifier.rb +0 -293
data/lib/sashite/epin.rb
CHANGED
|
@@ -1,224 +1,301 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require "sashite/pin"
|
|
4
4
|
|
|
5
5
|
module Sashite
|
|
6
|
-
# EPIN (Extended Piece Identifier Notation) implementation for Ruby
|
|
6
|
+
# EPIN (Extended Piece Identifier Notation) implementation for Ruby.
|
|
7
7
|
#
|
|
8
|
-
#
|
|
9
|
-
# in cross-style games.
|
|
8
|
+
# EPIN extends PIN by adding a **derivation marker** to track piece style
|
|
9
|
+
# in cross-style games.
|
|
10
10
|
#
|
|
11
|
-
#
|
|
11
|
+
# **EPIN is simply: PIN + optional style derivation marker (`'`)**
|
|
12
12
|
#
|
|
13
|
-
#
|
|
14
|
-
# - **Native pieces**: Using their own side's native style (no marker)
|
|
15
|
-
# - **Derived pieces**: Using the opponent's native style (marked with ')
|
|
13
|
+
# == Format
|
|
16
14
|
#
|
|
17
|
-
#
|
|
18
|
-
# different game traditions (e.g., Chess vs Makruk, Chess vs Shogi).
|
|
15
|
+
# <pin-token>[<derivation-marker>]
|
|
19
16
|
#
|
|
20
|
-
#
|
|
17
|
+
# Where +<pin-token>+ is a valid PIN token and +<derivation-marker>+ is
|
|
18
|
+
# an optional trailing apostrophe (<tt>'</tt>).
|
|
21
19
|
#
|
|
22
|
-
#
|
|
20
|
+
# == Five Fundamental Attributes
|
|
23
21
|
#
|
|
24
|
-
#
|
|
22
|
+
# EPIN exposes all five attributes from the Sashité Game Protocol:
|
|
25
23
|
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
24
|
+
# - *Piece Name* â†' +epin.pin.type+
|
|
25
|
+
# - *Piece Side* â†' +epin.pin.side+
|
|
26
|
+
# - *Piece State* â†' +epin.pin.state+
|
|
27
|
+
# - *Terminal Status* â†' +epin.pin.terminal+
|
|
28
|
+
# - *Piece Style* â†' +epin.derived+ (native vs derived)
|
|
28
29
|
#
|
|
29
|
-
#
|
|
30
|
+
# == Examples
|
|
30
31
|
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
32
|
+
# epin = Sashite::Epin.parse("K^'")
|
|
33
|
+
# epin.pin.type # => :K
|
|
34
|
+
# epin.pin.terminal # => true
|
|
35
|
+
# epin.derived # => true
|
|
35
36
|
#
|
|
36
|
-
# ## Five Fundamental Attributes
|
|
37
|
-
#
|
|
38
|
-
# EPIN represents all five piece attributes from the Sashité Game Protocol:
|
|
39
|
-
#
|
|
40
|
-
# From PIN component (4 attributes):
|
|
41
|
-
# - **Piece Name**: epin.pin.type
|
|
42
|
-
# - **Piece Side**: epin.pin.side
|
|
43
|
-
# - **Piece State**: epin.pin.state
|
|
44
|
-
# - **Terminal Status**: epin.pin.terminal?
|
|
45
|
-
#
|
|
46
|
-
# From EPIN (5th attribute):
|
|
47
|
-
# - **Piece Style**: epin.derived? (native vs derived)
|
|
48
|
-
#
|
|
49
|
-
# ## Format Structure
|
|
50
|
-
#
|
|
51
|
-
# Structure: `<pin>[']`
|
|
52
|
-
#
|
|
53
|
-
# Grammar (BNF):
|
|
54
|
-
# <epin> ::= <pin> | <pin> "'"
|
|
55
|
-
# <pin> ::= ["+" | "-"] <letter> ["^"]
|
|
56
|
-
# <letter> ::= "A" | ... | "Z" | "a" | ... | "z"
|
|
57
|
-
#
|
|
58
|
-
# Regular Expression: `/\A[-+]?[A-Za-z]\^?'?\z/`
|
|
59
|
-
#
|
|
60
|
-
# ## Semantics
|
|
61
|
-
#
|
|
62
|
-
# ### Native vs Derived
|
|
63
|
-
#
|
|
64
|
-
# In cross-style games (e.g., Chess vs Makruk):
|
|
65
|
-
# - First player's native style: Chess
|
|
66
|
-
# - Second player's native style: Makruk
|
|
67
|
-
#
|
|
68
|
-
# Then:
|
|
69
|
-
# - "K" = First player king in Chess style (native)
|
|
70
|
-
# - "K'" = First player king in Makruk style (derived from opponent)
|
|
71
|
-
# - "k" = Second player king in Makruk style (native)
|
|
72
|
-
# - "k'" = Second player king in Chess style (derived from opponent)
|
|
73
|
-
#
|
|
74
|
-
# ### Backward Compatibility
|
|
75
|
-
#
|
|
76
|
-
# Every valid PIN token is a valid EPIN token:
|
|
77
|
-
# - "K" is valid PIN and valid EPIN (native)
|
|
78
|
-
# - "+R^" is valid PIN and valid EPIN (native)
|
|
79
|
-
# - All PIN semantics preserved
|
|
80
|
-
#
|
|
81
|
-
# EPIN extends PIN by adding the optional derivation marker:
|
|
82
|
-
# - "K'" is valid EPIN (derived)
|
|
83
|
-
# - "+R^'" is valid EPIN (enhanced, terminal, derived)
|
|
84
|
-
#
|
|
85
|
-
# ## Examples
|
|
86
|
-
#
|
|
87
|
-
# ### Basic Usage
|
|
88
|
-
#
|
|
89
|
-
# # Parse EPIN strings
|
|
90
|
-
# native = Sashite::Epin.parse("K^") # Native king
|
|
91
|
-
# derived = Sashite::Epin.parse("K^'") # Derived king
|
|
92
|
-
#
|
|
93
|
-
# # Access attributes via PIN component
|
|
94
|
-
# native.pin.type # => :K
|
|
95
|
-
# native.pin.terminal? # => true
|
|
96
|
-
# native.derived? # => false
|
|
97
|
-
#
|
|
98
|
-
# # Create from PIN component
|
|
99
37
|
# pin = Sashite::Pin.parse("K^")
|
|
100
|
-
# epin = Sashite::Epin.new(pin, derived:
|
|
101
|
-
# epin.to_s
|
|
102
|
-
#
|
|
103
|
-
# ### Transformations
|
|
104
|
-
#
|
|
105
|
-
# epin = Sashite::Epin.parse("K^")
|
|
106
|
-
#
|
|
107
|
-
# # Mark as derived
|
|
108
|
-
# derived = epin.mark_derived
|
|
109
|
-
# derived.to_s # => "K^'"
|
|
110
|
-
#
|
|
111
|
-
# # Transform PIN component
|
|
112
|
-
# queen = epin.with_pin(epin.pin.with_type(:Q))
|
|
113
|
-
# queen.to_s # => "Q^"
|
|
114
|
-
#
|
|
115
|
-
# # Transform both
|
|
116
|
-
# derived_queen = epin
|
|
117
|
-
# .with_pin(epin.pin.with_type(:Q))
|
|
118
|
-
# .mark_derived
|
|
119
|
-
# derived_queen.to_s # => "Q^'"
|
|
120
|
-
#
|
|
121
|
-
# ### Cross-Style Games
|
|
122
|
-
#
|
|
123
|
-
# # Chess vs Makruk match
|
|
124
|
-
# # First player = Chess, Second player = Makruk
|
|
125
|
-
#
|
|
126
|
-
# chess_king = Sashite::Epin.parse("K^") # Native Chess king
|
|
127
|
-
# makruk_pawn = Sashite::Epin.parse("P'") # Derived Makruk pawn
|
|
38
|
+
# epin = Sashite::Epin.new(pin, derived: true)
|
|
39
|
+
# epin.to_s # => "K^'"
|
|
128
40
|
#
|
|
129
|
-
#
|
|
130
|
-
#
|
|
41
|
+
# Sashite::Epin.valid?("K^'") # => true
|
|
42
|
+
# Sashite::Epin.valid?("K'^") # => false
|
|
131
43
|
#
|
|
132
|
-
#
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
#
|
|
149
|
-
#
|
|
150
|
-
#
|
|
151
|
-
#
|
|
152
|
-
#
|
|
153
|
-
# @
|
|
154
|
-
#
|
|
155
|
-
#
|
|
156
|
-
#
|
|
157
|
-
#
|
|
158
|
-
# Sashite::Epin.
|
|
159
|
-
# Sashite::Epin
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
44
|
+
# See the EPIN Specification (https://sashite.dev/specs/epin/1.0.0/) for details.
|
|
45
|
+
class Epin
|
|
46
|
+
# Pattern for validating EPIN strings
|
|
47
|
+
EPIN_PATTERN = /\A(?<pin>[-+]?[A-Za-z]\^?)(?<derived>')?\z/
|
|
48
|
+
|
|
49
|
+
# @return [Sashite::Pin] The underlying PIN component
|
|
50
|
+
attr_reader :pin
|
|
51
|
+
|
|
52
|
+
# @return [Boolean] Derivation status (true = derived, false = native)
|
|
53
|
+
attr_reader :derived
|
|
54
|
+
|
|
55
|
+
# ========================================================================
|
|
56
|
+
# Creation and Parsing
|
|
57
|
+
# ========================================================================
|
|
58
|
+
|
|
59
|
+
# Creates a new EPIN instance from a PIN component.
|
|
60
|
+
#
|
|
61
|
+
# @param pin [Sashite::Pin] The underlying PIN instance
|
|
62
|
+
# @param derived [Boolean] Derivation status (default: false)
|
|
63
|
+
# @return [Epin] A new frozen Epin instance
|
|
64
|
+
#
|
|
65
|
+
# @example
|
|
66
|
+
# pin = Sashite::Pin.parse("K^")
|
|
67
|
+
# Sashite::Epin.new(pin)
|
|
68
|
+
# # => #<Sashite::Epin K^>
|
|
69
|
+
#
|
|
70
|
+
# Sashite::Epin.new(pin, derived: true)
|
|
71
|
+
# # => #<Sashite::Epin K^'>
|
|
72
|
+
def initialize(pin, derived: false)
|
|
73
|
+
raise ArgumentError, "Expected a Sashite::Pin instance, got: #{pin.inspect}" unless pin.is_a?(Pin)
|
|
74
|
+
|
|
75
|
+
@pin = pin
|
|
76
|
+
@derived = !!derived
|
|
77
|
+
|
|
78
|
+
freeze
|
|
164
79
|
end
|
|
165
80
|
|
|
166
|
-
#
|
|
167
|
-
#
|
|
168
|
-
#
|
|
169
|
-
#
|
|
170
|
-
#
|
|
171
|
-
#
|
|
172
|
-
# @
|
|
173
|
-
#
|
|
174
|
-
#
|
|
175
|
-
#
|
|
176
|
-
#
|
|
177
|
-
#
|
|
178
|
-
#
|
|
179
|
-
# Sashite::Epin.parse("+R")
|
|
180
|
-
# Sashite::Epin
|
|
181
|
-
#
|
|
182
|
-
#
|
|
183
|
-
#
|
|
184
|
-
# epin = Sashite::Epin.parse("+R^'")
|
|
185
|
-
# epin.pin.type # => :R (Piece Name)
|
|
186
|
-
# epin.pin.side # => :first (Piece Side)
|
|
187
|
-
# epin.pin.state # => :enhanced (Piece State)
|
|
188
|
-
# epin.pin.terminal? # => true (Terminal Status)
|
|
189
|
-
# epin.derived? # => true (Piece Style)
|
|
81
|
+
# Parses an EPIN string into an Epin instance.
|
|
82
|
+
#
|
|
83
|
+
# @param epin_string [String] The EPIN string to parse
|
|
84
|
+
# @return [Epin] A new Epin instance
|
|
85
|
+
# @raise [ArgumentError] If the string is not a valid EPIN
|
|
86
|
+
#
|
|
87
|
+
# @example
|
|
88
|
+
# Sashite::Epin.parse("K")
|
|
89
|
+
# # => #<Sashite::Epin K>
|
|
90
|
+
#
|
|
91
|
+
# Sashite::Epin.parse("K'")
|
|
92
|
+
# # => #<Sashite::Epin K'>
|
|
93
|
+
#
|
|
94
|
+
# Sashite::Epin.parse("+R^'")
|
|
95
|
+
# # => #<Sashite::Epin +R^'>
|
|
96
|
+
#
|
|
97
|
+
# Sashite::Epin.parse("invalid")
|
|
98
|
+
# # => ArgumentError: Invalid EPIN string: invalid
|
|
190
99
|
def self.parse(epin_string)
|
|
191
|
-
|
|
100
|
+
raise ArgumentError, "Invalid EPIN string: #{epin_string.inspect}" unless epin_string.is_a?(String)
|
|
101
|
+
|
|
102
|
+
match = EPIN_PATTERN.match(epin_string)
|
|
103
|
+
raise ArgumentError, "Invalid EPIN string: #{epin_string}" unless match
|
|
104
|
+
|
|
105
|
+
pin_string = match[:pin]
|
|
106
|
+
derived_marker = match[:derived]
|
|
107
|
+
|
|
108
|
+
pin = Pin.parse(pin_string)
|
|
109
|
+
derived = derived_marker == "'"
|
|
110
|
+
|
|
111
|
+
new(pin, derived: derived)
|
|
192
112
|
end
|
|
193
113
|
|
|
194
|
-
#
|
|
114
|
+
# Checks if a string is a valid EPIN notation.
|
|
195
115
|
#
|
|
196
|
-
#
|
|
197
|
-
#
|
|
198
|
-
# (which provides the fifth attribute: style).
|
|
116
|
+
# @param epin_string [String] The string to validate
|
|
117
|
+
# @return [Boolean] true if valid, false otherwise
|
|
199
118
|
#
|
|
200
|
-
# @
|
|
201
|
-
#
|
|
202
|
-
#
|
|
203
|
-
#
|
|
119
|
+
# @example
|
|
120
|
+
# Sashite::Epin.valid?("K") # => true
|
|
121
|
+
# Sashite::Epin.valid?("K'") # => true
|
|
122
|
+
# Sashite::Epin.valid?("+R^'") # => true
|
|
123
|
+
# Sashite::Epin.valid?("K'^") # => false
|
|
124
|
+
# Sashite::Epin.valid?("K''") # => false
|
|
125
|
+
# Sashite::Epin.valid?("invalid") # => false
|
|
126
|
+
def self.valid?(epin_string)
|
|
127
|
+
return false unless epin_string.is_a?(String)
|
|
128
|
+
|
|
129
|
+
EPIN_PATTERN.match?(epin_string)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# ========================================================================
|
|
133
|
+
# Conversion
|
|
134
|
+
# ========================================================================
|
|
135
|
+
|
|
136
|
+
# Converts the Epin to its string representation.
|
|
137
|
+
#
|
|
138
|
+
# @return [String] The EPIN string
|
|
204
139
|
#
|
|
205
|
-
# @example
|
|
140
|
+
# @example
|
|
206
141
|
# pin = Sashite::Pin.parse("K^")
|
|
207
|
-
#
|
|
208
|
-
#
|
|
142
|
+
# Sashite::Epin.new(pin).to_s
|
|
143
|
+
# # => "K^"
|
|
144
|
+
#
|
|
145
|
+
# Sashite::Epin.new(pin, derived: true).to_s
|
|
146
|
+
# # => "K^'"
|
|
147
|
+
def to_s
|
|
148
|
+
"#{pin}#{derivation_suffix}"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# ========================================================================
|
|
152
|
+
# Transformations
|
|
153
|
+
# ========================================================================
|
|
154
|
+
|
|
155
|
+
# Returns a new Epin with a different PIN component.
|
|
156
|
+
#
|
|
157
|
+
# @param new_pin [Sashite::Pin] The new PIN component
|
|
158
|
+
# @return [Epin] A new Epin with the specified PIN
|
|
159
|
+
#
|
|
160
|
+
# @example
|
|
161
|
+
# epin = Sashite::Epin.parse("K^'")
|
|
162
|
+
# new_pin = epin.pin.with_type(:Q)
|
|
163
|
+
# epin.with_pin(new_pin).to_s
|
|
164
|
+
# # => "Q^'"
|
|
165
|
+
def with_pin(new_pin)
|
|
166
|
+
return self if pin == new_pin
|
|
167
|
+
|
|
168
|
+
self.class.new(new_pin, derived: derived)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Returns a new Epin with a different derivation status.
|
|
172
|
+
#
|
|
173
|
+
# @param new_derived [Boolean] The new derivation status
|
|
174
|
+
# @return [Epin] A new Epin with the specified derivation status
|
|
175
|
+
#
|
|
176
|
+
# @example
|
|
177
|
+
# epin = Sashite::Epin.parse("K^")
|
|
178
|
+
# epin.with_derived(true).to_s
|
|
179
|
+
# # => "K^'"
|
|
180
|
+
#
|
|
181
|
+
# epin = Sashite::Epin.parse("K^'")
|
|
182
|
+
# epin.with_derived(false).to_s
|
|
183
|
+
# # => "K^"
|
|
184
|
+
def with_derived(new_derived)
|
|
185
|
+
return self if derived == !!new_derived
|
|
186
|
+
|
|
187
|
+
self.class.new(pin, derived: !!new_derived)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Returns a new Epin marked as derived.
|
|
191
|
+
#
|
|
192
|
+
# @return [Epin] A new Epin with derived: true
|
|
193
|
+
#
|
|
194
|
+
# @example
|
|
195
|
+
# epin = Sashite::Epin.parse("K^")
|
|
196
|
+
# epin.mark_derived.derived
|
|
197
|
+
# # => true
|
|
198
|
+
def mark_derived
|
|
199
|
+
return self if derived
|
|
200
|
+
|
|
201
|
+
self.class.new(pin, derived: true)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Returns a new Epin marked as native (not derived).
|
|
205
|
+
#
|
|
206
|
+
# @return [Epin] A new Epin with derived: false
|
|
207
|
+
#
|
|
208
|
+
# @example
|
|
209
|
+
# epin = Sashite::Epin.parse("K^'")
|
|
210
|
+
# epin.unmark_derived.derived
|
|
211
|
+
# # => false
|
|
212
|
+
def unmark_derived
|
|
213
|
+
return self unless derived
|
|
214
|
+
|
|
215
|
+
self.class.new(pin, derived: false)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# ========================================================================
|
|
219
|
+
# Queries
|
|
220
|
+
# ========================================================================
|
|
221
|
+
|
|
222
|
+
# Checks if the Epin is derived (uses opponent's style).
|
|
223
|
+
#
|
|
224
|
+
# @return [Boolean] true if derived
|
|
225
|
+
#
|
|
226
|
+
# @example
|
|
227
|
+
# Sashite::Epin.parse("K^'").derived? # => true
|
|
228
|
+
# Sashite::Epin.parse("K^").derived? # => false
|
|
229
|
+
def derived?
|
|
230
|
+
derived
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Checks if the Epin is native (uses own side's style).
|
|
234
|
+
#
|
|
235
|
+
# @return [Boolean] true if native
|
|
236
|
+
#
|
|
237
|
+
# @example
|
|
238
|
+
# Sashite::Epin.parse("K^").native? # => true
|
|
239
|
+
# Sashite::Epin.parse("K^'").native? # => false
|
|
240
|
+
def native?
|
|
241
|
+
!derived
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Checks if two Epins have the same derivation status.
|
|
245
|
+
#
|
|
246
|
+
# @param other [Epin] The other Epin to compare
|
|
247
|
+
# @return [Boolean] true if same derivation status
|
|
248
|
+
#
|
|
249
|
+
# @example
|
|
250
|
+
# epin1 = Sashite::Epin.parse("K^'")
|
|
251
|
+
# epin2 = Sashite::Epin.parse("Q'")
|
|
252
|
+
# epin1.same_derived?(epin2)
|
|
253
|
+
# # => true
|
|
254
|
+
#
|
|
255
|
+
# epin3 = Sashite::Epin.parse("K^")
|
|
256
|
+
# epin1.same_derived?(epin3)
|
|
257
|
+
# # => false
|
|
258
|
+
def same_derived?(other)
|
|
259
|
+
derived == other.derived
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# ========================================================================
|
|
263
|
+
# Comparison
|
|
264
|
+
# ========================================================================
|
|
265
|
+
|
|
266
|
+
# Checks equality with another Epin.
|
|
209
267
|
#
|
|
210
|
-
#
|
|
211
|
-
#
|
|
268
|
+
# @param other [Object] The object to compare
|
|
269
|
+
# @return [Boolean] true if equal
|
|
270
|
+
def ==(other)
|
|
271
|
+
return false unless other.is_a?(self.class)
|
|
272
|
+
|
|
273
|
+
pin == other.pin && derived == other.derived
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
alias eql? ==
|
|
277
|
+
|
|
278
|
+
# Returns a hash code for the Epin.
|
|
212
279
|
#
|
|
213
|
-
# @
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
280
|
+
# @return [Integer] Hash code
|
|
281
|
+
def hash
|
|
282
|
+
[pin, derived].hash
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Returns an inspect string for the Epin.
|
|
286
|
+
#
|
|
287
|
+
# @return [String] Inspect representation
|
|
288
|
+
def inspect
|
|
289
|
+
"#<#{self.class} #{self}>"
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
private
|
|
293
|
+
|
|
294
|
+
# Returns the derivation suffix for string representation.
|
|
217
295
|
#
|
|
218
|
-
#
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
Identifier.new(pin, derived: derived)
|
|
296
|
+
# @return [String] "'" if derived, "" otherwise
|
|
297
|
+
def derivation_suffix
|
|
298
|
+
derived ? "'" : ""
|
|
222
299
|
end
|
|
223
300
|
end
|
|
224
301
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sashite-epin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Cyril Kato
|
|
@@ -15,22 +15,18 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 3.
|
|
18
|
+
version: 3.3.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 3.
|
|
25
|
+
version: 3.3.0
|
|
26
26
|
description: |
|
|
27
|
-
EPIN (Extended Piece Identifier Notation)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
principles. EPIN adds derivation markers to PIN that distinguish pieces by their style
|
|
31
|
-
origin, enabling cross-style game scenarios and piece origin tracking. Represents all
|
|
32
|
-
four Game Protocol piece attributes with full PIN backward compatibility. Perfect for
|
|
33
|
-
game engines, cross-tradition tournaments, and hybrid board game environments.
|
|
27
|
+
EPIN (Extended Piece Identifier Notation) implementation for Ruby.
|
|
28
|
+
Extends PIN by adding a derivation marker to track piece style in cross-style
|
|
29
|
+
abstract strategy board games with a minimal compositional API.
|
|
34
30
|
email: contact@cyril.email
|
|
35
31
|
executables: []
|
|
36
32
|
extensions: []
|
|
@@ -40,7 +36,6 @@ files:
|
|
|
40
36
|
- README.md
|
|
41
37
|
- lib/sashite-epin.rb
|
|
42
38
|
- lib/sashite/epin.rb
|
|
43
|
-
- lib/sashite/epin/identifier.rb
|
|
44
39
|
homepage: https://github.com/sashite/epin.rb
|
|
45
40
|
licenses:
|
|
46
41
|
- MIT
|