sashite-pin 2.0.2 → 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 +4 -4
 - data/README.md +92 -153
 - data/lib/sashite/pin/{piece.rb → identifier.rb} +61 -84
 - data/lib/sashite/pin.rb +15 -15
 - metadata +9 -9
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: f69bdd89484b5fc844f13c7cedbbdf2efe15f75620fe1eb695d0258120cf16d6
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 38c51ef6f22d3267c26f5baa425306645e2a17f8448575da6759112a6b71f115
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 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  
     | 
| 
      
 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  
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
      
 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  
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
      
 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,171 +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 =  
     | 
| 
       52 
     | 
    
         
            -
            enhanced.to_s 
     | 
| 
       53 
     | 
    
         
            -
            diminished =  
     | 
| 
       54 
     | 
    
         
            -
            diminished.to_s 
     | 
| 
      
 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 =  
     | 
| 
       58 
     | 
    
         
            -
            flipped.to_s 
     | 
| 
      
 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 =  
     | 
| 
       62 
     | 
    
         
            -
            queen.to_s 
     | 
| 
      
 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 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
            enhanced.enhanced? 
     | 
| 
       67 
     | 
    
         
            -
            diminished.diminished? 
     | 
| 
      
 65 
     | 
    
         
            +
            identifier.normal?                            # => true
         
     | 
| 
      
 66 
     | 
    
         
            +
            enhanced.enhanced?                            # => true
         
     | 
| 
      
 67 
     | 
    
         
            +
            diminished.diminished?                        # => true
         
     | 
| 
       68 
68 
     | 
    
         | 
| 
       69 
69 
     | 
    
         
             
            # Side queries
         
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
            flipped.second_player? 
     | 
| 
      
 70 
     | 
    
         
            +
            identifier.first_player?                      # => true
         
     | 
| 
      
 71 
     | 
    
         
            +
            flipped.second_player?                        # => true
         
     | 
| 
       72 
72 
     | 
    
         | 
| 
       73 
73 
     | 
    
         
             
            # Attribute access
         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
            enhanced.prefix 
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
      
 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) 
     | 
| 
       84 
     | 
    
         
            -
            king1.same_side?(queen) 
     | 
| 
       85 
     | 
    
         
            -
            king1.same_type?(queen) 
     | 
| 
      
 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 
     | 
| 
      
 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 
     | 
    
         
            -
             
     | 
| 
       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 
     | 
    
         
            -
             
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       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 
     | 
    
         
            -
             
     | 
| 
      
 108 
     | 
    
         
            +
              * `+`: Enhanced state (promoted, upgraded, empowered)
         
     | 
| 
      
 109 
     | 
    
         
            +
              * `-`: Diminished state (weakened, restricted, temporary)
         
     | 
| 
      
 110 
     | 
    
         
            +
              * No prefix: Normal state
         
     | 
| 
       121 
111 
     | 
    
         | 
| 
       122 
     | 
    
         
            -
            ###  
     | 
| 
       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 
     | 
    
         
            -
             
     | 
| 
       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 
     | 
    
         
            -
            ###  
     | 
| 
       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 
     | 
    
         
            -
             
     | 
| 
       182 
     | 
    
         
            -
             
     | 
| 
       183 
     | 
    
         
            -
             
     | 
| 
       184 
     | 
    
         
            -
             
     | 
| 
       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 
     | 
    
         
            -
             
     | 
| 
       199 
     | 
    
         
            -
             
     | 
| 
       200 
     | 
    
         
            -
             
     | 
| 
      
 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 
     | 
    
         
            -
            ###  
     | 
| 
      
 133 
     | 
    
         
            +
            ### Identifier Class
         
     | 
| 
       203 
134 
     | 
    
         | 
| 
       204 
135 
     | 
    
         
             
            #### Creation and Parsing
         
     | 
| 
       205 
     | 
    
         
            -
             
     | 
| 
       206 
     | 
    
         
            -
             
     | 
| 
       207 
     | 
    
         
            -
             
     | 
| 
      
 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)
         
     | 
| 
       208 
140 
     | 
    
         | 
| 
       209 
141 
     | 
    
         
             
            #### Attribute Access
         
     | 
| 
       210 
     | 
    
         
            -
             
     | 
| 
       211 
     | 
    
         
            -
             
     | 
| 
       212 
     | 
    
         
            -
             
     | 
| 
       213 
     | 
    
         
            -
             
     | 
| 
       214 
     | 
    
         
            -
             
     | 
| 
       215 
     | 
    
         
            -
             
     | 
| 
      
 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
         
     | 
| 
       216 
149 
     | 
    
         | 
| 
       217 
150 
     | 
    
         
             
            #### Type and Case Handling
         
     | 
| 
       218 
151 
     | 
    
         | 
