Ceci est une page optimisée pour les mobiles. Cliquez sur ce texte pour afficher la vraie page.

XL 2019 Création aléatoire planning

Boostez vos compétences Excel avec notre communauté !

Rejoignez Excel Downloads, le rendez-vous des passionnés où l'entraide fait la force. Apprenez, échangez, progressez – et tout ça gratuitement ! 👉 Inscrivez-vous maintenant !

maroue

XLDnaute Nouveau
Bonjour à tous,

J'ai besoin de vos lumières.
Je dois créer un planning de permanence avec P1 et P2 ( qui signifie Permanence 1 et Permanence 2 )
Planning mensuel ou les week-end sont non travaillés.
Chaque personnes doit faire soit 2 P1 et 1 P2 ou inversement sur le mois.
Voici les personnes par initiales : HA, JB, LCB, SD, LE, MEK, MK, MLM, SM, LP, LRL, BU, EL, RC, TB, CM, ET
Faut que cela soit équitable et que le mois d'aprés cela change ( si au mois de juin une personne a fait 2 P1 et 1 P2, au mois de juillet elle fera 1 P1 et 2 P2 )

Je vous mets le "genre" de planning qu'il y a actuellement, c'est juste un tableau excel remplis manuellement par les personnes concernées ( y a des trous, et pas de "roulement "

Merci pour votre aide,
Bonne journée
 

Pièces jointes

Bonjour @maroue ,
Voici ton fichier en retour.

Sur la feuille SAISIE, il y a les 12 mois de l'année qui se mettent à jour au changement de la cellule Année (Cellule C2).
Les Samedis, Dimanches et Jours Fériés sont repérés automatiquement en fond de couleur.
La feuille est protégée (pas de mot de passe) ce qui permet de ne saisir uniquement les personnels dans les cases souhaitées.

Les personnels sont triés par ordre alphabétique pour simplifier la saisie (Zone de liste déroulante)

Plusieurs impossibilité de saisie.
- Si on saisie dans une case WE ou Jour Férié
- Si on saisie plus de 2 fois le même personnel dans une même permanence pour un même mois
- Si on saisie plus de 3 fois le même personnel (Permanence 1 et 2) pour un même mois
- Si on saisie la même permanence 1 et 2 sur le mois en cour et le mois précédent

A droite des mois, se trouve 2 tableaux (Jours fériés en fonction de l'année (Cellule C2) et plus a droite un récapitulatif des Permanence 1, Permanence 2 et Permanence Totale pour chaque mois.

Bref, voici ce que j'ai fait (Si j'ai bien compris la consigne)
Merci pour le retour
@+ Lolote83
 

Pièces jointes

Bonjour maroue, Lolote83,

Voyez le fichier joint et la macro affectée au bouton :
VB:
Sub Tirage()
Dim personnes, ub%, deb As Range, dates As Range, P1P2(), n%, i%, j%, mini%, maxi%, r%
personnes = Array("HA", "JB", "LCB", "SD", "LE", "MEK", "MK", "MLM", "SM", "LP", "LRL", "BU", "EL", "RC", "TB", "CM", "ET")
ub = UBound(personnes)
Set deb = [b2]
While Application.Count(deb.EntireColumn)
    Set dates = deb.EntireColumn.SpecialCells(xlCellTypeConstants, 1)
    ReDim P1P2(1 To 2, 0 To ub) 'RAZ du tableau auxiliaire
    n = 0
    For i = 1 To dates.Count
        For j = 2 To 3
            If dates(i, j).Interior.Color <> vbBlack Then n = n + 1
    Next j, i
    mini = Int(n / (ub + 1)) 'minimum pour chaque personne
    maxi = Application.RoundUp(n / (ub + 1), 0) 'maximum pour chaque personne
    For i = 1 To dates.Count
        For j = 2 To 3
            If dates(i, j).Interior.Color <> vbBlack Then
                n = IIf(Application.Sum(P1P2) < mini * (ub + 1), mini, maxi)
                Do
                    r = Application.RandBetween(0, ub)
                    If P1P2(j - 1, r) + P1P2(4 - j, r) < n Then _
                        If P1P2(j - 1, r) < P1P2(4 - j, r) + 1 Then _
                            P1P2(j - 1, r) = P1P2(j - 1, r) + 1: dates(i, j) = personnes(r): Exit Do
                Loop
            End If
    Next j, i
    Set deb = deb.Offset(, 4) 'tableau suivant
Wend
End Sub
Les cellules à ne pas remplir (jours fériés) doivent être colorées en noir comme sur le fichier fourni.

Bien comprendre que pour le comptage il y a 2 limites : mini et maxi.

On passe à maxi seulement quand chaque personne a un total égal à mini.

A+
 

Pièces jointes

bonjour maroue, lolote83, job75,
juste un essai pour voir si tout est okay, le reste est encore à optimaliser. Le but est de faire le planning directement pour une année et pour le moment encore sans jours fériés.
 

Pièces jointes

Dernière édition:
Pour vous éviter d'avoir à construire les tableaux des mois suivants j'ai ajouté cette macro (assez laborieuse, désolé) :
VB:
Sub Ajout_mois()
Dim deb As Range, mois%, annee%, Paques As Date, LundiPaques$, Ascension$, LundiPentecote$, feries, i&, dat As Date, n&, fer As Range, sem%, lig&

Set deb = Cells(1, Columns.Count).End(xlToLeft) 'dernier tableau
mois = Month(CDate(deb) + 31): annee = Year(CDate(deb) + 31)
Paques = Evaluate("DOLLAR((""4/""&" & annee & ")/7+MOD(19*MOD(" & annee & ",19)-7,30)*14%,)*7-6")
LundiPaques = Format(Paques + 1, "d/m")
Ascension = Format(Paques + 39, "d/m")
LundiPentecote = Format(Paques + 50, "d/m")
feries = Array("1/1", "1/5", "8/5", "14/7", "15/8", "1/11", "11/11", "25/12", LundiPaques, Ascension, LundiPentecote)

Application.ScreenUpdating = False
deb.MergeArea.Copy deb(1, 5) '1ère ligne
deb(2).Resize(, 3).Copy deb(2, 5) '2ème ligne
Set deb = deb(3, 5) 'cellule de la 1ère date
deb(1, 0).ColumnWidth = 10: deb(1, 2).Resize(, 2).ColumnWidth = 28 'lageurs des colonnes
deb.EntireColumn.Resize(, 3).HorizontalAlignment = xlCenter 'centrage
deb.EntireColumn.NumberFormat = "dddd d mmmm yyyy" 'format Date
For i = 1 To 31
    dat = DateSerial(annee, mois, i)
    If Month(dat) = mois And Weekday(dat, 2) < 6 Then
        n = n + 1
        deb(n) = dat
        deb(n).Resize(, 3).Borders.Weight = xlThin
        If IsNumeric(Application.Match(Format(dat, "d/m"), feries, 0)) Then _
            Set fer = Union(IIf(fer Is Nothing, deb(n, 2).Resize(, 2), fer), deb(n, 2).Resize(, 2))
        If Weekday(dat, 2) = 5 Then
            sem = sem + 1
            With Range(deb(lig + 1), deb(n)).Resize(, 3)
                .BorderAround Weight:=xlMedium
                If sem Mod 2 Then .Interior.Color = RGB(242, 242, 242) 'gris clair
            End With
            lig = n
        End If
    End If
Next i
If lig < n Then
    sem = sem + 1
    With Range(deb(lig + 1), deb(n)).Resize(, 3)
        .BorderAround Weight:=xlMedium
        If sem Mod 2 Then .Interior.Color = RGB(242, 242, 242) 'gris clair
    End With
End If
If Not fer Is Nothing Then fer.Interior.Color = vbBlack 'colore en noir les jours fériés
deb.EntireColumn.AutoFit 'ajustement largeur
End Sub
J'ai trouvé la formule de la date de Pâques sur un post de Roger2327 en 2014 :

https://excel-downloads.com/threads/date-de-paques.220074/#post-1391514

Bonne nuit.
 

Pièces jointes

Bonjour le forum,

La formule de calcul de la date de Pâques utilisée au post précédent est valable jusqu'à l'année 2203.

La 1ère formule donnée par ROGER2327 ne semble pas avoir de limite, je l'utilise dans ce fichier (3) :
VB:
mois = Month(CDate(deb) + 31): annee = Year(CDate(deb) + 31): ThisWorkbook.Names.Add "An", annee 'nom défini An
ThisWorkbook.Names.Add "X", Evaluate("MOD(INT(An/400)-INT(An/100)+INT(8*(INT(An/100)+11)/25)+11*MOD(An,19)+11,30)") 'calcul intermédiaire
Paques = Evaluate("DATE(An,4,25-X-INT((8-19*X+MOD(An,19))/544)-MOD(MOD(-X-INT((8-19*X+MOD(An,19))/544),7)+MOD(MOD(2-2*MOD(INT(An/100),4),7)+MOD(An,100)+INT(MOD(An,100)/4),7),7))")
A+
 

Pièces jointes

Bonjour le forum,

Dans ce fichier (4) un 3ème bouton permet de créer les 12 mois de l'année choisie :
VB:
ub MAJ_12_mois()
Dim annee, n%
Do
    annee = Application.InputBox("Année :", "MAJ 12 mois", CStr(annee))
    If annee = False Or annee = "" Then Exit Sub
Loop While Not annee Like "####"
Application.ScreenUpdating = False
Columns("E").Resize(, Columns.Count - 4).Delete
[B3] = DateSerial(annee - 1, 12, 1) 'décembre de l'année précédente
For n = 1 To 12: Ajout_mois: Next
[B:E].Delete
Application.Goto [A1], True: [B1].Select 'cadrage
End Sub
A+
 

Pièces jointes

Dernière édition:
Bonjour à tous,
@job75 , je viens de reprendre ton fichier du post #9 et j'ai rajouté à droite un tableau récapitulatif suite au tirage.
D'après la demande initiale de @maroue il est dit :
Faut que cela soit équitable et que le mois d'après cela change ( si au mois de juin une personne a fait 2 P1 et 1 P2, au mois de juillet elle fera 1 P1 et 2 P2 )

Or je constate que sur 2 mois consécutifs, il y a parfois la même répartition (2 P1 et 1 P2). Voir ci-dessous quelques exemples colorés qui me sembles erronés.


Peut être que j'ai mal compris la demande mais à mon avis, il ne peut y avoir 2 P1 et 1 P2 identique sur 2 mois consécutifs
Cordialement
@+ Lolote83
 

Pièces jointes

je crois qu'il y a quelques jours dont les 2 permanences sont fait par la même personne. Peut-être chez vous des autres cellules parce qu'après chaque lancement de la macro, on a une autre solution ...
 
Re bonjour,
@bsalv , même constat comme expliqué dans le post#10 ou des mois consécutifs sont identiques en nombre de P1 et P2.
Cependant, je réitère, peut être ais-je mal compris la demande initiale
Faut que cela soit équitable et que le mois d'aprés cela change ( si au mois de juin une personne a fait 2 P1 et 1 P2, au mois de juillet elle fera 1 P1 et 2 P2 )

Voir ici (colorés à la mano) quelques exemples suite tirage sur ton fichier joint au post#13


EDIT :
Je rectifie car j'ai simplement regardé que les mois consécutifs identiques et dans les exemples colorés il n'y a que des 1 pour 1. Donc peut être est-ce OK finalement

Cependant, nous n'avons toujours pas de nouvelle de @maroue afin de savoir si vos solutions sont correctes ou pas (@job75 et @bsalv)

@+ Lolote83
 
Dernière édition:
Avec des tirages aléatoires il me semble quasi impossible d'éviter des répétions d'un mois à l'autre.

Par contre sur 12 mois j'ai étudié les écarts entre le maximum et le minimum de jours des personnes.

Il peut varier de 3 à 10 suivant les tirages.

Dans ce dernier fichier, sur 12 mois, je fais donc 100 tirages pour récupérer un écart minimum :
VB:
Dim d As Object 'mémorise la variable
'----

Sub Tirage_optimal()
Dim t, plage As Range, ntirage%, mini%, n%, ecart%, tablo
t = Timer
Set plage = ActiveSheet.UsedRange.Offset(1)
ntirage = 100 'modifiable
mini = 50
Application.ScreenUpdating = False
For n = 1 To ntirage
    Tirage
    ecart = Application.Max(d.items) - Application.Min(d.items)
    If ecart < mini Then
        mini = ecart
        tablo = plage 'mémorise
    End If
Next
 plage = tablo 'restitution
Application.ScreenUpdating = True
MsgBox ntirage & " tirages effectués en " & Format(Timer - t, "0.00 \sec") & vbLf & vbLf & "Ecart obtenu " & mini, , "Tirage optimal"
End Sub
Le Dictionary est créé dans la macro Tirage.

En faisant pas mal d'essais j'ai pu obtenir un écart de 2.

A+
 

Pièces jointes

- Navigue sans publicité
- Accède à Cléa, notre assistante IA experte Excel... et pas que...
- Profite de fonctionnalités exclusives
Ton soutien permet à Excel Downloads de rester 100% gratuit et de continuer à rassembler les passionnés d'Excel.
Je deviens Supporter XLD
Les cookies sont requis pour utiliser ce site. Vous devez les accepter pour continuer à utiliser le site. En savoir plus…