Skip to content

Instantly share code, notes, and snippets.

@ThingEngineer
Created March 6, 2025 17:59
Show Gist options
  • Save ThingEngineer/37520c5738aebcf883db9485d964accc to your computer and use it in GitHub Desktop.
Save ThingEngineer/37520c5738aebcf883db9485d964accc to your computer and use it in GitHub Desktop.
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"}
    }'
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment