/* Logiquiz oplosser - Raymond van Dongelen, november 1997
   Overgetikt van zes uitgedraaide bladen (original/scans).

   De uitdraai begint halverwege de predicates. Het blok hieronder tot aan
   BEGIN UITDRAAI stond dus niet op papier: het is herleid uit hoe de
   clauses de domeinen en predicaten gebruiken. */

domains
  stringlist      = string*
  stringtupel     = stringtupel (string, string)
  stringtupellist = stringtupel*
  eigenschap      = eigenschap (string, string, string, string, char);
                    verschil (string, string, string, string, string, integer);
                    groter (string, string, string, string, string)
  feitlist        = eigenschap*

database
  domein (string, stringlist)
  feit (eigenschap)

predicates
  zetTeken (string, string, string, string, char)
  zetEigenschap (eigenschap)
  zetMinnen (string, string, string, string, eigenschap)
  alleenMinnenH (string, stringlist, string, string)
  alleenMinnenV (string, string, string, stringlist)
  rijMinnen (string, string, string, string, eigenschap)
  spiegel (string, string, string, string, eigenschap)
  leidFeitenAf (feitlist)
  maakLogi (string)
  writeList (integer, integer, string, string, stringlist)
  writeNamen (integer, string, stringlist, stringlist)
  show

/* BEGIN UITDRAAI */

  leidVerschilAf (stringlist, integer, stringtupel)
  /* Uit de lijst worden 2 strings gehaald, als deze een verschil hebben
     van de integer, worden ze in de stringtupel geplaatst */

  omgekeerdMin (string,  string, string,  stringlist, eigenschap)
  /*            Domein 1 Naam 1  domein 2 Lijst
     Zoekt alle namen uit domein 2 die niet in de lijst voorkomen
     en zet deze om in een eigenschap */

  kleinste (stringlist, string, string)
  /* Geeft de kleinste waarde uit een domein terug */

  grootste (stringlist, string, string)
  /* Geeft de grootste waarde uit een domein terug */

  pos (stringlist, string, integer)
  /* Vraag een element op uit een lijst */

  alleenMinnen (string,string,string,stringlist)
  /* Bestaat een rij in een domein uit enkel minnen */

  splits (feitlist, eigenschap, feitlist)
  splits (stringlist, string, stringlist)

  splitsLijst (stringtupellist, stringlist, stringlist)
  /* Maakt uit een lijst van tupels 2 lijsten */

  lijstVan (stringlist, integer, stringlist)
  /* Maak een lijst vanaf de integer tot het eind van de lijst */

  lijstTot (stringlist, integer, stringlist)
  /* Maak een lijst tot een bepaalde positie */

  zetMinnenLijst (string,string,string,stringlist,eigenschap)
  /* Zet op alle elementen uit de lijst een min */

  ongelijk (string,string,string,string)
  /* Zet een min neer op de positie, lukt ook als de min niet geplaatst kan worden
  */

  wissel (string,string,string,string,string,string,string,string)
  /* Geef de 2 combinaties van de Domeinen */