| 
         @@ -220,46 +153,52 @@ crossed_soldier.to_s                              # => "+P" 
     | 
|
| 
       220 
153 
     | 
    
         | 
| 
       221 
154 
     | 
    
         
             
            ```ruby
         
     | 
| 
       222 
155 
     | 
    
         
             
            # Both create the same internal type representation
         
     | 
| 
       223 
     | 
    
         
            -
             
     | 
| 
       224 
     | 
    
         
            -
             
     | 
| 
      
 156 
     | 
    
         
            +
            identifier1 = Sashite::Pin.parse("K")  # type: :K, side: :first
         
     | 
| 
      
 157 
     | 
    
         
            +
            identifier2 = Sashite::Pin.parse("k")  # type: :K, side: :second
         
     | 
| 
       225 
158 
     | 
    
         | 
| 
       226 
     | 
    
         
            -
             
     | 
| 
       227 
     | 
    
         
            -
             
     | 
| 
      
 159 
     | 
    
         
            +
            identifier1.type    # => :K (uppercase symbol)
         
     | 
| 
      
 160 
     | 
    
         
            +
            identifier2.type    # => :K (same uppercase symbol)
         
     | 
| 
       228 
161 
     | 
    
         | 
| 
       229 
     | 
    
         
            -
             
     | 
| 
       230 
     | 
    
         
            -
             
     | 
| 
      
 162 
     | 
    
         
            +
            identifier1.letter  # => "K" (uppercase display)
         
     | 
| 
      
 163 
     | 
    
         
            +
            identifier2.letter  # => "k" (lowercase display)
         
     | 
| 
       231 
164 
     | 
    
         
             
            ```
         
     | 
| 
       232 
165 
     | 
    
         | 
| 
       233 
166 
     | 
    
         
             
            #### State Queries
         
     | 
| 
       234 
     | 
    
         
            -
             
     | 
| 
       235 
     | 
    
         
            -
             
     | 
| 
       236 
     | 
    
         
            -
             
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
            * `#normal?` - Check if normal state (no modifiers)
         
     | 
| 
      
 169 
     | 
    
         
            +
            * `#enhanced?` - Check if enhanced state
         
     | 
| 
      
 170 
     | 
    
         
            +
            * `#diminished?` - Check if diminished state
         
     | 
| 
       237 
171 
     | 
    
         | 
| 
       238 
172 
     | 
    
         
             
            #### Side Queries
         
     | 
| 
       239 
     | 
    
         
            -
             
     | 
| 
       240 
     | 
    
         
            -
             
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
            * `#first_player?` - Check if first player identifier
         
     | 
| 
      
 175 
     | 
    
         
            +
            * `#second_player?` - Check if second player identifier
         
     | 
| 
       241 
176 
     | 
    
         | 
| 
       242 
177 
     | 
    
         
             
            #### State Transformations (immutable - return new instances)
         
     | 
| 
       243 
     | 
    
         
            -
             
     | 
| 
       244 
     | 
    
         
            -
             
     | 
| 
       245 
     | 
    
         
            -
             
     | 
| 
       246 
     | 
    
         
            -
             
     | 
| 
       247 
     | 
    
         
            -
             
     | 
| 
       248 
     | 
    
         
            -
             
     | 
| 
      
 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)
         
     | 
| 
       249 
185 
     | 
    
         | 
| 
       250 
186 
     | 
    
         
             
            #### Attribute Transformations (immutable - return new instances)
         
     | 
| 
       251 
     | 
    
         
            -
             
     | 
| 
       252 
     | 
    
         
            -
             
     | 
| 
       253 
     | 
    
         
            -
             
     | 
| 
      
 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
         
     | 
| 
       254 
191 
     | 
    
         | 
| 
       255 
192 
     | 
    
         
             
            #### Comparison Methods
         
     | 
| 
       256 
     | 
    
         
            -
             
     | 
| 
       257 
     | 
    
         
            -
             
     | 
| 
       258 
     | 
    
         
            -
             
     | 
| 
       259 
     | 
    
         
            -
             
     | 
| 
      
 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
         
     | 
| 
       260 
198 
     | 
    
         | 
| 
       261 
199 
     | 
    
         
             
            ### Constants
         
     | 
| 
       262 
     | 
    
         
            -
             
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
            * `Sashite::Pin::Identifier::PIN_PATTERN` - Regular expression for PIN validation (internal use)
         
     | 
| 
       263 
202 
     | 
    
         | 
| 
       264 
203 
     | 
    
         
             
            ## Advanced Usage
         
     | 
| 
       265 
204 
     | 
    
         | 
| 
         @@ -2,9 +2,9 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Sashite
         
     | 
| 
       4 
4 
     | 
    
         
             
              module Pin
         
     | 
