Class: Sashite::Pnn::Name

Inherits:
Object
  • Object
show all
Defined in:
lib/sashite/pnn/name.rb

Overview

Represents a piece name in PNN (Piece Name Notation) format.

PNN provides a canonical naming system for abstract strategy game pieces. Each name consists of an optional state modifier (+ or -) followed by a case-consistent alphabetic name and an optional terminal marker (^), encoding piece identity, player assignment, state, and terminal status in a human-readable format.

All instances are immutable.

Constant Summary collapse

PNN_PATTERN =

PNN validation pattern matching the specification

/\A([+-]?)([A-Z]+|[a-z]+)(\^?)\z/
ERROR_INVALID_NAME =

Error messages

"Invalid PNN string: %s"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name) ⇒ Name

Create a new piece name instance

Parameters:

  • name (String, Symbol)

    the piece name (e.g., “KING”, :queen, “+ROOK”, “-pawn”, “KING^”)

Raises:

  • (ArgumentError)

    if the name does not match PNN pattern



28
29
30
31
32
33
34
35
# File 'lib/sashite/pnn/name.rb', line 28

def initialize(name)
  string_value = name.to_s
  self.class.validate_format(string_value)

  @value = string_value.freeze
  @parsed = parse_components(string_value)
  freeze
end

Instance Attribute Details

#valueString (readonly)

Returns the canonical piece name.

Returns:

  • (String)

    the canonical piece name



22
23
24
# File 'lib/sashite/pnn/name.rb', line 22

def value
  @value
end

Class Method Details

.parse(string) ⇒ Name

Parse a PNN string into a Name object

Examples:

Sashite::Pnn::Name.parse("KING")    # => #<Pnn::Name value="KING">
Sashite::Pnn::Name.parse("+queen")  # => #<Pnn::Name value="+queen">
Sashite::Pnn::Name.parse("KING^")   # => #<Pnn::Name value="KING^">
Sashite::Pnn::Name.parse("+ROOK^")  # => #<Pnn::Name value="+ROOK^">

Parameters:

  • string (String)

    the PNN-formatted piece name

Returns:

  • (Name)

    a new Name instance

Raises:

  • (ArgumentError)

    if the string is invalid



48
49
50
# File 'lib/sashite/pnn/name.rb', line 48

def self.parse(string)
  new(string)
end

.valid?(string) ⇒ Boolean

Check whether the given string is a valid PNN name

Examples:

Sashite::Pnn::Name.valid?("KING")    # => true
Sashite::Pnn::Name.valid?("King")    # => false (mixed case)
Sashite::Pnn::Name.valid?("+queen")  # => true
Sashite::Pnn::Name.valid?("KING^")   # => true
Sashite::Pnn::Name.valid?("KING1")   # => false (contains digit)

Parameters:

  • string (String)

    input string to validate

Returns:

  • (Boolean)

    true if valid, false otherwise



63
64
65
# File 'lib/sashite/pnn/name.rb', line 63

def self.valid?(string)
  string.is_a?(::String) && string.match?(PNN_PATTERN)
end

.validate_format(str) ⇒ Object

Validate that the string is in proper PNN format

Parameters:

  • str (String)

Raises:

  • (ArgumentError)

    if invalid



71
72
73
# File 'lib/sashite/pnn/name.rb', line 71

def self.validate_format(str)
  raise ::ArgumentError, format(ERROR_INVALID_NAME, str.inspect) unless str.match?(PNN_PATTERN)
end

Instance Method Details

#==(other) ⇒ Boolean Also known as: eql?

Equality based on normalized string value

Parameters:

  • other (Object)

Returns:

  • (Boolean)


193
194
195
# File 'lib/sashite/pnn/name.rb', line 193

def ==(other)
  other.is_a?(self.class) && value == other.value
end

#base_nameString

Returns the base name without state modifier or terminal marker

Examples:

Sashite::Pnn::Name.parse("KING").base_name     # => "KING"
Sashite::Pnn::Name.parse("+queen").base_name   # => "queen"
Sashite::Pnn::Name.parse("-ROOK").base_name    # => "ROOK"
Sashite::Pnn::Name.parse("KING^").base_name    # => "KING"
Sashite::Pnn::Name.parse("+ROOK^").base_name   # => "ROOK"

Returns:

  • (String)

    the piece name without + or - prefix and without ^ suffix



92
93
94
# File 'lib/sashite/pnn/name.rb', line 92

def base_name
  @parsed[:base_name]
