Module: Sashite::Qpi
- Defined in:
- lib/sashite/qpi.rb,
lib/sashite/qpi/identifier.rb
Overview
QPI (Qualified Piece Identifier) implementation for Ruby
Provides a rule-agnostic format for identifying game pieces in abstract strategy board games by combining Style Identifier Notation (SIN) and Piece Identifier Notation (PIN) primitives with a colon separator. This combination enables complete piece identification across different game styles and contexts.
## Concept
QPI addresses the fundamental need to uniquely identify game pieces across different style systems while maintaining complete attribute information. By combining SIN and PIN primitives, QPI provides explicit representation of all four fundamental piece attributes from the Sashité Protocol.
## Four Fundamental Attributes
QPI represents all four piece attributes through primitive combination:
-
Family: Style identification from SIN component
-
Type: Piece type from PIN component
-
Side: Player assignment from both components (must be consistent)
-
State: Piece state from PIN component
## Format Structure
A QPI identifier consists of two primitive components separated by a colon:
-
**SIN component**: Style identification with player assignment
-
**PIN component**: Piece identification with type, side, and state
-
Separator: Colon (:) provides clear delimitation
The components must maintain semantic consistency: both SIN and PIN must represent the same player (first or second) through their respective case encodings.
## Semantic Consistency Constraint
QPI enforces a critical constraint: the style identified by the SIN component must be associated with the same player as indicated by the PIN component. This ensures that piece ownership and style ownership remain aligned, preventing impossible combinations like a first player style with a second player piece.
Examples of semantic consistency:
-
SIN “C” (first player) + PIN “K” (first player) = Valid
-
SIN “c” (second player) + PIN “k” (second player) = Valid
-
SIN “C” (first player) + PIN “k” (second player) = Invalid
-
SIN “c” (second player) + PIN “K” (first player) = Invalid
## Cross-Style Gaming Support
QPI enables cross-style gaming scenarios where different players use different game traditions. The explicit style identification allows pieces from different systems to coexist while maintaining clear attribution to their respective players.
## Format Specification
Structure: ‘<sin>:<pin>`
Grammar (BNF):
<qpi> ::= <uppercase-qpi> | <lowercase-qpi>
<uppercase-qpi> ::= <uppercase-letter> ":" <uppercase-pin>
<lowercase-qpi> ::= <lowercase-letter> ":" <lowercase-pin>
<uppercase-pin> ::= ["+" | "-"] <uppercase-letter>
<lowercase-pin> ::= ["+" | "-"] <lowercase-letter>
Regular Expression: ‘/A(:[-+]?[A-Z]|:[-+]?[a-z])z/`
## Attribute Mapping
QPI encodes piece attributes through primitive combination:
| Piece Attribute | QPI Encoding | Examples | |—————–|————–|———-| | Family | SIN component | ‘C:K` = Chess family, `O:K` = Ogi family | | Type | PIN letter choice | `C:K` = King, `C:P` = Pawn | | Side | Component cases | `C:K` = First player, `c:k` = Second player | | State | PIN prefix modifier | `O:+P` = Enhanced, `C:-P` = Diminished |
## System Constraints
-
**Semantic Consistency**: SIN and PIN components must represent the same player
-
**Component Validation**: Each component must be valid according to its specification
-
**Complete Attribution**: All four fundamental piece attributes explicitly represented
-
**Cross-Style Support**: Enables multi-tradition gaming environments
## Examples
### Single-Style Games
# Chess (both players use Chess style)
white_king = Sashite::Qpi.parse("C:K") # Chess king, first player
black_king = Sashite::Qpi.parse("c:k") # Chess king, second player
# Ogi (both players use Ogi style)
sente_king = Sashite::Qpi.parse("O:K") # Ogi king, first player (sente)
gote_rook = Sashite::Qpi.parse("o:+r") # Ogi promoted rook, second player (gote)
### Cross-Style Games
# Chess vs. Ogi match
chess_player = Sashite::Qpi.parse("C:K") # First player uses Chess
ogi_player = Sashite::Qpi.parse("o:k") # Second player uses Ogi
# Verify cross-style scenario
chess_player.cross_family?(ogi_player) # => true
### Attribute Access and Manipulation
identifier = Sashite::Qpi.parse("O:+R")
# Four fundamental attributes
identifier.family # => :O
identifier.type # => :R
identifier.side # => :first
identifier.state # => :enhanced
# Component extraction
identifier.to_sin # => "O"
identifier.to_pin # => "+R"
# Immutable transformations
flipped = identifier.flip # => "o:+r"
different_type = identifier.with_type(:Q) # => "O:+Q"
different_family = identifier.with_family(:C) # => "C:+R"
## Design Properties
-
Rule-agnostic: Independent of specific game mechanics
-
**Complete identification**: Explicit representation of all four piece attributes
-
**Cross-style support**: Enables multi-tradition gaming environments
-
**Semantic validation**: Ensures consistency between style and piece ownership
-
**Primitive foundation**: Built from foundational SIN and PIN building blocks
-
Extension-ready: Can be enhanced by human-readable naming systems
-
Context-flexible: Adaptable to various identification needs
-
Immutable: All instances are frozen and transformations return new objects
-
Functional: Pure functions with no side effects
Defined Under Namespace
Classes: Identifier
Class Method Summary collapse
-
.identifier(family, type, side, state = Pin::Identifier::NORMAL_STATE) ⇒ Qpi::Identifier
Create a new identifier instance with explicit parameters.
-
.parse(qpi_string) ⇒ Qpi::Identifier
Parse a QPI string into an Identifier object.
-
.valid?(qpi_string) ⇒ Boolean
Check if a string is a valid QPI notation.
Class Method Details
.identifier(family, type, side, state = Pin::Identifier::NORMAL_STATE) ⇒ Qpi::Identifier
Create a new identifier instance with explicit parameters
Constructs a QPI identifier by directly specifying all four fundamental attributes. This method provides parameter-based construction as an alternative to string parsing, enabling immediate validation and clearer API usage.
216 217 218 |
# File 'lib/sashite/qpi.rb', line 216 def self.identifier(family, type, side, state = Pin::Identifier::NORMAL_STATE) Identifier.new(family, type, side, state) end |
.parse(qpi_string) ⇒ Qpi::Identifier
Parse a QPI string into an Identifier object
Creates a new QPI identifier by parsing the string into SIN and PIN components, validating each component, and ensuring semantic consistency between them.
186 187 188 |
# File 'lib/sashite/qpi.rb', line 186 def self.parse(qpi_string) Identifier.parse(qpi_string) end |
.valid?(qpi_string) ⇒ Boolean
Check if a string is a valid QPI notation
Validates the string format and semantic consistency between SIN and PIN components. Both components must be individually valid and represent the same player through their respective case encodings.
163 164 165 |
# File 'lib/sashite/qpi.rb', line 163 def self.valid?(qpi_string) Identifier.valid?(qpi_string) end |