sashite-qpi 2.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b5ed07c3a3f3a6840db662c963fdbbf9df121b2eae6af9242bc2cf0cd7e3d1a
4
- data.tar.gz: 490241caa45a1f01551a6fc84b8f0b85a4a257496c0e87b08036b46885298d95
3
+ metadata.gz: 6174ad5c08247b566832cd22236980189b809f445cfca54ecda6f67938a8d9c5
4
+ data.tar.gz: 590406c9c7e14ec79fcb4b522f45b65f0872e88d1e4f3bdde849f4e912673ae6
5
5
  SHA512:
6
- metadata.gz: b487054a34ae585172a78f6db44a3ed228ee7d61e0f8d6eac0faca5ea2cc0e0d9c6f600e6c85be594cb58f2f3b59aa60490edb9a1b4cb874905d983d14f024f2
7
- data.tar.gz: 3c6768a42f8d1a336e594dac6267c617532f8bb310e90d638702badff7ce131c94a3306620ab57264f3f7345a679242b20f97f20534dc5848b6a9d42db0ad43c
6
+ metadata.gz: 343523eefe8442e27e37b7f773a54e7b11925f7125d765ae5e85cfe51b12c453c89129f788c7eced0285cd3011442880bd39b57f113aaa40e91a2ab1f946aa8c
7
+ data.tar.gz: 2f506015f10416d449eae6ef2fd44969c6c36ce5ec2a11ab928798a0cbc7762dda53c30a7ecfa6a8abd207999a0f1819a2115543501caef035917b6788764ac9
data/LICENSE CHANGED
@@ -186,7 +186,7 @@
186
186
  same "printed page" as the copyright notice for easier
187
187
  identification within third-party archives.
188
188
 
189
- Copyright 2025 Cyril Kato
189
+ Copyright 2025-2026 Cyril Kato
190
190
 
191
191
  Licensed under the Apache License, Version 2.0 (the "License");
192
192
  you may not use this file except in compliance with the License.
data/README.md CHANGED
@@ -51,8 +51,8 @@ qpi = Sashite::Qpi.parse("C:K^")
51
51
  qpi.to_s # => "C:K^"
52
52
 
53
53
  # Access the five Piece Identity attributes through components
54
- qpi.sin.style # => :C (Piece Style)
55
- qpi.pin.type # => :K (Piece Name)
54
+ qpi.sin.abbr # => :C (Piece Style)
55
+ qpi.pin.abbr # => :K (Piece Name)
56
56
  qpi.pin.side # => :first (Piece Side)
57
57
  qpi.pin.state # => :normal (Piece State)
58
58
  qpi.pin.terminal? # => true (Terminal Status)
@@ -100,8 +100,8 @@ Sashite::Qpi.valid?(":K") # => false
100
100
  qpi = Sashite::Qpi.parse("S:+R^")
101
101
 
102
102
  # Get components
103
- qpi.sin # => #<Sashite::Sin::Identifier style=:S side=:first>
104
- qpi.pin # => #<Sashite::Pin::Identifier type=:R state=:enhanced terminal=true>
103
+ qpi.sin # => #<Sashite::Sin::Identifier S>
104
+ qpi.pin # => #<Sashite::Pin::Identifier +R^>
105
105
 
106
106
  # Serialize components
107
107
  qpi.sin.to_s # => "S"
@@ -117,10 +117,10 @@ All attributes come directly from the components:
117
117
  qpi = Sashite::Qpi.parse("S:+R^")
118
118
 
119
119
  # From SIN component
120
- qpi.sin.style # => :S (Piece Style)
120
+ qpi.sin.abbr # => :S (Piece Style)
121
121
 
122
122
  # From PIN component
123
- qpi.pin.type # => :R (Piece Name)
123
+ qpi.pin.abbr # => :R (Piece Name)
124
124
  qpi.pin.side # => :first (Piece Side)
125
125
  qpi.pin.state # => :enhanced (Piece State)
126
126
  qpi.pin.terminal? # => true (Terminal Status)
@@ -165,10 +165,10 @@ qpi.with_pin(new_pin).to_s # => "C:+Q^"
165
165
  # Transform both
166
166
  qpi.with_sin(new_sin).with_pin(new_pin).to_s # => "S:+Q^"
167
167
 
168
- # Flip both components (change player)
169
- qpi.flip.to_s # => "c:k^"
168
+ # Flip PIN side (SIN unchanged)
169
+ qpi.flip.to_s # => "C:k^"
170
170
 
