class Ugoki::Position

The position abstraction.

Attributes

in_hand[R]

The list of pieces in hand.

@!attribute [r] in_hand

@return [Array] The list of pieces in hand.
in_hand_owned_pieces[R]

The list of pieces in hand owned by players.

@!attribute [r] in_hand_owned_pieces

@return [Array] The list of pieces in hand for the current side.
shape[R]

The shape of the board.

@!attribute [r] shape

@return [Array] The shape of the board.
side_id[R]

Players are identified by a number according to the order in which they traditionally play from the starting position.

@!attribute [r] side_id

@return [Integer] The identifier of the player who must play.
square[R]

The index of each piece on the board.

@!attribute [r] square

@return [Hash] The index of each piece on the board.
square_bottomside_pieces[R]

The index of each bottom-side piece on the board.

@!attribute [r] square_bottomside_pieces

@return [Hash] The index of each bottom-side piece on the board.
square_topside_pieces[R]

The index of each top-side piece on the board.

@!attribute [r] square_topside_pieces

@return [Hash] The index of each top-side piece on the board.

Public Class Methods

new(in_hand:, shape:, side_id:, square:) click to toggle source

Initialize a position.

@param in_hand [Array] The list of pieces in hand. @param shape [Array] The shape of the board. @param side_id [Integer] The identifier of the player who must play. @param square [Hash] The index of each piece on the board.

@example Dump a classic Tsume Shogi problem

new(
  "in_hand": [S r r b g g g g s n n n n p p p p p p p p p p p p p p p p p],
  "shape": [9, 9],
  "side_id": 0,
  "square": {
     3 => "s",
     4 => "k",
     5 => "s",
    22 => "+P",
    43 => "+B"
  }
)
# File lib/ugoki/position.rb, line 80
def initialize(in_hand:, shape:, side_id:, square:)
  @in_hand = in_hand
  @shape = shape
  @side_id = side_id
  @square = square

  @square_bottomside_pieces = square.select { |_, name| name.upcase == name }
  @square_topside_pieces = square.select { |_, name| name.downcase == name }

  @in_hand_owned_pieces = if turn_to_topside?
                            in_hand.select { |name| name.downcase == name }
                          else
                            in_hand.select { |name| name.upcase == name }
                          end
end
parse(feen) click to toggle source

@param feen [String] The FEEN string representing a position.

@see developer.sashite.com/specs/forsyth-edwards-expanded-notation

@return [Ugoki::Position] The state of the game.

# File lib/ugoki/position.rb, line 13
def self.parse(feen)
  new(**::FEEN::Parser.call(feen))
end

Public Instance Methods

match?(square_patterns) click to toggle source

@param square_patterns [Hash] A hash of integers and symbols.

@example A hash of square patterns

{ 10 => nil, 20 => nil, 30 => nil, 40 => nil, 50 => nil, 60 => nil, 70 => nil }

@return [Boolean] Is the position matching the given pattern?

# File lib/ugoki/position.rb, line 115
def match?(square_patterns)
  square_patterns.all? { |square_id, state| correct?(square_id, state) }
end
square_owned_pieces() click to toggle source

The list of pieces on the board owned by the current player, with squares.

@return [Hash] Top-side's pieces if turn to topside, bottom-side's ones

otherwise.
# File lib/ugoki/position.rb, line 100
def square_owned_pieces
  turn_to_topside? ? square_topside_pieces : square_bottomside_pieces
end
turn_to_topside?() click to toggle source

@return [Boolean] Is turn to top-side?

# File lib/ugoki/position.rb, line 105
def turn_to_topside?
  !side_id.zero?
end

Protected Instance Methods

correct?(square_id, state) click to toggle source

@param square_id [Integer] The square ID. @param state [Symbol] The state of the square.

@return [Boolean] Is the state of the square correct?

# File lib/ugoki/position.rb, line 125
def correct?(square_id, state)
  content = square_content(square_id)

  case state
  when :occupied
    !content.nil?
  when :enemy
    if turn_to_topside?
      !content.nil? && content.upcase == content
    else
      !content.nil? && content.downcase == content
    end
  else
    state == content
  end
end
square_content(square_id) click to toggle source

@param square_id [Integer] The square ID.

@return [String, nil] The square content.

# File lib/ugoki/position.rb, line 145
def square_content(square_id)
  square.fetch(square_id, nil)
end