sashite-pin 3.1.0 → 3.3.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: e469a5469a29de49338f5066b5b5743860459709ab2e771209d1c55ab7e7ff0d
4
- data.tar.gz: 680f65379ee7ea0ead2238ed646a29ee54d673a80de7f0c54f1c56a11cf8f98f
3
+ metadata.gz: 629bf8b689b39a81e6b52ca9b1386f53c6c807f5f57ae608fb99449ceb08854e
4
+ data.tar.gz: '0883b5de633e958ddbf72908ffd49832e999e0a1f99b615ce8aa5fa1222cd4f5'
5
5
  SHA512:
6
- metadata.gz: 1a4b4ce38433cdf1cd9a26baaba13fa8e48ff21676976287422ac917d3a41bc67e7eb688bf347a94cefb294542e98fa7d2bd292f923b7a8c6b66d73edfaebdd2
7
- data.tar.gz: 5da68a02154b85ab6a9b1070954f14be0a4f79e11e07c54448c0aae40772e4664c2b3368067a44c8fdef5a43b122a3c868e2cc8c6df5ed52f46afa2a2b65f021
6
+ metadata.gz: a64ac32e1afb6b84c388823f81022efe6eda1a469ce82920b4d8119f0e747e4f5a8788c92d397a48165b36fcfda45111df785dad8523f3e861e31acb55e6fd68
7
+ data.tar.gz: 99a1e0e87304f2b1f525483cf952a4a0d9fdf0768297010894e6d429f4431b7c5476f287f94e3e85dd9c4c46669546ed094c2afc0fdd6296c9bccebcd8aa255b
data/README.md CHANGED
@@ -1,17 +1,17 @@
1
- # Pin.rb
1
+ # Sashite::Pin
2
2
 