171
- # Native/Derived transformations
171
+ # Native/Derived transformations (modify PIN only)
172
172
  qpi = Sashite::Qpi.parse("C:r")
173
173
  qpi.native.to_s # => "C:R" (PIN case aligned with SIN case)
174
174
  qpi.derive.to_s # => "C:r" (already derived, unchanged)
@@ -183,16 +183,16 @@ qpi.derive.to_s # => "C:r" (PIN case differs from SIN case)
183
183
  ```ruby
184
184
  qpi = Sashite::Qpi.parse("C:K^")
185
185
 
186
- # Transform SIN via component
187
- qpi.with_sin(qpi.sin.with_style(:S)).to_s # => "S:K^"
188
-
189
186
  # Transform PIN via component
190
- qpi.with_pin(qpi.pin.with_type(:Q)).to_s # => "C:Q^"
191
- qpi.with_pin(qpi.pin.with_state(:enhanced)).to_s # => "C:+K^"
192
- qpi.with_pin(qpi.pin.with_terminal(false)).to_s # => "C:K"
187
+ qpi.with_pin(qpi.pin.with_abbr(:Q)).to_s # => "C:Q^"
188
+ qpi.with_pin(qpi.pin.with_state(:enhanced)).to_s # => "C:+K^"
189
+ qpi.with_pin(qpi.pin.with_terminal(false)).to_s # => "C:K"
190
+
191
+ # Replace SIN with new instance
192
+ qpi.with_sin(Sashite::Sin.parse("S")).to_s # => "S:K^"
193
193
 
194
194
  # Chain transformations
195
- qpi.flip.with_sin(qpi.sin.with_style(:S)).to_s # => "s:k^"
195
+ qpi.flip.with_sin(Sashite::Sin.parse("c")).to_s # => "c:k^"
196
196
  ```
197
197
 
198
198
  ### Component Queries
@@ -203,13 +203,13 @@ Since QPI is a composition, use the component APIs directly:
203
203
  qpi = Sashite::Qpi.parse("S:+P^")
204
204
 
205
205
  # SIN queries (style and side)
206
- qpi.sin.style # => :S
206
+ qpi.sin.abbr # => :S
207
207
  qpi.sin.side # => :first
208
208
  qpi.sin.first_player? # => true
209
- qpi.sin.letter # => "S"
209
+ qpi.sin.to_s # => "S"
210
210
 
211
- # PIN queries (type, state, terminal)
212
- qpi.pin.type # => :P
211
+ # PIN queries (abbr, state, terminal)
212
+ qpi.pin.abbr # => :P
213
213
  qpi.pin.state # => :enhanced
214
214
  qpi.pin.terminal? # => true
215
215
  qpi.pin.enhanced? # => true
@@ -219,10 +219,10 @@ qpi.pin.suffix # => "^"
219
219
 
220
220
  # Compare QPIs via components
221
221
  other = Sashite::Qpi.parse("C:+P^")
222
- qpi.sin.same_style?(other.sin) # => false (S vs C)
223
- qpi.pin.same_type?(other.pin) # => true (both P)
224
- qpi.sin.same_side?(other.sin) # => true (both first)
225
- qpi.pin.same_state?(other.pin) # => true (both enhanced)
222
+ qpi.sin.same_abbr?(other.sin) # => false (S vs C)
223
+ qpi.pin.same_abbr?(other.pin) # => true (both P)
224
+ qpi.sin.same_side?(other.sin) # => true (both first)
225
+ qpi.pin.same_state?(other.pin) # => true (both enhanced)
226
226
  ```
227
227
 
228
228
  ## API Reference
@@ -296,10 +296,10 @@ def Sashite::Qpi.valid?(string)
296
296
  def with_sin(new_sin) # => Identifier with different SIN
297
297
  def with_pin(new_pin) # => Identifier with different PIN
298
298
 
299
- # Flip transformation (transforms both components)
300
- def flip # => Identifier with both SIN and PIN flipped
299
+ # Flip transformation (modifies PIN only)
300
+ def flip # => Identifier with PIN side flipped
301
301
 
302
- # Native/Derived transformations
302
+ # Native/Derived transformations (modify PIN only)
303
303
  def native # => Identifier with PIN case aligned to SIN case
304
304
  def derive # => Identifier with PIN case opposite to SIN case
305
305
  ```