end

#diminished?Boolean

Check if the piece has diminished state (-)

Examples:

Sashite::Pnn::Name.parse("-pawn").diminished?  # => true
Sashite::Pnn::Name.parse("pawn").diminished?   # => false
Sashite::Pnn::Name.parse("-pawn^").diminished? # => true

Returns:

  • (Boolean)

    true if diminished, false otherwise



116
117
118
# File 'lib/sashite/pnn/name.rb', line 116

def diminished?
  @parsed[:state_modifier] == "-"
end

#enhanced?Boolean

Check if the piece has enhanced state (+)

Examples:

Sashite::Pnn::Name.parse("+KING").enhanced?    # => true
Sashite::Pnn::Name.parse("KING").enhanced?     # => false
Sashite::Pnn::Name.parse("+KING^").enhanced?   # => true

Returns:

  • (Boolean)

    true if enhanced, false otherwise



104
105
106
# File 'lib/sashite/pnn/name.rb', line 104

def enhanced?
  @parsed[:state_modifier] == "+"
end

#first_player?Boolean

Check if the piece belongs to the first player (uppercase)

Examples:

Sashite::Pnn::Name.parse("KING").first_player?     # => true
Sashite::Pnn::Name.parse("queen").first_player?    # => false
Sashite::Pnn::Name.parse("KING^").first_player?    # => true

Returns:

  • (Boolean)

    true if first player, false otherwise



153
154
155
# File 'lib/sashite/pnn/name.rb', line 153

def first_player?
  @parsed[:base_name] == @parsed[:base_name].upcase
end

#hashInteger

Hash based on class and value

Returns:

  • (Integer)


203
204
205
# File 'lib/sashite/pnn/name.rb', line 203

def hash
  [self.class, value].hash
end

#normal?Boolean

Check if the piece has normal state (no modifier)

Examples:

Sashite::Pnn::Name.parse("KING").normal?       # => true
Sashite::Pnn::Name.parse("+KING").normal?      # => false
Sashite::Pnn::Name.parse("KING^").normal?      # => true

Returns:

  • (Boolean)

    true if normal, false otherwise



128
129
130
# File 'lib/sashite/pnn/name.rb', line 128

def normal?
  @parsed[:state_modifier].empty?
end

#same_base_name?(other) ⇒ Boolean

Check if another piece has the same base name (ignoring case, state, and terminal marker)

Examples:

king = Sashite::Pnn::Name.parse("KING")
queen = Sashite::Pnn::Name.parse("king")
enhanced = Sashite::Pnn::Name.parse("+KING")
terminal = Sashite::Pnn::Name.parse("KING^")

king.same_base_name?(queen)     # => true (same piece, different player)
king.same_base_name?(enhanced)  # => true (same piece, different state)
king.same_base_name?(terminal)  # => true (same piece, terminal marker)

Parameters:

  • other (Name)

    another piece name to compare

Returns:

  • (Boolean)

    true if same base name, false otherwise



183
184
185
186
187
# File 'lib/sashite/pnn/name.rb', line 183

def same_base_name?(other)
  return false unless other.is_a?(self.class)

  base_name.downcase == other.base_name.downcase
end

#second_player?Boolean

Check if the piece belongs to the second player (lowercase)

Examples:

Sashite::Pnn::Name.parse("king").second_player?    # => true
Sashite::Pnn::Name.parse("QUEEN").second_player?   # => false
Sashite::Pnn::Name.parse("king^").second_player?   # => true

Returns:

  • (Boolean)

    true if second player, false otherwise



165
166
167
# File 'lib/sashite/pnn/name.rb', line 165

def second_player?
  @parsed[:base_name] == @parsed[:base_name].downcase
end

#terminal?Boolean

Check if the piece is a terminal piece (has ^ marker)

Examples:

Sashite::Pnn::Name.parse("KING^").terminal?    # => true
Sashite::Pnn::Name.parse("KING").terminal?     # => false
Sashite::Pnn::Name.parse("+KING^").terminal?   # => true
Sashite::Pnn::Name.parse("-pawn^").terminal?   # => true

Returns:

  • (Boolean)

    true if terminal, false otherwise



141
142
143
# File 'lib/sashite/pnn/name.rb', line 141

def terminal?
  @parsed[:terminal_marker] == "^"
end

#to_sString

Returns the string representation of the name

Returns:

  • (String)


78
79
80
# File 'lib/sashite/pnn/name.rb', line 78

def to_s
  value
end