sashite-epin 2.0.0 → 2.2.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 +158 -539
- data/lib/sashite/epin/constants.rb +15 -0
- data/lib/sashite/epin/errors/argument/messages.rb +25 -0
- data/lib/sashite/epin/errors/argument.rb +16 -0
- data/lib/sashite/epin/errors.rb +3 -0
- data/lib/sashite/epin/identifier.rb +118 -211
- data/lib/sashite/epin/parser.rb +101 -0
- data/lib/sashite/epin.rb +54 -198
- data/lib/sashite-epin.rb +0 -11
- metadata +12 -12
- data/LICENSE.md +0 -21
data/lib/sashite/epin.rb
CHANGED
|
@@ -1,224 +1,80 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "sashite/pin"
|
|
4
|
+
|
|
5
|
+
require_relative "epin/constants"
|
|
6
|
+
require_relative "epin/errors"
|
|
3
7
|
require_relative "epin/identifier"
|
|
8
|
+
require_relative "epin/parser"
|
|
4
9
|
|
|
5
10
|
module Sashite
|
|
6
|
-
# EPIN (Extended Piece Identifier Notation) implementation for Ruby
|
|
7
|
-
#
|
|
8
|
-
# Extends PIN (Piece Identifier Notation) with a derivation marker to track piece style
|
|
9
|
-
# in cross-style games. EPIN is simply: PIN + optional style derivation marker (').
|
|
10
|
-
#
|
|
11
|
-
# ## Core Concept
|
|
12
|
-
#
|
|
13
|
-
# EPIN addresses the need to distinguish between:
|
|
14
|
-
# - **Native pieces**: Using their own side's native style (no marker)
|
|
15
|
-
# - **Derived pieces**: Using the opponent's native style (marked with ')
|
|
16
|
-
#
|
|
17
|
-
# This distinction is essential for cross-style games where different players use
|
|
18
|
-
# different game traditions (e.g., Chess vs Makruk, Chess vs Shogi).
|
|
19
|
-
#
|
|
20
|
-
# ## Pure Composition
|
|
21
|
-
#
|
|
22
|
-
# EPIN doesn't reimplement PIN - it's pure composition:
|
|
23
|
-
#
|
|
24
|
-
# EPIN = PIN + derived flag
|
|
25
|
-
#
|
|
26
|
-
# All piece attributes (name, side, state, terminal) come from the PIN component.
|
|
27
|
-
# EPIN adds only the 5th attribute: piece style (native vs derived).
|
|
28
|
-
#
|
|
29
|
-
# ## Minimal API
|
|
30
|
-
#
|
|
31
|
-
# Module-level methods (3 total):
|
|
32
|
-
# 1. valid?(epin_string) - validate EPIN string
|
|
33
|
-
# 2. parse(epin_string) - parse into Identifier
|
|
34
|
-
# 3. new(pin, derived: false) - create from PIN component
|
|
35
|
-
#
|
|
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)
|
|
11
|
+
# EPIN (Extended Piece Identifier Notation) implementation for Ruby.
|
|
73
12
|
#
|
|
74
|
-
#
|
|
13
|
+
# EPIN extends PIN with an optional derivation marker (') that flags
|
|
14
|
+
# whether a piece uses a native or derived style.
|
|
75
15
|
#
|
|
76
|
-
#
|
|
77
|
-
# - "K" is valid PIN and valid EPIN (native)
|
|
78
|
-
# - "+R^" is valid PIN and valid EPIN (native)
|
|
79
|
-
# - All PIN semantics preserved
|
|
16
|
+
# == Format
|
|
80
17
|
#
|
|
81
|
-
#
|
|
82
|
-
# - "K'" is valid EPIN (derived)
|
|
83
|
-
# - "+R^'" is valid EPIN (enhanced, terminal, derived)
|
|
18
|
+
# <pin>[']
|
|
84
19
|
#
|
|
85
|
-
#
|
|
20
|
+
# - *PIN*: Any valid PIN token (abbr, side, state, terminal)
|
|
21
|
+
# - *Derivation marker*: <tt>'</tt> (derived) or absent (native)
|
|
86
22
|
#
|
|
87
|
-
#
|
|
23
|
+
# == Examples
|
|
88
24
|
#
|
|
89
|
-
#
|
|
90
|
-
#
|
|
91
|
-
#
|
|
25
|
+
# epin = Sashite::Epin.parse("K^'")
|
|
26
|
+
# epin.pin.abbr # => :K
|
|
27
|
+
# epin.pin.side # => :first
|
|
28
|
+
# epin.pin.terminal? # => true
|
|
29
|
+
# epin.derived? # => true
|
|
92
30
|
#
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
# native.pin.terminal? # => true
|
|
96
|
-
# native.derived? # => false
|
|
31
|
+
# epin = Sashite::Epin.parse("+R")
|
|
32
|
+
# epin.to_s # => "+R"
|
|
97
33
|
#
|
|
98
|
-
# #
|
|
99
|
-
#
|
|
100
|
-
# epin = Sashite::Epin.new(pin, derived: false)
|
|
101
|
-
# epin.to_s # => "K^"
|
|
34
|
+
# Sashite::Epin.valid?("K^'") # => true
|
|
35
|
+
# Sashite::Epin.valid?("invalid") # => false
|
|
102
36
|
#
|
|
103
|
-
#
|
|
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
|
|
128
|
-
#
|
|
129
|
-
# chess_king.native? # => true (uses Chess style)
|
|
130
|
-
# makruk_pawn.derived? # => true (uses Makruk style)
|
|
131
|
-
#
|
|
132
|
-
# ## Design Properties
|
|
133
|
-
#
|
|
134
|
-
# - **Rule-agnostic**: Independent of game mechanics
|
|
135
|
-
# - **Pure composition**: Extends PIN minimally (PIN + derived flag)
|
|
136
|
-
# - **Minimal API**: Only 3 module methods, 6 instance methods
|
|
137
|
-
# - **Component transparency**: Direct PIN access via epin.pin
|
|
138
|
-
# - **Backward compatible**: All PIN tokens are valid EPIN tokens
|
|
139
|
-
# - **Immutable**: All instances frozen, transformations return new objects
|
|
140
|
-
# - **Type-safe**: Full PIN type preservation
|
|
141
|
-
# - **Style-aware**: Tracks native vs derived pieces
|
|
142
|
-
# - **Compact**: Single character overhead for style information
|
|
143
|
-
#
|
|
144
|
-
# @see https://sashite.dev/specs/epin/1.0.0/ EPIN Specification v1.0.0
|
|
145
|
-
# @see https://sashite.dev/specs/epin/1.0.0/examples/ EPIN Examples
|
|
146
|
-
# @see https://sashite.dev/specs/pin/1.0.0/ PIN Specification (base component)
|
|
37
|
+
# @see https://sashite.dev/specs/epin/1.0.0/
|
|
147
38
|
module Epin
|
|
148
|
-
#
|
|
39
|
+
# Parses an EPIN string into an Identifier.
|
|
149
40
|
#
|
|
150
|
-
#
|
|
41
|
+
# @param string [String] The EPIN string to parse
|
|
42
|
+
# @return [Identifier] A new Identifier instance
|
|
43
|
+
# @raise [Errors::Argument] If the string is not a valid EPIN
|
|
151
44
|
#
|
|
152
|
-
# @
|
|
153
|
-
#
|
|
45
|
+
# @example
|
|
46
|
+
# Sashite::Epin.parse("K")
|
|
47
|
+
# # => #<Sashite::Epin::Identifier K>
|
|
154
48
|
#
|
|
155
|
-
#
|
|
156
|
-
# Sashite::Epin
|
|
157
|
-
# Sashite::Epin.valid?("K^'") # => true (valid PIN with derivation)
|
|
158
|
-
# Sashite::Epin.valid?("+R'") # => true (enhanced derived rook)
|
|
159
|
-
# Sashite::Epin.valid?("K^''") # => false (multiple markers)
|
|
160
|
-
# Sashite::Epin.valid?("KK'") # => false (invalid PIN part)
|
|
161
|
-
# Sashite::Epin.valid?("invalid") # => false (invalid format)
|
|
162
|
-
def self.valid?(epin_string)
|
|
163
|
-
Identifier.valid?(epin_string)
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
# Parse an EPIN string into an Identifier object
|
|
167
|
-
#
|
|
168
|
-
# Creates a new EPIN identifier by parsing the string, extracting the PIN part
|
|
169
|
-
# and derivation marker, validating the PIN component, and creating an identifier
|
|
170
|
-
# with the appropriate derivation status.
|
|
49
|
+
# Sashite::Epin.parse("K^'")
|
|
50
|
+
# # => #<Sashite::Epin::Identifier K^'>
|
|
171
51
|
#
|
|
172
|
-
#
|
|
173
|
-
#
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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)
|
|
190
|
-
def self.parse(epin_string)
|
|
191
|
-
Identifier.parse(epin_string)
|
|
52
|
+
# Sashite::Epin.parse("invalid")
|
|
53
|
+
# # => raises Errors::Argument
|
|
54
|
+
def self.parse(string)
|
|
55
|
+
components = Parser.parse(string)
|
|
56
|
+
|
|
57
|
+
pin = ::Sashite::Pin::Identifier.new(
|
|
58
|
+
components[:pin][:abbr],
|
|
59
|
+
components[:pin][:side],
|
|
60
|
+
components[:pin][:state],
|
|
61
|
+
terminal: components[:pin][:terminal]
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
Identifier.new(pin, derived: components[:derived])
|
|
192
65
|
end
|
|
193
66
|
|
|
194
|
-
#
|
|
195
|
-
#
|
|
196
|
-
# Constructs an EPIN identifier by combining a PIN component (which provides
|
|
197
|
-
# the four base attributes: name, side, state, terminal) with a derivation flag
|
|
198
|
-
# (which provides the fifth attribute: style).
|
|
199
|
-
#
|
|
200
|
-
# @param pin [Pin::Identifier] PIN component providing base attributes
|
|
201
|
-
# @param derived [Boolean] whether the piece uses derived style (default: false)
|
|
202
|
-
# @return [Epin::Identifier] new immutable identifier instance
|
|
203
|
-
# @raise [ArgumentError] if pin is not a Pin::Identifier
|
|
204
|
-
#
|
|
205
|
-
# @example Create identifiers from PIN components
|
|
206
|
-
# pin = Sashite::Pin.parse("K^")
|
|
207
|
-
# native = Sashite::Epin.new(pin, derived: false)
|
|
208
|
-
# native.to_s # => "K^"
|
|
209
|
-
#
|
|
210
|
-
# derived = Sashite::Epin.new(pin, derived: true)
|
|
211
|
-
# derived.to_s # => "K^'"
|
|
67
|
+
# Checks if a string is a valid EPIN notation.
|
|
212
68
|
#
|
|
213
|
-
# @
|
|
214
|
-
#
|
|
215
|
-
# chess_king = Sashite::Epin.new(Sashite::Pin.parse("K^"), derived: false)
|
|
216
|
-
# makruk_pawn = Sashite::Epin.new(Sashite::Pin.parse("P"), derived: true)
|
|
69
|
+
# @param string [String] The string to validate
|
|
70
|
+
# @return [Boolean] true if valid, false otherwise
|
|
217
71
|
#
|
|
218
|
-
#
|
|
219
|
-
#
|
|
220
|
-
|
|
221
|
-
|
|
72
|
+
# @example
|
|
73
|
+
# Sashite::Epin.valid?("K") # => true
|
|
74
|
+
# Sashite::Epin.valid?("K^'") # => true
|
|
75
|
+
# Sashite::Epin.valid?("invalid") # => false
|
|
76
|
+
def self.valid?(string)
|
|
77
|
+
Parser.valid?(string)
|
|
222
78
|
end
|
|
223
79
|
end
|
|
224
80
|
end
|
data/lib/sashite-epin.rb
CHANGED
|
@@ -1,14 +1,3 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "sashite/epin"
|
|
4
|
-
|
|
5
|
-
# Sashité namespace for board game notation libraries
|
|
6
|
-
#
|
|
7
|
-
# Sashité provides a collection of libraries for representing and manipulating
|
|
8
|
-
# board game concepts according to the Game Protocol specifications.
|
|
9
|
-
#
|
|
10
|
-
# @see https://sashite.dev/game-protocol/ Game Protocol Foundation
|
|
11
|
-
# @see https://sashite.dev/specs/ Sashité Specifications
|
|
12
|
-
# @author Sashité
|
|
13
|
-
module Sashite
|
|
14
|
-
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.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Cyril Kato
|
|
@@ -15,32 +15,32 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version:
|
|
18
|
+
version: 4.1.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:
|
|
25
|
+
version: 4.1.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: []
|
|
37
33
|
extra_rdoc_files: []
|
|
38
34
|
files:
|
|
39
|
-
- LICENSE.md
|
|
40
35
|
- README.md
|
|
41
36
|
- lib/sashite-epin.rb
|
|
42
37
|
- lib/sashite/epin.rb
|
|
38
|
+
- lib/sashite/epin/constants.rb
|
|
39
|
+
- lib/sashite/epin/errors.rb
|
|
40
|
+
- lib/sashite/epin/errors/argument.rb
|
|
41
|
+
- lib/sashite/epin/errors/argument/messages.rb
|
|
43
42
|
- lib/sashite/epin/identifier.rb
|
|
43
|
+
- lib/sashite/epin/parser.rb
|
|
44
44
|
homepage: https://github.com/sashite/epin.rb
|
|
45
45
|
licenses:
|
|
46
46
|
- MIT
|
|
@@ -65,7 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
65
65
|
- !ruby/object:Gem::Version
|
|
66
66
|
version: '0'
|
|
67
67
|
requirements: []
|
|
68
|
-
rubygems_version:
|
|
68
|
+
rubygems_version: 4.0.3
|
|
69
69
|
specification_version: 4
|
|
70
70
|
summary: EPIN (Extended Piece Identifier Notation) implementation for Ruby extending
|
|
71
71
|
PIN with style derivation markers.
|
data/LICENSE.md
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# The MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Sashité
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in
|
|
13
|
-
all copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
-
THE SOFTWARE.
|