| 
       5 
     | 
    
         
            -
                # Represents  
     | 
| 
      
 5 
     | 
    
         
            +
                # Represents an identifier in PIN (Piece Identifier Notation) format.
         
     | 
| 
       6 
6 
     | 
    
         
             
                #
         
     | 
| 
       7 
     | 
    
         
            -
                #  
     | 
| 
      
 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  
     | 
| 
      
 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  
     | 
| 
      
 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  
     | 
| 
      
 78 
     | 
    
         
            +
                  # Parse a PIN string into an Identifier object
         
     | 
| 
       79 
79 
     | 
    
         
             
                  #
         
     | 
| 
       80 
80 
     | 
    
         
             
                  # @param pin_string [String] PIN notation string
         
     | 
| 
       81 
     | 
    
         
            -
                  # @return [ 
     | 
| 
      
 81 
     | 
    
         
            +
                  # @return [Identifier] new identifier instance
         
     | 
| 
       82 
82 
     | 
    
         
             
                  # @raise [ArgumentError] if the PIN string is invalid
         
     | 
| 
       83 
83 
     | 
    
         
             
                  # @example
         
     | 
| 
       84 
     | 
    
         
            -
                  #   Pin:: 
     | 
| 
       85 
     | 
    
         
            -
                  #   Pin:: 
     | 
| 
       86 
     | 
    
         
            -
                  #   Pin:: 
     | 
| 
      
 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,18 +92,17 @@ module Sashite 
     | 
|
| 
       92 
92 
     | 
    
         
             
                    enhanced = matches[:prefix] == ENHANCED_PREFIX
         
     | 
| 
       93 
93 
     | 
    
         
             
                    diminished = matches[:prefix] == DIMINISHED_PREFIX
         
     | 
| 
       94 
94 
     | 
    
         | 
| 
       95 
     | 
    
         
            -
                     
     | 
| 
       96 
     | 
    
         
            -
                     
     | 
| 
       97 
     | 
    
         
            -
                     
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
       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 
108 
     | 
    
         
             
                  # Check if a string is a valid PIN notation
         
     | 
| 
         @@ -112,24 +111,22 @@ module Sashite 
     | 
|
| 
       112 
111 
     | 
    
         
             
                  # @return [Boolean] true if valid PIN, false otherwise
         
     | 
| 
       113 
112 
     | 
    
         
             
                  #
         
     | 
| 
       114 
113 
     | 
    
         
             
                  # @example
         
     | 
| 
       115 
     | 
    
         
            -
                  #   Sashite::Pin:: 
     | 
| 
       116 
     | 
    
         
            -
                  #   Sashite::Pin:: 
     | 
| 
       117 
     | 
    
         
            -
                  #   Sashite::Pin:: 
     | 
| 
       118 
     | 
    
         
            -
                  #   Sashite::Pin:: 
     | 
| 
       119 
     | 
    
         
            -
                  #   Sashite::Pin:: 
     | 
| 
      
 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
         
     | 
| 
       120 
119 
     | 
    
         
             
                  def self.valid?(pin_string)
         
     | 
| 
       121 
120 
     | 
    
         
             
                    return false unless pin_string.is_a?(::String)
         
     | 
| 
       122 
121 
     | 
    
         | 
| 
       123 
122 
     | 
    
         
             
                    pin_string.match?(PIN_PATTERN)
         
     | 
| 
       124 
123 
     | 
    
         
             
                  end
         
     | 
| 
       125 
124 
     | 
    
         | 
| 
       126 
     | 
    
         
            -
                  # Convert the  
     | 
| 
      
 125 
     | 
    
         
            +
                  # Convert the identifier to its PIN string representation
         
     | 
| 
       127 
126 
     | 
    
         
             
                  #
         
     | 
| 
       128 
127 
     | 
    
         
             
                  # @return [String] PIN notation string
         
     | 
| 
       129 
128 
     | 
    
         
             
                  # @example
         
     | 
| 
       130 
     | 
    
         
            -
                  #    
     | 
| 
       131 
     | 
    
         
            -
                  #   piece.to_s  # => "-p"
         
     | 
| 
       132 
     | 
    
         
            -
                  #   piece.to_s  # => "K"
         
     | 
| 
      
 129 
     | 
    
         
            +
                  #   identifier.to_s  # => "+R"
         
     | 
| 
       133 
130 
     | 
    
         
             
                  def to_s
         
     | 
| 
       134 
131 
     | 
    
         
             
                    "#{prefix}#{letter}"
         
     | 
| 
       135 
132 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -152,76 +149,62 @@ module Sashite 
     | 
|
| 
       152 
149 
     | 
    
         
             
                    end
         
     | 
| 
       153 
150 
     | 
    
         
             
                  end
         
     | 
| 
       154 
