Class: Sashite::Pnn::Piece
- Inherits:
-
Object
- Object
- Sashite::Pnn::Piece
- Defined in:
- lib/sashite/pnn/piece.rb
Overview
Represents a piece in PNN (Piece Name Notation) format.
A piece consists of a PIN component with an optional derivation marker:
-
PIN component: [<state>]<letter> (from PIN specification)
-
Derivation marker: “‘” (foreign style) or none (native style)
The case of the letter determines ownership:
-
Uppercase (A-Z): first player
-
Lowercase (a-z): second player
Style derivation logic:
-
No suffix: piece has the native style of its current side
-
Apostrophe suffix: piece has the foreign style (opposite side’s native style)
All instances are immutable - state manipulation methods return new instances. This extends the Game Protocol’s piece model with Style support through derivation.
Constant Summary collapse
- FOREIGN_SUFFIX =
Valid derivation suffixes
"'"
- NATIVE_SUFFIX =
""
- NATIVE =
Derivation constants
true
- FOREIGN =
false
- VALID_DERIVATIONS =
Valid derivations
[NATIVE, FOREIGN].freeze
- ERROR_INVALID_PNN =
Error messages
"Invalid PNN string: %s"
- ERROR_INVALID_DERIVATION =
"Derivation must be true (native) or false (foreign), got: %s"
Instance Attribute Summary collapse
-
#native ⇒ Boolean
readonly
The style derivation (true for native, false for foreign).
Class Method Summary collapse
-
.parse(pnn_string) ⇒ Piece
Parse a PNN string into a Piece object.
-
.valid?(pnn_string) ⇒ Boolean
Check if a string is a valid PNN notation.
-
.validate_derivation(derivation) ⇒ Object
Validate that the derivation is a valid boolean.
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
(also: #eql?)
Custom equality comparison.
-
#derive ⇒ Piece
Create a new piece with foreign style (derivation marker).
-
#derived? ⇒ Boolean
(also: #foreign?)
Check if the piece has foreign style (derivation marker).
-
#diminish ⇒ Piece
Create a new piece with diminished state.
-
#diminished? ⇒ Boolean
Check if the piece has diminished state.
-
#enhance ⇒ Piece
Create a new piece with enhanced state.
-
#enhanced? ⇒ Boolean
Check if the piece has enhanced state.
-
#first_player? ⇒ Boolean
Check if the piece belongs to the first player.
-
#flip ⇒ Piece
Create a new piece with opposite side.
-
#hash ⇒ Integer
Custom hash implementation for use in collections.
-
#initialize(type, side, state = Pin::Piece::NORMAL_STATE, native = NATIVE) ⇒ Piece
constructor
Create a new piece instance.
-
#letter ⇒ String
Get the letter representation (inherited from PIN logic).
-
#native? ⇒ Boolean
Check if the piece has native style (no derivation marker).
-
#normal? ⇒ Boolean
Check if the piece has normal state (no modifiers).
-
#normalize ⇒ Piece
Create a new piece with normal state (no modifiers).
-
#prefix ⇒ String
Get the prefix representation (inherited from PIN logic).
-
#same_side?(other) ⇒ Boolean
Check if this piece belongs to the same side as another.
-
#same_state?(other) ⇒ Boolean
Check if this piece has the same state as another.
-
#same_style?(other) ⇒ Boolean
Check if this piece has the same style derivation as another.
-
#same_type?(other) ⇒ Boolean
Check if this piece is the same type as another (ignoring side, state, and derivation).
-
#second_player? ⇒ Boolean
Check if the piece belongs to the second player.
-
#side ⇒ Symbol
The player side (:first or :second).
-
#state ⇒ Symbol
The piece state (:normal, :enhanced, or :diminished).
-
#suffix ⇒ String
Get the suffix representation.
-
#to_s ⇒ String
Convert the piece to its PNN string representation.
-
#type ⇒ Symbol
The piece type (:A to :Z).
-
#underive ⇒ Piece
Create a new piece with native style (no derivation marker).
-
#undiminish ⇒ Piece
Create a new piece without diminished state.
-
#unenhance ⇒ Piece
Create a new piece without enhanced state.
-
#with_derivation(new_native) ⇒ Piece
Create a new piece with a different derivation (keeping same type, side, and state).
-
#with_side(new_side) ⇒ Piece
Create a new piece with a different side (keeping same type, state, and derivation).
-
#with_state(new_state) ⇒ Piece
Create a new piece with a different state (keeping same type, side, and derivation).
-
#with_type(new_type) ⇒ Piece
Create a new piece with a different type (keeping same side, state, and derivation).
Constructor Details
#initialize(type, side, state = Pin::Piece::NORMAL_STATE, native = NATIVE) ⇒ Piece
Create a new piece instance
67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/sashite/pnn/piece.rb', line 67 def initialize(type, side, state = Pin::Piece::NORMAL_STATE, native = NATIVE) # Validate using PIN class methods for type, side, and state Pin::Piece.validate_type(type) Pin::Piece.validate_side(side) Pin::Piece.validate_state(state) self.class.validate_derivation(native) @piece = Pin::Piece.new(type, side, state) @native = native freeze end |
Instance Attribute Details
#native ⇒ Boolean (readonly)
Returns the style derivation (true for native, false for foreign).
55 56 57 |
# File 'lib/sashite/pnn/piece.rb', line 55 def native @native end |
Class Method Details
.parse(pnn_string) ⇒ Piece
Parse a PNN string into a Piece object
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/sashite/pnn/piece.rb', line 89 def self.parse(pnn_string) string_value = String(pnn_string) # Check for derivation suffix if string_value.end_with?(FOREIGN_SUFFIX) pin_part = string_value[0...-1] # Remove the apostrophe foreign = true else pin_part = string_value foreign = false end # Validate and parse the PIN part using existing PIN logic raise ::ArgumentError, format(ERROR_INVALID_PNN, string_value) unless Pin::Piece.valid?(pin_part) pin_piece = Pin::Piece.parse(pin_part) piece_native = !foreign new(pin_piece.type, pin_piece.side, pin_piece.state, piece_native) end |
.valid?(pnn_string) ⇒ Boolean
Check if a string is a valid PNN notation
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/sashite/pnn/piece.rb', line 121 def self.valid?(pnn_string) return false unless pnn_string.is_a?(::String) return false if pnn_string.empty? # Check for derivation suffix if pnn_string.end_with?(FOREIGN_SUFFIX) pin_part = pnn_string[0...-1] # Remove the apostrophe return false if pin_part.empty? # Can't have just an apostrophe else pin_part = pnn_string end # Validate the PIN part using existing PIN validation Pin::Piece.valid?(pin_part) end |
.validate_derivation(derivation) ⇒ Object
Validate that the derivation is a valid boolean
425 426 427 428 429 |
# File 'lib/sashite/pnn/piece.rb', line 425 def self.validate_derivation(derivation) return if VALID_DERIVATIONS.include?(derivation) raise ::ArgumentError, format(ERROR_INVALID_DERIVATION, derivation.inspect) end |
Instance Method Details
#==(other) ⇒ Boolean Also known as: eql?
Custom equality comparison
405 406 407 408 409 |
# File 'lib/sashite/pnn/piece.rb', line 405 def ==(other) return false unless other.is_a?(self.class) @piece == other.instance_variable_get(:@piece) && native == other.native end |
#derive ⇒ Piece
Create a new piece with foreign style (derivation marker)
238 239 240 241 242 |
# File 'lib/sashite/pnn/piece.rb', line 238 def derive return self if derived? self.class.new(type, side, state, FOREIGN) end |
#derived? ⇒ Boolean Also known as: foreign?
Check if the piece has foreign style (derivation marker)
352 353 354 |
# File 'lib/sashite/pnn/piece.rb', line 352 def derived? native == FOREIGN end |
#diminish ⇒ Piece
Create a new piece with diminished state
196 197 198 199 200 |
# File 'lib/sashite/pnn/piece.rb', line 196 def diminish return self if diminished? self.class.new(type, side, Pin::Piece::DIMINISHED_STATE, native) end |
#diminished? ⇒ Boolean
Check if the piece has diminished state
317 318 319 |
# File 'lib/sashite/pnn/piece.rb', line 317 def diminished? @piece.diminished? end |
#enhance ⇒ Piece
Create a new piece with enhanced state
174 175 176 177 178 |
# File 'lib/sashite/pnn/piece.rb', line 174 def enhance return self if enhanced? self.class.new(type, side, Pin::Piece::ENHANCED_STATE, native) end |
#enhanced? ⇒ Boolean
Check if the piece has enhanced state
310 311 312 |
# File 'lib/sashite/pnn/piece.rb', line 310 def enhanced? @piece.enhanced? end |
#first_player? ⇒ Boolean
Check if the piece belongs to the first player
331 332 333 |
# File 'lib/sashite/pnn/piece.rb', line 331 def first_player? @piece.first_player? end |
#flip ⇒ Piece
Create a new piece with opposite side
229 230 231 |
# File 'lib/sashite/pnn/piece.rb', line 229 def flip self.class.new(type, opposite_side, state, native) end |
#hash ⇒ Integer
Custom hash implementation for use in collections
417 418 419 |
# File 'lib/sashite/pnn/piece.rb', line 417 def hash [self.class, @piece, native].hash end |
#letter ⇒ String
Get the letter representation (inherited from PIN logic)
151 152 153 |
# File 'lib/sashite/pnn/piece.rb', line 151 def letter @piece.letter end |
#native? ⇒ Boolean
Check if the piece has native style (no derivation marker)
345 346 347 |
# File 'lib/sashite/pnn/piece.rb', line 345 def native? native == NATIVE end |
#normal? ⇒ Boolean
Check if the piece has normal state (no modifiers)
324 325 326 |
# File 'lib/sashite/pnn/piece.rb', line 324 def normal? @piece.normal? end |
#normalize ⇒ Piece
Create a new piece with normal state (no modifiers)
218 219 220 221 222 |
# File 'lib/sashite/pnn/piece.rb', line 218 def normalize return self if normal? self.class.new(type, side, Pin::Piece::NORMAL_STATE, native) end |
#prefix ⇒ String
Get the prefix representation (inherited from PIN logic)
158 159 160 |
# File 'lib/sashite/pnn/piece.rb', line 158 def prefix @piece.prefix end |
#same_side?(other) ⇒ Boolean
Check if this piece belongs to the same side as another
375 376 377 378 379 |
# File 'lib/sashite/pnn/piece.rb', line 375 def same_side?(other) return false unless other.is_a?(self.class) @piece.same_side?(other.instance_variable_get(:@piece)) end |
#same_state?(other) ⇒ Boolean
Check if this piece has the same state as another
385 386 387 388 389 |
# File 'lib/sashite/pnn/piece.rb', line 385 def same_state?(other) return false unless other.is_a?(self.class) @piece.same_state?(other.instance_variable_get(:@piece)) end |
#same_style?(other) ⇒ Boolean
Check if this piece has the same style derivation as another
395 396 397 398 399 |
# File 'lib/sashite/pnn/piece.rb', line 395 def same_style?(other) return false unless other.is_a?(self.class) native == other.native end |
#same_type?(other) ⇒ Boolean
Check if this piece is the same type as another (ignoring side, state, and derivation)
365 366 367 368 369 |
# File 'lib/sashite/pnn/piece.rb', line 365 def same_type?(other) return false unless other.is_a?(self.class) @piece.same_type?(other.instance_variable_get(:@piece)) end |
#second_player? ⇒ Boolean
Check if the piece belongs to the second player
338 339 340 |
# File 'lib/sashite/pnn/piece.rb', line 338 def second_player? @piece.second_player? end |
#side ⇒ Symbol
Returns the player side (:first or :second).
45 46 47 |
# File 'lib/sashite/pnn/piece.rb', line 45 def side @piece.side end |
#state ⇒ Symbol
Returns the piece state (:normal, :enhanced, or :diminished).
50 51 52 |
# File 'lib/sashite/pnn/piece.rb', line 50 def state @piece.state end |
#suffix ⇒ String
Get the suffix representation
165 166 167 |
# File 'lib/sashite/pnn/piece.rb', line 165 def suffix native? ? NATIVE_SUFFIX : FOREIGN_SUFFIX end |
#to_s ⇒ String
Convert the piece to its PNN string representation
144 145 146 |
# File 'lib/sashite/pnn/piece.rb', line 144 def to_s "#{prefix}#{letter}#{suffix}" end |
#type ⇒ Symbol
Returns the piece type (:A to :Z).
40 41 42 |
# File 'lib/sashite/pnn/piece.rb', line 40 def type @piece.type end |
#underive ⇒ Piece
Create a new piece with native style (no derivation marker)
249 250 251 252 253 |
# File 'lib/sashite/pnn/piece.rb', line 249 def underive return self if native? self.class.new(type, side, state, NATIVE) end |
#undiminish ⇒ Piece
Create a new piece without diminished state
207 208 209 210 211 |
# File 'lib/sashite/pnn/piece.rb', line 207 def undiminish return self unless diminished? self.class.new(type, side, Pin::Piece::NORMAL_STATE, native) end |
#unenhance ⇒ Piece
Create a new piece without enhanced state
185 186 187 188 189 |
# File 'lib/sashite/pnn/piece.rb', line 185 def unenhance return self unless enhanced? self.class.new(type, side, Pin::Piece::NORMAL_STATE, native) end |
#with_derivation(new_native) ⇒ Piece
Create a new piece with a different derivation (keeping same type, side, and state)
300 301 302 303 304 305 |
# File 'lib/sashite/pnn/piece.rb', line 300 def with_derivation(new_native) self.class.validate_derivation(new_native) return self if native == new_native self.class.new(type, side, state, new_native) end |
#with_side(new_side) ⇒ Piece
Create a new piece with a different side (keeping same type, state, and derivation)
274 275 276 277 278 279 |
# File 'lib/sashite/pnn/piece.rb', line 274 def with_side(new_side) Pin::Piece.validate_side(new_side) return self if side == new_side self.class.new(type, new_side, state, native) end |
#with_state(new_state) ⇒ Piece
Create a new piece with a different state (keeping same type, side, and derivation)
287 288 289 290 291 292 |
# File 'lib/sashite/pnn/piece.rb', line 287 def with_state(new_state) Pin::Piece.validate_state(new_state) return self if state == new_state self.class.new(type, side, new_state, native) end |
#with_type(new_type) ⇒ Piece
Create a new piece with a different type (keeping same side, state, and derivation)
261 262 263 264 265 266 |
# File 'lib/sashite/pnn/piece.rb', line 261 def with_type(new_type) Pin::Piece.validate_type(new_type) return self if type == new_type self.class.new(new_type, side, state, native) end |