clauses

  splits([H|T], H, T).
  splits([H|T], X, [H|TX]) :- splits(T, X, TX).

  pos ([H|_], H, 0).
  pos ([_|T], X, Positie) :-
    pos (T, X, Pos),
    Positie = Pos +1.

  kleinste ([], X, X) :- !.

  kleinste ([H|T], X, Antw) :-
    str_int (H, Hint),
    str_int (X, Xint),
    Hint < Xint,
    kleinste (T, H, Antw).

  kleinste ([H|T], X, Antw) :-
    str_int (H, Hint),
    str_int (X, Xint),
    Hint >= Xint,
    kleinste (T, X, Antw).

  grootste ([], X, X) :- !.

  grootste ([H|T], X, Antw) :-
    str_int (H, Hint),
    str_int (X, Xint),
    Hint >= Xint,
    grootste (T, H, Antw).

  grootste ([H|T], X, Antw) :-
    str_int (H, Hint),
    str_int (X, Xint),
    Hint < Xint,
    grootste (T, X, Antw).

  zetTeken (D1, N1, D2, N2, Teken) :-
    feit (eigenschap (D1,_,D2,_,_)),
    not (feit (eigenschap (D1, N1, D2, N2, _))),
    assert (feit (eigenschap (D1,N1,D2,N2, Teken))),!
    .

  zetTeken (D1, N1, D2, N2, Teken) :-
    feit (eigenschap (D2,_,D1,_,_)),
    not (feit (eigenschap (D2, N2, D1, N1, _))),
    assert (feit (eigenschap (D2,N2,D1,N1, Teken))),!
    .

  zetTeken (D1, N1, D2, N2, Teken) :-
    not (feit (eigenschap (D1, N1, D2, N2, _))),
    not (feit (eigenschap (D2, N2, D1, N1, _))),
    assert (feit (eigenschap (D1,N1,D2,N2, Teken))),!.

  zetEigenschap (eigenschap (D1,N1, D2,N2,Teken)) :-
    !,zetTeken (D1,N1,D2,N2,Teken).

  /* Zet de minnen horizontaal */
  zetMinnen (D1, N1, D2, N2, X) :-
    domein (D1, NaamLijst),
    splits (NaamLijst, Naam, _),
    Naam <> N1,
    zetTeken (D1, Naam, D2,N2, '-'),
    X = eigenschap (D1, Naam, D2, N2, '-').

  /* Zet de minnen verticaal */
  zetMinnen (D1, N1, D2, N2, X) :-
    domein (D2, NaamLijst),
    splits (NaamLijst, Naam, _),
    Naam <> N2,
    zetTeken (D1, N1, D2,Naam, '-'),
    X = eigenschap (D1, N1, D2, Naam, '-').

  alleenMinnenH (_, [], _, _).
  alleenMinnenH (D1, [H|T], D2, N2) :-
    feit (eigenschap (D1, H, D2, N2, '-')),
    alleenMinnenH (D1, T, D2, N2),!.

  alleenMinnenV (_, _, _,[]).
  alleenMinnenV (D1, N1, D2, [H|T]) :-
    feit (eigenschap (D1, N1, D2, H, '-')),
    alleenMinnenV (D1, N1, D2, T),!.

  lijstVan (X, 0, X).
  lijstVan ([_|T], Positie, R) :-
    Positie <> 0,
    Pos1 = Positie -1,
    lijstVan (T, Pos1, R).

  lijstTot (_, 0 ,[]).
  lijstTot ([H|T], Pos, [H|R]) :-
    Pos <> 0,
    Pos1 = Pos -1,
    LijstTot (T, Pos1, R).

  alleenMinnen (_,_,_,[]).
  alleenMinnen (D1, N1, D2, [H|T]) :-
    feit (eigenschap (D1, N1, D2, H, '-')),
    alleenMinnen (D1, D2, N1, T).

  zetMinnenLijst (D1, N1, D2, Ds, O) :-
    splits (Ds, X, _),
    O = eigenschap (D1, N1, D2, X, '-'),
    zetEigenschap (O).


  rijMinnen (D1, N1, D2, N2, O) :-
    domein (D1, NaamLijst),
    splits (NaamLijst, N1, Lijst), /* Op D1, N1, D3, N2 staat toch al een min */
    splits (Lijst, Onbekend, MLijst),
    O = eigenschap (D1, Onbekend, D2, N2, '+'),
    not (feit (eigenschap (D1, Onbekend, D2, N2, _))),/* Er is een feit nog niet
  bekend */
    alleenMinnenH (D1, MLijst, D2, N2).

  rijMinnen (D1, N1, D2, N2, O) :-
    domein (D2, NaamLijst),
    splits (NaamLijst, N2, Lijst), /* Op D1, N1, D2, N2 staat toch al een min */
    splits (Lijst, Onbekend, MLijst),
    O = eigenschap (D1, N1, D2, Onbekend, '+'),
    not (feit (eigenschap (D1, N1, D2, Onbekend, _))), /* Er is een feit nog niet
  bekend */
    alleenMinnenV (D1, N1, D2, MLijst).

  spiegel (D1, N1, D2, N2, O) :-
    feit (eigenschap (D3, N3, D1, N1, Teken)),
    D3 <> D2,
    O = eigenschap (D3, N3, D2, N2, Teken).

  spiegel (D1, N1, D2, N2, O) :-
    feit (eigenschap (D1, N1, D3, N3, Teken)),
    D3 <> D2,
    O = eigenschap (D3, N3, D2, N2, Teken).

  spiegel (D1, N1, D2, N2, O) :-
    feit (eigenschap (D3, N3,D2,N2,Teken)),
    D3 <> D1,
    O = eigenschap (D3, N3, D1, N1, Teken).

  spiegel (D1, N1, D2, N2, O) :-
    feit (eigenschap (D2,N2,D3, N3, Teken)),
    D3 <> D1,
    O = eigenschap (D3, N3, D1, N1, Teken).

  leidVerschilAf (Lijst, Verschil, R) :-
    splits (Lijst, X, RestLijst),
    splits (RestLijst, Y, _),
    str_int (X, Xint),
    str_int (Y, Yint),
    Xint + Verschil = Yint,
    R = stringtupel (X,Y).

  splitsLijst ([], [], []).
  splitsLijst ([stringtupel (X,Y)|T], [X|Tl1], [Y|Tl2]) :-
    splitsLijst (T, Tl1, Tl2).

  omgekeerdMin (D1, N1, D2, Lijst, Min) :-
    domein (D2, Ds),
    splits (Ds, Naam,_),
    not (splits (Lijst, Naam, _)),
    Min = eigenschap (D1, N1, D2, Naam, '-'),
    zetEigenschap (Min).

  ongelijk (D1,_,D1,_).
  ongelijk (D1,N1,D2,N2) :-
    D1 <> D2,
    zetTeken (D1, N1, D2, N2, '-'),
    leidFeitenAf ([eigenschap (D1,N1,D2,N2, '-')]).

  ongelijk (_,_,_,_).

  wissel (D1,N1,D2,N2,D1,N1,D2,N2).
  wissel (D1,N1,D2,N2,D2,N2,D1,N1).

  leidFeitenAf ([]).

  /* Als er een plus voorkomt kunnen er minnen gezet worden */
  leidFeitenAf ([eigenschap (D1,N1,D2,N2,'+')|_]) :-
    findall (X, zetMinnen (D1,N1,D2,N2,X), Y),
    leidFeitenAf (Y),
    fail.

  /* Als er een plus gezet is kan er gespiegeld worden */
  leidFeitenAf ([eigenschap (D1, N1, D2, N2, '+') | _]) :-
    spiegel (D1, N1, D2, N2, O),
    zetEigenschap (O),
    leidFeitenAf ([O]),
    fail.

  /* Zoek naar een rij minnen, zodat er een plus gezet kan worden */
  leidFeitenAf ([eigenschap (D1,N1,D2,N2,'-')|_]) :-
    rijMinnen (D1, N1, D2, N2, Plus),
    zetEigenschap (Plus),
    leidFeitenAf ([Plus]),
    fail.

  /* Voor groter dan */
  leidFeitenAf ([eigenschap (P1,Q1,P2,Q2,'-')|_]) :-
    wissel (P1,Q1,P2,Q2,D1,N1,D2,N2),
    feit (groter (D1, D3, D2, N1, N3)),
    domein (D2, Ds),
    pos (Ds, N2, Positie),
    LijstVan (Ds, Positie, MinLijst),
    alleenMinnen (D1,N1,D2,MinLijst),
    Pos1 = Positie - 1,
    pos (Ds, ElemVerder, Pos1),
    findall (X, zetMinnenLijst (D3,N3,D2, [ElemVerder|MinLijst], X), Y),
    leidFeitenAf (Y),
    fail.

  leidFeitenAf ([eigenschap (P1,Q1,P2,Q2,'-')|_]) :-
    wissel (P1,Q1,P2,Q2,D1,N1,D2,N2),
    feit (groter (D3, D1, D2, N3, N1)),
    domein (D2, Ds),
    pos (Ds, N2, Positie),
    lijstTot (Ds, Positie, MinLijst),

    alleenMinnen (D1, N1,D2, MinLijst),
    Pos1 = Positie + 1,
    pos (Ds, ElemVerder, Pos1),
    findall (X, zetMinnenLijst (D3, N3,D2, [ElemVerder|MinLijst], X), Y),
    leidFeitenAf (Y),
    fail.

  /* Verschil */
  leidFeitenAf ([eigenschap (P1,Q1,P2,Q2,Teken)|_]) :-
    wissel (P1,Q1,P2,Q2,D1,N1,D2,N2),
    feit (verschil (D1, D3, D2, N1, N3, Aantal)),
    str_int (N2, N2int),
    Waarde = N2int + Aantal,
    str_int (WaardeString, Waarde),
    Domein (D2, Ds),
    splits (Ds, WaardeString, _),
    NE = eigenschap (D3, N3, D2, WaardeString, Teken),
    zetEigenschap (NE),
    leidFeitenAf ([NE]),
    fail.

  leidFeitenAf ([eigenschap (P1,Q1,P2,Q2,Teken)|_]) :-
    wissel (P1,Q1,P2,Q2,D1,N1,D2,N2),
    feit (verschil (D3, D1, D2, N3, N1, Aantal)),
    str_int (N2, N2int),
    Waarde = N2int - Aantal,
    str_int (WaardeString, Waarde),
    Domein (D2, Ds),
    splits (Ds, WaardeString, _),
    NE = eigenschap (D3, N3, D2, WaardeString, Teken),
    zetEigenschap (NE),
    leidFeitenAf ([NE]),
    fail.


  leidFeitenAf ([verschil (D1, D2, D3, N1, N2, Aantal) |_]) :-
    domein (D3, X),
    findall (Paar, leidVerschilAf (X, Aantal,Paar),PaarLijst),
    ongelijk (D1, N1, D2, N2),
    splitsLijst (PaarLijst, Lijst1, Lijst2),
    findall (Min,omgekeerdMin (D1, N1, D3, Lijst1, Min), Minnen1),
    findall (Min,omgekeerdMin (D2, N2, D3, Lijst2, Min), Minnen2),

    leidFeitenAf (Minnen1),
    leidFeitenAf (Minnen2), fail.

  leidFeitenAf ([groter (D1, D2, D3, N1, N2) |_]) :-
    domein (D3, [H|Ds]),
    kleinste (Ds, H, X),
    ongelijk (D1, N1,D2, N2),
    NE = eigenschap (D1,N1, D3, X, '-'),
    zetEigenschap (NE),
    leidFeitenAf ([NE]), fail.

  leidFeitenAf ([groter (_, D2, D3, _, N2) |_]) :-
    domein (D3, [H|Ds]),
    grootste (Ds, H, X),
    NE = eigenschap (D2, N2, D3, X, '-'),
    zetEigenschap (NE),
    leidFeitenAf ([NE]), fail.

  leidFeitenAf ([_|T]) :-
    write ('#'),
    leidFeitenAf (T).

  maakLogi (File) :-
    retractAll (_),
    write ("Een moment a.u.b. "),nl,
    consult (File), !,
    findall (X, feit (X), Y),
    leidFeitenAf (Y), show
    .