3
3
  [![Version](https://img.shields.io/github/v/tag/sashite/pin.rb?label=Version&logo=github)](https://github.com/sashite/pin.rb/tags)
4
4
  [![Yard documentation](https://img.shields.io/badge/Yard-documentation-blue.svg?logo=github)](https://rubydoc.info/github/sashite/pin.rb/main)
5
5
  ![Ruby](https://github.com/sashite/pin.rb/actions/workflows/main.yml/badge.svg?branch=main)
6
6
  [![License](https://img.shields.io/github/license/sashite/pin.rb?label=License&logo=github)](https://github.com/sashite/pin.rb/raw/main/LICENSE.md)
7
7
 
8
- > **PIN** (Piece Identifier Notation) implementation for the Ruby language.
8
+ > **PIN** (Piece Identifier Notation) implementation for Ruby.
9
9
 
10
10
  ## What is PIN?
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 identifier objects and functional programming principles.
14
+ This gem implements the [PIN Specification v1.0.0](https://sashite.dev/specs/pin/1.0.0/).
15
15
 
16
16
  ## Installation
17
17
 
@@ -31,62 +31,74 @@ gem install sashite-pin
31
31
  ```ruby
32
32
  require "sashite/pin"
33
33
 
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
34
+ # Parse PIN strings
35
+ pin = Sashite::Pin.parse("K")
36
+ pin.type # => :K
37
+ pin.side # => :first
38
+ pin.state # => :normal
39
+ pin.terminal # => false
40
+
41
+ pin.to_s # => "K"
42
+
43
+ # Parse with different attributes
44
+ king = Sashite::Pin.parse("K^") # Terminal king
45
+ rook = Sashite::Pin.parse("+R") # Enhanced rook
46
+ pawn = Sashite::Pin.parse("-p") # Diminished second player pawn
40
47
 
41
48
  # 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>
49
+ pin = Sashite::Pin.new(:K, :first)
50
+ pin = Sashite::Pin.new(:R, :second, :enhanced)
51
+ pin = Sashite::Pin.new(:K, :first, :normal, terminal: true)
52
+
53
+ # Validation
54
+ Sashite::Pin.valid?("K") # => true
55
+ Sashite::Pin.valid?("+R") # => true
56
+ Sashite::Pin.valid?("K^") # => true
57
+ Sashite::Pin.valid?("invalid") # => false
58
+
59
+ # State transformations (return new instances)
60
+ enhanced = pin.enhance
61
+ enhanced.to_s # => "+K"
62
+
63
+ diminished = pin.diminish
64
+ diminished.to_s # => "-K"
44
65
 
45
- # Validate PIN strings
46
- Sashite::Pin.valid?("K") # => true
47
- Sashite::Pin.valid?("+R") # => true
48
- Sashite::Pin.valid?("invalid") # => false
66
+ normalized = enhanced.normalize
67
+ normalized.to_s # => "K"
49
68
 
50
- # State manipulation (returns new immutable instances)
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"
69
+ # Side transformation
70
+ flipped = pin.flip
71
+ flipped.to_s # => "k"
55
72
 
56
- # Side manipulation
57
- flipped = identifier.flip # => #<Pin::Identifier type=:K side=:second state=:normal>
58
- flipped.to_s # => "k"
73
+ # Terminal transformations
74
+ terminal = pin.mark_terminal
75
+ terminal.to_s # => "K^"
59
76
 
60
- # Type manipulation
61
- queen = identifier.with_type(:Q) # => #<Pin::Identifier type=:Q side=:first state=:normal>
62
- queen.to_s # => "Q"
77
+ non_terminal = terminal.unmark_terminal
78
+ non_terminal.to_s # => "K"
79
+
80
+ # Type transformation
81
+ queen = pin.with_type(:Q)
82
+ queen.to_s # => "Q"
63
83
 
64
84
  # State queries
65
- identifier.normal? # => true
66
- enhanced.enhanced? # => true
67
- diminished.diminished? # => true
85
+ pin.normal? # => true
86
+ enhanced.enhanced? # => true
87
+ diminished.diminished? # => true
68
88
 
69
89
  # Side queries
70
- identifier.first_player? # => true
71
- flipped.second_player? # => true
90
+ pin.first_player? # => true
91
+ flipped.second_player? # => true
72
92
 
73
- # Attribute access
74
- identifier.letter # => "K"
75
- enhanced.prefix # => "+"
76
- identifier.prefix # => ""
93
+ # Terminal queries
94
+ terminal.terminal? # => true
77
95
 
78
- # Type and side comparison
96
+ # Comparison
79
97
  king1 = Sashite::Pin.parse("K")
80
98
  king2 = Sashite::Pin.parse("k")
81
- queen = Sashite::Pin.parse("Q")
82
-
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
99
 
87
- # Functional transformations can be chained
88
- pawn = Sashite::Pin.parse("P")
89
- enemy_promoted = pawn.flip.enhance # => "+p" (second player promoted pawn)
100
+ king1.same_type?(king2) # => true
101
+ king1.same_side?(king2) # => false
90
102
  ```
91
103
 
92
104
  ## Format Specification
@@ -94,348 +106,130 @@ enemy_promoted = pawn.flip.enhance # => "+p" (second player promoted
94
106
  ### Structure
95
107
 
96
108
  ```
97
- [<state>]<letter>
109
+ [<state-modifier>]<letter>[<terminal-marker>]
98
110
  ```
99
111
 
100
112
  ### Components
101
113
 
102
- * **Letter** (`A-Z`, `a-z`): Represents piece type and side
103
-
104
- * Uppercase: First player pieces
105
- * Lowercase: Second player pieces
106
- * **State** (optional prefix):
107
-
108
- * `+`: Enhanced state (promoted, upgraded, empowered)
109
- * `-`: Diminished state (weakened, restricted, temporary)
110
- * No prefix: Normal state
114
+ | Component | Values | Description |
115
+ |-----------|--------|-------------|
116
+ | Letter | `A-Z`, `a-z` | Piece type and side |
117
+ | State Modifier | `+`, `-`, (none) | Enhanced, diminished, or normal |
118
+ | Terminal Marker | `^`, (none) | Terminal piece or not |
111
119
 
112
- ### Regular Expression
120
+ ### Side Convention
113
121
 
114
- ```ruby
115
- /\A[-+]?[A-Za-z]\z/
116
- ```
122
+ - **Uppercase** (`A-Z`): First player
123
+ - **Lowercase** (`a-z`): Second player
117
124
 
118
125
  ### Examples
119
126
 
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)
127
+ | PIN | Side | State | Terminal | Description |
128
+ |-----|------|-------|----------|-------------|
129
+ | `K` | First | Normal | No | Standard king |
130
+ | `K^` | First | Normal | Yes | Terminal king |
131
+ | `+R` | First | Enhanced | No | Promoted rook |
132
+ | `-p` | Second | Diminished | No | Weakened pawn |
133
+ | `+K^` | First | Enhanced | Yes | Enhanced terminal king |
124
134
 
125
135
  ## API Reference
126
136
 
127
- ### Main Module Methods
128
-
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
132
-
133
- ### Identifier Class
134
-
135
- #### Creation and Parsing
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)
140
-
141
- #### Attribute Access
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
149
-
150
- #### Type and Case Handling
151
-
152
- **Important**: The `type` attribute is always stored as an uppercase symbol (`:A` to `:Z`), regardless of the input case when parsing. The display case in `#letter` and `#to_s` is determined by the `side` attribute:
137
+ ### Parsing and Validation
153
138
 
154
139
  ```ruby
155
- # Both create the same internal type representation
156
- identifier1 = Sashite::Pin.parse("K") # type: :K, side: :first
157
- identifier2 = Sashite::Pin.parse("k") # type: :K, side: :second
158
-
159
- identifier1.type # => :K (uppercase symbol)
160
- identifier2.type # => :K (same uppercase symbol)
161
-
162
- identifier1.letter # => "K" (uppercase display)
163
- identifier2.letter # => "k" (lowercase display)
140
+ Sashite::Pin.parse(pin_string) # => Sashite::Pin | raises ArgumentError
141
+ Sashite::Pin.valid?(pin_string) # => boolean
164
142
  ```
165
143
 
166
- #### State Queries
167
-
168
- * `#normal?` - Check if normal state (no modifiers)
169
- * `#enhanced?` - Check if enhanced state
170
- * `#diminished?` - Check if diminished state
171
-
172
- #### Side Queries
173
-
174
- * `#first_player?` - Check if first player identifier
175
- * `#second_player?` - Check if second player identifier
176
-
177
- #### State Transformations (immutable - return new instances)
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)
185
-
186
- #### Attribute Transformations (immutable - return new instances)
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
191
-
192
- #### Comparison Methods
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
198
-
199
- ### Constants
200
-
201
- * `Sashite::Pin::Identifier::PIN_PATTERN` - Regular expression for PIN validation (internal use)
202
-
203
- ## Advanced Usage
204
-
205
- ### Type Normalization Examples
144
+ ### Creation
206
145
 
207
146
  ```ruby
208
- # Parsing different cases results in same type
209
- white_king = Sashite::Pin.parse("K")
210
- black_king = Sashite::Pin.parse("k")
147
+ Sashite::Pin.new(type, side)
148
+ Sashite::Pin.new(type, side, state)
149
+ Sashite::Pin.new(type, side, state, terminal: boolean)
150
+ ```
211
151
 
212
- # Types are normalized to uppercase
213
- white_king.type # => :K
214
- black_king.type # => :K (same type!)
152
+ ### Conversion
215
153
 
216
- # Sides are different
217
- white_king.side # => :first
218
- black_king.side # => :second
154
+ ```ruby
155
+ pin.to_s # => String
156
+ pin.letter # => String (case determined by side)
157
+ pin.prefix # => String ("+" | "-" | "")
158
+ pin.suffix # => String ("^" | "")
159
+ ```
219
160
 
220
- # Display follows side convention
221
- white_king.letter # => "K"
222
- black_king.letter # => "k"
161
+ ### Transformations
223
162
 
224
- # Same type, different sides
225
- white_king.same_type?(black_king) # => true
226
- white_king.same_side?(black_king) # => false
227
- ```
163
+ All transformations return new `Sashite::Pin` instances:
228
164
 
229
- ### Immutable Transformations
230
165
  ```ruby
231
- # All transformations return new instances
232
- original = Sashite::Pin.piece(:K, :first, :normal)
233
- enhanced = original.enhance
234
- diminished = original.diminish
235
-
236
- # Original piece is never modified
237
- puts original.to_s # => "K"
238
- puts enhanced.to_s # => "+K"
239
- puts diminished.to_s # => "-K"
240
-
241
- # Transformations can be chained
242
- result = original.flip.enhance.with_type(:Q)
243
- puts result.to_s # => "+q"
166
+ # State
167
+ pin.enhance # => Sashite::Pin with :enhanced state
168
+ pin.diminish # => Sashite::Pin with :diminished state
169
+ pin.normalize # => Sashite::Pin with :normal state
170
+
171
+ # Side
172
+ pin.flip # => Sashite::Pin with opposite side
173
+
174
+ # Terminal
175
+ pin.mark_terminal # => Sashite::Pin with terminal: true
176
+ pin.unmark_terminal # => Sashite::Pin with terminal: false
177
+
178
+ # Attribute changes
179
+ pin.with_type(new_type) # => Sashite::Pin with different type
180
+ pin.with_side(new_side) # => Sashite::Pin with different side
181
+ pin.with_state(new_state) # => Sashite::Pin with different state
182
+ pin.with_terminal(boolean) # => Sashite::Pin with specified terminal status
244
183
  ```
245
184
 
246
- ### Game State Management
247
- ```ruby
248
- class GameBoard
249
- def initialize
250
- @pieces = {}
251
- end
252
-
253
- def place(square, piece)
254
- @pieces[square] = piece
255
- end
256
-
257
- def promote(square, new_type = :Q)
258
- piece = @pieces[square]
259
- return nil unless piece&.normal? # Can only promote normal pieces
260
-
261
- @pieces[square] = piece.with_type(new_type).enhance
262
- end
263
-
264
- def capture(from_square, to_square)
265
- captured = @pieces[to_square]
266
- @pieces[to_square] = @pieces.delete(from_square)
267
- captured
268
- end
269
-
270
- def pieces_by_side(side)
271
- @pieces.select { |_, piece| piece.side == side }
272
- end
273
-
274
- def promoted_pieces
275
- @pieces.select { |_, piece| piece.enhanced? }
276
- end
277
- end
278
-
279
- # Usage
280
- board = GameBoard.new
281
- board.place("e1", Sashite::Pin.piece(:K, :first, :normal))
282
- board.place("e8", Sashite::Pin.piece(:K, :second, :normal))
283
- board.place("a7", Sashite::Pin.piece(:P, :first, :normal))
284
-
285
- # Promote pawn
286
- board.promote("a7", :Q)
287
- promoted = board.promoted_pieces
288
- puts promoted.values.first.to_s # => "+Q"
289
- ```
185
+ ### Queries
290
186
 
291
- ### Piece Analysis
292
187
  ```ruby
293
- def analyze_pieces(pins)
294
- pieces = pins.map { |pin| Sashite::Pin.parse(pin) }
295
-
296
- {
297
- total: pieces.size,
298
- by_side: pieces.group_by(&:side),
299
- by_type: pieces.group_by(&:type),
300
- by_state: pieces.group_by(&:state),
301
- promoted: pieces.count(&:enhanced?),
302
- weakened: pieces.count(&:diminished?)
303
- }
304
- end
305
-
306
- pins = %w[K Q +R B N P k q r +b n -p]
307
- analysis = analyze_pieces(pins)
308
- puts analysis[:by_side][:first].size # => 6
309
- puts analysis[:promoted] # => 2
188
+ # State
189
+ pin.normal?
190
+ pin.enhanced?
191
+ pin.diminished?
192
+
193
+ # Side
194
+ pin.first_player?
195
+ pin.second_player?
196
+
197
+ # Terminal
198
+ pin.terminal?
199
+
200
+ # Comparison
201
+ pin.same_type?(other)
202
+ pin.same_side?(other)
203
+ pin.same_state?(other)
204
+ pin.same_terminal?(other)
310
205
  ```
311
206
 
312
- ### Move Validation Example
207
+ ## Data Structure
208
+
313
209
  ```ruby
314
- def can_promote?(piece, target_rank)
315
- return false unless piece.normal? # Already promoted pieces can't promote again
316
-
317
- case piece.type
318
- when :P # Pawn
319
- (piece.first_player? && target_rank == 8) ||
320
- (piece.second_player? && target_rank == 1)
321
- when :R, :B, :S, :N, :L # Shōgi pieces that can promote
322
- true
323
- else
324
- false
325
- end
326
- end
327
-
328
- pawn = Sashite::Pin.piece(:P, :first, :normal)
329
- puts can_promote?(pawn, 8) # => true
330
-
331
- promoted_pawn = pawn.enhance
332
- puts can_promote?(promoted_pawn, 8) # => false (already promoted)
210
+ Sashite::Pin
211
+ #type => :A..:Z # Piece type (always uppercase symbol)
212
+ #side => :first | :second # Player side
213
+ #state => :normal | :enhanced | :diminished
214
+ #terminal => true | false
333
215
  ```
334
216
 
335
217
  ## Protocol Mapping
336
218
 
337
219
  Following the [Game Protocol](https://sashite.dev/game-protocol/):
338
220
 
339
- | Protocol Attribute | PIN Encoding | Examples | Notes |
340
- |-------------------|--------------|----------|-------|
341
- | **Type** | ASCII letter choice | `K`/`k` = King, `P`/`p` = Pawn | Type is always stored as uppercase symbol (`:K`, `:P`) |
342
- | **Side** | Letter case in display | `K` = First player, `k` = Second player | Case is determined by side during rendering |
343
- | **State** | Optional prefix | `+K` = Enhanced, `-K` = Diminished, `K` = Normal | |
344
-
345
- **Type Convention**: All piece types are internally represented as uppercase symbols (`:A` to `:Z`). The display case is determined by the `side` attribute: first player pieces display as uppercase, second player pieces as lowercase.
346
-
347
- **Canonical principle**: Identical pieces must have identical PIN representations.
348
-
349
- **Note**: PIN does not represent the **Style** attribute from the Game Protocol. For style-aware piece notation, see [Piece Name Notation (PNN)](https://sashite.dev/specs/pnn/).
350
-
351
- ## Properties
352
-
353
- * **ASCII Compatible**: Maximum portability across systems
354
- * **Rule-Agnostic**: Independent of specific game mechanics
355
- * **Compact Format**: 1-2 characters per piece
356
- * **Visual Distinction**: Clear player differentiation through case
357
- * **Type Normalization**: Consistent uppercase type representation internally
358
- * **Protocol Compliant**: Direct implementation of Sashité piece attributes
359
- * **Immutable**: All piece instances are frozen and transformations return new objects
360
- * **Functional**: Pure functions with no side effects
361
-
362
- ## Implementation Notes
363
-
364
- ### Type Normalization Convention
365
-
366
- PIN follows a strict type normalization convention:
367
-
368
- 1. **Internal Storage**: All piece types are stored as uppercase symbols (`:A` to `:Z`)
369
- 2. **Input Flexibility**: Both `"K"` and `"k"` are valid input during parsing
370
- 3. **Case Semantics**: Input case determines the `side` attribute, not the `type`
371
- 4. **Display Logic**: Output case is computed from `side` during rendering
372
-
373
- This design ensures:
374
- - Consistent internal representation regardless of input format
375
- - Clear separation between piece identity (type) and ownership (side)
376
- - Predictable behavior when comparing pieces of the same type
377
-
378
- ### Example Flow
379
-
380
- ```ruby
381
- # Input: "k" (lowercase)
382
- # ↓ Parsing
383
- # type: :K (normalized to uppercase)
384
- # side: :second (inferred from lowercase input)
385
- # ↓ Display
386
- # letter: "k" (computed from type + side)
387
- # PIN: "k" (final representation)
388
- ```
389
-
390
- This ensures that `parse(pin).to_s == pin` for all valid PIN strings while maintaining internal consistency.
391
-
392
- ## System Constraints
393
-
394
- - **Maximum 26 piece types** per game system (one per ASCII letter)
395
- - **Exactly 2 players** (uppercase/lowercase distinction)
396
- - **3 state levels** (enhanced, normal, diminished)
221
+ | Protocol Attribute | PIN Encoding |
222
+ |-------------------|--------------|
223
+ | Piece Name | ASCII letter choice |
224
+ | Piece Side | Letter case |
225
+ | Piece State | Optional prefix (`+`/`-`) |
226
+ | Terminal Status | Optional suffix (`^`) |
397
227
 
398
228
  ## Related Specifications
399
229
 
400
- - [Game Protocol](https://sashite.dev/game-protocol/) - Conceptual foundation for abstract strategy board games
401
- - [PNN](https://sashite.dev/specs/pnn/) - Piece Name Notation (style-aware piece representation)
402
- - [CELL](https://sashite.dev/specs/cell/) - Board position coordinates
403
- - [HAND](https://sashite.dev/specs/hand/) - Reserve location notation
404
- - [PMN](https://sashite.dev/specs/pmn/) - Portable Move Notation
405
-
406
- ## Documentation
407
-
408
- - [Official PIN Specification v1.0.0](https://sashite.dev/specs/pin/1.0.0/)
409
- - [PIN Examples Documentation](https://sashite.dev/specs/pin/1.0.0/examples/)
410
- - [Game Protocol Foundation](https://sashite.dev/game-protocol/)
411
- - [API Documentation](https://rubydoc.info/github/sashite/pin.rb/main)
412
-
413
- ## Development
414
-
415
- ```sh
416
- # Clone the repository
417
- git clone https://github.com/sashite/pin.rb.git
418
- cd pin.rb
419
-
420
- # Install dependencies
421
- bundle install
422
-
423
- # Run tests
424
- ruby test.rb
425
-
426
- # Generate documentation
427
- yard doc
428
- ```
429
-
430
- ## Contributing
431
-
432
- 1. Fork the repository
433
- 2. Create a feature branch (`git checkout -b feature/new-feature`)
434
- 3. Add tests for your changes
435
- 4. Ensure all tests pass (`ruby test.rb`)
436
- 5. Commit your changes (`git commit -am 'Add new feature'`)
437
- 6. Push to the branch (`git push origin feature/new-feature`)
438
- 7. Create a Pull Request
230
+ - [Game Protocol](https://sashite.dev/game-protocol/) Conceptual foundation
231
+ - [PNN](https://sashite.dev/specs/pnn/) Piece Name Notation
232
+ - [PIN Specification](https://sashite.dev/specs/pin/1.0.0/) Official specification
439
233
 
440
234
  ## License
441
235