@@ -323,8 +323,8 @@ QPI encodes complete **Piece Identity** as defined in the [Glossary](https://sas
323
323
 
324
324
  | Piece Attribute | QPI Access | Encoding |
325
325
  |---------------------|----------------------|--------------------------------------------------------|
326
- | **Piece Style** | `qpi.sin.style` | SIN letter (case-insensitive identity) |
327
- | **Piece Name** | `qpi.pin.type` | PIN letter (case-insensitive identity) |
326
+ | **Piece Style** | `qpi.sin.abbr` | SIN letter (case-insensitive identity) |
327
+ | **Piece Name** | `qpi.pin.abbr` | PIN letter (case-insensitive identity) |
328
328
  | **Piece Side** | `qpi.pin.side` | PIN letter case (uppercase = first, lowercase = second)|
329
329
  | **Piece State** | `qpi.pin.state` | PIN modifier (`+` = enhanced, `-` = diminished) |
330
330
  | **Terminal Status** | `qpi.pin.terminal?` | PIN marker (`^` = terminal) |
@@ -336,7 +336,7 @@ Additionally, QPI provides a **Native/Derived relationship** via `native?`, `der
336
336
  - **Pure composition**: QPI composes SIN and PIN without reimplementing features
337
337
  - **Minimal API**: Core methods (`sin`, `pin`, `native?`, `derived?`, `native`, `derive`, `to_s`) plus transformations
338
338
  - **Component transparency**: Access components directly, no wrapper methods
339
- - **QPI-specific conveniences**: `flip`, `native`, `derive` (operations that span both components)
339
+ - **QPI-specific conveniences**: `flip`, `native`, `derive` (operations that modify PIN only, per spec)
340
340
  - **Immutable identifiers**: Frozen instances prevent mutation
341
341
  - **Ruby idioms**: `valid?` predicate, `to_s` conversion, `ArgumentError` for invalid input
342
342
  - **No duplication**: Delegates to `sashite-sin` and `sashite-pin`
@@ -22,8 +22,8 @@ module Sashite
22
22
  # qpi = Identifier.new(sin, pin)
23
23
  #
24
24
  # @example Accessing components
25
- # qpi.sin.style # => :C
26
- # qpi.pin.type # => :K
25
+ # qpi.sin.abbr # => :C
26
+ # qpi.pin.abbr # => :K
27
27
  # qpi.pin.side # => :first
28
28
  # qpi.pin.state # => :normal
29
29
  # qpi.pin.terminal? # => true
@@ -181,15 +181,22 @@ module Sashite
181
181
  self.class.new(sin, new_pin)
182
182
  end
183
183
 
184
- # Returns a new Identifier with both components flipped.
184
+ # Returns a new Identifier with PIN side flipped.
185
185
  #
186
- # @return [Identifier] A new Identifier with both SIN and PIN flipped
186
+ # The SIN component remains unchanged. This reflects the QPI specification
187
+ # constraint that SIN (Player Style + Player Side) is stable within a Match,
188
+ # while PIN side (Piece Side) may change via Mutation.
189
+ #
190
+ # @return [Identifier] A new Identifier with PIN side flipped
187
191
  #
188
192
  # @example
189
193
  # qpi = Identifier.new(Sin.parse("C"), Pin.parse("K^"))
190
- # qpi.flip.to_s # => "c:k^"
194
+ # qpi.flip.to_s # => "C:k^"
195
+ #
196
+ # qpi = Identifier.new(Sin.parse("c"), Pin.parse("r"))
197
+ # qpi.flip.to_s # => "c:R"
191
198
  def flip
192
- self.class.new(sin.flip, pin.flip)
199
+ self.class.new(sin, pin.flip)
193
200
  end
194
201
 
195
202
  # ========================================================================
data/lib/sashite/qpi.rb CHANGED
@@ -39,8 +39,8 @@ module Sashite
39
39
  # == Examples
40
40
  #
41
41
  # qpi = Sashite::Qpi.parse("C:K^")
42
- # qpi.sin.style # => :C
43
- # qpi.pin.type # => :K
42
+ # qpi.sin.abbr # => :C
43
+ # qpi.pin.abbr # => :K
44
44
  # qpi.pin.side # => :first
45
45
  # qpi.pin.state # => :normal
46
46
  # qpi.pin.terminal? # => true
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sashite-qpi
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyril Kato
@@ -15,28 +15,28 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 4.0.0
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: 4.0.0
25
+ version: 4.1.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: sashite-sin
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: 3.0.0
32
+ version: 3.1.0
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: 3.0.0
39
+ version: 3.1.0
40
40
  description: QPI (Qualified Piece Identifier) implementation for Ruby. Provides a
41
41
  rule-agnostic format for complete piece identification in abstract strategy board
42
42
  games by combining SIN and PIN primitives, with Native/Derived relationship support.