Module: Feen::Parser::PiecesInHand

Defined in:
lib/feen/parser/pieces_in_hand.rb

Overview

Handles parsing of the pieces in hand section of a FEEN string. Pieces in hand represent pieces available for dropping onto the board. According to FEEN v1.0.0 specification, pieces in hand MAY include PNN modifiers. Format: “UPPERCASE_PIECES/LOWERCASE_PIECES”

Constant Summary collapse

ERRORS =

Error messages for validation

{
  invalid_type:      "Pieces in hand must be a string, got %s",
  empty_string:      "Pieces in hand string cannot be empty",
  invalid_format:    "Invalid pieces in hand format: %s",
  missing_separator: "Pieces in hand format must contain exactly one '/' separator. Got: %s",
  invalid_pnn:       "Invalid PNN piece notation: '%s'",
  invalid_count:     "Invalid count format: '%s'. Count cannot be '0' or '1'"
}.freeze
VALID_COUNT_PATTERN =

Valid count pattern: 2-9 or any number with 2+ digits (no 0, 1, or leading zeros)

/\A(?:[2-9]|[1-9]\d+)\z/
PIECE_WITH_COUNT_PATTERN =

Pattern for piece with optional count in pieces in hand (with full PNN support)

/(?:([2-9]|[1-9]\d+))?([-+]?[a-zA-Z]'?)/
VALID_FORMAT_PATTERN =

Complete validation pattern for pieces in hand string (with PNN modifier support)

%r{\A
  (?:                                     # Uppercase section (optional)
    (?:(?:[2-9]|[1-9]\d+)?[-+]?[A-Z]'?)*  # Zero or more uppercase pieces with optional counts and modifiers
  )
  /                                       # Mandatory separator
  (?:                                     # Lowercase section (optional)
    (?:(?:[2-9]|[1-9]\d+)?[-+]?[a-z]'?)*  # Zero or more lowercase pieces with optional counts and modifiers
  )
\z}x

Class Method Summary collapse

Class Method Details

.parse(pieces_in_hand_str) ⇒ Array<String>

Parses the pieces in hand section of a FEEN string.

Examples:

Parse no pieces in hand

PiecesInHand.parse("/")
# => []

Parse pieces with case separation

PiecesInHand.parse("3P2B/p")
# => ["P", "P", "P", "B", "B", "p"]

Parse pieces with PNN modifiers

PiecesInHand.parse("2+B5BK3-P-P'3+P'9PR2SS'/bp")
# => ["+B", "+B", "B", "B", "B", "B", "B", "K", "-P", "-P", "-P", "-P'", "+P'", "+P'", "+P'", "P", "P", "P", "P", "P", "P", "P", "P", "P", "R", "S", "S", "S'", "b", "p"]

Parameters:

  • pieces_in_hand_str (String)

    FEEN pieces in hand string in format “UPPERCASE/lowercase”

Returns:

  • (Array<String>)

    Array of piece identifiers (may include PNN modifiers), expanded based on their counts. Pieces are returned in the order they appear in the canonical FEEN string (not sorted alphabetically).

Raises:

  • (ArgumentError)

    If the input string is invalid



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/feen/parser/pieces_in_hand.rb', line 58

def self.parse(pieces_in_hand_str)
  validate_input_type(pieces_in_hand_str)
  validate_format(pieces_in_hand_str)

  # Handle the no-pieces case early
  return [] if pieces_in_hand_str == "/"

  # Split by the separator to get uppercase and lowercase sections
  uppercase_section, lowercase_section = pieces_in_hand_str.split("/", 2)

  # Parse each section separately
  uppercase_pieces = parse_pieces_section(uppercase_section || "", :uppercase)
  lowercase_pieces = parse_pieces_section(lowercase_section || "", :lowercase)

  # Combine all pieces in order (uppercase first, then lowercase)
  # Do NOT sort - preserve the canonical order from the FEEN string
  uppercase_pieces + lowercase_pieces
end