with Instrument;
use Instrument;

procedure Puzza2 is


    subtype Short_Integer is Integer;
    Size : constant Short_Integer := 511;-- D*D*D - 1
    Classmax : constant Short_Integer := 3;
    Typemax : constant Short_Integer := 12;
    D : constant Short_Integer := 8;

    subtype Piececlass is Short_Integer range 0 .. Classmax;
    subtype Piecetype is Short_Integer range 0 .. Typemax;
    subtype Position is Short_Integer range 0 .. Size;

    Piececount : array (Piececlass) of Short_Integer range 0 .. 13;
    Class : array (Piecetype) of Piececlass;
    Piecemax : array (Piecetype) of Position;
    Puzzle : array (Position) of Boolean;
    P : array (Piecetype, Position) of Boolean;
    M, N : Position;
    Kount : Short_Integer;

    function Fit (I : Piecetype; J : Position) return Boolean is
    begin
        for K in 0 .. Piecemax (I) loop
            if P (I, K) then
                if Puzzle (J + K) then
                    return (False);
                end if;
            end if;
        end loop;
        return (True);
    end Fit;

    function Place (I : Piecetype; J : Position) return Position is
    begin
        for K in 0 .. Piecemax (I) loop
            if P (I, K) then
                Puzzle (J + K) := True;
            end if;
        end loop;
        Piececount (Class (I)) := Piececount (Class (I)) - 1;
        for K in J .. Size loop
            if not Puzzle (K) then
                return (K);
            end if;
        end loop;
        return (0);
    end Place;

    procedure Remove (I : Piecetype; J : Position) is
    begin
        for K in 0 .. Piecemax (I) loop
            if P (I, K) then
                Puzzle (J + K) := False;
            end if;
        end loop;
        Piececount (Class (I)) := Piececount (Class (I)) + 1;
    end Remove;

    function Trial (J : Position) return Boolean is
        K : Position;
    begin
        for I in 0 .. Typemax loop
            if Piececount (Class (I)) /= 0 then
                if Fit (I, J) then
                    K := Place (I, J);
                    if Trial (K) or (K = 0) then
                        Kount := Kount + 1;
                        return (True);
                    else
                        Remove (I, J);
                    end if;
                end if;
            end if;
        end loop;
        Kount := Kount + 1;
        return (False);
    end Trial;