151 
     | 
    
         | 
| 
       155 
     | 
    
         
            -
                  # Create a new  
     | 
| 
      
 152 
     | 
    
         
            +
                  # Create a new identifier with enhanced state
         
     | 
| 
       156 
153 
     | 
    
         
             
                  #
         
     | 
| 
       157 
     | 
    
         
            -
                  # @return [ 
     | 
| 
       158 
     | 
    
         
            -
                  # @example
         
     | 
| 
       159 
     | 
    
         
            -
                  #   piece.enhance  # (:K, :first, :normal) => (:K, :first, :enhanced)
         
     | 
| 
      
 154 
     | 
    
         
            +
                  # @return [Identifier] new identifier instance with enhanced state
         
     | 
| 
       160 
155 
     | 
    
         
             
                  def enhance
         
     | 
| 
       161 
156 
     | 
    
         
             
                    return self if enhanced?
         
     | 
| 
       162 
157 
     | 
    
         | 
| 
       163 
158 
     | 
    
         
             
                    self.class.new(type, side, ENHANCED_STATE)
         
     | 
| 
       164 
159 
     | 
    
         
             
                  end
         
     | 
| 
       165 
160 
     | 
    
         | 
| 
       166 
     | 
    
         
            -
                  # Create a new  
     | 
| 
      
 161 
     | 
    
         
            +
                  # Create a new identifier without enhanced state
         
     | 
| 
       167 
162 
     | 
    
         
             
                  #
         
     | 
| 
       168 
     | 
    
         
            -
                  # @return [ 
     | 
| 
       169 
     | 
    
         
            -
                  # @example
         
     | 
| 
       170 
     | 
    
         
            -
                  #   piece.unenhance  # (:K, :first, :enhanced) => (:K, :first, :normal)
         
     | 
| 
      
 163 
     | 
    
         
            +
                  # @return [Identifier] new identifier instance with normal state
         
     | 
| 
       171 
164 
     | 
    
         
             
                  def unenhance
         
     | 
| 
       172 
165 
     | 
    
         
             
                    return self unless enhanced?
         
     | 
| 
       173 
166 
     | 
    
         | 
| 
       174 
167 
     | 
    
         
             
                    self.class.new(type, side, NORMAL_STATE)
         
     | 
| 
       175 
168 
     | 
    
         
             
                  end
         
     | 
| 
       176 
169 
     | 
    
         | 
| 
       177 
     | 
    
         
            -
                  # Create a new  
     | 
| 
      
 170 
     | 
    
         
            +
                  # Create a new identifier with diminished state
         
     | 
| 
       178 
171 
     | 
    
         
             
                  #
         
     | 
| 
       179 
     | 
    
         
            -
                  # @return [ 
     | 
| 
       180 
     | 
    
         
            -
                  # @example
         
     | 
| 
       181 
     | 
    
         
            -
                  #   piece.diminish  # (:K, :first, :normal) => (:K, :first, :diminished)
         
     | 
| 
      
 172 
     | 
    
         
            +
                  # @return [Identifier] new identifier instance with diminished state
         
     | 
| 
       182 
173 
     | 
    
         
             
                  def diminish
         
     | 
| 
       183 
174 
     | 
    
         
             
                    return self if diminished?
         
     | 
| 
       184 
175 
     | 
    
         | 
| 
       185 
176 
     | 
    
         
             
                    self.class.new(type, side, DIMINISHED_STATE)
         
     | 
| 
       186 
177 
     | 
    
         
             
                  end
         
     | 
| 
       187 
178 
     | 
    
         | 
| 
       188 
     | 
    
         
            -
                  # Create a new  
     | 
| 
      
 179 
     | 
    
         
            +
                  # Create a new identifier without diminished state
         
     | 
| 
       189 
180 
     | 
    
         
             
                  #
         
     | 
| 
       190 
     | 
    
         
            -
                  # @return [ 
     | 
| 
       191 
     | 
    
         
            -
                  # @example
         
     | 
| 
       192 
     | 
    
         
            -
                  #   piece.undiminish  # (:K, :first, :diminished) => (:K, :first, :normal)
         
     | 
| 
      
 181 
     | 
    
         
            +
                  # @return [Identifier] new identifier instance with normal state
         
     | 
| 
       193 
182 
     | 
    
         
             
                  def undiminish
         
     | 
| 
       194 
183 
     | 
    
         
             
                    return self unless diminished?
         
     | 
| 
       195 
184 
     | 
    
         | 
| 
       196 
185 
     | 
    
         
             
                    self.class.new(type, side, NORMAL_STATE)
         
     | 
| 
       197 
186 
     | 
    
         
             
                  end
         
     | 
| 
       198 
187 
     | 
    
         | 
| 
       199 
     | 
    
         
            -
                  # Create a new  
     | 
