Class: Sashite::Feen::Placement

Inherits:
Object
  • Object
show all
Defined in:
lib/sashite/feen/placement.rb

Overview

Immutable representation of board piece placement.

Stores board configuration as a flat array of ranks with explicit separators, allowing representation of any valid FEEN structure including highly irregular multi-dimensional boards.

This design supports complete flexibility:

  • Any number of dimensions (1D to nD)

  • Irregular board shapes (different rank sizes)

  • Arbitrary separator patterns (different separator lengths)

Examples:

1D board (no separators)

ranks = [[king, nil, pawn]]
placement = Placement.new(ranks)

Regular 2D board

ranks = [
  [rook, knight, bishop, queen, king, bishop, knight, rook],
  [pawn, pawn, pawn, pawn, pawn, pawn, pawn, pawn],
  # ... 6 more ranks
]
separators = ["/", "/", "/", "/", "/", "/", "/"]
placement = Placement.new(ranks, separators)

Irregular 3D board

ranks = [[r1], [r2], [r3], [r4]]
separators = ["/", "//", "/"]  # Mixed dimension separators
placement = Placement.new(ranks, separators)

Highly irregular structure

# "99999/3///K/k//r"
ranks = [[nil]*99999, [nil]*3, [king], [king_b], [rook]]
separators = ["/", "///", "/", "//"]
placement = Placement.new(ranks, separators)

See Also:

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ranks, separators = [], dimension = nil) ⇒ Placement

Create a new immutable Placement object.

Examples:

Create 1D placement

Placement.new([[king, nil, pawn]])

Create 2D placement

Placement.new(
  [[rank1_pieces], [rank2_pieces]],
  ["/"]
)

Create 3D placement with explicit dimension

Placement.new(
  [[r1], [r2], [r3]],
  ["/", "//"],
  3
)

Parameters:

  • ranks (Array<Array>)

    Array of ranks (each rank is array of pieces/nils)

  • separators (Array<String>) (defaults to: [])

    Separators between ranks (default: [])

  • dimension (Integer, nil) (defaults to: nil)

    Explicit dimension (auto-calculated if nil)

Raises:

  • (ArgumentError)

    If separators count doesn’t match ranks

  • (ArgumentError)

    If any separator is invalid

  • (ArgumentError)

    If dimension is less than 1



86
87
88
89
90
91
92
93
# File 'lib/sashite/feen/placement.rb', line 86

def initialize(ranks, separators = [], dimension = nil)
  @ranks = deep_freeze_ranks(ranks)
  @separators = separators.freeze
  @dimension = dimension || calculate_dimension(separators)

  validate!
  freeze
end

Instance Attribute Details

#dimensionInteger (readonly)

Returns Board dimensionality Calculated as: 1 + (maximum consecutive “/” characters in any separator) Examples:

- No separators → 1D
- Only "/" → 2D
- At least one "//" → 3D
- At least one "///" → 4D.

Returns:

  • (Integer)

    Board dimensionality Calculated as: 1 + (maximum consecutive “/” characters in any separator) Examples:

    - No separators → 1D
    - Only "/" → 2D
    - At least one "//" → 3D
    - At least one "///" → 4D
    


59
60
61
# File 'lib/sashite/feen/placement.rb', line 59

def dimension
  @dimension
end

#ranksArray<Array> (readonly)

Returns Flat array of all ranks Each rank is an array containing piece objects and/or nils.

Returns:

  • (Array<Array>)

    Flat array of all ranks Each rank is an array containing piece objects and/or nils



44
45
46
# File 'lib/sashite/feen/placement.rb', line 44

def ranks
  @ranks
end

#separatorsArray<String> (readonly)

Returns Separators between consecutive ranks separators is the separator between ranks and ranks Each separator is a string of one or more “/” characters Always has length = ranks.length - 1 (or empty for single rank).

Returns:

  • (Array<String>)

    Separators between consecutive ranks separators is the separator between ranks and ranks Each separator is a string of one or more “/” characters Always has length = ranks.length - 1 (or empty for single rank)



50
51
52
# File 'lib/sashite/feen/placement.rb', line 50