begin
    Start ("PUZZA2", "PUZZLE");
    for M in 0 .. Size loop
        Puzzle (M) := True;
    end loop;
    for I in Short_Integer range 1 .. 5 loop
        for J in Short_Integer range 1 .. 5 loop
            for K in Short_Integer range 1 .. 5 loop
                Puzzle (I + D * (J + D * K)) := False;
            end loop;
        end loop;
    end loop;
    for I in 0 .. Typemax loop
        for M in 0 .. Size loop
            P (I, M) := False;
        end loop;
    end loop;
    for I in Short_Integer range 0 .. 3 loop
        for J in Short_Integer range 0 .. 1 loop
            for K in Short_Integer range 0 .. 0 loop
                P (0, I + D * (J + D * K)) := True;
            end loop;
        end loop;
    end loop;
    Class (0) := 0;
    Piecemax (0) := 3 + D * 1 + D * D * 0;
    for I in Short_Integer range 0 .. 1 loop
        for J in Short_Integer range 0 .. 0 loop
            for K in Short_Integer range 0 .. 3 loop
                P (1, I + D * (J + D * K)) := True;
            end loop;
        end loop;
    end loop;
    Class (1) := 0;
    Piecemax (1) := 1 + D * 0 + D * D * 3;
    for I in Short_Integer range 0 .. 0 loop
        for J in Short_Integer range 0 .. 3 loop
            for K in Short_Integer range 0 .. 1 loop
                P (2, I + D * (J + D * K)) := True;
            end loop;
        end loop;
    end loop;
    Class (2) := 0;
    Piecemax (2) := 0 + D * 3 + D * D * 1;
    for I in Short_Integer range 0 .. 1 loop
        for J in Short_Integer range 0 .. 3 loop
            for K in Short_Integer range 0 .. 0 loop
                P (3, I + D * (J + D * K)) := True;
            end loop;
        end loop;
    end loop;
    Class (3) := 0;
    Piecemax (3) := 1 + D * 3 + D * D * 0;
    for I in Short_Integer range 0 .. 3 loop
        for J in Short_Integer range 0 .. 0 loop
            for K in Short_Integer range 0 .. 1 loop
                P (4, I + D * (J + D * K)) := True;
            end loop;
        end loop;
    end loop;
    Class (4) := 0;
    Piecemax (4) := 3 + D * 0 + D * D * 1;
    for I in Short_Integer range 0 .. 0 loop
        for J in Short_Integer range 0 .. 1 loop
            for K in Short_Integer range 0 .. 3 loop
                P (5, I + D * (J + D * K)) := True;
            end loop;
        end loop;
    end loop;
    Class (5) := 0;
    Piecemax (5) := 0 + D * 1 + D * D * 3;
    for I in Short_Integer range 0 .. 2 loop
        for J in Short_Integer range 0 .. 0 loop
            for K in Short_Integer range 0 .. 0 loop
                P (6, I + D * (J + D * K)) := True;
            end loop;
        end loop;
    end loop;
    Class (6) := 1;
    Piecemax (6) := 2 + D * 0 + D * D * 0;
    for I in Short_Integer range 0 .. 0 loop
        for J in Short_Integer range 0 .. 2 loop
            for K in Short_Integer range 0 .. 0 loop
                P (7, I + D * (J + D * K)) := True;
            end loop;
        end loop;
    end loop;
    Class (7) := 1;
    Piecemax (7) := 0 + D * 2 + D * D * 0;
    for I in Short_Integer range 0 .. 0 loop
        for J in Short_Integer range 0 .. 0 loop
            for K in Short_Integer range 0 .. 2 loop
                P (8, I + D * (J + D * K)) := True;
            end loop;
        end loop;
    end loop;
    Class (8) := 1;
    Piecemax (8) := 0 + D * 0 + D * D * 2;
    for I in Short_Integer range 0 .. 1 loop
        for J in Short_Integer range 0 .. 1 loop
            for K in Short_Integer range 0 .. 0 loop
                P (9, I + D * (J + D * K)) := True;
            end loop;
        end loop;
    end loop;
    Class (9) := 2;
    Piecemax (9) := 1 + D * 1 + D * D * 0;
    for I in Short_Integer range 0 .. 1 loop
        for J in Short_Integer range 0 .. 0 loop
            for K in Short_Integer range 0 .. 1 loop
                P (10, I + D * (J + D * K)) := True;
            end loop;
        end loop;
    end loop;
    Class (10) := 2;
    Piecemax (10) := 1 + D * 0 + D * D * 1;
    for I in Short_Integer range 0 .. 0 loop
        for J in Short_Integer range 0 .. 1 loop
            for K in Short_Integer range 0 .. 1 loop
                P (11, I + D * (J + D * K)) := True;
            end loop;
        end loop;
    end loop;
    Class (11) := 2;
    Piecemax (11) := 0 + D * 1 + D * D * 1;
    for I in Short_Integer range 0 .. 1 loop
        for J in Short_Integer range 0 .. 1 loop
            for K in Short_Integer range 0 .. 1 loop
                P (12, I + D * (J + D * K)) := True;
            end loop;
        end loop;
    end loop;
    Class (12) := 3;
    Piecemax (12) := 1 + D * 1 + D * D * 1;
    Piececount (0) := 13;
    Piececount (1) := 3;
    Piececount (2) := 1;
    Piececount (3) := 1;
    M := 1 + D * (1 + D * 1);
    Kount := 0;
    if Fit (0, M) then
        N := Place (0, M);
    else
        Comment ("ERROR");
    end if;
    if Trial (N) then
        Kount := Ident_Int (Kount);
    else
        Comment ("FAILED");
    end if;
    Stop;
end Puzza2;