| 
      
 188 
     | 
    
         
            +
                  # Create a new identifier with normal state (no modifiers)
         
     | 
| 
       200 
189 
     | 
    
         
             
                  #
         
     | 
| 
       201 
     | 
    
         
            -
                  # @return [ 
     | 
| 
       202 
     | 
    
         
            -
                  # @example
         
     | 
| 
       203 
     | 
    
         
            -
                  #   piece.normalize  # (:K, :first, :enhanced) => (:K, :first, :normal)
         
     | 
| 
      
 190 
     | 
    
         
            +
                  # @return [Identifier] new identifier instance with normal state
         
     | 
| 
       204 
191 
     | 
    
         
             
                  def normalize
         
     | 
| 
       205 
192 
     | 
    
         
             
                    return self if normal?
         
     | 
| 
       206 
193 
     | 
    
         | 
| 
       207 
194 
     | 
    
         
             
                    self.class.new(type, side, NORMAL_STATE)
         
     | 
| 
       208 
195 
     | 
    
         
             
                  end
         
     | 
| 
       209 
196 
     | 
    
         | 
| 
       210 
     | 
    
         
            -
                  # Create a new  
     | 
| 
      
 197 
     | 
    
         
            +
                  # Create a new identifier with opposite side
         
     | 
| 
       211 
198 
     | 
    
         
             
                  #
         
     | 
| 
       212 
     | 
    
         
            -
                  # @return [ 
     | 
| 
       213 
     | 
    
         
            -
                  # @example
         
     | 
| 
       214 
     | 
    
         
            -
                  #   piece.flip  # (:K, :first, :normal) => (:K, :second, :normal)
         
     | 
| 
      
 199 
     | 
    
         
            +
                  # @return [Identifier] new identifier instance with opposite side
         
     | 
| 
       215 
200 
     | 
    
         
             
                  def flip
         
     | 
| 
       216 
201 
     | 
    
         
             
                    self.class.new(type, opposite_side, state)
         
     | 
| 
       217 
202 
     | 
    
         
             
                  end
         
     | 
| 
       218 
203 
     | 
    
         | 
| 
       219 
     | 
    
         
            -
                  # Create a new  
     | 
| 
      
 204 
     | 
    
         
            +
                  # Create a new identifier with a different type
         
     | 
| 
       220 
205 
     | 
    
         
             
                  #
         
     | 
| 
       221 
206 
     | 
    
         
             
                  # @param new_type [Symbol] new type (:A to :Z)
         
     | 
| 
       222 
     | 
    
         
            -
                  # @return [ 
     | 
| 
       223 
     | 
    
         
            -
                  # @example
         
     | 
| 
       224 
     | 
    
         
            -
                  #   piece.with_type(:Q)  # (:K, :first, :normal) => (:Q, :first, :normal)
         
     | 
| 
      
 207 
     | 
    
         
            +
                  # @return [Identifier] new identifier instance with new type
         
     | 
| 
       225 
208 
     | 
    
         
             
                  def with_type(new_type)
         
     | 
| 
       226 
209 
     | 
    
         
             
                    self.class.validate_type(new_type)
         
     | 
| 
       227 
210 
     | 
    
         
             
                    return self if type == new_type
         
     | 
| 
         @@ -229,12 +212,10 @@ module Sashite 
     | 
|
| 
       229 
212 
     | 
    
         
             
                    self.class.new(new_type, side, state)
         
     | 
| 
       230 
213 
     | 
    
         
             
                  end
         
     | 
| 
       231 
214 
     | 
    
         | 
| 
       232 
     | 
    
         
            -
                  # Create a new  
     | 
| 
      
 215 
     | 
    
         
            +
                  # Create a new identifier with a different side
         
     | 
| 
       233 
216 
     | 
    
         
             
                  #
         
     | 
| 
       234 
     | 
    
         
            -
                  # @param new_side [Symbol] :first or :second
         
     | 
| 
       235 
     | 
    
         
            -
                  # @return [ 
     | 
| 
       236 
     | 
    
         
            -
                  # @example
         
     | 
| 
       237 
     | 
    
         
            -
                  #   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
         
     | 
| 
       238 
219 
     | 
    
         
             
                  def with_side(new_side)
         
     | 
| 
       239 
220 
     | 
    
         
             
                    self.class.validate_side(new_side)
         
     | 
| 
       240 
221 
     | 
    
         
             
                    return self if side == new_side
         
     | 
| 
         @@ -242,12 +223,10 @@ module Sashite 
     | 
|
| 
       242 
223 
     | 
    
         
             
                    self.class.new(type, new_side, state)
         
     | 
| 
       243 
224 
     | 
    
         
             
                  end
         
     | 
| 
       244 
225 
     | 
    
         | 
