sashite-pin 2.0.1 → 3.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0335d119541a7fa271689c6235a9c785a4c46f6c70e9577d4cddcc597d520dd5
4
- data.tar.gz: 7d95e04c803457156561bfe0fd8e270db5df1929b58721b9ed8266646f60e7e1
3
+ metadata.gz: f69bdd89484b5fc844f13c7cedbbdf2efe15f75620fe1eb695d0258120cf16d6
4
+ data.tar.gz: 38c51ef6f22d3267c26f5baa425306645e2a17f8448575da6759112a6b71f115
5
5
  SHA512:
6
- metadata.gz: 6904c80bee041595400f4074ed48a975ad6337c3c5a8c66f9d18ad7864f19e23d04e34b30c725d37ce9c4bfde58667328a82bbd1c38208c123cb44a9da00b283
7
- data.tar.gz: 32289d6453d81ff2e1920aeb7d69eedfac6bc61f9acdd1929e7ca4bc09c6988bb2a64bc3620130cfb63024977e0508b7c5ffce695590382eac3420d85454c67a
6
+ metadata.gz: c98b8c1e383c0414341be4ea7ea9f3f5f5864330f16f3faed608a315cd46a52e039f539c4d45f45d8b84aa6965d999560f0d0d937cf4743ec6c05655e9b6470d
7
+ data.tar.gz: 847ca5d4e6c6bd5697d665bebc103e01f876fc2a5f8c0947a27ef3589de94bd9d482bb69322817985e9dc6d23a3588801c8021ab54467b70bda49929cd62aef4
data/README.md CHANGED
@@ -11,14 +11,14 @@
11
11
 
