-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathplanifier.pl
313 lines (282 loc) · 9.34 KB
/
planifier.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
/* planifier.pl
* @changelog
* e5737a6 Guillaume Clochard Fri Jan 13 15:51:36 2017 +0100 Max 5 cours par jours
* fc23e26 Guillaume Clochard Fri Jan 13 15:07:01 2017 +0100 Éviter début et fin de journée
* f1482a6 Guillaume Clochard Fri Jan 13 14:51:27 2017 +0100 Limiter à un examen par jour max
* e361335 Guillaume Clochard Fri Jan 13 14:42:19 2017 +0100 Pas de cours le jeudi
* 729b6b0 Guillaume Clochard Fri Jan 13 12:07:00 2017 +0100 Ajout foncitionalité subsidiaire
* ce446c3 Guillaume Clochard Thu Jan 12 20:47:05 2017 +0100 Fix Sélection du moment avant la salle
* 8802f99 Guillaume Clochard Tue Jan 10 11:15:49 2017 +0100 Ordonnancement des séances
* 5f85b31 Guillaume Clochard Tue Jan 10 08:44:36 2017 +0100 Fix tests sequencement
* ae2cb06 Guillaume Clochard Tue Jan 10 05:42:32 2017 +0100 Ajout contrainte salle différente si même moment
* c4631fc Guillaume Clochard Tue Jan 10 05:35:55 2017 +0100 Affichage chronologique d'une solution
* ca927e3 Guillaume Clochard Fri Jan 6 16:36:36 2017 +0100 Optimisation ordre des tests
* d8c51c6 Guillaume Clochard Fri Jan 6 16:26:56 2017 +0100 Fix récursion planifier/2
* ccf325a Guillaume Clochard Fri Jan 6 15:00:18 2017 +0100 Fix gestion liste de groupes
* ea7e1d8 Guillaume Clochard Fri Jan 6 14:38:15 2017 +0100 Gestion d'une liste de profs
* 845efc1 Guillaume Clochard Fri Jan 6 14:15:54 2017 +0100 creneauValide
* 37b8972 Thomas Coquereau Fri Jan 6 11:29:11 2017 +0100 ADD test groupes compatibles and REFACTO profDisponibles
* b927ab3 Guillaume Clochard Tue Jan 3 17:21:46 2017 +0100 Ajout profDisponible/5
* 2619d84 Guillaume Clochard Tue Jan 3 17:20:55 2017 +0100 Ajout typesCoursIdentiques/2
*/
/**
* typesCoursIdentiques(+X, +Y).
*
* @arg X Un type de cours
* @arg Y Un type de cours
*/
typesCoursIdentiques(X, X).
/**
* memeMomentCreneau(+H, +J, +M, +C).
*
* Définit si les deux créneaux sont au même moment.
*
* @arg H La plage horaire
* @arg J Le jour
* @arg M Le mois
* @arg C Un créneau [S, H, J, M, L]
*/
memeMomentCreneau(H, J, M, [_, H2, J2, M2, _]) :- H = H2, J = J2, M = M2, !.
/**
* memeSalle(+L, +C).
*
* Définit si L est une salle du créneau C
*
* @arg L Une salle
* @arg C Un créneau [S, H, J, M, L]
*/
memeSalle(L, [_, _, _, _, L]) :- !.
/**
* memeProfs(+P, +C).
*
* Définit si Ps sont des prof du créneau C.
*
* @arg Ps Des enseignant
* @arg C Un créneau [S, H, J, M, L]
*/
memeProfs([P|_], [S, _, _, _, _]) :- profSeance(P2, S), P2 = P, !.
memeProfs([_|Ps], [S, H, J, M, L]) :- memeProfs(Ps, [S, H, J, M, L]), !.
/**
* groupesIncompatibleCreneau(+Gs, +C).
*
* Définit si Gs sont incompatibles avec le groupe de C.
*
* @arg Gs Les groupes
* @arg C Un créneau [S, H, J, M, L]
*/
groupesIncompatibleCreneau([G|_], [S, _, _, _, _]) :-
groupeSeance(G2, S),
incompatibles(G, G2),
!.
groupesIncompatibleCreneau([_|Gs], [S, H, J, M, L]) :-
groupesIncompatibleCreneau(Gs, [S, H, J, M, L]),
!.
/**
* momentBefore(+H1, +J1, +M1, +H2, +J2, +M2).
*
* Définit si la date 1 est bien après la date 2
*
* @arg H1 La plage horaire
* @arg J1 Le jour
* @arg M1 Le mois
* @arg H2 La plage horaire
* @arg J2 Le jour
* @arg M2 Le mois
*/
momentBefore(_, J1, M1, _, J2, M2) :-
dateBefore(J2, M2, J1, M1), % 2 se déroule un jour placé avant
!.
momentBefore(H1, J1, M1, H2, J2, M2) :-
J1 = J2,
M1 = M2,
H2 < H1, % S2 se déroule même jour, mais plage plus petite
!.
/**
* customSequenceValide(+J1, +M1, +J2, +M2, +Jmin, +Jmax).
*
* Définit si le créneau potentiel est conforme avec le séquencement voulu
*
* @arg J1 Le jour
* @arg M1 Le mois
* @arg J2 Le jour
* @arg M2 Le mois
* @arg Jmin Le nombre de jours minimum entre 1 et 2
* @arg JMax Le nombre de jours maximum entre 1 et 2
*/
customSequenceValide(J1, M1, J2, M2, Jmin, Jmax) :-
joursParMois(Nb),
Offset is ((J1 + M1 * Nb) - (J2 + M2 * Nb)),
Offset >= Jmin,
Offset =< Jmax,
!. % 1 se déroule bien entre JMin et Jmax jours après 2
/**
* sequencementValideCreneau(+S, +H, +J, +M, +C).
*
* Définit si le créneau potentiel est conforme avec le séquencement voulu
*
* @arg S Une séance
* @arg H La plage horaire
* @arg J Le jour
* @arg M Le mois
* @arg C Un créneau [S, H, J, M, L]
*/
% la séance n'est pas en lien avec le créneau transmis
sequencementValideCreneau(S, _, _, _, [S2, _, _, _, _]):-
\+ suitSeance(S, S2),
\+ suitSeance(S, S2, _, _),
\+ suitSeance(S2, S),
\+ suitSeance(S2, S, _, _),
!.
sequencementValideCreneau(S, H, J, M, [S2, H2, J2, M2, _]) :-
suitSeance(S, S2), % S suit S2
momentBefore(H, J, M, H2, J2, M2),
!.
sequencementValideCreneau(S, H, J, M, [S2, H2, J2, M2, _]) :-
suitSeance(S2, S), % S2 suit S
momentBefore(H2, J2, M2, H, J, M),
!.
sequencementValideCreneau(S, _, J, M, [S2, _, J2, M2, _]) :-
suitSeance(S, S2, Jmin, Jmax), % S suit S2
customSequenceValide(J, M, J2, M2, Jmin, Jmax),
!.
sequencementValideCreneau(S, _, J, M, [S2, _, J2, M2, _]) :-
suitSeance(S2, S, Jmin, Jmax), % S2 suit S
customSequenceValide(J2, M2, J, M, Jmin, Jmax),
!.
/**
* conflitExamen(+S, +J, +M, +C)
*
* Est vrai si C se déroule le même jour et que les deux créneaux sont des
* examents
*
* @arg S Séance
* @arg J Jour
* @arg M Mois
* @arg C Un créneau
*/
conflitExamen(S, J, M, [S2, _, J, M, _]) :-
seance(S, ds, _, _),
seance(S2, ds, _, _).
/**
* creneauValideCreneau(+S, +Ps, +Gs, +H, +J, +M, +L, +C).
*
* Définit si un cours n'est pas incompatible au moment donné avec les autres
* cours de la liste de créneaux.
*
* @arg Ps Les enseignants
* @arg Gs Les groupes
* @arg H La plage horaire
* @arg J Le jour
* @arg M Le mois
* @arg L La salle
* @arg C Un créneau [S, H, J, M, L]
*/
creneauValideCreneau(S, Ps, Gs, H, J, M, L, C) :-
% le créneau valide le séquencement avec C
sequencementValideCreneau(S, H, J, M, C),
\+ conflitExamen(S, J, M, C),
(
% le créneau n'est pas au même moment que C
(\+ memeMomentCreneau(H, J, M, C));
% ou il ne concerne pas un même prof, des groupes incompatibles
% ou une même salle
(
\+ groupesIncompatibleCreneau(Gs, C),
\+ memeProfs(Ps, C),
\+ memeSalle(L, C)
)
),
!.
/**
* creneauValide(+S, +Ps, +Gs, +H, +J, +M, +L, +Cs).
*
* Définit si un creneau est valide (Pas de conflit avec les créneaux existants)
*
* @arg S La séance
* @arg Ps Les enseignants
* @arg Gs Les groupes
* @arg H La plage horaire
* @arg J Le jour
* @arg M Le mois
* @arg L La salle
* @arg Cs Liste de créneaux [S, H, J, M, L]
*/
creneauValide(_, _, _, _, _, _, _, []) :- !.
creneauValide(S, Ps, Gs, H, J, M, L, [C|Cs]) :-
creneauValideCreneau(S, Ps, Gs, H, J, M, L, C),
creneauValide(S, Ps, Gs, H, J, M, L, Cs),
!.
/**
* jeudiApresMidi(+H, +J)
*
* Est vrai si le moment passé est un jeudi après midi
*
* Partant du principe qu'il y a 5 jours dans une semaine et que l'annee
* commence un lundi, sans cas particulier, alors les jeudis tombent le 4eme
* jour de chaque semaine.
*
* @arg H Plage horaire
* @arg J Jour
*/
jeudiApresMidi(H, J) :-
(J + 1) mod 5 is 0,
H > 3.
/**
* effectifGroupes(+Gs, -S)
*
* @arg Gs Liste de groupes
* @arg S Somme des effectifs des groupes
*/
effectifGroupes([], 0) :- !.
effectifGroupes([G], S) :- groupe(G, S), !.
effectifGroupes([G|Gs], S) :-
effectifGroupes(Gs, S1),
groupe(G, S2),
S is S1 + S2,
!.
/**
* tropDeCoursCeJour(+J, +M, +Max, +Cs)
*
* @arg J Jour
* @arg M Mois
* @arg Max Nombre max de cours par jour
* @arg Cs Liste de créneaux déjà planifiés
*/
tropDeCoursCeJour(J, M, Max, Cs) :-
findall(S, member([S, _, J, M, _], Cs), Csjour),
length(Csjour, X),
X > Max.
/**
* planifier(+Ss, +Ds, -Cs).
*
* @arg Ss Listes des séances à planifier
* @arg Ds Listes des créneaux déjà planifié
* @arg Cs Listes des créneaux construits
*/
planifier([], _, []) :- !.
planifier(Ss, Ds, [C|Cs]) :-
member(S, Ss), % La séance courante
delete(Ss, S, Ss2), % On l'enlève de la liste
planifier(Ss2, Ds, Cs), % on traite le sous-problème
append(Ds, Cs, Cs2), % on crée une liste qui regroupe les créneaux existants
% Création du créneau et tests ---------------------------------------------
seance(S, TypeS, _, _),
date(J, M), % une date
\+ tropDeCoursCeJour(J, M, 5, Cs2), % max 5 cours par jour
member(H, [2, 3, 4, 5, 1, 6]), % une plage horaire
% évitons premier et dernier créneau
\+ jeudiApresMidi(H, J),
% une salle
salle(L, TailleL),
accueille(L, TypeL),
typesCoursIdentiques(TypeS, TypeL), % type de salle valide
findall(G, groupeSeance(G, S), Gs), % tous les groupes de la séance
effectifGroupes(Gs, Effectif),
Effectif =< TailleL, % taille de salle valide
findall(P, profSeance(P, S), Ps), % tous les enseignants de la séance
% test des contraintes (profs, incompatibilité groupes, séquencement)
% sur cette proposition de créneau
creneauValide(S, Ps, Gs, H, J, M, L, Cs2),
% Fin création du créneau et tests -----------------------------------------
C = [S, H, J, M, L].
planifier(Ss, Cs) :- planifier(Ss, [], Cs).