sashite-pin 2.0.0 → 2.0.1

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +82 -7
  3. data/lib/sashite/pin/piece.rb +10 -2
  4. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a140d90c9c73aeb4773d2e94c0825cdddfe6ce5dff722325eb58bbea896ba62e
4
- data.tar.gz: 273fbe7adfa54613f4d582feb053690724d686f2f1d966d0f6871d33e77450b3
3
+ metadata.gz: 0335d119541a7fa271689c6235a9c785a4c46f6c70e9577d4cddcc597d520dd5
4
+ data.tar.gz: 7d95e04c803457156561bfe0fd8e270db5df1929b58721b9ed8266646f60e7e1
5
5
  SHA512:
6
- metadata.gz: dcdd60202c06776b8243d1330c54f93d6a38d919f9d5201660287967c987c69a119c9f1884a0c8bf3f3099d14b715b3c2d656c8725b39092df352f6ea9d5a2d8
7
- data.tar.gz: 4e87b25c1180e9cebcf47756cce651022d5c5b3227200010f2de408744910f20f596ee80bd34d6bf0ee597982189c92c22aed88907de30fea4c6c2455ac92072
6
+ metadata.gz: 6904c80bee041595400f4074ed48a975ad6337c3c5a8c66f9d18ad7864f19e23d04e34b30c725d37ce9c4bfde58667328a82bbd1c38208c123cb44a9da00b283
7
+ data.tar.gz: 32289d6453d81ff2e1920aeb7d69eedfac6bc61f9acdd1929e7ca4bc09c6988bb2a64bc3620130cfb63024977e0508b7c5ffce695590382eac3420d85454c67a
data/README.md CHANGED
@@ -206,13 +206,29 @@ crossed_soldier.to_s # => "+P"
206
206
  - `Sashite::Pin::Piece.parse(pin_string)` - Parse PIN string (same as module method)
207
207
 
208
208
  #### Attribute Access
209
- - `#type` - Get piece type (symbol :A to :Z)
209
+ - `#type` - Get piece type (symbol :A to :Z, always uppercase)
210
210
  - `#side` - Get player side (:first or :second)
211
211
  - `#state` - Get state (:normal, :enhanced, or :diminished)
212
- - `#letter` - Get letter representation (string)
212
+ - `#letter` - Get letter representation (string, case determined by side)
213
213
  - `#prefix` - Get state prefix (string: "+", "-", or "")
214
214
  - `#to_s` - Convert to PIN string representation
215
215
 
216
+ #### Type and Case Handling
217
+
218
+ **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:
219
+
220
+ ```ruby
221
+ # 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
224
+
225
+ piece1.type # => :K (uppercase symbol)
226
+ piece2.type # => :K (same uppercase symbol)
227
+
228
+ piece1.letter # => "K" (uppercase display)
229
+ piece2.letter # => "k" (lowercase display)
230
+ ```
231
+
216
232
  #### State Queries
217
233
  - `#normal?` - Check if normal state (no modifiers)
218
234
  - `#enhanced?` - Check if enhanced state
@@ -246,6 +262,30 @@ crossed_soldier.to_s # => "+P"
246
262
 
247
263
  ## Advanced Usage
248
264
 
265
+ ### Type Normalization Examples
266
+
267
+ ```ruby
268
+ # Parsing different cases results in same type
269
+ white_king = Sashite::Pin.parse("K")
270
+ black_king = Sashite::Pin.parse("k")
271
+
272
+ # Types are normalized to uppercase
273
+ white_king.type # => :K
274
+ black_king.type # => :K (same type!)
275
+
276
+ # Sides are different
277
+ white_king.side # => :first
278
+ black_king.side # => :second
279
+
280
+ # Display follows side convention
281
+ white_king.letter # => "K"
282
+ black_king.letter # => "k"
283
+
284
+ # Same type, different sides
285
+ white_king.same_type?(black_king) # => true
286
+ white_king.same_side?(black_king) # => false
287
+ ```
288
+
249
289
  ### Immutable Transformations
