sashite-pin 2.0.0 → 2.0.2
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 +84 -8
- data/lib/sashite/pin/piece.rb +29 -4
- data/lib/sashite/pin.rb +3 -9
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70bbc211cb1dd38efa9f0c39b2d0e1b0fd09c2dcf2d7ac3773719ce11786a5ac
|
4
|
+
data.tar.gz: cd6831f22ee3e9fd8ce559f5535bbcbb1d9ca13ba9083a9d9c1fe66d41e2eef9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0808aac8a46423256ec3546a4eb71d5882d3535b4a74929680cd31f84294ffd406716565f53ef072ff35c5c1131bb2612ab93398001d3d80772bb34a3dc3d07
|
7
|
+
data.tar.gz: ba7ecb1765c03c801f014bdbb9792fcae5dacd8d119890b0c73f0e550a345a8fc307cb39a82b803c986ef7fa50f76ad5fff39c6a7bffc5fe39e1b06bebe6b809
|
data/README.md
CHANGED
@@ -204,15 +204,32 @@ crossed_soldier.to_s # => "+P"
|
|
204
204
|
#### Creation and Parsing
|
205
205
|
- `Sashite::Pin::Piece.new(type, side, state = :normal)` - Create piece instance
|
206
206
|
- `Sashite::Pin::Piece.parse(pin_string)` - Parse PIN string (same as module method)
|
207
|
+
- `Sashite::Pin::Piece.valid?(pin_string)` - Validate PIN string (class method)
|
207
208
|
|
208
209
|
#### Attribute Access
|
209
|
-
- `#type` - Get piece type (symbol :A to :Z)
|
210
|
+
- `#type` - Get piece type (symbol :A to :Z, always uppercase)
|
210
211
|
- `#side` - Get player side (:first or :second)
|
211
212
|
- `#state` - Get state (:normal, :enhanced, or :diminished)
|
212
|
-
- `#letter` - Get letter representation (string)
|
213
|
+
- `#letter` - Get letter representation (string, case determined by side)
|
213
214
|
- `#prefix` - Get state prefix (string: "+", "-", or "")
|
214
215
|
- `#to_s` - Convert to PIN string representation
|
215
216
|
|
217
|
+
#### Type and Case Handling
|
218
|
+
|
219
|
+
**Important**: The `type` attribute is always stored as an uppercase symbol (`:A` to `:Z`), regardless of the input case when parsing. The display case in `#letter` and `#to_s` is determined by the `side` attribute:
|
220
|
+
|
221
|
+
```ruby
|
222
|
+
# Both create the same internal type representation
|
223
|
+
piece1 = Sashite::Pin.parse("K") # type: :K, side: :first
|
224
|
+
piece2 = Sashite::Pin.parse("k") # type: :K, side: :second
|
225
|
+
|
226
|
+
piece1.type # => :K (uppercase symbol)
|
227
|
+
piece2.type # => :K (same uppercase symbol)
|
228
|
+
|
229
|
+
piece1.letter # => "K" (uppercase display)
|
230
|
+
piece2.letter # => "k" (lowercase display)
|
231
|
+
```
|
232
|
+
|
216
233
|
#### State Queries
|
217
234
|
- `#normal?` - Check if normal state (no modifiers)
|
218
235
|
- `#enhanced?` - Check if enhanced state
|
@@ -242,10 +259,34 @@ crossed_soldier.to_s # => "+P"
|
|
242
259
|
- `#==(other)` - Full equality comparison
|
243
260
|
|
244
261
|
### Constants
|
245
|
-
- `Sashite::Pin::
|
262
|
+
- `Sashite::Pin::Piece::PIN_PATTERN` - Regular expression for PIN validation (internal use)
|
246
263
|
|
247
264
|
## Advanced Usage
|
248
265
|
|
266
|
+
### Type Normalization Examples
|
267
|
+
|
268
|
+
```ruby
|
269
|
+
# Parsing different cases results in same type
|
270
|
+
white_king = Sashite::Pin.parse("K")
|
271
|
+
black_king = Sashite::Pin.parse("k")
|
272
|
+
|
273
|
+
# Types are normalized to uppercase
|
274
|
+
white_king.type # => :K
|
275
|
+
black_king.type # => :K (same type!)
|
276
|
+
|
277
|
+
# Sides are different
|
278
|
+
white_king.side # => :first
|
279
|
+
black_king.side # => :second
|
280
|
+
|
281
|
+
# Display follows side convention
|
282
|
+
white_king.letter # => "K"
|
283
|
+
black_king.letter # => "k"
|
284
|
+
|
285
|
+
# Same type, different sides
|
286
|
+
white_king.same_type?(black_king) # => true
|
287
|
+
white_king.same_side?(black_king) # => false
|
288
|
+
```
|
289
|
+
|
249
290
|
### Immutable Transformations
|
250
291
|
```ruby
|
251
292
|
# All transformations return new instances
|
@@ -356,11 +397,15 @@ puts can_promote?(promoted_pawn, 8) # => false (already promoted)
|
|
356
397
|
|
357
398
|
Following the [Game Protocol](https://sashite.dev/game-protocol/):
|
358
399
|
|
359
|
-
| Protocol Attribute | PIN Encoding | Examples |
|
360
|
-
|
361
|
-
| **Type** |
|
362
|
-
| **Side** |
|
363
|
-
| **State** |
|
400
|
+
| Protocol Attribute | PIN Encoding | Examples | Notes |
|
401
|
+
|-------------------|--------------|----------|-------|
|
402
|
+
| **Type** | ASCII letter choice | `K`/`k` = King, `P`/`p` = Pawn | Type is always stored as uppercase symbol (`:K`, `:P`) |
|
403
|
+
| **Side** | Letter case in display | `K` = First player, `k` = Second player | Case is determined by side during rendering |
|
404
|
+
| **State** | Optional prefix | `+K` = Enhanced, `-K` = Diminished, `K` = Normal | |
|
405
|
+
|
406
|
+
**Type Convention**: All piece types are internally represented as uppercase symbols (`:A` to `:Z`). The display case is determined by the `side` attribute: first player pieces display as uppercase, second player pieces as lowercase.
|
407
|
+
|
408
|
+
**Canonical principle**: Identical pieces must have identical PIN representations.
|
364
409
|
|
365
410
|
**Note**: PIN does not represent the **Style** attribute from the Game Protocol. For style-aware piece notation, see [Piece Name Notation (PNN)](https://sashite.dev/specs/pnn/).
|
366
411
|
|
@@ -370,10 +415,41 @@ Following the [Game Protocol](https://sashite.dev/game-protocol/):
|
|
370
415
|
* **Rule-Agnostic**: Independent of specific game mechanics
|
371
416
|
* **Compact Format**: 1-2 characters per piece
|
372
417
|
* **Visual Distinction**: Clear player differentiation through case
|
418
|
+
* **Type Normalization**: Consistent uppercase type representation internally
|
373
419
|
* **Protocol Compliant**: Direct implementation of Sashité piece attributes
|
374
420
|
* **Immutable**: All piece instances are frozen and transformations return new objects
|
375
421
|
* **Functional**: Pure functions with no side effects
|
376
422
|
|
423
|
+
## Implementation Notes
|
424
|
+
|
425
|
+
### Type Normalization Convention
|
426
|
+
|
427
|
+
PIN follows a strict type normalization convention:
|
428
|
+
|
429
|
+
1. **Internal Storage**: All piece types are stored as uppercase symbols (`:A` to `:Z`)
|
430
|
+
2. **Input Flexibility**: Both `"K"` and `"k"` are valid input during parsing
|
431
|
+
3. **Case Semantics**: Input case determines the `side` attribute, not the `type`
|
432
|
+
4. **Display Logic**: Output case is computed from `side` during rendering
|
433
|
+
|
434
|
+
This design ensures:
|
435
|
+
- Consistent internal representation regardless of input format
|
436
|
+
- Clear separation between piece identity (type) and ownership (side)
|
437
|
+
- Predictable behavior when comparing pieces of the same type
|
438
|
+
|
439
|
+
### Example Flow
|
440
|
+
|
441
|
+
```ruby
|
442
|
+
# Input: "k" (lowercase)
|
443
|
+
# ↓ Parsing
|
444
|
+
# type: :K (normalized to uppercase)
|
445
|
+
# side: :second (inferred from lowercase input)
|
446
|
+
# ↓ Display
|
447
|
+
# letter: "k" (computed from type + side)
|
448
|
+
# PIN: "k" (final representation)
|
449
|
+
```
|
450
|
+
|
451
|
+
This ensures that `parse(pin).to_s == pin` for all valid PIN strings while maintaining internal consistency.
|
452
|
+
|
377
453
|
## System Constraints
|
378
454
|
|
379
455
|
- **Maximum 26 piece types** per game system (one per ASCII letter)
|
data/lib/sashite/pin/piece.rb
CHANGED
@@ -106,6 +106,23 @@ module Sashite
|
|
106
106
|
new(piece_type, piece_side, piece_state)
|
107
107
|
end
|
108
108
|
|
109
|
+
# Check if a string is a valid PIN notation
|
110
|
+
#
|
111
|
+
# @param pin_string [String] The string to validate
|
112
|
+
# @return [Boolean] true if valid PIN, false otherwise
|
113
|
+
#
|
114
|
+
# @example
|
115
|
+
# Sashite::Pin::Piece.valid?("K") # => true
|
116
|
+
# Sashite::Pin::Piece.valid?("+R") # => true
|
117
|
+
# Sashite::Pin::Piece.valid?("-p") # => true
|
118
|
+
# Sashite::Pin::Piece.valid?("KK") # => false
|
119
|
+
# Sashite::Pin::Piece.valid?("++K") # => false
|
120
|
+
def self.valid?(pin_string)
|
121
|
+
return false unless pin_string.is_a?(::String)
|
122
|
+
|
123
|
+
pin_string.match?(PIN_PATTERN)
|
124
|
+
end
|
125
|
+
|
109
126
|
# Convert the piece to its PIN string representation
|
110
127
|
#
|
111
128
|
# @return [String] PIN notation string
|
@@ -190,14 +207,13 @@ module Sashite
|
|
190
207
|
self.class.new(type, side, NORMAL_STATE)
|
191
208
|
end
|
192
209
|
|
193
|
-
# Create a new piece with opposite
|
210
|
+
# Create a new piece with opposite side
|
194
211
|
#
|
195
|
-
# @return [Piece] new piece instance with
|
212
|
+
# @return [Piece] new piece instance with opposite side
|
196
213
|
# @example
|
197
214
|
# piece.flip # (:K, :first, :normal) => (:K, :second, :normal)
|
198
215
|
def flip
|
199
|
-
|
200
|
-
self.class.new(type, new_side, state)
|
216
|
+
self.class.new(type, opposite_side, state)
|
201
217
|
end
|
202
218
|
|
203
219
|
# Create a new piece with a different type (keeping same side and state)
|
@@ -369,6 +385,15 @@ module Sashite
|
|
369
385
|
end
|
370
386
|
|
371
387
|
private_class_method :match_pattern
|
388
|
+
|
389
|
+
private
|
390
|
+
|
391
|
+
# Get the opposite side of the current piece
|
392
|
+
#
|
393
|
+
# @return [Symbol] :first if current side is :second, :second if current side is :first
|
394
|
+
def opposite_side
|
395
|
+
first_player? ? SECOND_PLAYER : FIRST_PLAYER
|
396
|
+
end
|
372
397
|
end
|
373
398
|
end
|
374
399
|
end
|
data/lib/sashite/pin.rb
CHANGED
@@ -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
|
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,10 +31,8 @@ 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?(
|
39
|
-
|
40
|
-
|
41
|
-
pin.match?(PIN_REGEX)
|
34
|
+
def self.valid?(pin_string)
|
35
|
+
Piece.valid?(pin_string)
|
42
36
|
end
|
43
37
|
|
44
38
|
# Parse a PIN string into a Piece object
|
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.
|
4
|
+
version: 2.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cyril Kato
|
@@ -15,7 +15,8 @@ description: |
|
|
15
15
|
a modern Ruby interface featuring immutable piece objects and functional programming
|
16
16
|
principles. PIN translates piece attributes from the Game Protocol into a compact,
|
17
17
|
portable notation system using ASCII letters with optional state modifiers and
|
18
|
-
case-based
|
18
|
+
case-based side encoding. Perfect for game engines, board game notation systems,
|
19
|
+
and multi-game environments.
|
19
20
|
email: contact@cyril.email
|
20
21
|
executables: []
|
21
22
|
extensions: []
|