Class: Sashite::Epin

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

Overview

EPIN (Extended Piece Identifier Notation) implementation for Ruby.

EPIN extends PIN by adding a **derivation marker** to track piece style in cross-style games.

**EPIN is simply: PIN + optional style derivation marker (‘’‘)**

Format

<pin-token>[<derivation-marker>]

Where <pin-token> is a valid PIN token and <derivation-marker> is an optional trailing apostrophe (').

Five Fundamental Attributes

EPIN exposes all five attributes from the Sashité Game Protocol:

  • *Piece Name* ↑ epin.pin.type

  • *Piece Side* ↑ epin.pin.side

  • *Piece State* ↑ epin.pin.state

  • *Terminal Status* ↑ epin.pin.terminal

  • *Piece Style* ↑ epin.derived (native vs derived)

Examples

epin = Sashite::Epin.parse("K^'")
epin.pin.type      # => :K
epin.pin.terminal  # => true
epin.derived       # => true

pin = Sashite::Pin.parse("K^")
epin = Sashite::Epin.new(pin, derived: true)
epin.to_s  # => "K^'"

Sashite::Epin.valid?("K^'")   # => true
Sashite::Epin.valid?("K'^")   # => false

See the EPIN Specification (sashite.dev/specs/epin/1.0.0/) for details.

Constant Summary collapse

EPIN_PATTERN =

Pattern for validating EPIN strings

/\A(?<pin>[-+]?[A-Za-z]\^?)(?<derived>')?\z/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pin, derived: false) ⇒ Epin

Creates a new EPIN instance from a PIN component.

Examples:

pin = Sashite::Pin.parse("K^")
Sashite::Epin.new(pin)
# => #<Sashite::Epin K^>

Sashite::Epin.new(pin, derived: true)
# => #<Sashite::Epin K^'>

Parameters:

  • pin (Sashite::Pin)

    The underlying PIN instance

  • derived (Boolean) (defaults to: false)

    Derivation status (default: false)

Raises:

  • (ArgumentError)


72
73
74
75
76
77
78
79
# File 'lib/sashite/epin.rb', line 72

def initialize(pin, derived: false)
  raise ArgumentError, "Expected a Sashite::Pin instance, got: #{pin.inspect}" unless pin.is_a?(Pin)

  @pin = pin
  @derived = !!derived

  freeze
end

Instance Attribute Details

#derivedBoolean (readonly)

Returns Derivation status (true = derived, false = native).

Returns:

  • (Boolean)

    Derivation status (true = derived, false = native)



53
54
55
# File 'lib/sashite/epin.rb', line 53

def derived
  @derived
end

#pinSashite::Pin (readonly)

Returns The underlying PIN component.

Returns:

  • (Sashite::Pin)

    The underlying PIN component



50
51
52
# File 'lib/sashite/epin.rb', line 50

def pin
  @pin
end

Class Method Details

.parse(epin_string) ⇒ Epin

Parses an EPIN string into an Epin instance.

Examples:

Sashite::Epin.parse("K")
# => #<Sashite::Epin K>

Sashite::Epin.parse("K'")
# => #<Sashite::Epin K'>

Sashite::Epin.parse("+R^'")
# => #<Sashite::Epin +R^'>

Sashite::Epin.parse("invalid")
# => ArgumentError: Invalid EPIN string: invalid

Parameters:

  • epin_string (String)

    The EPIN string to parse

Returns:

  • (Epin)

    A new Epin instance

Raises:

  • (ArgumentError)

    If the string is not a valid EPIN



99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/sashite/epin.rb', line 99

def self.parse(epin_string)
  raise ArgumentError, "Invalid EPIN string: #{epin_string.inspect}" unless epin_string.is_a?(String)

  match = EPIN_PATTERN.match(epin_string)
  raise ArgumentError, "Invalid EPIN string: #{epin_string}" unless match

  pin_string = match[:pin]
  derived_marker = match[:derived]

  pin = Pin.parse(pin_string)
  derived = derived_marker == "'"

  new(pin, derived: derived)
end

.valid?(epin_string) ⇒ Boolean

Checks if a string is a valid EPIN notation.

Examples:

Sashite::Epin.valid?("K")      # => true
Sashite::Epin.valid?("K'")     # => true
Sashite::Epin.valid?("+R^'")   # => true
Sashite::Epin.valid?("K'^")    # => false
Sashite::Epin.valid?("K''")    # => false
Sashite::Epin.valid?("invalid") # => false

Parameters:

  • epin_string (String)

    The string to validate

Returns:

  • (Boolean)

    true if valid, false otherwise



126
127
128
129
130
# File 'lib/sashite/epin.rb', line 126

def self.valid?(epin_string)
  return false unless epin_string.is_a?(String)

  EPIN_PATTERN.match?(epin_string)
end

Instance Method Details

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

Checks equality with another Epin.

Parameters:

  • other (Object)

    The object to compare

Returns:

  • (Boolean)

    true if equal



270
271
272
273
274
# File 'lib/sashite/epin.rb', line 270

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

  pin == other.pin && derived == other.derived
end

#derived?Boolean

Checks if the Epin is derived (uses opponent’s style).

Examples:

Sashite::Epin.parse("K^'").derived?  # => true
Sashite::Epin.parse("K^").derived?   # => false

Returns:

  • (Boolean)

    true if derived



229
230
231
# File 'lib/sashite/epin.rb', line 229

def derived?
  derived
end

#hashInteger

Returns a hash code for the Epin.

Returns:

  • (Integer)

    Hash code



281
282
283
# File 'lib/sashite/epin.rb', line 281

def hash
  [pin, derived].hash
end

#inspectString

Returns an inspect string for the Epin.

Returns:

  • (String)

    Inspect representation



288
289
290
# File 'lib/sashite/epin.rb', line 288

def inspect
  "#<#{self.class} #{self}>"
end

#mark_derivedEpin

Returns a new Epin marked as derived.

Examples:

epin = Sashite::Epin.parse("K^")
epin.mark_derived.derived
# => true

Returns:

  • (Epin)

    A new Epin with derived: true



198
199
200
201
202
# File 'lib/sashite/epin.rb', line 198

def mark_derived
  return self if derived

  self.class.new(pin, derived: true)
end

#native?Boolean

Checks if the Epin is native (uses own side’s style).

Examples:

Sashite::Epin.parse("K^").native?   # => true
Sashite::Epin.parse("K^'").native?  # => false

Returns:

  • (Boolean)

    true if native



240
241
242
# File 'lib/sashite/epin.rb', line 240

def native?
  !derived
end

#same_derived?(other) ⇒ Boolean

Checks if two Epins have the same derivation status.

Examples:

epin1 = Sashite::Epin.parse("K^'")
epin2 = Sashite::Epin.parse("Q'")
epin1.same_derived?(epin2)
# => true

epin3 = Sashite::Epin.parse("K^")
epin1.same_derived?(epin3)
# => false

Parameters:

  • other (Epin)

    The other Epin to compare

Returns:

  • (Boolean)

    true if same derivation status



258
259
260
# File 'lib/sashite/epin.rb', line 258

def same_derived?(other)
  derived == other.derived
end

#to_sString

Converts the Epin to its string representation.

Examples:

pin = Sashite::Pin.parse("K^")
Sashite::Epin.new(pin).to_s
# => "K^"

Sashite::Epin.new(pin, derived: true).to_s
# => "K^'"

Returns:

  • (String)

    The EPIN string



147
148
149
# File 'lib/sashite/epin.rb', line 147

def to_s
  "#{pin}#{derivation_suffix}"
end

#unmark_derivedEpin

Returns a new Epin marked as native (not derived).

Examples:

epin = Sashite::Epin.parse("K^'")
epin.unmark_derived.derived
# => false

Returns:

  • (Epin)

    A new Epin with derived: false



212
213
214
215
216
# File 'lib/sashite/epin.rb', line 212

def unmark_derived
  return self unless derived

  self.class.new(pin, derived: false)
end

#with_derived(new_derived) ⇒ Epin

Returns a new Epin with a different derivation status.

Examples:

epin = Sashite::Epin.parse("K^")
epin.with_derived(true).to_s
# => "K^'"

epin = Sashite::Epin.parse("K^'")
epin.with_derived(false).to_s
# => "K^"

Parameters:

  • new_derived (Boolean)

    The new derivation status

Returns:

  • (Epin)

    A new Epin with the specified derivation status



184
185
186
187
188
# File 'lib/sashite/epin.rb', line 184

def with_derived(new_derived)
  return self if derived == !!new_derived

  self.class.new(pin, derived: !!new_derived)
end

#with_pin(new_pin) ⇒ Epin

Returns a new Epin with a different PIN component.

Examples:

epin = Sashite::Epin.parse("K^'")
new_pin = epin.pin.with_type(:Q)
epin.with_pin(new_pin).to_s
# => "Q^'"

Parameters:

  • new_pin (Sashite::Pin)

    The new PIN component

Returns:

  • (Epin)

    A new Epin with the specified PIN



165
166
167
168
169
# File 'lib/sashite/epin.rb', line 165

def with_pin(new_pin)
  return self if pin == new_pin

  self.class.new(new_pin, derived: derived)
end