 /*
  * compile with: gplc alldiff.pl
  * run with: alldiff [N]
  * default to N = 10
  */

:- initialization(run).

run :-
	argument_list([AL]),
	catch(number_atom(L, AL), _, fail),
	run(L), !.

run :-
	run(10).


run(L) :-
	format('computing sols for ~d~n', [L]),
	g_assign(count_mod, 0),
	g_assign(count, 0),
        length(Ls, L),
        fd_domain(Ls, 1, L),
        fd_all_different(Ls),
        fd_labeling(Ls),
	check(Ls, L),
        fail.

run(L) :-
	g_read(count_mod, M),
	g_read(count, N),
	format('sols for ~d = #mod: ~d   count: ~d~n', [L, M, N]),
	factorial(L, M1, N1),
	(   M1 = M, N1 = N ->
	    write('OK !\n')
	;
	    format('ERROR !!! should be #mod: ~d   count: ~d~n', [M1, N1])
	),
	fail.

%run(_).

run(_) :-
	stop.

factorial( 0,              0,     1).
factorial( 1,              0,     1).
factorial( 2,              0,     2).
factorial( 3,              0,     6).
factorial( 4,              0,    24).
factorial( 5,              0,   120).
factorial( 6,              0,   720).
factorial( 7,              0,  5040).
factorial( 8,              0, 40320).
factorial( 9,              3, 62880).
factorial(10,             36, 28800).
factorial(11,            399, 16800).
factorial(12,           4790, 01600).
factorial(13,          62270, 20800).
factorial(14,         871782, 91200).
factorial(15,       13076743, 68000).
factorial(16,      209227898, 88000).
factorial(17,     3556874280, 96000).
factorial(18,    64023737057, 28000).
factorial(19,  1216451004088, 32000).
factorial(20, 24329020081766, 40000).


check(Ls, L) :-
	g_inc(count, N),
        (   N =:= 100000 ->	% if you modify this constant, modify the above table accordingly
            g_assign(count, 0),
	    g_inc(count_mod, M),
	    write(M), nl
	;
	    true
        ),
	g_assign(mask, 0),
	(   check1(Ls, L) ->
	    true
	;
	    portray_clause(false-Ls), halt
        ).


check1([], _).

check1([X|Ls], L) :-
	integer(X),
	X >= 1,
	X =< L,
	g_test_reset_bit(mask, X),
	g_set_bit(mask, X),
	check1(Ls, L).
