Class: Sashite::Ggn::Ruleset::Source::Destination::Engine

Inherits:
Object
  • Object
show all
Includes:
MoveValidator
Defined in:
lib/sashite/ggn/ruleset/source/destination/engine.rb,
lib/sashite/ggn/ruleset/source/destination/engine/transition.rb

Overview

Evaluates pseudo-legal move conditions for a specific source-destination pair.

The Engine is the core logic component that determines whether a move is valid under the basic movement constraints defined in GGN. It evaluates require/prevent conditions and returns the resulting board transformation.

Since GGN focuses exclusively on board-to-board transformations, the Engine only handles pieces moving, capturing, or transforming on the game board.

The class uses a functional approach with filter_map for optimal performance and clean, readable code that avoids mutation of external variables.

Examples:

Evaluating a simple move

engine = destinations.to('e4')
transitions = engine.where(board_state, 'CHESS')
puts "Move valid!" if transitions.any?

Handling promotion choices

engine = destinations.to('e8')  # pawn promotion
transitions = engine.where(board_state, 'CHESS')
transitions.each_with_index do |t, i|
  puts "Choice #{i + 1}: promotes to #{t.diff['e8']}"
end

Defined Under Namespace

Classes: Transition

Constant Summary

Constants included from MoveValidator

MoveValidator::GAN_SEPARATOR

Instance Method Summary collapse

Constructor Details

#initialize(*transitions, actor:, origin:, target:) ⇒ Engine

Creates a new Engine with conditional transition rules.

Examples:

Creating an engine for a pawn move

transition_rules = [
  {
    "require" => { "e4" => "empty", "e3" => "empty" },
    "perform" => { "e2" => nil, "e4" => "CHESS:P" }
  }
]
engine = Engine.new(*transition_rules, actor: "CHESS:P", origin: "e2", target: "e4")

Parameters:

  • transitions (Array)

    Transition rules as individual arguments, each containing require/prevent conditions and perform actions.

  • actor (String)

    GAN identifier of the piece being moved

  • origin (String)

    Source square

  • target (String)

    Destination square

Raises:

  • (ArgumentError)

    If parameters are invalid



55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/sashite/ggn/ruleset/source/destination/engine.rb', line 55

def initialize(*transitions, actor:, origin:, target:)
  raise ::ArgumentError, "actor must be a String" unless actor.is_a?(::String)
  raise ::ArgumentError, "origin must be a String" unless origin.is_a?(::String)
  raise ::ArgumentError, "target must be a String" unless target.is_a?(::String)

  @transitions = transitions
  @actor = actor
  @origin = origin
  @target = target

  freeze
end

Instance Method Details

#where(board_state, active_game) ⇒ Array<Transition>

Evaluates move validity and returns all resulting transitions.

Uses a functional approach with filter_map to process transitions efficiently. This method checks each conditional transition and returns all that match the current board state, supporting multiple promotion choices and optional transformations as defined in the GGN specification.

Examples:

Single valid move

board_state = { 'e2' => 'CHESS:P', 'e3' => nil, 'e4' => nil }
transitions = engine.where(board_state, 'CHESS')
transitions.size  # => 1
transitions.first.diff  # => { 'e2' => nil, 'e4' => 'CHESS:P' }

Multiple promotion choices

board_state = { 'e7' => 'CHESS:P', 'e8' => nil }
transitions = engine.where(board_state, 'CHESS')
transitions.size  # => 4 (Queen, Rook, Bishop, Knight)
transitions.map { |t| t.diff['e8'] }  # => ['CHESS:Q', 'CHESS:R', 'CHESS:B', 'CHESS:N']

Invalid move (wrong piece)

board_state = { 'e2' => 'CHESS:Q', 'e3' => nil, 'e4' => nil }
transitions = engine.where(board_state, 'CHESS')  # => []

Invalid move (blocked path)

board_state = { 'e2' => 'CHESS:P', 'e3' => 'CHESS:N', 'e4' => nil }
transitions = engine.where(board_state, 'CHESS')  # => []

Parameters:

  • board_state (Hash)

    Current board state mapping square labels to piece identifiers (nil for empty squares)

  • active_game (String)

    Current player’s game identifier (e.g., ‘CHESS’, ‘shogi’). This corresponds to the first element of the GAMES-TURN field in FEEN notation.

Returns:

  • (Array<Transition>)

    Array of Transition objects for all valid variants, empty array if no valid transitions exist

Raises:

  • (ArgumentError)

    If any parameter is invalid or malformed



104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/sashite/ggn/ruleset/source/destination/engine.rb', line 104

def where(board_state, active_game)
  # Validate all input parameters before processing
  validate_parameters!(board_state, active_game)

  # Early return if basic move context is invalid (wrong piece, wrong player, etc.)
  return [] unless valid_move_context?(board_state, active_game)

  # Use filter_map for functional approach: filter valid transitions and map to Transition objects
  # This avoids mutation and is more performant than select + map for large datasets
  @transitions.filter_map do |transition|
    # Only create Transition objects for transitions that match current board state
    create_transition(transition) if transition_matches?(transition, board_state, active_game)
  end
end