| 
       245 
     | 
    
         
            -
                  # Create a new  
     | 
| 
      
 226 
     | 
    
         
            +
                  # Create a new identifier with a different state
         
     | 
| 
       246 
227 
     | 
    
         
             
                  #
         
     | 
| 
       247 
     | 
    
         
            -
                  # @param new_state [Symbol] :normal, :enhanced, or :diminished
         
     | 
| 
       248 
     | 
    
         
            -
                  # @return [ 
     | 
| 
       249 
     | 
    
         
            -
                  # @example
         
     | 
| 
       250 
     | 
    
         
            -
                  #   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
         
     | 
| 
       251 
230 
     | 
    
         
             
                  def with_state(new_state)
         
     | 
| 
       252 
231 
     | 
    
         
             
                    self.class.validate_state(new_state)
         
     | 
| 
       253 
232 
     | 
    
         
             
                    return self if state == new_state
         
     | 
| 
         @@ -255,56 +234,54 @@ module Sashite 
     | 
|
| 
       255 
234 
     | 
    
         
             
                    self.class.new(type, side, new_state)
         
     | 
| 
       256 
235 
     | 
    
         
             
                  end
         
     | 
| 
       257 
236 
     | 
    
         | 
| 
       258 
     | 
    
         
            -
                  # Check if the  
     | 
| 
      
 237 
     | 
    
         
            +
                  # Check if the identifier has enhanced state
         
     | 
| 
       259 
238 
     | 
    
         
             
                  #
         
     | 
| 
       260 
239 
     | 
    
         
             
                  # @return [Boolean] true if enhanced
         
     | 
| 
       261 
240 
     | 
    
         
             
                  def enhanced?
         
     | 
| 
       262 
241 
     | 
    
         
             
                    state == ENHANCED_STATE
         
     | 
| 
       263 
242 
     | 
    
         
             
                  end
         
     | 
| 
       264 
243 
     | 
    
         | 
| 
       265 
     | 
    
         
            -
                  # Check if the  
     | 
| 
      
 244 
     | 
    
         
            +
                  # Check if the identifier has diminished state
         
     | 
| 
       266 
245 
     | 
    
         
             
                  #
         
     | 
| 
       267 
246 
     | 
    
         
             
                  # @return [Boolean] true if diminished
         
     | 
| 
       268 
247 
     | 
    
         
             
                  def diminished?
         
     | 
| 
       269 
248 
     | 
    
         
             
                    state == DIMINISHED_STATE
         
     | 
| 
       270 
249 
     | 
    
         
             
                  end
         
     | 
| 
       271 
250 
     | 
    
         | 
| 
       272 
     | 
    
         
            -
                  # Check if the  
     | 
| 
      
 251 
     | 
    
         
            +
                  # Check if the identifier has normal state
         
     | 
| 
       273 
252 
     | 
    
         
             
                  #
         
     | 
| 
       274 
     | 
    
         
            -
                  # @return [Boolean] true if  
     | 
| 
      
 253 
     | 
    
         
            +
                  # @return [Boolean] true if normal
         
     | 
| 
       275 
254 
     | 
    
         
             
                  def normal?
         
     | 
| 
       276 
255 
     | 
    
         
             
                    state == NORMAL_STATE
         
     | 
| 
       277 
256 
     | 
    
         
             
                  end
         
     | 
| 
       278 
257 
     | 
    
         | 
| 
       279 
     | 
    
         
            -
                  # Check if the  
     | 
| 
      
 258 
     | 
    
         
            +
                  # Check if the identifier belongs to the first player
         
     | 
| 
       280 
259 
     | 
    
         
             
                  #
         
     | 
| 
       281 
260 
     | 
    
         
             
                  # @return [Boolean] true if first player
         
     | 
| 
       282 
261 
     | 
    
         
             
                  def first_player?
         
     | 
| 
       283 
262 
     | 
    
         
             
                    side == FIRST_PLAYER
         
     | 
| 
       284 
263 
     | 
    
         
             
                  end
         
     | 
| 
       285 
264 
     | 
    
         | 
| 
       286 
     | 
    
         
            -
                  # Check if the  
     | 
| 
      
 265 
     | 
    
         
            +
                  # Check if the identifier belongs to the second player
         
     | 
| 
       287 
266 
     | 
    
         
             
                  #
         
     | 
| 
       288 
267 
     | 
    
         
             
                  # @return [Boolean] true if second player
         
     | 
| 
       289 
268 
     | 
    
         
             
                  def second_player?
         
     | 
| 
       290 
269 
     | 
    
         
             
                    side == SECOND_PLAYER
         
     | 
| 
       291 
270 
     | 
    
         
             
                  end
         
     | 
| 
       292 
271 
     | 
    
         | 