12
12
  PIN (Piece Identifier Notation) provides an ASCII-based format for representing pieces in abstract strategy board games. PIN translates piece attributes from the [Game Protocol](https://sashite.dev/game-protocol/) into a compact, portable notation system.
13
13
 
14
- This gem implements the [PIN Specification v1.0.0](https://sashite.dev/specs/pin/1.0.0/), providing a modern Ruby interface with immutable piece objects and functional programming principles.
14
+ This gem implements the [PIN Specification v1.0.0](https://sashite.dev/specs/pin/1.0.0/), providing a modern Ruby interface with immutable identifier objects and functional programming principles.
15
15
 
16
16
  ## Installation
17
17
 
18
18
  ```ruby
19
19
  # In your Gemfile
20
20
  gem "sashite-pin"
21
- ```
21
+ ````
22
22
 
23
23
  Or install manually:
24
24
 
@@ -31,16 +31,16 @@ gem install sashite-pin
31
31
  ```ruby
32
32
  require "sashite/pin"
33
33
 
34
- # Parse PIN strings into piece objects
35
- piece = Sashite::Pin.parse("K") # => #<Pin::Piece type=:K side=:first state=:normal>
36
- piece.to_s # => "K"
37
- piece.type # => :K
38
- piece.side # => :first
39
- piece.state # => :normal
34
+ # Parse PIN strings into identifier objects
35
+ identifier = Sashite::Pin.parse("K") # => #<Pin::Identifier type=:K side=:first state=:normal>
36
+ identifier.to_s # => "K"
37
+ identifier.type # => :K
38
+ identifier.side # => :first
39
+ identifier.state # => :normal
40
40
 
41
- # Create pieces directly
42
- piece = Sashite::Pin.piece(:K, :first, :normal) # => #<Pin::Piece type=:K side=:first state=:normal>
43
- piece = Sashite::Pin::Piece.new(:R, :second, :enhanced) # => #<Pin::Piece type=:R side=:second state=:enhanced>
41
+ # Create identifiers directly
42
+ identifier = Sashite::Pin.identifier(:K, :first, :normal) # => #<Pin::Identifier type=:K side=:first state=:normal>
43
+ identifier = Sashite::Pin::Identifier.new(:R, :second, :enhanced) # => #<Pin::Identifier type=:R side=:second state=:enhanced>
44
44
 
45
45
  # Validate PIN strings
46
46
  Sashite::Pin.valid?("K") # => true
@@ -48,170 +48,104 @@ Sashite::Pin.valid?("+R") # => true
48
48
  Sashite::Pin.valid?("invalid") # => false
49
49
 
50
50
  # State manipulation (returns new immutable instances)
51
- enhanced = piece.enhance # => #<Pin::Piece type=:K side=:first state=:enhanced>
52
- enhanced.to_s # => "+K"
53
- diminished = piece.diminish # => #<Pin::Piece type=:K side=:first state=:diminished>
54
- diminished.to_s # => "-K"
51
+ enhanced = identifier.enhance # => #<Pin::Identifier type=:K side=:first state=:enhanced>
52
+ enhanced.to_s # => "+K"
53
+ diminished = identifier.diminish # => #<Pin::Identifier type=:K side=:first state=:diminished>
54
+ diminished.to_s # => "-K"
55
55
 
56
56
  # Side manipulation
57
- flipped = piece.flip # => #<Pin::Piece type=:K side=:second state=:normal>
58
- flipped.to_s # => "k"
57
+ flipped = identifier.flip # => #<Pin::Identifier type=:K side=:second state=:normal>
58
+ flipped.to_s # => "k"
59
59
 
60
60
  # Type manipulation
61
- queen = piece.with_type(:Q) # => #<Pin::Piece type=:Q side=:first state=:normal>
62
- queen.to_s # => "Q"
61
+ queen = identifier.with_type(:Q) # => #<Pin::Identifier type=:Q side=:first state=:normal>
62
+ queen.to_s # => "Q"
63
63
 
64
64
  # State queries
65
- piece.normal? # => true
66
- enhanced.enhanced? # => true
67
- diminished.diminished? # => true
65
+ identifier.normal? # => true
66
+ enhanced.enhanced? # => true
67
+ diminished.diminished? # => true
68
68
 
69
69
  # Side queries
70
- piece.first_player? # => true
71
- flipped.second_player? # => true
70
+ identifier.first_player? # => true
71
+ flipped.second_player? # => true
72
72
 
73
73
  # Attribute access
74
- piece.letter # => "K"
75
- enhanced.prefix # => "+"
76
- piece.prefix # => ""
74
+ identifier.letter # => "K"
75
+ enhanced.prefix # => "+"
76
+ identifier.prefix # => ""
77
77
 
78
78
  # Type and side comparison
79
79
  king1 = Sashite::Pin.parse("K")
80
80
  king2 = Sashite::Pin.parse("k")
81
81
  queen = Sashite::Pin.parse("Q")
82
82
 
83
- king1.same_type?(king2) # => true (both kings)
84
- king1.same_side?(queen) # => true (both first player)
85
- king1.same_type?(queen) # => false (different types)
83
+ king1.same_type?(king2) # => true (both kings)
84
+ king1.same_side?(queen) # => true (both first player)
85
+ king1.same_type?(queen) # => false (different types)
86
86
 
87
87
  # Functional transformations can be chained
88
88
  pawn = Sashite::Pin.parse("P")
89
- enemy_promoted = pawn.flip.enhance # => "+p" (second player promoted pawn)
89
+ enemy_promoted = pawn.flip.enhance # => "+p" (second player promoted pawn)
90
90
  ```
91
91
 
92
92
  ## Format Specification
93
93
 
94
94
  ### Structure
95
+
95
96
  ```
96
97
  [<state>]<letter>
97
98
  ```
98
99
 
99
100
  ### Components
100
101
 
101
- - **Letter** (`A-Z`, `a-z`): Represents piece type and side
102
- - Uppercase: First player pieces
103
- - Lowercase: Second player pieces
104
- - **State** (optional prefix):
105
- - `+`: Enhanced state (promoted, upgraded, empowered)
106
- - `-`: Diminished state (weakened, restricted, temporary)
107
- - No prefix: Normal state
108
-
109
- ### Regular Expression
110
- ```ruby
111
- /\A[-+]?[A-Za-z]\z/
112
- ```
102
+ * **Letter** (`A-Z`, `a-z`): Represents piece type and side
113
103
 
114
- ### Examples
115
- - `K` - First player king (normal state)
116
- - `k` - Second player king (normal state)
117
- - `+R` - First player rook (enhanced state)
118
- - `-p` - Second player pawn (diminished state)
104
+ * Uppercase: First player pieces
105
+ * Lowercase: Second player pieces
106
+ * **State** (optional prefix):
119
107
 
120
- ## Game Examples
108
+ * `+`: Enhanced state (promoted, upgraded, empowered)
109
+ * `-`: Diminished state (weakened, restricted, temporary)
110
+ * No prefix: Normal state
121
111
 
122
- ### Western Chess
123
- ```ruby
124
- # Standard pieces
125
- king = Sashite::Pin.piece(:K, :first, :normal) # => white king
126
- king.first_player? # => true
127
- king.type # => :K
128
-
129
- # State modifiers for special conditions
130
- castling_king = king.enhance # => castling-eligible king
131
- castling_king.to_s # => "+K"
132
-
133
- vulnerable_pawn = Sashite::Pin.piece(:P, :first, :diminished) # => en passant vulnerable
134
- vulnerable_pawn.to_s # => "-P"
135
-
136
- # All piece types
137
- piece_types = [:K, :Q, :R, :B, :N, :P]
138
- white_pieces = piece_types.map { |type| Sashite::Pin.piece(type, :first, :normal) }
139
- black_pieces = white_pieces.map(&:flip) # Convert to black pieces
140
- ```
112
+ ### Regular Expression
141
113
 
142
- ### Japanese Chess (Shōgi)
143
114
  ```ruby
144
- # Basic pieces
145
- rook = Sashite::Pin.piece(:R, :first, :normal) # => white rook
146
- bishop = Sashite::Pin.piece(:B, :first, :normal) # => white bishop
147
-
148
- # Promoted pieces (enhanced state)
149
- dragon_king = rook.enhance # => promoted rook (Dragon King)
150
- dragon_king.to_s # => "+R"
151
-
152
- dragon_horse = bishop.enhance # => promoted bishop (Dragon Horse)
153
- dragon_horse.to_s # => "+B"
154
-
155
- # Promoted pawn
156
- pawn = Sashite::Pin.piece(:P, :first, :normal)
157
- tokin = pawn.enhance # => promoted pawn (Tokin)
158
- tokin.to_s # => "+P"
159
-
160
- # All promotable pieces can use the same pattern
161
- promotable_types = [:R, :B, :S, :N, :L, :P]
162
- promotable = promotable_types.map { |type| Sashite::Pin.piece(type, :first, :normal) }
163
- promoted = promotable.map(&:enhance)
115
+ /\A[-+]?[A-Za-z]\z/
164
116
  ```
165
117
 
166
- ### Thai Chess (Makruk)
167
- ```ruby
168
- # Basic pieces
169
- met = Sashite::Pin.piece(:M, :first, :normal) # => white Met (queen)
170
- pawn = Sashite::Pin.piece(:P, :first, :normal) # => white Bia (pawn)
171
-
172
- # Promoted pawns
173
- bia_kaew = pawn.enhance # => promoted pawn (Bia Kaew)
174
- bia_kaew.to_s # => "+P"
175
-
176
- # Makruk pieces
177
- makruk_types = [:K, :M, :R, :B, :N, :P]
178
- makruk_pieces = makruk_types.map { |type| Sashite::Pin.piece(type, :first, :normal) }
179
- ```
118
+ ### Examples
180
119
 
181
- ### Chinese Chess (Xiangqi)
182
- ```ruby
183
- # Pieces with positional states
184
- general = Sashite::Pin.piece(:G, :first, :normal) # => red general
185
- flying_general = general.enhance # => flying general (special state)
186
- flying_general.to_s # => "+G"
187
-
188
- # Soldiers that crossed the river
189
- soldier = Sashite::Pin.piece(:P, :first, :normal)
190
- crossed_soldier = soldier.enhance # => soldier with enhanced movement
191
- crossed_soldier.to_s # => "+P"
192
- ```
120
+ * `K` - First player king (normal state)
121
+ * `k` - Second player king (normal state)
122
+ * `+R` - First player rook (enhanced state)
123
+ * `-p` - Second player pawn (diminished state)
193
124
 
194
125
  ## API Reference
195
126
 
196
127
  ### Main Module Methods
197
128
 
198
- - `Sashite::Pin.valid?(pin_string)` - Check if string is valid PIN notation
199
- - `Sashite::Pin.parse(pin_string)` - Parse PIN string into Piece object
200
- - `Sashite::Pin.piece(type, side, state = :normal)` - Create piece instance directly
129
+ * `Sashite::Pin.valid?(pin_string)` - Check if string is valid PIN notation
130
+ * `Sashite::Pin.parse(pin_string)` - Parse PIN string into Identifier object
131
+ * `Sashite::Pin.identifier(type, side, state = :normal)` - Create identifier instance directly
201
132
 
202
- ### Piece Class
133
+ ### Identifier Class
203
134
 
204
135
  #### Creation and Parsing
205
- - `Sashite::Pin::Piece.new(type, side, state = :normal)` - Create piece instance
206
- - `Sashite::Pin::Piece.parse(pin_string)` - Parse PIN string (same as module method)
136
+
137
+ * `Sashite::Pin::Identifier.new(type, side, state = :normal)` - Create identifier instance
138
+ * `Sashite::Pin::Identifier.parse(pin_string)` - Parse PIN string (same as module method)
139
+ * `Sashite::Pin::Identifier.valid?(pin_string)` - Validate PIN string (class method)
207
140
 
208
141
  #### Attribute Access
209
- - `#type` - Get piece type (symbol :A to :Z, always uppercase)
210
- - `#side` - Get player side (:first or :second)
211
- - `#state` - Get state (:normal, :enhanced, or :diminished)
212
- - `#letter` - Get letter representation (string, case determined by side)
213
- - `#prefix` - Get state prefix (string: "+", "-", or "")
214
- - `#to_s` - Convert to PIN string representation
142
+
143
+ * `#type` - Get piece type (symbol \:A to \:Z, always uppercase)
144
+ * `#side` - Get player side (\:first or \:second)
145
+ * `#state` - Get state (\:normal, \:enhanced, or \:diminished)
146
+ * `#letter` - Get letter representation (string, case determined by side)
147
+ * `#prefix` - Get state prefix (string: "+", "-", or "")
148
+ * `#to_s` - Convert to PIN string representation
215
149
 
216
150
  #### Type and Case Handling
217
151
 
@@ -219,46 +153,52 @@ crossed_soldier.to_s # => "+P"
219
153
 
220
154
  ```ruby
221
155
  # Both create the same internal type representation
222
- piece1 = Sashite::Pin.parse("K") # type: :K, side: :first
223
- piece2 = Sashite::Pin.parse("k") # type: :K, side: :second
156
+ identifier1 = Sashite::Pin.parse("K") # type: :K, side: :first
157
+ identifier2 = Sashite::Pin.parse("k") # type: :K, side: :second
224
158
 
225
- piece1.type # => :K (uppercase symbol)
226
- piece2.type # => :K (same uppercase symbol)
159
+ identifier1.type # => :K (uppercase symbol)
160
+ identifier2.type # => :K (same uppercase symbol)
227
161
 
228
- piece1.letter # => "K" (uppercase display)
229
- piece2.letter # => "k" (lowercase display)
162
+ identifier1.letter # => "K" (uppercase display)
163
+ identifier2.letter # => "k" (lowercase display)
230
164
  ```
231
165
 
232
166
  #### State Queries
233
- - `#normal?` - Check if normal state (no modifiers)
234
- - `#enhanced?` - Check if enhanced state
235
- - `#diminished?` - Check if diminished state
167
+
168
+ * `#normal?` - Check if normal state (no modifiers)
169
+ * `#enhanced?` - Check if enhanced state
170
+ * `#diminished?` - Check if diminished state
236
171
 
237
172
  #### Side Queries
238
- - `#first_player?` - Check if first player piece
239
- - `#second_player?` - Check if second player piece
173
+
174
+ * `#first_player?` - Check if first player identifier
175
+ * `#second_player?` - Check if second player identifier
240
176
 
241
177
  #### State Transformations (immutable - return new instances)
242
- - `#enhance` - Create enhanced version
243
- - `#unenhance` - Remove enhanced state
244
- - `#diminish` - Create diminished version
245
- - `#undiminish` - Remove diminished state
246
- - `#normalize` - Remove all state modifiers
247
- - `#flip` - Switch player (change side)
178
+
179
+ * `#enhance` - Create enhanced version
180
+ * `#unenhance` - Remove enhanced state
181
+ * `#diminish` - Create diminished version
182
+ * `#undiminish` - Remove diminished state
183
+ * `#normalize` - Remove all state modifiers
184
+ * `#flip` - Switch player (change side)
248
185
 
249
186
  #### Attribute Transformations (immutable - return new instances)
250
- - `#with_type(new_type)` - Create piece with different type
251
- - `#with_side(new_side)` - Create piece with different side
252
- - `#with_state(new_state)` - Create piece with different state
187
+
188
+ * `#with_type(new_type)` - Create identifier with different type
189
+ * `#with_side(new_side)` - Create identifier with different side
190
+ * `#with_state(new_state)` - Create identifier with different state
253
191
 
254
192
  #### Comparison Methods
255
- - `#same_type?(other)` - Check if same piece type
256
- - `#same_side?(other)` - Check if same side
257
- - `#same_state?(other)` - Check if same state
258
- - `#==(other)` - Full equality comparison
193
+
194
+ * `#same_type?(other)` - Check if same piece type
195
+ * `#same_side?(other)` - Check if same side
196
+ * `#same_state?(other)` - Check if same state
197
+ * `#==(other)` - Full equality comparison
259
198
 
260
199
  ### Constants
261
- - `Sashite::Pin::PIN_REGEX` - Regular expression for PIN validation
200
+
201
+ * `Sashite::Pin::Identifier::PIN_PATTERN` - Regular expression for PIN validation (internal use)
262
202
 
263
203
  ## Advanced Usage
264
204
 
@@ -2,9 +2,9 @@
2
2
 
3
3
  module Sashite
4
4
  module Pin
5
- # Represents a piece in PIN (Piece Identifier Notation) format.
5
+ # Represents an identifier in PIN (Piece Identifier Notation) format.
6
6
  #
7
- # A piece consists of a single ASCII letter with optional state modifiers:
7
+ # An identifier consists of a single ASCII letter with optional state modifiers:
8
8
  # - Enhanced state: prefix '+'
9
9
  # - Diminished state: prefix '-'
10
10
  # - Normal state: no modifier
@@ -15,7 +15,7 @@ module Sashite
15
15
  #
16
16
  # All instances are immutable - state manipulation methods return new instances.
17
17
  # This follows the Game Protocol's piece model with Type, Side, and State attributes.
18
- class Piece
18
+ class Identifier
19
19
  # PIN validation pattern matching the specification
20
20
  PIN_PATTERN = /\A(?<prefix>[-+])?(?<letter>[a-zA-Z])\z/
21
21
 
@@ -57,7 +57,7 @@ module Sashite
57
57
  # @return [Symbol] the piece state (:normal, :enhanced, or :diminished)
58
58
  attr_reader :state
59
59
 
60
- # Create a new piece instance
60
+ # Create a new identifier instance
61
61
  #
62
62
  # @param type [Symbol] piece type (:A to :Z)
63
63
  # @param side [Symbol] player side (:first or :second)
@@ -75,15 +75,15 @@ module Sashite
75
75
  freeze
76
76
  end
77
77
 
78
- # Parse a PIN string into a Piece object
78
+ # Parse a PIN string into an Identifier object
79
79
  #
80
80
  # @param pin_string [String] PIN notation string
81
- # @return [Piece] new piece instance
81
+ # @return [Identifier] new identifier instance
82
82
  # @raise [ArgumentError] if the PIN string is invalid
83
83
  # @example
84
- # Pin::Piece.parse("k") # => #<Pin::Piece type=:K side=:second state=:normal>
85
- # Pin::Piece.parse("+R") # => #<Pin::Piece type=:R side=:first state=:enhanced>
86
- # Pin::Piece.parse("-p") # => #<Pin::Piece type=:P side=:second state=:diminished>
84
+ # Pin::Identifier.parse("k") # => #<Pin::Identifier type=:K side=:second state=:normal>
85
+ # Pin::Identifier.parse("+R") # => #<Pin::Identifier type=:R side=:first state=:enhanced>
86
+ # Pin::Identifier.parse("-p") # => #<Pin::Identifier type=:P side=:second state=:diminished>
87
87
  def self.parse(pin_string)
88
88
  string_value = String(pin_string)
89
89
  matches = match_pattern(string_value)
@@ -92,27 +92,41 @@ module Sashite
92
92
  enhanced = matches[:prefix] == ENHANCED_PREFIX
93
93
  diminished = matches[:prefix] == DIMINISHED_PREFIX
94
94
 
95
- # Extract type and side from letter
96
- piece_type = letter.upcase.to_sym
97
- piece_side = letter == letter.upcase ? FIRST_PLAYER : SECOND_PLAYER
98
- piece_state = if enhanced
99
- ENHANCED_STATE
100
- elsif diminished
101
- DIMINISHED_STATE
102
- else
103
- NORMAL_STATE
104
- end
105
-
106
- new(piece_type, piece_side, piece_state)
95
+ type = letter.upcase.to_sym
96
+ side = letter == letter.upcase ? FIRST_PLAYER : SECOND_PLAYER
97
+ state = if enhanced
98
+ ENHANCED_STATE
99
+ elsif diminished
100
+ DIMINISHED_STATE
101
+ else
102
+ NORMAL_STATE
103
+ end
104
+
105
+ new(type, side, state)
107
106
  end
108
107
 
109
- # Convert the piece to its PIN string representation
108
+ # Check if a string is a valid PIN notation
109
+ #
110
+ # @param pin_string [String] The string to validate
111
+ # @return [Boolean] true if valid PIN, false otherwise
112
+ #
113
+ # @example
114
+ # Sashite::Pin::Identifier.valid?("K") # => true
115
+ # Sashite::Pin::Identifier.valid?("+R") # => true
116
+ # Sashite::Pin::Identifier.valid?("-p") # => true
117
+ # Sashite::Pin::Identifier.valid?("KK") # => false
118
+ # Sashite::Pin::Identifier.valid?("++K") # => false
119
+ def self.valid?(pin_string)
120
+ return false unless pin_string.is_a?(::String)
121
+
122
+ pin_string.match?(PIN_PATTERN)
123
+ end
124
+
125
+ # Convert the identifier to its PIN string representation
110
126
  #
111
127
  # @return [String] PIN notation string
112
128
  # @example
113
- # piece.to_s # => "+R"
114
- # piece.to_s # => "-p"
115
- # piece.to_s # => "K"
129
+ # identifier.to_s # => "+R"
116
130
  def to_s
117
131
  "#{prefix}#{letter}"
118
132
  end
@@ -135,76 +149,62 @@ module Sashite
135
149
  end
136
150
  end
137
151
 
138
- # Create a new piece with enhanced state
152
+ # Create a new identifier with enhanced state
139
153
  #
140
- # @return [Piece] new piece instance with enhanced state
141
- # @example
142
- # piece.enhance # (:K, :first, :normal) => (:K, :first, :enhanced)
154
+ # @return [Identifier] new identifier instance with enhanced state
143
155
  def enhance
144
156
  return self if enhanced?
145
157
 
146
158
  self.class.new(type, side, ENHANCED_STATE)
147
159
  end
148
160
 
149
- # Create a new piece without enhanced state
161
+ # Create a new identifier without enhanced state
150
162
  #
151
- # @return [Piece] new piece instance without enhanced state
152
- # @example
153
- # piece.unenhance # (:K, :first, :enhanced) => (:K, :first, :normal)
163
+ # @return [Identifier] new identifier instance with normal state
154
164
  def unenhance
155
165
  return self unless enhanced?
156
166
 
157
167
  self.class.new(type, side, NORMAL_STATE)
158
168
  end
159
169
 
160
- # Create a new piece with diminished state
170
+ # Create a new identifier with diminished state
161
171
  #
162
- # @return [Piece] new piece instance with diminished state
163
- # @example
164
- # piece.diminish # (:K, :first, :normal) => (:K, :first, :diminished)
172
+ # @return [Identifier] new identifier instance with diminished state
165
173
  def diminish
166
174
  return self if diminished?
167
175
 
168
176
  self.class.new(type, side, DIMINISHED_STATE)
169
177
  end
170
178
 
171
- # Create a new piece without diminished state
179
+ # Create a new identifier without diminished state
172
180
  #
173
- # @return [Piece] new piece instance without diminished state
174
- # @example
175
- # piece.undiminish # (:K, :first, :diminished) => (:K, :first, :normal)
181
+ # @return [Identifier] new identifier instance with normal state
176
182
  def undiminish
177
183
  return self unless diminished?
178
184
 
179
185
  self.class.new(type, side, NORMAL_STATE)
180
186
  end
181
187
 
182
- # Create a new piece with normal state (no modifiers)
188
+ # Create a new identifier with normal state (no modifiers)
183
189
  #
184
- # @return [Piece] new piece instance with normal state
185
- # @example
186
- # piece.normalize # (:K, :first, :enhanced) => (:K, :first, :normal)
190
+ # @return [Identifier] new identifier instance with normal state
187
191
  def normalize
188
192
  return self if normal?
189
193
 
190
194
  self.class.new(type, side, NORMAL_STATE)
191
195
  end
192
196
 
193
- # Create a new piece with opposite ownership (case)
197
+ # Create a new identifier with opposite side
194
198
  #
195
- # @return [Piece] new piece instance with flipped case
196
- # @example
197
- # piece.flip # (:K, :first, :normal) => (:K, :second, :normal)
199
+ # @return [Identifier] new identifier instance with opposite side
198
200
  def flip
199
201
  self.class.new(type, opposite_side, state)
200
202
  end
201
203
 
202
- # Create a new piece with a different type (keeping same side and state)
204
+ # Create a new identifier with a different type
203
205
  #
204
206
  # @param new_type [Symbol] new type (:A to :Z)
205
- # @return [Piece] new piece instance with different type
206
- # @example
207
- # piece.with_type(:Q) # (:K, :first, :normal) => (:Q, :first, :normal)
207
+ # @return [Identifier] new identifier instance with new type
208
208
  def with_type(new_type)
209
209
  self.class.validate_type(new_type)
210
210
  return self if type == new_type
@@ -212,12 +212,10 @@ module Sashite
212
212
  self.class.new(new_type, side, state)
213
213
  end
214
214
 
215
- # Create a new piece with a different side (keeping same type and state)
215
+ # Create a new identifier with a different side
216
216
  #
217
- # @param new_side [Symbol] :first or :second
218
- # @return [Piece] new piece instance with different side
219
- # @example
220
- # piece.with_side(:second) # (:K, :first, :normal) => (:K, :second, :normal)
217
+ # @param new_side [Symbol] new side (:first or :second)
218
+ # @return [Identifier] new identifier instance with new side
221
219
  def with_side(new_side)
222
220
  self.class.validate_side(new_side)
223
221
  return self if side == new_side
@@ -225,12 +223,10 @@ module Sashite
225
223
  self.class.new(type, new_side, state)
226
224
  end
227
225
 
228
- # Create a new piece with a different state (keeping same type and side)
226
+ # Create a new identifier with a different state
229
227
  #
230
- # @param new_state [Symbol] :normal, :enhanced, or :diminished
231
- # @return [Piece] new piece instance with different state
232
- # @example
233
- # piece.with_state(:enhanced) # (:K, :first, :normal) => (:K, :first, :enhanced)
228
+ # @param new_state [Symbol] new state (:normal, :enhanced, or :diminished)
229
+ # @return [Identifier] new identifier instance with new state
234
230
  def with_state(new_state)
235
231
  self.class.validate_state(new_state)
236
232
  return self if state == new_state
@@ -238,56 +234,54 @@ module Sashite
238
234
  self.class.new(type, side, new_state)
239
235
  end
240
236
 
241
- # Check if the piece has enhanced state
237
+ # Check if the identifier has enhanced state
242
238
  #
243
239
  # @return [Boolean] true if enhanced
244
240
  def enhanced?
245
241
  state == ENHANCED_STATE
246
242
  end
247
243
 
248
- # Check if the piece has diminished state
244
+ # Check if the identifier has diminished state
249
245
  #
250
246
  # @return [Boolean] true if diminished
251
247
  def diminished?
252
248
  state == DIMINISHED_STATE
253
249
  end
254
250
 
255
- # Check if the piece has normal state (no modifiers)
251
+ # Check if the identifier has normal state
256
252
  #
257
- # @return [Boolean] true if no modifiers are present
253
+ # @return [Boolean] true if normal
258
254
  def normal?
259
255
  state == NORMAL_STATE
260
256
  end
261
257
 
262
- # Check if the piece belongs to the first player
258
+ # Check if the identifier belongs to the first player
263
259
  #
264
260
  # @return [Boolean] true if first player
265
261
  def first_player?
266
262
  side == FIRST_PLAYER
267
263
  end
268
264
 
269
- # Check if the piece belongs to the second player
265
+ # Check if the identifier belongs to the second player
270
266
  #
271
267
  # @return [Boolean] true if second player
272
268
  def second_player?
273
269
  side == SECOND_PLAYER
274
270
  end
275
271
 
276
- # Check if this piece is the same type as another (ignoring side and state)
272
+ # Check if this identifier is the same type as another
277
273
  #
278
- # @param other [Piece] piece to compare with
274
+ # @param other [Identifier] identifier to compare with
279
275
  # @return [Boolean] true if same type
280
- # @example
281
- # king1.same_type?(king2) # (:K, :first, :normal) and (:K, :second, :enhanced) => true
282
276
  def same_type?(other)
283
277
  return false unless other.is_a?(self.class)
284
278
 
285
279
  type == other.type
286
280
  end
287
281
 
288
- # Check if this piece belongs to the same side as another
282
+ # Check if this identifier has the same side as another
289
283
  #
290
- # @param other [Piece] piece to compare with
284
+ # @param other [Identifier] identifier to compare with
291
285
  # @return [Boolean] true if same side
292
286
  def same_side?(other)
293
287
  return false unless other.is_a?(self.class)
@@ -295,9 +289,9 @@ module Sashite
295
289
  side == other.side
296
290
  end
297
291
 
298
- # Check if this piece has the same state as another
292
+ # Check if this identifier has the same state as another
299
293
  #
300
- # @param other [Piece] piece to compare with
294
+ # @param other [Identifier] identifier to compare with
301
295
  # @return [Boolean] true if same state
302
296
  def same_state?(other)
303
297
  return false unless other.is_a?(self.class)
@@ -308,7 +302,7 @@ module Sashite
308
302
  # Custom equality comparison
309
303
  #
310
304
  # @param other [Object] object to compare with
311
- # @return [Boolean] true if pieces are equal
305
+ # @return [Boolean] true if identifiers are equal
312
306
  def ==(other)
313
307
  return false unless other.is_a?(self.class)
314
308
 
@@ -371,7 +365,7 @@ module Sashite
371
365
 
372
366
  private
373
367
 
374
- # Get the opposite side of the current piece
368
+ # Get the opposite side of the current identifier
375
369
  #
376
370
  # @return [Symbol] :first if current side is :second, :second if current side is :first
377
371
  def opposite_side
data/lib/sashite/pin.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "pin/piece"
3
+ require_relative "pin/identifier"
4
4
 
5
5
  module Sashite
6
6
  # PIN (Piece Identifier Notation) implementation for Ruby
@@ -20,13 +20,9 @@ module Sashite
20
20
  #
21
21
  # See: https://sashite.dev/specs/pin/1.0.0/
22
22
  module Pin
23
- # Regular expression for PIN validation
24
- # Matches: optional state modifier followed by a single letter
25
- PIN_REGEX = /\A[-+]?[A-Za-z]\z/
26
-
27
23
  # Check if a string is a valid PIN notation
28
24
  #
29
- # @param pin [String] The string to validate
25
+ # @param pin_string [String] The string to validate
30
26
  # @return [Boolean] true if valid PIN, false otherwise
31
27
  #
32
28
  # @example
@@ -35,38 +31,36 @@ module Sashite
35
31
  # Sashite::Pin.valid?("-p") # => true
36
32
  # Sashite::Pin.valid?("KK") # => false
37
33
  # Sashite::Pin.valid?("++K") # => false
38
- def self.valid?(pin)
39
- return false unless pin.is_a?(::String)
40
-
41
- pin.match?(PIN_REGEX)
34
+ def self.valid?(pin_string)
35
+ Identifier.valid?(pin_string)
42
36
  end
43
37
 
44
- # Parse a PIN string into a Piece object
38
+ # Parse a PIN string into an Identifier object
45
39
  #
46
40
  # @param pin_string [String] PIN notation string
47
- # @return [Pin::Piece] new piece instance
41
+ # @return [Pin::Identifier] new identifier instance
48
42
  # @raise [ArgumentError] if the PIN string is invalid
49
43
  # @example
50
- # Sashite::Pin.parse("K") # => #<Pin::Piece type=:K side=:first state=:normal>
51
- # Sashite::Pin.parse("+R") # => #<Pin::Piece type=:R side=:first state=:enhanced>
52
- # Sashite::Pin.parse("-p") # => #<Pin::Piece type=:P side=:second state=:diminished>
44
+ # Sashite::Pin.parse("K") # => #<Pin::Identifier type=:K side=:first state=:normal>
45
+ # Sashite::Pin.parse("+R") # => #<Pin::Identifier type=:R side=:first state=:enhanced>
46
+ # Sashite::Pin.parse("-p") # => #<Pin::Identifier type=:P side=:second state=:diminished>
53
47
  def self.parse(pin_string)
54
- Piece.parse(pin_string)
48
+ Identifier.parse(pin_string)
55
49
  end
56
50
 
57
- # Create a new piece instance
51
+ # Create a new identifier instance
58
52
  #
59
53
  # @param type [Symbol] piece type (:A to :Z)
60
54
  # @param side [Symbol] player side (:first or :second)
61
55
  # @param state [Symbol] piece state (:normal, :enhanced, or :diminished)
62
- # @return [Pin::Piece] new piece instance
56
+ # @return [Pin::Identifier] new identifier instance
63
57
  # @raise [ArgumentError] if parameters are invalid
64
58
  # @example
65
- # Sashite::Pin.piece(:K, :first, :normal) # => #<Pin::Piece type=:K side=:first state=:normal>
66
- # Sashite::Pin.piece(:R, :first, :enhanced) # => #<Pin::Piece type=:R side=:first state=:enhanced>
67
- # Sashite::Pin.piece(:P, :second, :diminished) # => #<Pin::Piece type=:P side=:second state=:diminished>
68
- def self.piece(type, side, state = :normal)
69
- Piece.new(type, side, state)
59
+ # Sashite::Pin.identifier(:K, :first, :normal) # => #<Pin::Identifier type=:K side=:first state=:normal>
60
+ # Sashite::Pin.identifier(:R, :first, :enhanced) # => #<Pin::Identifier type=:R side=:first state=:enhanced>
61
+ # Sashite::Pin.identifier(:P, :second, :diminished) # => #<Pin::Identifier type=:P side=:second state=:diminished>
62
+ def self.identifier(type, side, state = :normal)
63
+ Identifier.new(type, side, state)
70
64
  end
71
65
  end
72
66
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sashite-pin
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyril Kato
@@ -10,13 +10,13 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: |
13
- PIN (Piece Identifier Notation) provides an ASCII-based format for representing pieces
13
+ PIN (Piece Identifier Notation) provides a rule-agnostic format for identifying pieces
14
14
  in abstract strategy board games. This gem implements the PIN Specification v1.0.0 with
15
- a modern Ruby interface featuring immutable piece objects and functional programming
16
- principles. PIN translates piece attributes from the Game Protocol into a compact,
17
- portable notation system using ASCII letters with optional state modifiers and
18
- case-based side encoding. Perfect for game engines, board game notation systems,
19
- and multi-game environments.
15
+ a modern Ruby interface featuring immutable identifier objects and functional programming
16
+ principles. PIN uses single ASCII letters with optional state modifiers and case-based
17
+ side encoding (A-Z for first player, a-z for second player), enabling precise and portable
18
+ identification of pieces across multiple games. Perfect for game engines, board game notation
19
+ systems, and hybrid gaming platforms requiring compact, stateful piece representation.
20
20
  email: contact@cyril.email
21
21
  executables: []
22
22
  extensions: []
@@ -26,7 +26,7 @@ files:
26
26
  - README.md
27
27
  - lib/sashite-pin.rb
28
28
  - lib/sashite/pin.rb
29
- - lib/sashite/pin/piece.rb
29
+ - lib/sashite/pin/identifier.rb
30
30
  homepage: https://github.com/sashite/pin.rb
31
31
  licenses:
32
32
  - MIT
@@ -53,6 +53,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
53
53
  requirements: []
54
54
  rubygems_version: 3.6.9
55
55
  specification_version: 4
56
- summary: PIN (Piece Identifier Notation) implementation for Ruby with immutable piece
56
+ summary: PIN (Piece Identifier Notation) implementation for Ruby with immutable identifier
57
57
  objects
58
58
  test_files: []