Class: PortableMoveNotation::Move

Inherits:
Object
  • Object
show all
Defined in:
lib/portable_move_notation/move.rb

Overview

Move

A Move is an *ordered list* of Action instances that, applied **in order**, realise a deterministic change of game state under Portable Move Notation (PMN) v1.0.0. A move can be as small as a single pawn push or as large as a compound fairy‐move that relocates several pieces at once.

PMN v1.0.0 uses an array-of-arrays format where each inner array represents a single action: ‘[source_square, destination_square, piece_name, captured_piece]`

The class is deliberately **rule‑agnostic**: it guarantees only that the underlying data *matches the PMN schema*. Whether the move is legal in a given game is beyond its responsibility and must be enforced by an engine or referee layer.

Quick start

“‘ruby require “portable_move_notation”

# Plain chess pawn move: e2 → e4 pawn = PortableMoveNotation::Action.new(“e2”, “e4”, “P”, nil) move = PortableMoveNotation::Move.new(pawn) puts move.to_json # => [[“e2”,“e4”,“P”,null]]

parsed = PortableMoveNotation::Move.from_json(move.to_json) parsed.actions.first.dst_square # => “e4” “‘

Composite example (Chess kingside castling)

“‘ruby king = PortableMoveNotation::Action.new(“e1”, “g1”, “K”, nil) rook = PortableMoveNotation::Action.new(“h1”, “f1”, “R”, nil) castle = PortableMoveNotation::Move.new(king, rook) “`

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*actions) ⇒ Move

Parameters:

Raises:

  • (ArgumentError)

    If actions is empty or contains non‑Action items.



103
104
105
106
107
# File 'lib/portable_move_notation/move.rb', line 103

def initialize(*actions)
  validate_actions(actions)
  @actions = actions.freeze
  freeze
end

Instance Attribute Details

#actionsArray<Action> (readonly)

Returns Ordered, frozen list of actions.

Returns:

  • (Array<Action>)

    Ordered, frozen list of actions.



97
98
99
# File 'lib/portable_move_notation/move.rb', line 97

def actions
  @actions
end

Class Method Details

.from_json(json_string) ⇒ Move

Constructs a PortableMoveNotation::Move from its canonical JSON representation.

Examples:

json = '[["e2","e4","P",null]]'
PortableMoveNotation::Move.from_json(json)

Parameters:

  • json_string (String)

    PMN‑formatted JSON (array of action arrays).

Returns:

Raises:

  • (JSON::ParserError)

    If json_string is not valid JSON.

  • (ArgumentError)

    If an action array is malformed.



76
77
78
# File 'lib/portable_move_notation/move.rb', line 76

def self.from_json(json_string)
  from_pmn(::JSON.parse(json_string))
end

.from_pmn(pmn_array) ⇒ Move

Constructs a PortableMoveNotation::Move from an *already parsed* PMN array.

Parameters:

  • pmn_array (Array<Array>)

    PMN action arrays (4-element arrays).

Returns:

Raises:

  • (ArgumentError)

    If an action array is malformed.



85
86
87
88
89
90
# File 'lib/portable_move_notation/move.rb', line 85

def self.from_pmn(pmn_array)
  actions = pmn_array.map do |action_array|
    Action.from_array(action_array)
  end
  new(*actions)
end

.valid?(pmn_data) ⇒ Boolean

Validates that pmn_data is an **array of PMN action arrays**. The method does not instantiate Action objects on success; it merely checks that each element could be turned into one.

Examples:

Validate PMN parsed from JSON

data = JSON.parse('[["e2","e4","P",null]]')
PortableMoveNotation::Move.valid?(data)  # => true

Parameters:

  • pmn_data (Array<Array>)

    Raw PMN structure (array of 4-element arrays).

Returns:



60
61
62
63
64
# File 'lib/portable_move_notation/move.rb', line 60

def self.valid?(pmn_data)
  return false unless pmn_data.is_a?(::Array) && !pmn_data.empty?

  pmn_data.all? { |action_array| Action.valid?(action_array) }
end

Instance Method Details

#==(other) ⇒ Object

Compare moves based on their PMN array representation



136
137
138
# File 'lib/portable_move_notation/move.rb', line 136

def ==(other)
  other.is_a?(Move) && to_pmn == other.to_pmn
end

#[](index) ⇒ Object

Access individual actions by index



178
179
180
# File 'lib/portable_move_notation/move.rb', line 178

def [](index)
  actions[index]
end

#eachObject

Iterate over actions



173
174
175
# File 'lib/portable_move_notation/move.rb', line 173

def each(&)
  actions.each(&)
end

#empty?Boolean

Check if move is empty (shouldn’t happen with current validation)

Returns:

  • (Boolean)


168
169
170
# File 'lib/portable_move_notation/move.rb', line 168

def empty?
  actions.empty?
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


145
146
147
# File 'lib/portable_move_notation/move.rb', line 145

def eql?(other)
  self == other
end

#hashObject

Hash based on PMN array representation



141
142
143
# File 'lib/portable_move_notation/move.rb', line 141

def hash
  to_pmn.hash
end

#inspectObject

Human-readable string representation



150
151
152
# File 'lib/portable_move_notation/move.rb', line 150

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

#sizeObject

Number of actions in this move



163
164
165
# File 'lib/portable_move_notation/move.rb', line 163

def size
  actions.size
end

#to_json(*_args) ⇒ String

Converts the move to a **JSON string** following PMN v1.0.0 format.

Returns:

  • (String)

    JSON representation as array of action arrays



127
128
129
# File 'lib/portable_move_notation/move.rb', line 127

def to_json(*_args)
  ::JSON.generate(to_pmn)
end

#to_pmnArray<Array> Also known as: to_a

Converts the move to an **array of PMN action arrays**. This is the canonical PMN v1.0.0 format.

Returns:

  • (Array<Array>)

    Array of 4-element action arrays



117
118
119
# File 'lib/portable_move_notation/move.rb', line 117

def to_pmn
  actions.map(&:to_a)
end

#to_sObject



154
155
156
# File 'lib/portable_move_notation/move.rb', line 154

def to_s
  to_pmn.to_s
end