| 
       293 
     | 
    
         
            -
                  # Check if this  
     | 
| 
      
 272 
     | 
    
         
            +
                  # Check if this identifier is the same type as another
         
     | 
| 
       294 
273 
     | 
    
         
             
                  #
         
     | 
| 
       295 
     | 
    
         
            -
                  # @param other [ 
     | 
| 
      
 274 
     | 
    
         
            +
                  # @param other [Identifier] identifier to compare with
         
     | 
| 
       296 
275 
     | 
    
         
             
                  # @return [Boolean] true if same type
         
     | 
| 
       297 
     | 
    
         
            -
                  # @example
         
     | 
| 
       298 
     | 
    
         
            -
                  #   king1.same_type?(king2)  # (:K, :first, :normal) and (:K, :second, :enhanced) => true
         
     | 
| 
       299 
276 
     | 
    
         
             
                  def same_type?(other)
         
     | 
| 
       300 
277 
     | 
    
         
             
                    return false unless other.is_a?(self.class)
         
     | 
| 
       301 
278 
     | 
    
         | 
| 
       302 
279 
     | 
    
         
             
                    type == other.type
         
     | 
| 
       303 
280 
     | 
    
         
             
                  end
         
     | 
| 
       304 
281 
     | 
    
         | 
| 
       305 
     | 
    
         
            -
                  # Check if this  
     | 
| 
      
 282 
     | 
    
         
            +
                  # Check if this identifier has the same side as another
         
     | 
| 
       306 
283 
     | 
    
         
             
                  #
         
     | 
| 
       307 
     | 
    
         
            -
                  # @param other [ 
     | 
| 
      
 284 
     | 
    
         
            +
                  # @param other [Identifier] identifier to compare with
         
     | 
| 
       308 
285 
     | 
    
         
             
                  # @return [Boolean] true if same side
         
     | 
| 
       309 
286 
     | 
    
         
             
                  def same_side?(other)
         
     | 
| 
       310 
287 
     | 
    
         
             
                    return false unless other.is_a?(self.class)
         
     | 
| 
         @@ -312,9 +289,9 @@ module Sashite 
     | 
|
| 
       312 
289 
     | 
    
         
             
                    side == other.side
         
     | 
| 
       313 
290 
     | 
    
         
             
                  end
         
     | 
| 
       314 
291 
     | 
    
         | 
| 
       315 
     | 
    
         
            -
                  # Check if this  
     | 
| 
      
 292 
     | 
    
         
            +
                  # Check if this identifier has the same state as another
         
     | 
| 
       316 
293 
     | 
    
         
             
                  #
         
     | 
| 
       317 
     | 
    
         
            -
                  # @param other [ 
     | 
| 
      
 294 
     | 
    
         
            +
                  # @param other [Identifier] identifier to compare with
         
     | 
| 
       318 
295 
     | 
    
         
             
                  # @return [Boolean] true if same state
         
     | 
| 
       319 
296 
     | 
    
         
             
                  def same_state?(other)
         
     | 
| 
       320 
297 
     | 
    
         
             
                    return false unless other.is_a?(self.class)
         
     | 
| 
         @@ -325,7 +302,7 @@ module Sashite 
     | 
|
| 
       325 
302 
     | 
    
         
             
                  # Custom equality comparison
         
     | 
| 
       326 
303 
     | 
    
         
             
                  #
         
     | 
| 
       327 
304 
     | 
    
         
             
                  # @param other [Object] object to compare with
         
     | 
| 
       328 
     | 
    
         
            -
                  # @return [Boolean] true if  
     | 
| 
      
 305 
     | 
    
         
            +
                  # @return [Boolean] true if identifiers are equal
         
     | 
| 
       329 
306 
     | 
    
         
             
                  def ==(other)
         
     | 
| 
       330 
307 
     | 
    
         
             
                    return false unless other.is_a?(self.class)
         
     | 
| 
       331 
308 
     | 
    
         | 
| 
         @@ -388,7 +365,7 @@ module Sashite 
     | 
|
| 
       388 
365 
     | 
    
         | 
| 
       389 
366 
     | 
    
         
             
                  private
         
     | 
| 
       390 
367 
     | 
    
         | 
| 
       391 
     | 
    
         
            -
                  # Get the opposite side of the current  
     | 
| 
      
 368 
     | 
    
         
            +
                  # Get the opposite side of the current identifier
         
     | 
| 
       392 
369 
     | 
    
         
             
                  #
         
     | 
| 
       393 
370 
     | 
    
         
             
                  # @return [Symbol] :first if current side is :second, :second if current side is :first
         
     | 
| 
       394 
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/ 
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative "pin/identifier"
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            module Sashite
         
     | 
| 
       6 
6 
     | 
    
         
             
              # PIN (Piece Identifier Notation) implementation for Ruby
         
     | 
