Class: Sashite::Pin::Identifier
- Inherits:
-
Object
- Object
- Sashite::Pin::Identifier
- Defined in:
- lib/sashite/pin/identifier.rb
Overview
Represents an identifier in PIN (Piece Identifier Notation) format.
An identifier consists of a single ASCII letter with optional state modifiers:
-
Enhanced state: prefix ‘+’
-
Diminished state: prefix ‘-’
-
Normal state: no modifier
The case of the letter determines ownership:
-
Uppercase (A-Z): first player
-
Lowercase (a-z): second player
All instances are immutable - state manipulation methods return new instances. This follows the Game Protocol’s piece model with Type, Side, and State attributes.
Constant Summary collapse
- PIN_PATTERN =
PIN validation pattern matching the specification
/\A(?<prefix>[-+])?(?<letter>[a-zA-Z])\z/
- ENHANCED_PREFIX =
Valid state modifiers
"+"
- DIMINISHED_PREFIX =
"-"
- NORMAL_PREFIX =
""
- ENHANCED_STATE =
State constants
:enhanced
- DIMINISHED_STATE =
:diminished
- NORMAL_STATE =
:normal
- FIRST_PLAYER =
Player side constants
:first
- SECOND_PLAYER =
:second
- VALID_TYPES =
Valid types (A-Z)
(:A..:Z).to_a.freeze
- VALID_SIDES =
Valid sides
[FIRST_PLAYER, SECOND_PLAYER].freeze
- VALID_STATES =
Valid states
[NORMAL_STATE, ENHANCED_STATE, DIMINISHED_STATE].freeze
- ERROR_INVALID_PIN =
Error messages
"Invalid PIN string: %s"
- ERROR_INVALID_TYPE =
"Type must be a symbol from :A to :Z, got: %s"
- ERROR_INVALID_SIDE =
"Side must be :first or :second, got: %s"
- ERROR_INVALID_STATE =
"State must be :normal, :enhanced, or :diminished, got: %s"
Instance Attribute Summary collapse
-
#side ⇒ Symbol
readonly
The player side (:first or :second).
-
#state ⇒ Symbol
readonly
The piece state (:normal, :enhanced, or :diminished).
-
#type ⇒ Symbol
readonly
The piece type (:A to :Z).
Class Method Summary collapse
-
.parse(pin_string) ⇒ Identifier
Parse a PIN string into an Identifier object.
-
.valid?(pin_string) ⇒ Boolean
Check if a string is a valid PIN notation.
-
.validate_side(side) ⇒ Object
Validate that the side is a valid symbol.
-
.validate_state(state) ⇒ Object
Validate that the state is a valid symbol.
-
.validate_type(type) ⇒ Object
Validate that the type is a valid symbol.
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
(also: #eql?)
Custom equality comparison.
-
#diminish ⇒ Identifier
Create a new identifier with diminished state.
-
#diminished? ⇒ Boolean
Check if the identifier has diminished state.
-
#enhance ⇒ Identifier
Create a new identifier with enhanced state.
-
#enhanced? ⇒ Boolean
Check if the identifier has enhanced state.
-
#first_player? ⇒ Boolean
Check if the identifier belongs to the first player.
-
#flip ⇒ Identifier
Create a new identifier with opposite side.
-
#hash ⇒ Integer
Custom hash implementation for use in collections.
-
#initialize(type, side, state = NORMAL_STATE) ⇒ Identifier
constructor
Create a new identifier instance.
-
#letter ⇒ String
Get the letter representation.
-
#normal? ⇒ Boolean
Check if the identifier has normal state.
-
#normalize ⇒ Identifier
Create a new identifier with normal state (no modifiers).
-
#prefix ⇒ String
Get the prefix representation.
-
#same_side?(other) ⇒ Boolean
Check if this identifier has the same side as another.
-
#same_state?(other) ⇒ Boolean
Check if this identifier has the same state as another.
-
#same_type?(other) ⇒ Boolean
Check if this identifier is the same type as another.
-
#second_player? ⇒ Boolean
Check if the identifier belongs to the second player.
-
#to_s ⇒ String
Convert the identifier to its PIN string representation.
-
#undiminish ⇒ Identifier
Create a new identifier without diminished state.
-
#unenhance ⇒ Identifier
Create a new identifier without enhanced state.
-
#with_side(new_side) ⇒ Identifier
Create a new identifier with a different side.
-
#with_state(new_state) ⇒ Identifier
Create a new identifier with a different state.
-
#with_type(new_type) ⇒ Identifier
Create a new identifier with a different type.
Constructor Details
#initialize(type, side, state = NORMAL_STATE) ⇒ Identifier
Create a new identifier instance
66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/sashite/pin/identifier.rb', line 66 def initialize(type, side, state = NORMAL_STATE) self.class.validate_type(type) self.class.validate_side(side) self.class.validate_state(state) @type = type @side = side @state = state freeze end |
Instance Attribute Details
#side ⇒ Symbol (readonly)
Returns the player side (:first or :second).
55 56 57 |
# File 'lib/sashite/pin/identifier.rb', line 55 def side @side end |
#state ⇒ Symbol (readonly)
Returns the piece state (:normal, :enhanced, or :diminished).
58 59 60 |
# File 'lib/sashite/pin/identifier.rb', line 58 def state @state end |
#type ⇒ Symbol (readonly)
Returns the piece type (:A to :Z).
52 53 54 |
# File 'lib/sashite/pin/identifier.rb', line 52 def type @type end |
Class Method Details
.parse(pin_string) ⇒ Identifier
Parse a PIN string into an Identifier object
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/sashite/pin/identifier.rb', line 87 def self.parse(pin_string) string_value = String(pin_string) matches = match_pattern(string_value) letter = matches[:letter] enhanced = matches[:prefix] == ENHANCED_PREFIX diminished = matches[:prefix] == DIMINISHED_PREFIX type = letter.upcase.to_sym side = letter == letter.upcase ? FIRST_PLAYER : SECOND_PLAYER state = if enhanced ENHANCED_STATE elsif diminished DIMINISHED_STATE else NORMAL_STATE end new(type, side, state) end |
.valid?(pin_string) ⇒ Boolean
Check if a string is a valid PIN notation
119 120 121 122 123 |
# File 'lib/sashite/pin/identifier.rb', line 119 def self.valid?(pin_string) return false unless pin_string.is_a?(::String) pin_string.match?(PIN_PATTERN) end |
.validate_side(side) ⇒ Object
Validate that the side is a valid symbol
336 337 338 339 340 |
# File 'lib/sashite/pin/identifier.rb', line 336 def self.validate_side(side) return if VALID_SIDES.include?(side) raise ::ArgumentError, format(ERROR_INVALID_SIDE, side.inspect) end |
.validate_state(state) ⇒ Object
Validate that the state is a valid symbol
346 347 348 349 350 |
# File 'lib/sashite/pin/identifier.rb', line 346 def self.validate_state(state) return if VALID_STATES.include?(state) raise ::ArgumentError, format(ERROR_INVALID_STATE, state.inspect) end |
.validate_type(type) ⇒ Object
Validate that the type is a valid symbol
326 327 328 329 330 |
# File 'lib/sashite/pin/identifier.rb', line 326 def self.validate_type(type) return if VALID_TYPES.include?(type) raise ::ArgumentError, format(ERROR_INVALID_TYPE, type.inspect) end |
Instance Method Details
#==(other) ⇒ Boolean Also known as: eql?
Custom equality comparison
306 307 308 309 310 |
# File 'lib/sashite/pin/identifier.rb', line 306 def ==(other) return false unless other.is_a?(self.class) type == other.type && side == other.side && state == other.state end |
#diminish ⇒ Identifier
Create a new identifier with diminished state
173 174 175 176 177 |
# File 'lib/sashite/pin/identifier.rb', line 173 def diminish return self if diminished? self.class.new(type, side, DIMINISHED_STATE) end |
#diminished? ⇒ Boolean
Check if the identifier has diminished state
247 248 249 |
# File 'lib/sashite/pin/identifier.rb', line 247 def diminished? state == DIMINISHED_STATE end |
#enhance ⇒ Identifier
Create a new identifier with enhanced state
155 156 157 158 159 |
# File 'lib/sashite/pin/identifier.rb', line 155 def enhance return self if enhanced? self.class.new(type, side, ENHANCED_STATE) end |
#enhanced? ⇒ Boolean
Check if the identifier has enhanced state
240 241 242 |
# File 'lib/sashite/pin/identifier.rb', line 240 def enhanced? state == ENHANCED_STATE end |
#first_player? ⇒ Boolean
Check if the identifier belongs to the first player
261 262 263 |
# File 'lib/sashite/pin/identifier.rb', line 261 def first_player? side == FIRST_PLAYER end |
#flip ⇒ Identifier
Create a new identifier with opposite side
200 201 202 |
# File 'lib/sashite/pin/identifier.rb', line 200 def flip self.class.new(type, opposite_side, state) end |
#hash ⇒ Integer
Custom hash implementation for use in collections
318 319 320 |
# File 'lib/sashite/pin/identifier.rb', line 318 def hash [self.class, type, side, state].hash end |
#letter ⇒ String
Get the letter representation
137 138 139 |
# File 'lib/sashite/pin/identifier.rb', line 137 def letter first_player? ? type.to_s.upcase : type.to_s.downcase end |
#normal? ⇒ Boolean
Check if the identifier has normal state
254 255 256 |
# File 'lib/sashite/pin/identifier.rb', line 254 def normal? state == NORMAL_STATE end |
#normalize ⇒ Identifier
Create a new identifier with normal state (no modifiers)
191 192 193 194 195 |
# File 'lib/sashite/pin/identifier.rb', line 191 def normalize return self if normal? self.class.new(type, side, NORMAL_STATE) end |
#prefix ⇒ String
Get the prefix representation
144 145 146 147 148 149 150 |
# File 'lib/sashite/pin/identifier.rb', line 144 def prefix case state when ENHANCED_STATE then ENHANCED_PREFIX when DIMINISHED_STATE then DIMINISHED_PREFIX else NORMAL_PREFIX end end |
#same_side?(other) ⇒ Boolean
Check if this identifier has the same side as another
286 287 288 289 290 |
# File 'lib/sashite/pin/identifier.rb', line 286 def same_side?(other) return false unless other.is_a?(self.class) side == other.side end |
#same_state?(other) ⇒ Boolean
Check if this identifier has the same state as another
296 297 298 299 300 |
# File 'lib/sashite/pin/identifier.rb', line 296 def same_state?(other) return false unless other.is_a?(self.class) state == other.state end |
#same_type?(other) ⇒ Boolean
Check if this identifier is the same type as another
276 277 278 279 280 |
# File 'lib/sashite/pin/identifier.rb', line 276 def same_type?(other) return false unless other.is_a?(self.class) type == other.type end |
#second_player? ⇒ Boolean
Check if the identifier belongs to the second player
268 269 270 |
# File 'lib/sashite/pin/identifier.rb', line 268 def second_player? side == SECOND_PLAYER end |
#to_s ⇒ String
Convert the identifier to its PIN string representation
130 131 132 |
# File 'lib/sashite/pin/identifier.rb', line 130 def to_s "#{prefix}#{letter}" end |
#undiminish ⇒ Identifier
Create a new identifier without diminished state
182 183 184 185 186 |
# File 'lib/sashite/pin/identifier.rb', line 182 def undiminish return self unless diminished? self.class.new(type, side, NORMAL_STATE) end |
#unenhance ⇒ Identifier
Create a new identifier without enhanced state
164 165 166 167 168 |
# File 'lib/sashite/pin/identifier.rb', line 164 def unenhance return self unless enhanced? self.class.new(type, side, NORMAL_STATE) end |
#with_side(new_side) ⇒ Identifier
Create a new identifier with a different side
219 220 221 222 223 224 |
# File 'lib/sashite/pin/identifier.rb', line 219 def with_side(new_side) self.class.validate_side(new_side) return self if side == new_side self.class.new(type, new_side, state) end |
#with_state(new_state) ⇒ Identifier
Create a new identifier with a different state
230 231 232 233 234 235 |
# File 'lib/sashite/pin/identifier.rb', line 230 def with_state(new_state) self.class.validate_state(new_state) return self if state == new_state self.class.new(type, side, new_state) end |
#with_type(new_type) ⇒ Identifier
Create a new identifier with a different type
208 209 210 211 212 213 |
# File 'lib/sashite/pin/identifier.rb', line 208 def with_type(new_type) self.class.validate_type(new_type) return self if type == new_type self.class.new(new_type, side, state) end |