def separators
  @separators
end

Instance Method Details

#==(other) ⇒ Boolean Also known as: eql?

Compare two placements for equality.

Two placements are equal if they have the same ranks, separators, and dimension.

Examples:

placement1 == placement2  # => true (if identical)

Parameters:

  • other (Placement)

    Another placement object

Returns:

  • (Boolean)

    True if all attributes are equal



187
188
189
190
191
192
# File 'lib/sashite/feen/placement.rb', line 187

def ==(other)
  other.is_a?(Placement) &&
    ranks == other.ranks &&
    separators == other.separators &&
    dimension == other.dimension
end

#all_piecesArray

Get all pieces from all ranks (flattened).

Examples:

placement.all_pieces.size  # => 32 (for chess starting position)

Returns:

  • (Array)

    Flat array of all pieces (nils excluded)



121
122
123
# File 'lib/sashite/feen/placement.rb', line 121

def all_pieces
  @ranks.flatten.compact
end

#hashInteger

Generate hash code for placement.

Ensures that equal placements have equal hash codes for use in hash-based collections.

Examples:

placement1.hash == placement2.hash  # => true (if equal)

Returns:

  • (Integer)

    Hash code based on ranks, separators, and dimension



205
206
207
# File 'lib/sashite/feen/placement.rb', line 205

def hash
  [ranks, separators, dimension].hash
end

#inspectString

Get a human-readable representation of the placement.

Examples:

placement.inspect
# => "#<Sashite::Feen::Placement dimension=2 ranks=8 separators=7>"

Returns:

  • (String)

    Debug representation



216
217
218
# File 'lib/sashite/feen/placement.rb', line 216

def inspect
  "#<#{self.class.name} dimension=#{dimension} ranks=#{rank_count} separators=#{separators.size}>"
end

#one_dimensional?Boolean

Check if the board is 1-dimensional (single rank, no separators).

Examples:

placement.one_dimensional?  # => false (for 2D chess board)

Returns:

  • (Boolean)

    True if dimension is 1



111
112
113
# File 'lib/sashite/feen/placement.rb', line 111

def one_dimensional?
  @dimension == 1
end

#rank_countInteger

Get total number of ranks across all dimensions.

Examples:

placement.rank_count  # => 8 (for standard chess board)

Returns:

  • (Integer)

    Total rank count



101
102
103
# File 'lib/sashite/feen/placement.rb', line 101

def rank_count
  @ranks.size
end

#to_aArray

Convert placement to array representation based on dimensionality.

The returned structure depends on board dimension:

  • 1D boards: Returns single rank array (or empty array if no ranks)

  • 2D+ boards: Returns array of ranks

Examples:

1D board (single rank)

placement = Placement.new([[K, nil, P]], [], 1)
placement.to_a  # => [K, nil, P]

1D empty board

placement = Placement.new([], [], 1)
placement.to_a  # => []

2D board (multiple ranks)

placement = Placement.new([[r, n], [p, p]], ["/"], 2)
placement.to_a  # => [[r, n], [p, p]]

3D board (returns flat array of all ranks)

placement = Placement.new([[r], [n], [b]], ["/", "//"], 3)
placement.to_a  # => [[r], [n], [b]]

Returns:

  • (Array)

    Array representation of the board



158
159
160
161
162
# File 'lib/sashite/feen/placement.rb', line 158

def to_a
  return ranks.first || [] if one_dimensional?

  ranks
end

#to_sString

Convert placement to its FEEN string representation.

Delegates to Dumper::PiecePlacement for canonical serialization.

Examples:

placement.to_s
# => "+rnbq+kbn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+KBN+R"

Returns:

  • (String)

    FEEN piece placement field



173
174
175
# File 'lib/sashite/feen/placement.rb', line 173

def to_s
  Dumper::PiecePlacement.dump(self)
end

#total_squaresInteger

Get total number of squares across all ranks.

Examples:

placement.total_squares  # => 64 (for 8x8 chess board)

Returns:

  • (Integer)

    Total square count



131
132
133
# File 'lib/sashite/feen/placement.rb', line 131

def total_squares
  @ranks.sum(&:size)
end