| 
         @@ -32,35 +32,35 @@ module Sashite 
     | 
|
| 
       32 
32 
     | 
    
         
             
                #   Sashite::Pin.valid?("KK")   # => false
         
     | 
| 
       33 
33 
     | 
    
         
             
                #   Sashite::Pin.valid?("++K")  # => false
         
     | 
| 
       34 
34 
     | 
    
         
             
                def self.valid?(pin_string)
         
     | 
| 
       35 
     | 
    
         
            -
                   
     | 
| 
      
 35 
     | 
    
         
            +
                  Identifier.valid?(pin_string)
         
     | 
| 
       36 
36 
     | 
    
         
             
                end
         
     | 
| 
       37 
37 
     | 
    
         | 
| 
       38 
     | 
    
         
            -
                # Parse a PIN string into  
     | 
| 
      
 38 
     | 
    
         
            +
                # Parse a PIN string into an Identifier object
         
     | 
| 
       39 
39 
     | 
    
         
             
                #
         
     | 
| 
       40 
40 
     | 
    
         
             
                # @param pin_string [String] PIN notation string
         
     | 
| 
       41 
     | 
    
         
            -
                # @return [Pin:: 
     | 
| 
      
 41 
     | 
    
         
            +
                # @return [Pin::Identifier] new identifier instance
         
     | 
| 
       42 
42 
     | 
    
         
             
                # @raise [ArgumentError] if the PIN string is invalid
         
     | 
| 
       43 
43 
     | 
    
         
             
                # @example
         
     | 
| 
       44 
     | 
    
         
            -
                #   Sashite::Pin.parse("K")     # => #<Pin:: 
     | 
| 
       45 
     | 
    
         
            -
                #   Sashite::Pin.parse("+R")    # => #<Pin:: 
     | 
| 
       46 
     | 
    
         
            -
                #   Sashite::Pin.parse("-p")    # => #<Pin:: 
     | 
| 
      
 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>
         
     | 
| 
       47 
47 
     | 
    
         
             
                def self.parse(pin_string)
         
     | 
| 
       48 
     | 
    
         
            -
                   
     | 
| 
      
 48 
     | 
    
         
            +
                  Identifier.parse(pin_string)
         
     | 
| 
       49 
49 
     | 
    
         
             
                end
         
     | 
| 
       50 
50 
     | 
    
         | 
| 
       51 
     | 
    
         
            -
                # Create a new  
     | 
| 
      
 51 
     | 
    
         
            +
                # Create a new identifier instance
         
     | 
| 
       52 
52 
     | 
    
         
             
                #
         
     | 
| 
       53 
53 
     | 
    
         
             
                # @param type [Symbol] piece type (:A to :Z)
         
     | 
| 
       54 
54 
     | 
    
         
             
                # @param side [Symbol] player side (:first or :second)
         
     | 
| 
       55 
55 
     | 
    
         
             
                # @param state [Symbol] piece state (:normal, :enhanced, or :diminished)
         
     | 
| 
       56 
     | 
    
         
            -
                # @return [Pin:: 
     | 
| 
      
 56 
     | 
    
         
            +
                # @return [Pin::Identifier] new identifier instance
         
     | 
| 
       57 
57 
     | 
    
         
             
                # @raise [ArgumentError] if parameters are invalid
         
     | 
| 
       58 
58 
     | 
    
         
             
                # @example
         
     | 
| 
       59 
     | 
    
         
            -
                #   Sashite::Pin. 
     | 
| 
       60 
     | 
    
         
            -
                #   Sashite::Pin. 
     | 
| 
       61 
     | 
    
         
            -
                #   Sashite::Pin. 
     | 
| 
       62 
     | 
    
         
            -
                def self. 
     | 
| 
       63 
     | 
    
         
            -
                   
     | 
| 
      
 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)
         
     | 
| 
       64 
64 
     | 
    
         
             
                end
         
     | 
| 
       65 
65 
     | 
    
         
             
              end
         
     | 
| 
       66 
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:  
     | 
| 
      
 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  
     | 
| 
      
 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  
     | 
| 
       16 
     | 
    
         
            -
              principles. PIN  
     | 
| 
       17 
     | 
    
         
            -
               
     | 
| 
       18 
     | 
    
         
            -
               
     | 
| 
       19 
     | 
    
         
            -
              and  
     | 
| 
      
 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/ 
     | 
| 
      
 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  
     | 
| 
      
 56 
     | 
    
         
            +
            summary: PIN (Piece Identifier Notation) implementation for Ruby with immutable identifier
         
     | 
| 
       57 
57 
     | 
    
         
             
              objects
         
     | 
| 
       58 
58 
     | 
    
         
             
            test_files: []
         
     |