コード例 #1
0
        public override int CalculateLocalCost(IAllel[] rowOfAlleles, int index)
        {
            string doctor = _doctorIds[index];
            DutyRequirementForMonthDto dutyRequirement = _dutyRequirementsForMonth.FirstOrDefault(d => d.UserId == doctor);

            if (dutyRequirement == null)
            {
                return(0);
            }

            int numberOfRequiredDuties = dutyRequirement.RequiredTotalDutiesInMonth;
            int numberOfAssignedDuties = rowOfAlleles.Count(a => a != null && a.Value == Allel.OnDuty.Value);

            return(numberOfRequiredDuties - numberOfAssignedDuties);
        }
コード例 #2
0
        private IEnumerable <int> MatrixAssignedDutyRequirements(IAllel[,] dna)
        {
            for (int i = 0; i < dna.GetLength(0); i++)
            {
                string doctor = _doctorIds[i];
                DutyRequirementForMonthDto dutyRequirement = _dutyRequirementsForMonth
                                                             .FirstOrDefault(d => d.UserId == doctor);

                if (dutyRequirement == null)
                {
                    continue;
                }

                for (int j = 0; j < dna.GetLength(1); j++)
                {
                    if (dna[i, j] != null && dna[i, j].Value == Allel.OnDuty.Value)
                    {
                        yield return(1);
                    }
                }
            }
        }
