Pouknouki

MICHEL ET SES AMIS

Dec 2nd, 2016
199
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.35 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2.  
  3. ################# AFFICHAGE DES RESULTATS ####################
  4.  
  5. import matplotlib.pyplot as plt
  6. plt.rcdefaults()
  7. import matplotlib.patches as mpatches
  8.  
  9. def minutesVersHeures(minutes):
  10.     return minutes // 60, minutes % 60
  11.  
  12. def ajouterOral(Oral, OrauxType, Color, patches):
  13.     import copy
  14.     temp = copy.deepcopy([o.Matiere for o in OrauxType])
  15.     temp.sort()
  16.     NumeroOral = temp.index(Oral.OralType_.Matiere)
  17.     rect = mpatches.Rectangle((Oral.Heure, NumeroOral), Oral.OralType_.Duree, 1, color = Color, ec = "black")
  18.     patches.append(rect)
  19.  
  20.  
  21. def afficher(patches, margin = 8)
  22.     fig, ax = plt.subplots()
  23.     for p in patches:
  24.         ax.add_patch(p)
  25.     maxMachines = max(rect.get_y() for rect in patches) + 1
  26.     maxJobs = max(rect.get_x() + margin for rect in patches)
  27.     plt.axis([0, maxJobs, 0, maxMachines])
  28.     plt.show()
  29.  
  30. ################### PARCOURS D'ARBRE EN PROFONDEUR #############################
  31.  
  32. # On part d'une situation initiale vide
  33. # On pose un oral à une heure (minimale)
  34. # On appelle la fonction avec cette nouvelle configuration et un oral en moins à placer.
  35.  
  36. # Cette fonction ne doit pas être appelée par le programme, seulement par solutionOptimale() !
  37. # Un oral est un élément de N * N : Prof * Eleve
  38.  
  39. def dureeSolutionOptimale(Solution):
  40.     #Oral[2] : Heure de début
  41.     #Oral[1] : Durée de l'oral
  42.     return max([oral[2] + oral[1] for oral in Solution])
  43.  
  44. def trouverPremiereHeure(solution, Jury, Eleve, Pause, Duree):
  45.     heure = 0
  46.     orauxDuJury = [oral for oral in solution if oral[0] == Jury]
  47.     orauxDuCandidat = [oral for oral in solution if oral[2] == Eleve]
  48.     while True:
  49.         incompatible = False
  50.         for oral in orauxDuCandidat:
  51.             if oral[2] <= heure and oral[2] + oral[1] + Pause > heure:
  52.                 incompatible = True
  53.             elif oral[2] >= heure and heure + Duree + Pause > oral[2]:
  54.                 incompatible = True
  55.         for oral in orauxDuJury:
  56.             if oral[2] <= heure and oral[2] + oral[1] > heure:
  57.                 incompatible = True
  58.             elif oral[2] >= heure and heure + Duree > oral[2]:
  59.                 incompatible = True
  60.         if incompatible:
  61.             heure += 1
  62.         else:
  63.             break
  64.     return heure
  65.  
  66. def solutionOptimaleAux(Oraux, Solution, MakespanHeuristique, Pause):
  67.     solutionModifiable = copy.deepcopy(Solution)
  68.     for Oral in Oraux:
  69.         solutionModifiable.append((Oral[0], Oral[1], trouverPremiereHeure(solutionModifiable, Oral[0][0], Oral[0][1], Pause, Oral[1])))
  70.         if dureeSolutionOptimale(solutionModifiable) >= MakespanHeuristique:
  71.             return None
  72.         else:
  73.             resultat = solutionOptimaleAux([OralAGarder for OralAGarder in Oraux if OralAGarder != Oral], solutionModifiable, MakespanHeuristique, Pause)
  74.             if resultat == None:
  75.                 solutionModifiable = solutionModifiable[:-1]
  76.             else:
  77.                 return resultat
  78.  
  79. def solutionOptimale(Eleves, Jurys):
  80.     Eleves.sort(key = lambda Eleve: Eleve.Nom)
  81.     Jurys.sort(key = lambda Jury: Jury.Nom)
  82.  
  83.     Pause = Eleves[0].Pause
  84.     DictEleves = {}
  85.     DictJurys = {}
  86.  
  87.     Oraux = []
  88.  
  89.     for i in range(len(Eleves)):
  90.         DictEleves[i] = Eleves[i]
  91.     for p in range(len(Jurys)):
  92.         DictJurys[p] = Jurys[p]
  93.  
  94.     for i in DictJurys.keys():
  95.         Duree = DictJurys[i].OralType_.Duree
  96.         for e in DictEleves.keys():
  97.             # Le nouvel oral est sous le format ((n° prof, n° élève), durée) : on évite de se trimballer des objets
  98.             Oraux.append(((i, e), Duree))
  99.  
  100.     resultatHeuristique = creerMeilleurEmploiDuTempsAvecPermutations(Jurys, Eleves)
  101.     meilleurMakespanHeuristique = resultatHeuristique[2]
  102.     resultatAux = solutionOptimaleAux(Oraux, [], meilleurMakespanHeuristique, Pause)
  103.     if resultatAux == None:
  104.         print("L'heuristique donne la meilleure solution.")
  105.         return resultatHeuristique
  106.     else:
  107.         return resultatAux
  108.  
  109. ################### CLASSES ELEVES / JURYS / ORAUX #############################
  110.  
  111. import copy
  112.  
  113. class Eleve:
  114.     Pause = 1
  115.     def __init__(self, Nom, Oraux):
  116.         self.Nom = Nom
  117.         self.Oraux = Oraux
  118.  
  119.     def estDisponible(self, Heure, OralType_, overrideAssocie = False):
  120.         if self.associe(OralType_) and not overrideAssocie:
  121.             return False
  122.         for Oral in self.Oraux:
  123.             if Oral.Heure <= Heure and Oral.HeureFin + self.Pause > Heure:
  124.                 return False
  125.             elif Oral.Heure >= Heure and Heure + OralType_.Duree + self.Pause > Oral.Heure:
  126.                 return False
  127.         return True
  128.  
  129.     def copieVide(self):
  130.         newEleve = Eleve(self.Nom, [])
  131.         return newEleve
  132.     def deplacerOral(self, oralADeplacer, nouvelleHeure):
  133.         for o in self.Oraux:
  134.             if o == oralADeplacer:
  135.                 o.changerHeure(nouvelleHeure)
  136.        
  137.     def associe(self, OralType_):
  138.         return OralType_ in [o.OralType_ for o in self.Oraux]
  139.        
  140.     def Associer(self, Oral):
  141.         self.Oraux.append(Oral)
  142.    
  143.     def __str__(self):
  144.         renvoye = self.Nom + "\n"
  145.         for o in self.Oraux:
  146.             renvoye += "\t"
  147.             renvoye += o.OralType_.Matiere + " de " + str(o.Heure) + " à " + str(o.HeureFin) + " pour " + o.Eleve.Nom + " avec " + o.Jury.Nom         
  148.             renvoye += "\n"
  149.         return renvoye
  150.  
  151. class Jury:
  152.     def __init__(self, Nom, OT, Oraux):
  153.         self.Nom = Nom
  154.         self.OralType_ = OT
  155.         self.Oraux = Oraux
  156.    
  157.     def copieVide(self):
  158.         newJury = Jury(copy.copy(self.Nom), self.OralType_, [])
  159.         return newJury
  160.    
  161.     def __str__(self):
  162.         return self.Nom
  163.  
  164.     def Associer(self, Oral):
  165.         self.Oraux.append(Oral)
  166.  
  167.     def estDisponible(self, Heure):
  168.         for Oral in self.Oraux:
  169.             if Oral.Heure <= Heure and Oral.HeureFin > Heure:
  170.                 return False
  171.             elif Oral.Heure >= Heure and Heure + self.OralType_.Duree > Oral.Heure:
  172.                 return False
  173.         return True    
  174.  
  175. class OralType:
  176.     def __init__(self, Matiere, Duree):
  177.         self.Matiere = Matiere
  178.         self.Duree = Duree
  179.  
  180. class Oral:
  181.     def __init__(self, OT, Jury, Eleve, Heure):
  182.         self.OralType_ = OT
  183.         self.Jury = Jury
  184.         self.Eleve = Eleve
  185.         self.Heure = Heure
  186.         self.HeureFin = Heure + OT.Duree
  187.         self.Duree = OT.Duree
  188.        
  189.     def __str__(self):
  190.         return self.OralType_.Matiere + " de " + str(self.Heure) + " à " + str(self.HeureFin) + " pour " + self.Eleve.Nom + " avec " + self.Jury.Nom
  191.  
  192.     def changerHeure(self, nouvelleHeure):
  193.         self.Heure = nouvelleHeure
  194.         self.HeureFin = nouvelleHeure + self.OralType_.Duree
  195.  
  196. ################# FONCTION DE GENERATION / VERIFICATION / ... #####################
  197.  
  198. def creerEmploiDuTemps(Jurys, Eleves):
  199.     for j in range(len(Jurys)):
  200.         heure = 0
  201.         while not Associes(Eleves, Jurys[j].OralType_):
  202.             AssociesDansCetteBoucle = 0
  203.             for e in range(len(Eleves)):
  204.                 if Eleves[e].estDisponible(heure, Jurys[j].OralType_):
  205.                     if Jurys[j].estDisponible(heure):
  206.                         #Création du nouvel objet oral
  207.                         newOral = Oral(Jurys[j].OralType_, Jurys[j], Eleves[e], heure)
  208.                         #Ajout de l'oral à l'élève en cours
  209.                         Eleves[e].Associer(newOral)
  210.                         #Ajout de l'oral au jury en cours
  211.                         Jurys[j].Associer(newOral)
  212.  
  213.                         #Modification des paramètres de recherche
  214.                         AssociesDansCetteBoucle += 1
  215.                         heure += Jurys[j].OralType_.Duree
  216.                         break #Sortie du for (élèves)
  217.             if AssociesDansCetteBoucle == 0:
  218.                 heure += 1
  219.    
  220. def trouverPermutations(Liste):
  221.     renvoye = []
  222.     ListeTravail = [elt.copieVide() for elt in Liste]
  223.     longueurListe = len(ListeTravail)
  224.     if longueurListe == 0:
  225.         return []
  226.     elif longueurListe == 1:
  227.         return [[ListeTravail[0].copieVide()]]
  228.     for elt in Liste:
  229.         temp = [copy.copy(autre) for autre in Liste if autre is not elt]
  230.         for perm in trouverPermutations(temp):
  231.             renvoye.append([elt.copieVide()] + perm)
  232.     return renvoye
  233.  
  234. def dureeEmploiDuTemps(Jurys):
  235.     maximum = 0
  236.     for Jury in Jurys:
  237.         for Oral in Jury.Oraux:
  238.             if Oral.HeureFin > maximum:
  239.                 maximum = Oral.HeureFin
  240.     return maximum
  241.  
  242. def Gerard(Jurys):
  243.     '''
  244.     Gerard trouve le dernier oral.
  245.     '''
  246.     maxi = 0
  247.     oralMaxi = None
  248.     juryMaxi = None
  249.     for Jury in Jurys:
  250.         for Oral in Jury.Oraux:
  251.             if Oral.Heure + Jury.OralType_.Duree > maxi:
  252.                 maxi = Oral.Heure + Jury.OralType_.Duree
  253.                 oralMaxi = Oral
  254.                 juryMaxi = Jury
  255.     return maxi, oralMaxi, juryMaxi        
  256.    
  257. def Michel(Eleve, OralADeplacer, Heure, maxHeure):
  258.     '''
  259.     Michel trouve où il peut déplacer l'oral fautif.
  260.     '''
  261.     #A la recherche de l'oral fautif
  262.     fautif = None
  263.  
  264.     for Oral in Eleve.Oraux:
  265.         if Oral.Heure <= Heure and Oral.HeureFin + Eleve.Pause > Heure:
  266.             fautif = Oral
  267.             break
  268.         elif Oral.Heure >= Heure and Heure + OralADeplacer.OralType_.Duree + Eleve.Pause > Oral.Heure:
  269.             fautif = Oral
  270.             break
  271.     # On a trouvé l'oral fautif !
  272.     #Où peut-on le mettre ?
  273.     nouvelleHeureFautif = 0
  274.     trouve = False
  275.     assert fautif != None, "fautif = none"
  276.     while nouvelleHeureFautif + Oral.Duree < maxHeure and not trouve:
  277.         if Pascal(Eleve, OralADeplacer, Heure, fautif, nouvelleHeureFautif):
  278.             trouve = True
  279.             break
  280.         nouvelleHeureFautif += 1
  281.     Eleve.deplacerOral(OralADeplacer, Heure)
  282.     Eleve.deplacerOral(fautif, nouvelleHeureFautif)
  283.        
  284. def Pascal(Eleve, OralADeplacer, Heure, OralTrouve, nouvelleHeure):
  285.     '''
  286.     Pascal fait un test : il déplace l'oral qu'on souhaite déplacer à sa nouvelle heure
  287.     puis déplace l'oral qui pose problème à la nouvelleHeure
  288.     Si c'est bon, il renvoie True ; sinon False
  289.     '''
  290.     sauvegarde = OralADeplacer.Heure
  291.     OralADeplacer.changerHeure(Heure)
  292.    
  293.     if Eleve.estDisponible(nouvelleHeure, OralTrouve.OralType_, True):
  294.         if OralTrouve.Jury.estDisponible(nouvelleHeure):
  295.             aRenvoyer = True
  296.         else:
  297. #           print("Prof pas disponible à " + str(nouvelleHeure))
  298. #           print(OralTrouve.Prof)
  299.             aRenvoyer = False
  300.     else:
  301. #       print("Eleve pas disonible à " + str(nouvelleHeure))
  302. #       print(Eleve)
  303.         aRenvoyer = False
  304.     OralADeplacer.changerHeure(sauvegarde)
  305.     return aRenvoyer
  306.        
  307.            
  308. def Thierry(Jury, Oral):
  309.     '''
  310.     Thierry trouve les trous où on peut mettre l'oral par rapport au prof
  311.     '''
  312.     disponible = []
  313.     for i in range(Oral.Heure):
  314.         if Jury.estDisponible(i):
  315.             disponible.append(i)
  316.     return disponible
  317.    
  318. def Bernard(Jurys):
  319.     '''
  320.     Bernard appelle ses potos pour faire le travail à sa place.
  321.     '''
  322.     maxi, oralMaxi, juryMaxi = Gerard(Jurys)
  323.     HeuresPossiblesProf = Thierry(juryMaxi, oralMaxi)
  324.     for Heure in HeuresPossiblesProf:
  325.         if oralMaxi.Eleve.estDisponible(Heure, oralMaxi.OralType_):
  326.             #bouger l'oral
  327.             oralMaxi.Eleve.deplacerOral(oralMaxi, Heure)
  328.         else:
  329.             #trouver une place libre et mettre l'oral
  330.             Michel(oralMaxi.Eleve, oralMaxi, Heure, maxi)
  331.             return
  332.  
  333.  
  334. def creerMeilleurEmploiDuTempsAvecPermutations(Jurys, Eleves):
  335.     meilleurMakespan = -1
  336.     meilleureSerie = ([], [])  
  337.     permutations = copy.deepcopy(trouverPermutations(Jurys))
  338.     for permutation in permutations:
  339.         tempEleves = [Eleve.copieVide() for Eleve in Eleves]       
  340.         creerEmploiDuTemps(permutation, tempEleves)
  341.         duree = dureeEmploiDuTemps(permutation)
  342.         if duree < meilleurMakespan or meilleurMakespan == -1:
  343.             meilleurMakespan = duree
  344.             meilleureSerie = (permutation, tempEleves, meilleurMakespan)
  345.     return meilleureSerie          
  346.  
  347. def creerEmploiDuTempsSansPermutations(Jurys, Eleves):
  348.     creerEmploiDuTemps(Jurys, Eleves)
  349.     return Jurys, Eleves, dureeEmploiDuTemps(Jurys)
  350.    
  351. def Associes(Eleves, OralType_):
  352.     for E in Eleves:
  353.         if E.associe(OralType_) == False:
  354.             return False
  355.     return True
  356.  
  357. ############## TESTS ###################
  358.  
  359.  
  360. Epreuves = {"Français" : OralType("Français", 4), "Anglais" : OralType("Anglais", 6), "Maths" : OralType("Maths", 4), "Physique" : OralType("Physique", 6)}
  361. Jurys = [Jury("Gugger", Epreuves["Maths"], []), Jury("Demange", Epreuves["Anglais"], []), Jury("Dervieux", Epreuves["Physique"], []), Jury("Astier", Epreuves["Français"], [])]
  362. #Eleves = [Eleve("Thomas", []), Eleve("Benjamin", []), Eleve("Matthis", []), Eleve("Esprit", []), Eleve("Eldred", []), Eleve("Louis-Matis", [])]
  363. Eleves = [Eleve("Thomas", []), Eleve("Benjamin", []), Eleve("Esprit", [])]
  364.  
  365. #Couleurs jolies pour l'affichage
  366. Couleurs = ['darksalmon', 'mediumaquamarine', 'pink', 'springgreen', 'peru', 'dimgrey', 'brown']
  367.  
  368.  
  369.  
  370.  
  371. #Génération d'un emploi du temps avec les données du dessus ^
  372. EDT = creerMeilleurEmploiDuTempsAvecPermutations(Jurys, Eleves)
  373. print("Génération d'un emploi du temps pour {} élèves et {} jurys (avec une pause minimale de {} minutes entre chaque épreuve pour les élèves).".format(len(Eleves), len(Jurys), Eleves[0].Pause * 10))
  374. print("Makespan : {} heures, {} minutes".format(minutesVersHeures(EDT[2] * 10)[0], minutesVersHeures(EDT[2] * 10)[1]))
  375. if EDT[2] == max([Oral.Duree for Oral in Epreuves.values()]) * len(Eleves):
  376.     optimal = True
  377.     print("Solution optimale. (Makespan = Makespan_min = t_max * n)")
  378. else:
  379.     optimal = False
  380.  
  381. if not optimal:
  382.     print("Application de Bernard.")
  383.     compteur = 1
  384.     duree = dureeEmploiDuTemps(EDT[0])
  385.     Bernard(EDT[0])
  386.     dureeBernard = EDT[0]
  387.     while duree != dureeBernard:
  388.         compteur += 1
  389.         Bernard(EDT[0])
  390.         duree = dureeBernard
  391.         dureeBernard = dureeEmploiDuTemps(EDT[0])
  392.     print("Bernard est venu aider " + str(compteur) + " fois !")
  393.    
  394. print("Affichage de la solution en cours.")
  395.  
  396. #Génération de la solution optimale en utilisant le parcours d'arbre
  397.  
  398. #print("Génération de la solution optimale (ça peut prendre du temps...)")
  399. #EDT = solutionOptimale(Eleves, Jurys)
  400. #print("Génération terminée, affichage des résultats.")
  401.  
  402.  
  403. #Préparation de l'affichage
  404. #Liste qui contient les rectangles
  405. patches = []
  406. #Pour chaque prof
  407. for Prof in EDT[0]:
  408.     #On utilise cette liste pour obtenir les couleurs associées aux élèves
  409.     temp = copy.deepcopy([e.Eleve.Nom for e in Prof.Oraux])
  410.     temp.sort()
  411.     for oral in Prof.Oraux:
  412.         #On ajoute un rectangle correspondant à la combinaison oral / élève dans patches
  413.         ajouterOral(oral, [Epreuves[k] for k in Epreuves.keys()], Couleurs[temp.index(oral.Eleve.Nom)], patches)
  414. #Affiche la fenêtre graphique
  415. afficher(patches)
Advertisement
Add Comment
Please, Sign In to add comment