/* Display gedeelte */


  writeList (_,_,_,_,[]).
  writeList (X,Y,Domein, Naam, [H|T]) :-
    feit (eigenschap (Domein, Naam, H, Inhoud, '+')),
    cursor (Y,X),
    write (Inhoud),
    X1 = X +22,
    writeList (X1,Y,Domein, Naam, T),!.

  writeList (X,Y,Domein, Naam, [H|T]) :-
    feit (eigenschap (H, Inhoud,Domein, Naam,'+')),
    cursor (Y,X),
    X1 = X +22,
    write (Inhoud),
    writeList (X1, Y, Domein, Naam, T),!.

  writeNamen (_,_,_,[]).
  writeNamen (Y,Domein,DList,[H|T]) :-
    cursor (Y,0),
    write (H),
    writeList (10,Y, Domein, H, DList), !,
    Y1 = Y +1,
    writeNamen (Y1,Domein, DList,T).

  show :-
    clearwindow,
    write
    ("+-----------------------------------------------------------------------"),nl,
    write (" Logiquiz oplosser                                       november 1997 "),nl,
    write ("                                                                      "),nl,
    write (" Auteur: Raymond van Dongelen                                         "),nl,
    write ("------------------------------------------------------------------------"),nl,
    nl,
    domein (D,NList),
    findall (X, domein (X,_), OudeDlist),
    splits (OudeDList, D, DList),
    !,
    writeNamen (7,D, DList, NList),
    nl,
    nl,
    readChar (_).
