sashite-pin 2.0.2 → 3.1.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 +91 -152
- data/lib/sashite/pin/{piece.rb → identifier.rb} +61 -84
- data/lib/sashite/pin.rb +16 -16
- 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: e469a5469a29de49338f5066b5b5743860459709ab2e771209d1c55ab7e7ff0d
|
|
4
|
+
data.tar.gz: 680f65379ee7ea0ead2238ed646a29ee54d673a80de7f0c54f1c56a11cf8f98f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1a4b4ce38433cdf1cd9a26baaba13fa8e48ff21676976287422ac917d3a41bc67e7eb688bf347a94cefb294542e98fa7d2bd292f923b7a8c6b66d73edfaebdd2
|
|
7
|
+
data.tar.gz: 5da68a02154b85ab6a9b1070954f14be0a4f79e11e07c54448c0aae40772e4664c2b3368067a44c8fdef5a43b122a3c868e2cc8c6df5ed52f46afa2a2b65f021
|
data/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
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
|
|
|
@@ -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
|
|
@@ -18,7 +18,7 @@ module Sashite
|
|
|
18
18
|
# "+R" - First player rook (enhanced state)
|
|
19
19
|
# "-p" - Second player pawn (diminished state)
|
|
20
20
|
#
|
|
21
|
-
#
|
|
21
|
+
# @see https://sashite.dev/specs/pin/1.0.0/
|
|
22
22
|
module Pin
|
|
23
23
|
# Check if a string is a valid PIN notation
|
|
24
24
|
#
|
|
@@ -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)
|
|
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.1.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: []
|