-
Notifications
You must be signed in to change notification settings - Fork 0
Building Positions
Cyril Kato edited this page Oct 5, 2025
·
1 revision
FEEN positions can be built programmatically by constructing the three core components: Placement, Hands, and Styles. This is useful for generating positions, testing, or creating game engines.
A position requires three components:
require "sashite/feen"
# 1. Build Placement (board configuration)
ranks = [
[nil, nil, nil, nil, nil, nil, nil, nil],
[nil, nil, nil, nil, nil, nil, nil, nil],
[nil, nil, nil, nil, nil, nil, nil, nil],
[nil, nil, nil, nil, nil, nil, nil, nil],
[nil, nil, nil, nil, nil, nil, nil, nil],
[nil, nil, nil, nil, nil, nil, nil, nil],
[nil, nil, nil, nil, nil, nil, nil, nil],
[nil, nil, nil, nil, nil, nil, nil, nil]
]
separators = ["/", "/", "/", "/", "/", "/", "/"]
placement = Sashite::Feen::Placement.new(ranks, separators, 2)
# 2. Build Hands (captured pieces)
hands = Sashite::Feen::Hands.new([], [])
# 3. Build Styles (game style and turn)
active = Sashite::Sin.parse("C")
inactive = Sashite::Sin.parse("c")
styles = Sashite::Feen::Styles.new(active, inactive)
# 4. Create Position
position = Sashite::Feen::Position.new(placement, hands, styles)
puts position.to_s
# => "8/8/8/8/8/8/8/8 / C/c"Create pieces using EPIN and place them on the board:
# Parse pieces from EPIN strings
white_king = Sashite::Epin.parse("K")
white_queen = Sashite::Epin.parse("Q")
white_rook = Sashite::Epin.parse("R")
black_king = Sashite::Epin.parse("k")
black_queen = Sashite::Epin.parse("q")
black_rook = Sashite::Epin.parse("r")
# Build ranks (8×8 board)
ranks = [
[black_rook, nil, nil, black_queen, black_king, nil, nil, black_rook],
Array.new(8, nil),
Array.new(8, nil),
Array.new(8, nil),
Array.new(8, nil),
Array.new(8, nil),
Array.new(8, nil),
[white_rook, nil, nil, white_queen, white_king, nil, nil, white_rook]
]
separators = ["/"] * 7
placement = Sashite::Feen::Placement.new(ranks, separators, 2)
hands = Sashite::Feen::Hands.new([], [])
styles = Sashite::Feen::Styles.new(
Sashite::Sin.parse("C"),
Sashite::Sin.parse("c")
)
position = Sashite::Feen::Position.new(placement, hands, styles)
puts position.to_s
# => "r2qk2r/8/8/8/8/8/8/R2QK2R / C/c"Build hands with captured pieces:
# Create pieces for hands
white_pawns = [
Sashite::Epin.parse("P"),
Sashite::Epin.parse("P")
]
black_pawn = Sashite::Epin.parse("p")
# Empty board for clarity
ranks = [Array.new(8, nil)] * 8
separators = ["/"] * 7
placement = Sashite::Feen::Placement.new(ranks, separators, 2)
# Hands with captured pieces
hands = Sashite::Feen::Hands.new(white_pawns, [black_pawn])
styles = Sashite::Feen::Styles.new(
Sashite::Sin.parse("C"),
Sashite::Sin.parse("c")
)
position = Sashite::Feen::Position.new(placement, hands, styles)
puts position.to_s
# => "8/8/8/8/8/8/8/8 2P/p C/c"For one-dimensional boards, use empty separators:
# Single rank (1D board)
king = Sashite::Epin.parse("K")
pawn = Sashite::Epin.parse("P")
enemy_king = Sashite::Epin.parse("k")
ranks = [[king, nil, nil, pawn, nil, nil, nil, enemy_king]]
separators = [] # No separators for 1D
placement = Sashite::Feen::Placement.new(ranks, separators, 1)
hands = Sashite::Feen::Hands.new([], [])
styles = Sashite::Feen::Styles.new(
Sashite::Sin.parse("C"),
Sashite::Sin.parse("c")
)
position = Sashite::Feen::Position.new(placement, hands, styles)
puts position.to_s
# => "K2P3k / C/c"
puts position.placement.one_dimensional?
# => trueUse double slashes for three-dimensional boards:
# Simple 2×2×2 cube
ranks = [
[nil, nil], # Plane 1, Rank 1
[nil, nil], # Plane 1, Rank 2
[nil, nil], # Plane 2, Rank 1
[nil, nil] # Plane 2, Rank 2
]
# Single "/" between ranks, "//" between planes
separators = ["/", "//", "/"]
placement = Sashite::Feen::Placement.new(ranks, separators, 3)
hands = Sashite::Feen::Hands.new([], [])
styles = Sashite::Feen::Styles.new(
Sashite::Sin.parse("R"),
Sashite::Sin.parse("r")
)
position = Sashite::Feen::Position.new(placement, hands, styles)
puts position.to_s
# => "2/2//2/2 / R/r"
puts position.placement.dimension
# => 3Create pieces with enhanced or diminished states:
# Enhanced pieces (promoted/upgraded)
enhanced_rook = Sashite::Epin.parse("+R")
enhanced_pawn = Sashite::Epin.parse("+P")
# Diminished pieces (weakened/restricted)
diminished_king = Sashite::Epin.parse("-K")
# Foreign pieces (using opponent's style)
foreign_pawn = Sashite::Epin.parse("p'")
ranks = [
[enhanced_rook, enhanced_pawn, nil, nil, nil, nil, nil, nil],
Array.new(8, nil),
Array.new(8, nil),
Array.new(8, nil),
Array.new(8, nil),
Array.new(8, nil),
Array.new(8, nil),
[nil, nil, nil, nil, nil, nil, diminished_king, nil]
]
separators = ["/"] * 7
placement = Sashite::Feen::Placement.new(ranks, separators, 2)
hands = Sashite::Feen::Hands.new([foreign_pawn], [])
styles = Sashite::Feen::Styles.new(
Sashite::Sin.parse("C"),
Sashite::Sin.parse("s")
)
position = Sashite::Feen::Position.new(placement, hands, styles)
puts position.to_s
# => "+R+P6/8/8/8/8/8/8/6-K1 p'/ C/s"Create a builder function for common scenarios:
def empty_chess_position(active_player: :white)
ranks = [Array.new(8, nil)] * 8
separators = ["/"] * 7
placement = Sashite::Feen::Placement.new(ranks, separators, 2)
hands = Sashite::Feen::Hands.new([], [])
active, inactive = if active_player == :white
[Sashite::Sin.parse("C"), Sashite::Sin.parse("c")]
else
[Sashite::Sin.parse("c"), Sashite::Sin.parse("C")]
end
styles = Sashite::Feen::Styles.new(active, inactive)
Sashite::Feen::Position.new(placement, hands, styles)
end
# Use the helper
position = empty_chess_position(active_player: :black)
puts position.to_s
# => "8/8/8/8/8/8/8/8 / c/C"Positions are immutable, so create new instances for changes:
original = Sashite::Feen.parse("8/8/8/8/8/8/8/8 / C/c")
# To "modify", create a new position with changed component
new_styles = Sashite::Feen::Styles.new(
original.styles.inactive, # Swap active/inactive
original.styles.active
)
updated = Sashite::Feen::Position.new(
original.placement,
original.hands,
new_styles
)
puts original.to_s
# => "8/8/8/8/8/8/8/8 / C/c"
puts updated.to_s
# => "8/8/8/8/8/8/8/8 / c/C"- Build positions from three components: Placement, Hands, Styles
- Use EPIN to create piece objects with states and derivation
- Use SIN to create style identifiers
- Ranks and separators define board structure
- All components are immutable - create new instances to "modify"
- Helper functions can simplify common position creation patterns