コード例 #3
0
ファイル: SpeciesOriginator.cs プロジェクト: aspdev/Scheduler
        private void SetDuties()
        {
            Parallel.ForEach(_individuals, (individual) =>
            {
                List <DutyRequirementForMonthDto> dutyRequirementsForMonth =
                    new List <DutyRequirementForMonthDto>(_dutyRequirementsForMonth);
                List <string> doctorsAvailableForSchedule = new List <string>(_doctorIds);

                for (int i = 0; i < DateTime.DaysInMonth(_date.Year, _date.Month); i++)
                {
                    // 1. Usuwamy z listy doctorsAvailableForSchedule lekarzy, którzy wyczerpali dostępną ilość dyżurów

                    foreach (var doctorId in new List <string>(doctorsAvailableForSchedule))
                    {
                        var doctorDutyRequirements = dutyRequirementsForMonth.FirstOrDefault(dr => dr.UserId == doctorId);

                        if (doctorDutyRequirements != null)
                        {
                            if (doctorDutyRequirements.RequiredTotalDutiesInMonth == 0)
                            {
                                doctorsAvailableForSchedule.Remove(doctorId);
                            }
                        }
                    }

                    // 2. Jeżeli nadal na liście doctorsAvailableForSchedule jest dostępny lekarz kontunuujemy

                    if (doctorsAvailableForSchedule.Count > 0)
                    {
                        // 2. Tworzymy z listy doctorsAvailableForSchedule początkową pulę lekarzy dostępnych danego dnia (doctorsAvailableForDay)

                        List <string> doctorsAvailableForDay = new List <string>(doctorsAvailableForSchedule);

                        // 3. Usuwamy lekarzy, którzy zgłosili niemożność lub mieli dyżur pooprzedniego dnia

                        for (int j = i; j < i + 1; j++)
                        {
                            for (int k = 0; k < _totalNumberOfDoctors; k++)
                            {
                                for (int m = j; m <= j; m++)
                                {
                                    if (individual.Dna[k, m] == Allel.DayOff)
                                    {
                                        doctorsAvailableForDay.Remove(_doctorIds[k]);
                                        continue;
                                    }

                                    // poprzedni dzień

                                    if (m > 0)
                                    {
                                        if (individual.Dna[k, m - 1] == Allel.OnDuty)
                                        {
                                            doctorsAvailableForDay.Remove(_doctorIds[k]);
                                            continue;
                                        }
                                    }

                                    // ostatni dzień poprzedniego miesiąca

                                    if (m == 0 && _doctorsOnDutyLastDayOfPreviousMonth.Count > 0)
                                    {
                                        if (_doctorsOnDutyLastDayOfPreviousMonth.Contains(_doctorIds[k]))
                                        {
                                            doctorsAvailableForDay.Remove(_doctorIds[k]);
                                        }
                                    }
                                }
                            }
                        }

                        DateTime currentDate = new DateTime(_date.Year, _date.Month, i + 1);

                        if (doctorsAvailableForDay.Count > 0)
                        {
                            // 4.Jeżeli w danym dniu przypada święto, usuwamy lekarza z listy dostępnych w tym dniu jeśli lekarz wyczerpał limit dostępności w święta(Item3)

                            if (IsWeekendOrPublicHoliday(currentDate))
                            {
                                foreach (var doctorId in new List <string>(doctorsAvailableForDay))
                                {
                                    var doctorDutyRequirements =
                                        dutyRequirementsForMonth.FirstOrDefault(dr => dr.UserId == doctorId);

                                    if (doctorDutyRequirements != null)
                                    {
                                        if (doctorDutyRequirements.RequiredTotalHolidayDuties == 0)
                                        {
                                            doctorsAvailableForDay.Remove(doctorId);
                                        }
                                    }
                                }
                            }



                            // 5. Jeżeli dzień nie jest świąteczny, usuwamy lekarza z listy dostępnych w tym dniu jeśi lekarz wyczerpał limit dostepności w dni robocze (Item2)

                            if (!IsWeekendOrPublicHoliday(currentDate))
                            {
                                foreach (var doctorId in new List <string>(doctorsAvailableForDay))
                                {
                                    var doctorDutyRequirements =
                                        dutyRequirementsForMonth.FirstOrDefault(dr => dr.UserId == doctorId);

                                    if (doctorDutyRequirements != null)
                                    {
                                        if (doctorDutyRequirements.RequiredTotalWeekdayDuties == 0)
                                        {
                                            doctorsAvailableForDay.Remove(doctorId);
                                        }
                                    }
                                }
                            }

                            // 6. Dodajemy lekarzy na dyżur. Odniesieniem jest indeks na liście _doctorsId i wiersze tablicy

                            for (int t = 0; t < _numberOfDoctorsOnDuty; t++)
                            {
                                if (doctorsAvailableForDay.Count > 0)
                                {
                                    var doctor =
                                        doctorsAvailableForDay[
                                            RandomGenerator.IntBetween(0, doctorsAvailableForDay.Count)];

                                    int index = _doctorIds.IndexOf(doctor);
                                    individual.Dna[index, i] = Allel.OnDuty;

                                    var doctorDutyRequirements =
                                        dutyRequirementsForMonth.FirstOrDefault(d => d.UserId == doctor);

                                    if (doctorDutyRequirements != null)
                                    {
                                        int requiredTotalDuties;
                                        int requiredWeekdayDuties;
                                        int requiredHolidayDuties;

                                        if (IsWeekendOrPublicHoliday(currentDate))
                                        {
                                            requiredTotalDuties   = doctorDutyRequirements.RequiredTotalDutiesInMonth - 1;
                                            requiredWeekdayDuties = doctorDutyRequirements.RequiredTotalWeekdayDuties;
                                            requiredHolidayDuties = doctorDutyRequirements.RequiredTotalHolidayDuties - 1;
                                        }
                                        else
                                        {
                                            requiredTotalDuties   = doctorDutyRequirements.RequiredTotalDutiesInMonth - 1;
                                            requiredWeekdayDuties = doctorDutyRequirements.RequiredTotalWeekdayDuties - 1;
                                            requiredHolidayDuties = doctorDutyRequirements.RequiredTotalHolidayDuties;
                                        }

                                        DutyRequirementForMonthDto updated = new DutyRequirementForMonthDto
                                        {
                                            UserId = doctorDutyRequirements.UserId,
                                            RequiredTotalDutiesInMonth = requiredTotalDuties,
                                            RequiredTotalWeekdayDuties = requiredWeekdayDuties,
                                            RequiredTotalHolidayDuties = requiredHolidayDuties
                                        };

                                        dutyRequirementsForMonth.Remove(doctorDutyRequirements);
                                        dutyRequirementsForMonth.Add(updated);
                                    }

                                    doctorsAvailableForDay.Remove(doctor);
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                    }
                    else
                    {
                        // 7. Jeżeli nie ma lekarzy z dostępnymi dniami dyżurowymi w grafiku (doctorsAvailableForScheduler) przerywamy pętlę
                        break;
                    }
                }
            });
        }
コード例 #4
0
ファイル: SpeciesOriginator.cs プロジェクト: aspdev/Scheduler
        public IAllel[,] Repair(IAllel[,] dna)
        {
            List <int> rows = new List <int>();

            // 1. Usuwamy zbędne allele jeśli w kolumnie istnieje więcej niż liczba lekarzy wymaganych na dyżurze

            // a) zliczamy allel OnDuty i rząd zapisujemy na liście

            // TODO: Usuwane allele mogą być tymi, których ilość została na sztywno zdefiniowana przez lekarza

            for (int i = 0; i < DateTime.DaysInMonth(_date.Year, _date.Month); i++)
            {
                for (int j = 0; j < _totalNumberOfDoctors; j++)
                {
                    for (int k = i; k <= i; k++)
                    {
                        if (dna[j, k] != null && dna[j, k].Value == Allel.OnDuty.Value)
                        {
                            rows.Add(j);
                        }
                    }
                }

                // b. jeśli w danym dniu jest więcej alleli OnDuty niż powinno być usuwamy zbędne

                if (rows.Count > _numberOfDoctorsOnDuty)
                {
                    RemoveRedundantAlleles(dna, i, rows);
                }

                rows.Clear();
            }

            // 2. Jeśli w kolumnie jest mniej lekarzy niż powinno być dopełniamy do wymaganej liczby

            /*
             * Niedostępności:
             * - kiedy ma już przypisany dyżur,
             * - kiedy jest wstawiona niemożność,
             * - kiedy ma dyżur następnego dnia,
             * - kiedy miał dyżur poprzedniego dnia,
             * - kiedy miał dyżur ostatniego dnia w poprzednim miesiącu (przypadek szczególny dla dyżurów 1 dnia)
             *
             */

            List <int> unavailableDoctors = new List <int>();

            for (int i = 0; i < DateTime.DaysInMonth(_date.Year, _date.Month); i++)
            {
                int onDutyCount = 0; // zliczamy ile jest na dyżurze

                for (int j = 0; j < _totalNumberOfDoctors; j++)
                {
                    for (int k = i; k <= i; k++)
                    {
                        if (dna[j, k] != null && dna[j, k].Value == Allel.OnDuty.Value)
                        {
                            onDutyCount++;
                            rows.Add(j);  // niedostępny jeśli ma juz przypisany dużur
                        }

                        if (dna[j, k] != null && dna[j, k].Value == Allel.DayOff.Value)
                        {
                            rows.Add(j); // niedostępny jeśli jest "niemożność"
                        }

                        if (k < (DateTime.DaysInMonth(_date.Year, _date.Month) - 1))
                        {
                            if (dna[j, k + 1] != null && dna[j, k + 1].Value == Allel.OnDuty.Value)
                            {
                                rows.Add(j); // niedostępny jeśli ma dyżur następnego dnia
                            }
                        }

                        if (k > 0)
                        {
                            if (dna[j, k - 1] != null && dna[j, k - 1].Value == Allel.OnDuty.Value)
                            {
                                rows.Add(j); // niedostępny niedostępny jeśli miał dyżur poprzedniego dnia
                            }
                        }

                        if (k == 0)
                        {
                            foreach (var doctor in _doctorsOnDutyLastDayOfPreviousMonth)
                            {
                                int index = _doctorIds.IndexOf(doctor);
                                rows.Add(index); // niedostępny - przypadek szczególny - dużur poprzedniego dnia w poprzednim miesiącu
                            }
                        }

                        // spawdzamy czy możemy dodać lekarza ze względu na limity, które zdefiniował

                        /*
                         * Ponieważ istnieje korelacja pomiędzy indeksami listy "doctorIds" oraz indeksami wierszy w tablicy,
                         * możliwe jest wyciągniecie GuidId lekarza z listy doctorIds i sprawdzenie jego wymagań dyżurowych
                         */

                        // if(unavailableDoctors.Contains(j) --> nie wykonuj kodu poniżej, wiemy, że już jest niedostępny

                        if (!unavailableDoctors.Contains(j))
                        {
                            string doctorId = _doctorIds[j];
                            DutyRequirementForMonthDto doctorDutyRequirement =
                                _dutyRequirementsForMonth.FirstOrDefault(d => d.UserId == doctorId);

                            // jeżeli sformułowano wymagania dotyczące ilości dyżurów
                            if (doctorDutyRequirement != null)
                            {
                                var numberOfDutiesInTheRow = dna.GetRow(j)
                                                             .Count(a => a != null && a.Value == Allel.OnDuty.Value);

                                if (numberOfDutiesInTheRow >= doctorDutyRequirement.RequiredTotalDutiesInMonth)
                                {
                                    //rows.Add(j); // niesdostępny - wyczerpał zdefiniowany limit
                                    unavailableDoctors.Add(j); // dodajemy do listy niedostępnych
                                }
                                else
                                {
                                    DateTime currentDate = new DateTime(_date.Year, _date.Month, k + 1);

                                    // jeśli dzień jest świętem sprawdzamy czy limit świąt został wyczerpany

                                    if (IsWeekendOrPublicHoliday(currentDate))
                                    {
                                        var doctorDuties       = dna.GetRow(j);
                                        int holidayDutiesCount = 0;

                                        // liczymy ile dyżurów ma w święta

                                        for (int d = 0; d < doctorDuties.Length; d++)
                                        {
                                            if (IsWeekendOrPublicHoliday(new DateTime(_date.Year, _date.Month, d + 1)) &&
                                                doctorDuties[d] != null &&
                                                doctorDuties[d].Value == Allel.OnDuty.Value)
                                            {
                                                holidayDutiesCount++;
                                            }
                                        }

                                        if (holidayDutiesCount >= doctorDutyRequirement.RequiredTotalHolidayDuties)
                                        {
                                            rows.Add(j); // niedostępny w święta - wyczerpał limit świąt
                                        }
                                    }
                                    else //sprawdzamy dni powszednie
                                    {
                                        var doctorDuties       = dna.GetRow(j);
                                        int weekdayDutiesCount = 0;

                                        // liczymy ile dyżurów ma w dni powszednie

                                        for (int d = 0; d < doctorDuties.Length; d++)
                                        {
                                            if ((!IsWeekendOrPublicHoliday(new DateTime(_date.Year, _date.Month, d + 1))) &&
                                                doctorDuties[d] != null && doctorDuties[d].Value == Allel.OnDuty.Value)
                                            {
                                                weekdayDutiesCount++;
                                            }
                                        }

                                        if (weekdayDutiesCount >= doctorDutyRequirement.RequiredTotalWeekdayDuties)
                                        {
                                            rows.Add(j); // niedsotępny w dniu powszednie - wyczerpał limit
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                // tutaj musimy dodać niedostepnych do rows

                var inaccessibleRows = rows.Union(unavailableDoctors).ToList();


                if (onDutyCount < _numberOfDoctorsOnDuty) // jeśli na dyżurze jest mniej niż wymagane uzupełniamy
                {
                    InsertMissingAllels(dna, i, onDutyCount, inaccessibleRows);
                }

                rows.Clear();
            }

            return(dna);
        }