277 lines
5.7 KiB
SQL
277 lines
5.7 KiB
SQL
-- A column of a matrix.
|
|
CREATE TYPE INTEGER_ARRAY AS INTEGER ARRAY[]@
|
|
-- The whole matrix of any size.
|
|
CREATE TYPE INTEGER_MATRIX AS INTEGER_ARRAY ARRAY[]@
|
|
|
|
/**
|
|
* Retrieves the value from a matrix at a specific position.
|
|
*
|
|
* IN X: Row number.
|
|
* IN Y: Column number.
|
|
* IN M: Matrix.
|
|
* RETURN the integer value at that position.
|
|
*/
|
|
CREATE OR REPLACE FUNCTION GET_INTEGER_VALUE(
|
|
IN X SMALLINT,
|
|
IN Y SMALLINT,
|
|
IN M INTEGER_MATRIX)
|
|
RETURNS INTEGER
|
|
F_GET_INTEGER_VALUE: BEGIN
|
|
DECLARE A INTEGER_ARRAY;
|
|
DECLARE RET INTEGER;
|
|
|
|
SET A = M[X];
|
|
SET RET = A[Y];
|
|
RETURN RET;
|
|
END F_GET_INTEGER_VALUE
|
|
@
|
|
|
|
/**
|
|
* Establishes the given value at a specific position in the matrix.
|
|
*
|
|
* IN X: Row number.
|
|
* IN Y: Column number.
|
|
* INOUT M: Matrix.
|
|
* IN VAL: Value to set in the matrix.
|
|
*/
|
|
CREATE OR REPLACE PROCEDURE SET_INTEGER_VALUE(
|
|
IN X SMALLINT,
|
|
IN Y SMALLINT,
|
|
INOUT M INTEGER_MATRIX,
|
|
IN VAL INTEGER)
|
|
P_SET_INTEGER_VALUE: BEGIN
|
|
DECLARE A INTEGER_ARRAY;
|
|
|
|
SET A = M[X];
|
|
SET A[Y] = VAL;
|
|
SET M[X] = A;
|
|
END P_SET_INTEGER_VALUE
|
|
@
|
|
|
|
/**
|
|
* Initializes the matriz at a given size with the same value in all positions.
|
|
*
|
|
* INOUT M: Matrix.
|
|
* IN X: Number of rows.
|
|
* IN Y: Number of columns per row.
|
|
* IN VAL: Value to set in the matrix.
|
|
*/
|
|
CREATE OR REPLACE PROCEDURE INIT_INTEGER_MATRIX(
|
|
INOUT M INTEGER_MATRIX,
|
|
IN X SMALLINT,
|
|
IN Y SMALLINT,
|
|
IN VAL INTEGER)
|
|
P_INIT_INTEGER_MATRIX: BEGIN
|
|
DECLARE I SMALLINT DEFAULT 1;
|
|
DECLARE J SMALLINT;
|
|
DECLARE A INTEGER_ARRAY;
|
|
|
|
WHILE (I <= X) DO
|
|
SET A = ARRAY[];
|
|
SET J = 1;
|
|
WHILE (J <= Y) DO
|
|
SET A[J] = VAL;
|
|
SET J = J + 1;
|
|
END WHILE;
|
|
SET M[I] = A;
|
|
SET I = I + 1;
|
|
END WHILE;
|
|
END P_INIT_INTEGER_MATRIX
|
|
@
|
|
|
|
/**
|
|
* Prints the content of the matrix to the standard output.
|
|
*
|
|
* INOUT M: Matrix.
|
|
*/
|
|
CREATE OR REPLACE PROCEDURE PRINT_INTEGER_MATRIX(
|
|
IN M INTEGER_MATRIX)
|
|
P_PRINT_INTEGER_MATRIX: BEGIN
|
|
DECLARE I SMALLINT DEFAULT 1;
|
|
DECLARE J SMALLINT;
|
|
DECLARE X SMALLINT;
|
|
DECLARE Y SMALLINT;
|
|
DECLARE VAL INTEGER;
|
|
DECLARE A INTEGER_ARRAY;
|
|
DECLARE RET VARCHAR(256);
|
|
|
|
SET X = CARDINALITY(M);
|
|
CALL DBMS_OUTPUT.PUT_LINE('>>>>>');
|
|
WHILE (I <= X) DO
|
|
SET A = M[I];
|
|
SET RET = '[';
|
|
SET Y = CARDINALITY(A);
|
|
SET J = 1;
|
|
WHILE (J <= Y) DO
|
|
SET VAL = A[J];
|
|
SET RET = RET || VAL;
|
|
SET J = J + 1;
|
|
IF (J <= Y) THEN
|
|
SET RET = RET || ',';
|
|
END IF;
|
|
END WHILE;
|
|
SET RET = RET || ']';
|
|
CALL DBMS_OUTPUT.PUT_LINE(RET);
|
|
SET I = I + 1;
|
|
END WHILE;
|
|
CALL DBMS_OUTPUT.PUT_LINE('<<<<<');
|
|
END P_PRINT_INTEGER_MATRIX
|
|
@
|
|
|
|
/**
|
|
* Checks if a queen is safe in the given position.
|
|
*
|
|
* IN M: Matrix representing the chessboard.
|
|
* IN ROW: Row of the queen.
|
|
* IN COL: Column in the row for the queen.
|
|
* IN SIZE: Size of the chessboard (max row, max col).
|
|
* RETURNS true if the position is safe.
|
|
*/
|
|
CREATE OR REPLACE FUNCTION IS_SAFE(
|
|
IN M INTEGER_MATRIX,
|
|
IN ROW SMALLINT,
|
|
IN COL SMALLINT,
|
|
IN SIZE SMALLINT)
|
|
MODIFIES SQL DATA
|
|
RETURNS BOOLEAN
|
|
F_IS_SAFE: BEGIN
|
|
DECLARE I SMALLINT;
|
|
DECLARE J SMALLINT;
|
|
DECLARE VAL INTEGER;
|
|
|
|
-- Debug purposes.
|
|
--CALL SET_INTEGER_VALUE(ROW, COL, M, -1);
|
|
--CALL PRINT_INTEGER_MATRIX(M);
|
|
--CALL SET_INTEGER_VALUE(ROW, COL, M, 0);
|
|
|
|
SET I = 1;
|
|
WHILE (I <= COL) DO
|
|
SET VAL = GET_INTEGER_VALUE(ROW, I, M);
|
|
IF (VAL = 1) THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
SET I = I + 1;
|
|
END WHILE;
|
|
|
|
SET I = ROW;
|
|
SET J = COL;
|
|
WHILE (I >= 1 AND J >= 1) DO
|
|
SET VAL = GET_INTEGER_VALUE(I, J, M);
|
|
IF (VAL = 1) THEN
|
|
CALL SET_INTEGER_VALUE(ROW, COL, M, 0);
|
|
RETURN FALSE;
|
|
END IF;
|
|
SET I = I - 1;
|
|
SET J = J - 1;
|
|
END WHILE;
|
|
|
|
SET I = ROW;
|
|
SET J = COL;
|
|
WHILE (J >= 1 AND I <= SIZE) DO
|
|
SET VAL = GET_INTEGER_VALUE(I, J, M);
|
|
IF (VAL = 1) THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
SET I = I + 1;
|
|
SET J = J - 1;
|
|
END WHILE;
|
|
|
|
RETURN TRUE;
|
|
END F_IS_SAFE
|
|
@
|
|
|
|
/**
|
|
* Dummy procedure for the recurssion.
|
|
*
|
|
* IN SIZE: Size of the chessboard (max row, max col).
|
|
* IN COL: Column to analyse.
|
|
* OUT RET: True if it was possible to put all queens
|
|
*/
|
|
CREATE OR REPLACE PROCEDURE SOLVE_N_QUEENS(
|
|
INOUT M INTEGER_MATRIX,
|
|
IN SIZE SMALLINT,
|
|
IN COL SMALLINT,
|
|
OUT RET BOOLEAN)
|
|
P_SOLVE_N_QUEENS: BEGIN
|
|
END P_SOLVE_N_QUEENS
|
|
@
|
|
|
|
/**
|
|
* Solves the n-queens algoritm.
|
|
*
|
|
* IN SIZE: Size of the chessboard (max row, max col).
|
|
* IN COL: Column to analyse.
|
|
* OUT RET: True if it was possible to put all queens
|
|
*/
|
|
CREATE OR REPLACE PROCEDURE SOLVE_N_QUEENS(
|
|
INOUT M INTEGER_MATRIX,
|
|
IN SIZE SMALLINT,
|
|
IN COL SMALLINT,
|
|
OUT RET BOOLEAN)
|
|
MODIFIES SQL DATA
|
|
P_SOLVE_N_QUEENS: BEGIN
|
|
DECLARE I SMALLINT;
|
|
DECLARE SAFE BOOLEAN;
|
|
DECLARE SOLVED BOOLEAN;
|
|
|
|
-- Debug purposes.
|
|
--CALL PRINT_INTEGER_MATRIX(M);
|
|
SET RET = FALSE;
|
|
IF (COL > SIZE) THEN
|
|
SET RET = TRUE;
|
|
ELSE
|
|
SET I = 1;
|
|
WHILE (I <= SIZE AND NOT RET) DO
|
|
SET SAFE = IS_SAFE(M, I, COL, SIZE);
|
|
IF (SAFE) THEN
|
|
CALL SET_INTEGER_VALUE(I, COL, M, 1);
|
|
CALL SOLVE_N_QUEENS(M, SIZE, COL + 1, SOLVED);
|
|
IF (SOLVED) THEN
|
|
SET RET = TRUE;
|
|
ELSE
|
|
CALL SET_INTEGER_VALUE(I, COL, M, 0); -- Backtrack.
|
|
END IF;
|
|
|
|
END IF;
|
|
|
|
SET I = I + 1;
|
|
END WHILE;
|
|
|
|
END IF;
|
|
END P_SOLVE_N_QUEENS
|
|
@
|
|
|
|
/**
|
|
* Main procedure to solve the n-queen algoritm.
|
|
*
|
|
* IN SIZE: Size of the chessboard. The bigger it is, the more time it takes.
|
|
*/
|
|
CREATE OR REPLACE PROCEDURE N_QUEENS(
|
|
IN SIZE SMALLINT)
|
|
P_N_QUEENS: BEGIN
|
|
DECLARE M INTEGER_MATRIX;
|
|
DECLARE SOL BOOLEAN DEFAULT FALSE;
|
|
|
|
CALL INIT_INTEGER_MATRIX(M, SIZE, SIZE, 0);
|
|
|
|
CALL SOLVE_N_QUEENS(M, SIZE, 1, SOL);
|
|
IF (SOL = TRUE) THEN
|
|
CALL PRINT_INTEGER_MATRIX(M);
|
|
ELSE
|
|
CALL DBMS_OUTPUT.PUT_LINE('Solution does not exist.');
|
|
END IF;
|
|
|
|
END P_N_QUEENS
|
|
@
|
|
|
|
--#SET TERMINATOR ;
|
|
|
|
-- Activates the standard output for the current session.
|
|
SET SERVEROUTPUT ON;
|
|
|
|
CALL N_QUEENS(4);
|
|
|
|
CALL N_QUEENS(8);
|
|
|
|
CALL N_QUEENS(16);
|