CREATE OR REPLACE FUNCTION v_knight(
piece_id VARCHAR, -- ID of the piece being moved
target_pos VARCHAR, -- Target position in chess notation
board_state JSONB -- JSON containing all pieces and their positions
)
RETURNS TABLE (
is_valid BOOLEAN,
message VARCHAR
) AS $$
DECLARE
curr_file INTEGER;
curr_rank INTEGER;
target_file INTEGER;
target_rank INTEGER;
file_diff INTEGER;
rank_diff INTEGER;
piece_color VARCHAR;
piece_type VARCHAR;
current_pos VARCHAR;
target_piece JSONB;
moving_piece JSONB;
BEGIN
-- Get piece information from board state
moving_piece := board_state->piece_id;
IF moving_piece IS NULL THEN
RETURN QUERY SELECT FALSE, 'Piece not found in board state';
RETURN;
END IF;
piece_type := moving_piece->>'type';
piece_color := moving_piece->>'color';
current_pos := moving_piece->>'position';
-- Validate piece type
IF piece_type != 'knight' THEN
RETURN QUERY SELECT FALSE, 'This function only validates knight moves';
RETURN;
END IF;
-- Convert chess notation to numerical coordinates
curr_file := ASCII(LOWER(SUBSTRING(current_pos, 1, 1))) - ASCII('a') + 1;
curr_rank := SUBSTRING(current_pos, 2, 1)::INTEGER;
target_file := ASCII(LOWER(SUBSTRING(target_pos, 1, 1))) - ASCII('a') + 1;
target_rank := SUBSTRING(target_pos, 2, 1)::INTEGER;
-- Check if positions are valid chess coordinates
IF curr_file < 1 OR curr_file > 8 OR curr_rank < 1 OR curr_rank > 8 OR
target_file < 1 OR target_file > 8 OR target_rank < 1 OR target_rank > 8 THEN
RETURN QUERY SELECT FALSE, 'Invalid chess coordinates';
RETURN;
END IF;
-- Calculate difference between positions
file_diff := ABS(target_file - curr_file);
rank_diff := ABS(target_rank - curr_rank);
-- Knight movement validation (L-shape: 2 squares in one direction, 1 in the other)
IF NOT ((file_diff = 2 AND rank_diff = 1) OR (file_diff = 1 AND rank_diff = 2)) THEN
RETURN QUERY SELECT FALSE, 'Invalid knight movement pattern';
RETURN;
END IF;
-- Check if target square has a piece of the same color
SELECT value INTO target_piece
FROM jsonb_each(board_state)
WHERE value->>'position' = target_pos;
IF target_piece IS NOT NULL AND target_piece->>'color' = piece_color THEN
RETURN QUERY SELECT FALSE, 'Cannot capture your own piece';
RETURN;
END IF;
-- All checks passed - valid move
RETURN QUERY SELECT TRUE, 'success';
END;
$$ LANGUAGE plpgsql;
Example v_knight call and board state in JSON format:
SELECT * FROM v_knight(
'white_knight1',
'c3',
'{
"white_knight1": {"type": "knight", "color": "white", "position": "b1"},
"white_pawn1": {"type": "pawn", "color": "white", "position": "a2"},
"black_pawn1": {"type": "pawn", "color": "black", "position": "c3"}
}'
);