250
290
  ```ruby
251
291
  # All transformations return new instances
@@ -356,11 +396,15 @@ puts can_promote?(promoted_pawn, 8) # => false (already promoted)
356
396
 
357
397
  Following the [Game Protocol](https://sashite.dev/game-protocol/):
358
398
 
359
- | Protocol Attribute | PIN Encoding | Examples |
360
- |-------------------|--------------|----------|
361
- | **Type** | Symbol choice | `:K`/`:k` = King, `:P`/`:p` = Pawn |
362
- | **Side** | Symbol value | `:first` = First player, `:second` = Second player |
363
- | **State** | Symbol value | `:enhanced` = Enhanced, `:diminished` = Diminished, `:normal` = Normal |
399
+ | Protocol Attribute | PIN Encoding | Examples | Notes |
400
+ |-------------------|--------------|----------|-------|
401
+ | **Type** | ASCII letter choice | `K`/`k` = King, `P`/`p` = Pawn | Type is always stored as uppercase symbol (`:K`, `:P`) |
402
+ | **Side** | Letter case in display | `K` = First player, `k` = Second player | Case is determined by side during rendering |
403
+ | **State** | Optional prefix | `+K` = Enhanced, `-K` = Diminished, `K` = Normal | |
404
+
405
+ **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.
406
+
407
+ **Canonical principle**: Identical pieces must have identical PIN representations.
364
408
 
365
409
  **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
410
 
@@ -370,10 +414,41 @@ Following the [Game Protocol](https://sashite.dev/game-protocol/):
370
414
  * **Rule-Agnostic**: Independent of specific game mechanics
371
415
  * **Compact Format**: 1-2 characters per piece
372
416
  * **Visual Distinction**: Clear player differentiation through case
417
+ * **Type Normalization**: Consistent uppercase type representation internally
373
418
  * **Protocol Compliant**: Direct implementation of Sashité piece attributes
374
419
  * **Immutable**: All piece instances are frozen and transformations return new objects
375
420
  * **Functional**: Pure functions with no side effects
376
421
 
422
+ ## Implementation Notes
423
+
424
+ ### Type Normalization Convention
425
+
426
+ PIN follows a strict type normalization convention:
427
+
428
+ 1. **Internal Storage**: All piece types are stored as uppercase symbols (`:A` to `:Z`)
429
+ 2. **Input Flexibility**: Both `"K"` and `"k"` are valid input during parsing
430
+ 3. **Case Semantics**: Input case determines the `side` attribute, not the `type`
431
+ 4. **Display Logic**: Output case is computed from `side` during rendering
432
+
433
+ This design ensures:
434
+ - Consistent internal representation regardless of input format
435
+ - Clear separation between piece identity (type) and ownership (side)
436
+ - Predictable behavior when comparing pieces of the same type
437
+
438
+ ### Example Flow
439
+
440
+ ```ruby
441
+ # Input: "k" (lowercase)
442
+ # ↓ Parsing
443
+ # type: :K (normalized to uppercase)
444
+ # side: :second (inferred from lowercase input)
445
+ # ↓ Display
446
+ # letter: "k" (computed from type + side)
447
+ # PIN: "k" (final representation)
448
+ ```
449
+
450
+ This ensures that `parse(pin).to_s == pin` for all valid PIN strings while maintaining internal consistency.
451
+
377
452
  ## System Constraints
378
453
 
379
454
  - **Maximum 26 piece types** per game system (one per ASCII letter)
@@ -196,8 +196,7 @@ module Sashite
196
196
  # @example
197
197
  # piece.flip # (:K, :first, :normal) => (:K, :second, :normal)
198
198
  def flip
199
- new_side = first_player? ? SECOND_PLAYER : FIRST_PLAYER
200
- self.class.new(type, new_side, state)
199
+ self.class.new(type, opposite_side, state)
201
200
  end
202
201
 
203
202
  # Create a new piece with a different type (keeping same side and state)
@@ -369,6 +368,15 @@ module Sashite
369
368
  end
370
369
 
371
370
  private_class_method :match_pattern
371
+
372
+ private
373
+
374
+ # Get the opposite side of the current piece
375
+ #
376
+ # @return [Symbol] :first if current side is :second, :second if current side is :first
377
+ def opposite_side
378
+ first_player? ? SECOND_PLAYER : FIRST_PLAYER
379
+ end
372
380
  end
373
381
  end
374
382
  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.0
4
+ version: 2.0.1
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 player group classification.
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: []