Search code examples
prologlogicconstraintsswi-prologclpfd

Second End View puzzle, Prolog


I write code in swi-prolog to solve Second End View Pazzles 7*7 (example http://www.funwithpuzzles.com/2009/10/abcd-second-end-view-ev4.html like this 5*5) for numbers 1-6

:- [library(clpfd)].

gen_row(Ls):-length(Ls, 7), Ls ins 0..6.

abc_view :-

maplist(gen_row, [R1,R2,R3,R4,R5,R6,R7]),
transpose([R1,R2,R3,R4,R5,R6,R7], [C1,C2,C3,C4,C5,C6,C7]),
maplist(all_distinct, [R1,R2,R3,R4,R5,R6,R7]),
maplist(all_distinct, [C1,C2,C3,C4,C5,C6,C7]),

start(R1, 4),
start(R2, 2),
start(R3, 3),
start(R4, 5),
start(R5, 3),
finish(R1, 6),
finish(R2, 4),
finish(R3, 2),
finish(R5, 1),
finish(R7, 2),

start(C2, 3),
start(C3, 4),
start(C4, 3),
start(C5, 5),
start(C6, 4),
start(C7, 1),
finish(C1, 3),
finish(C2, 2),
finish(C3, 5),
finish(C4, 5),
finish(C5, 6),
finish(C6, 1),
finish(C7, 4),

    maplist(writeln, [R1,R2,R3,R4,R5,R6,R7]).

How logic i need to write to solve it, maybe on more simple example for 4*4 or 5*5.. i'll be happy for any help. i need to write it for 3 tests but it will be grait for even one.


Solution

  • I got a solution, effectively the problem is much more simple that the 'SkyScrape & Fences' puzzle I solved previously.

    I'm afraid I previously misunderstood the problem and placed a wrong comment, suggesting you to abandon the (right) path you already took.

    /*  File:    second_end_view_puzzle.pl
        Author:  Carlo,,,
        Created: Oct  8 2012
        Purpose: help to solve Second End View puzzle as quested at
                 https://stackoverflow.com/q/12717609/874024
    */
    
    
    :- [library(clpfd)].
    
    gen_row(Ls) :-
        length(Ls, 7),
        Ls ins 0..6.
    
    abc_view :-
    
        Rows = [R1,R2,R3,R4,R5,_R6,R7],
        maplist(gen_row, Rows),
        transpose(Rows, [C1,C2,C3,C4,C5,C6,C7]),
        maplist(all_distinct, Rows),
        maplist(all_distinct, [C1,C2,C3,C4,C5,C6,C7]),
    
        start(R1, 4),
        start(R2, 2),
        start(R3, 3),
        start(R4, 5),
        start(R5, 3),
        finish(R1, 6),
        finish(R2, 4),
        finish(R3, 2),
        finish(R5, 1),
        finish(R7, 2),
    
        start(C2, 3),
        start(C3, 4),
        start(C4, 3),
        start(C5, 5),
        start(C6, 4),
        start(C7, 1),
        finish(C1, 3),
        finish(C2, 2),
        finish(C3, 5),
        finish(C4, 5),
        finish(C5, 6),
        finish(C6, 1),
        finish(C7, 4),
    
        maplist(label, Rows),
        maplist(writeln, Rows).
    
    % place the constraint 'SECOND in that direction' using a reified check
    start(Vars, Num) :-
        Vars = [A,B,C|_],
        X #<==> ( A #= 0 #\/ B #= 0 ) #/\ C #= Num,
        Y #<==> A #\= 0 #/\ B #= Num,
        X + Y #= 1 .
    
    finish(Vars, Num) :-
        reverse(Vars, Sarv), start(Sarv, Num).
    

    edit test:

    ?- abc_view.
    [5,4,0,2,1,6,3]
    [6,0,2,3,5,4,1]
    [1,3,4,6,2,5,0]
    [2,5,1,4,0,3,6]
    [0,6,3,5,4,1,2]
    [3,2,5,1,6,0,4]
    [4,1,6,0,3,2,5]
    true ;
    false.
    

    edit here is the 'porting' to GnuProlog. I've copied from SWI-Prolog CLP(FD) library the transpose/2 code.

    /*  File:    second_end_view_puzzle.pl
        Author:  Carlo,,,
        Created: Oct  8 2012
        Purpose: help to solve Second End View puzzle as quested at
                 https://stackoverflow.com/q/12717609/874024
    */
    
    gen_row(Ls) :-
        length(Ls, 7),
        fd_domain(Ls, 0, 6).
    
    transpose(Ms, Ts) :-
            %must_be(list(list), Ms),
            (   Ms = [] -> Ts = []
            ;   Ms = [F|_],
                transpose(F, Ms, Ts)
            ).
    
    transpose([], _, []).
    transpose([_|Rs], Ms, [Ts|Tss]) :-
            lists_firsts_rests(Ms, Ts, Ms1),
            transpose(Rs, Ms1, Tss).
    
    lists_firsts_rests([], [], []).
    lists_firsts_rests([[F|Os]|Rest], [F|Fs], [Os|Oss]) :-
            lists_firsts_rests(Rest, Fs, Oss).
    
    writeln(X) :- write(X), nl.
    
    abc_view :-
    
        Rows = [R1,R2,R3,R4,R5,_R6,R7],
        maplist(gen_row, Rows),
        transpose(Rows, [C1,C2,C3,C4,C5,C6,C7]),
        maplist(fd_all_different, Rows),
        maplist(fd_all_different, [C1,C2,C3,C4,C5,C6,C7]),
    
        start(R1, 4),
        start(R2, 2),
        start(R3, 3),
        start(R4, 5),
        start(R5, 3),
        finish(R1, 6),
        finish(R2, 4),
        finish(R3, 2),
        finish(R5, 1),
        finish(R7, 2),
    
        start(C2, 3),
        start(C3, 4),
        start(C4, 3),
        start(C5, 5),
        start(C6, 4),
        start(C7, 1),
        finish(C1, 3),
        finish(C2, 2),
        finish(C3, 5),
        finish(C4, 5),
        finish(C5, 6),
        finish(C6, 1),
        finish(C7, 4),
    
        maplist(fd_labeling, Rows),
        maplist(writeln, Rows).
    
    % place the constraint 'SECOND in that direction' using a reified check
    start(Vars, Num) :-
        Vars = [A,B,C|_],
        X #<=> ( A #= 0 #\/ B #= 0 ) #/\ C #= Num,
        Y #<=> A #\= 0 #/\ B #= Num,
        X + Y #= 1 .
    
    finish(Vars, Num) :-
        reverse(Vars, Sarv), start(Sarv, Num).