#maxint=30.

% Orario del Primo Trimestre del Primo Anno SMFN
% Studenti divisi in 8 gruppi

orario(Gruppo,Giorno,Ora,Lezione) v -orario(Gruppo,Giorno,Ora,Lezione) :-
	 oraAmmissibile(Gruppo,Giorno,Ora,Lezione),
	 not oraAssegnata(Gruppo,Giorno,Ora).

% eventuali allocazioni obbligate (lezioni che *devono* necessariamente
% essere tenute in un orario prefissato, ad esempio per via della
% disponibilita` dei laboratori) devono essere specificate
% in forma di fatti del tipo "prefissato(Gruppo,Giorno,Lezione)".
% la presenza di tali fatti riduce lo spazio di ricerca.
%prefissato(1,sab,8,labInformatica).
%prefissato(1,sab,9,labInformatica).

oraAssegnata(Gr,Gi,H) :- prefissato(Gr,Gi,H,_).

orario(Gruppo,Giorno,Ora,Lezione) :-
	prefissato(Gruppo,Giorno,Ora,Lezione).

% qui bisogna elencare tutti i vincoli forti (cioe` non derogabili)
% esistenti sull'orario, che sono esprimibili con i soli predicati
% di base (oraInizio, gruppo, lezione, giorno).

inammissibile(G,sab,H,L):-
	gruppo(G), oraInizio(H), H > 12, lezione(L).

inammissibile(G,sab,H,L):-
	gruppo(G), oraInizio(H), lezione(L),
	L <> informatica, L <> labInformatica.

oraAmmissibile(Gruppo,Giorno,Ora,Lezione) :- 
	gruppo(Gruppo), giorno(Giorno), 
	oraInizio(Ora), lezione(Lezione),
	not inammissibile(Gruppo,Giorno,Ora,Lezione).

% una classe segue una sola lezione alla volta.
:- gruppo(Gr),giorno(Gi),oraInizio(H),not #count{L:orario(Gr,Gi,H,L)} <=1.

% VINCOLI FORTI

% per ogni materia bisogna svolgere esattamente le ore previste.
:- oreSettimanali(L,N), gruppo(Gr), not #count{Gi,H : orario(Gr,Gi,H,L)} =N.

% lezioni di almeno due ore
:- orario(Gr,Gi,H,L), not precedeStessaLezione(Gr,Gi,H,L),
   not segueStessaLezione(Gr,Gi,H,L).

segueStessaLezione(Gr,Gi,H,L) :- 
	orario(Gr,Gi,H,L), orario(Gr,Gi,H1,L),
	oraSuccessiva(H,H1).

precedeStessaLezione(Gr,Gi,H,L) :- 
	orario(Gr,Gi,H,L), orario(Gr,Gi,H1,L),
	oraSuccessiva(H1,H).

% nella stessa giornata non piu` di due ore della stessa materia.
% basta imporre che la stessa materia non occorra a due
% ore di distanza nella stessa giornata; cio` e` sufficiente
% poiche` le lezioni non eccedono le due ore.
% in effetti questo vincolo sussume il precedente vincolo
% "lezioni di non piu` di due ore"
:- gruppo(Gr),giorno(Gi),lezione(L),not #count{H:orario(Gr,Gi,H,L)}<=2.

% max 6 ore al giorno. 
:- gruppo(Gr),giorno(Gi),not #count{H:orario(Gr,Gi,H,L)}<=6.

% minimizzazione dei "buchi"
impegnato(Gr,Gi,H) :-  orario(Gr,Gi,H,_).
buco(Gr,Gi,Durata) :- 
	impegnato(Gr,Gi,H1), impegnato(Gr,Gi,H2),
	not impegnatoTra(Gr,Gi,H1,H2), 
	H2=H1+Diff, Diff=Durata+1, Durata > 0.

impegnatoTra(Gr,Gi,H1,H2) :-
	oraInizio(H1), oraInizio(H2), H1<H2,
	impegnato(Gr,Gi,H3), H3 < H2, H3 > H1.

:~ buco(Gr,Gi,Durata). [Durata:2]

% PREFERENZE DEI DOCENTI.

% il docente di calcolo non gradisce lezioni pomeridiane.
:~  orario(Gi,Gr,H,calcolo), H>12. [1:1]

% il docente di informatica non gradisce lezioni in primo mattino.
:~  orario(Gi,Gr,H,informatica), H<11. [1:1]

% DATI DI INGRESSO
numeroGruppi(1).
gruppo(G) :- numeroGruppi(N), #int(G), G>0, G<=N.

giorno(lun).
giorno(mar).
giorno(mer).
giorno(gio).
giorno(ven).
giorno(sab).

%il primo argomento e` il piu` piccolo
giornoSuccessivo(lun,mar).
giornoSuccessivo(mar,mer).
giornoSuccessivo(mer,gio).
giornoSuccessivo(gio,ven).
giornoSuccessivo(ven,sab).

oraInizio(8).
oraInizio(9).
oraInizio(10).
oraInizio(11).
oraInizio(12).
oraInizio(14).
oraInizio(15).
oraInizio(16).
oraInizio(17).
oraInizio(18).

%il primo argomento e` il piu` piccolo
oraSuccessiva(8,9).
oraSuccessiva(9,10).
oraSuccessiva(10,11).
oraSuccessiva(11,12).
oraSuccessiva(14,15).
oraSuccessiva(15,16).
oraSuccessiva(16,17).
oraSuccessiva(17,18).

%il primo argomento e` il piu` piccolo
precede(H,H1) :- oraInizio(H), oraInizio(H1), H < H1.
precede(G,G1) :- giornoSuccessivo(G,G1).
precede(G,G1) :- giornoSuccessivo(G,G2), precede(G2,G1).

lezione(Lezione) :- oreSettimanali(Lezione,_). 

oreSettimanali(informatica,4).
oreSettimanali(labInformatica,2).
oreSettimanali(fisica,4).
oreSettimanali(calcolo,6).
oreSettimanali(inglese,4).
