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^'>

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)



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

def derived
  @derived
end

#pinSashite::Pin (readonly)



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

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


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.



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


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

def derived?
  derived
end

#hashInteger

Returns a hash code for the Epin.



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

def hash
  [pin, derived].hash
end

#inspectString

Returns an inspect string for the Epin.



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


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


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


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^'"


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


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^"


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^'"


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