private bool FindSolutions(IEnumerable<Subject> subjects)
        {
            var subject = subjects.FirstOrDefault();
            if (subject == null)
            {
                double weight = GetSolutionWeight(currentSolution, groups);

                if (bestSolutions.Count == 0)
                {
                    bestSolutions.AddFirst(new Tuple<ScheduledTimeSlot[], double>(GetCurrentSolutionArray(), weight));
                }
                else
                {
                    LinkedListNode<Tuple<ScheduledTimeSlot[], double>> scheduledTimeSlot;
                    for (scheduledTimeSlot = bestSolutions.First; scheduledTimeSlot != null; scheduledTimeSlot = scheduledTimeSlot.Next)
                    {
                        if (weight >= scheduledTimeSlot.Value.Item2)
                        {
                            ScheduledTimeSlot[] copy = new ScheduledTimeSlot[currentSolution.Count];
                            currentSolution.CopyTo(copy, 0);
                            bestSolutions.AddBefore(scheduledTimeSlot, new Tuple<ScheduledTimeSlot[], double>(copy, weight));
                            if (bestSolutions.Count > 10)
                            {
                                bestSolutions.RemoveLast();
                            }
                            break;
                        }
                    }
                }
                return weight != Double.MaxValue;
            }

            foreach (var room in rooms.
                Where(r => r.types.IsSupersetOf(subject.roomTypes)).
                Where(r => r.capacity >= subject.attendingPeopleCount).
                Where(r => subject.teachers.All(t => t.requirements.requiredRooms.Contains(r))))
            {
                var roomAvailabilities = room.availability.SelectMany(a => a.GetAllWindows(subject.duration)).ToList();
                foreach (var windowTimeSlot in roomAvailabilities)
                {
                    int dayOfWeek = (int) windowTimeSlot.Day - 1;
                    if (subject.GetGroups().All(g => groupAvailabilities[g][dayOfWeek].Any(a => a.Includes(windowTimeSlot))))
                    {
                        if (subject.teachers.All(t => t.requirements.weight != 1 ||
                            t.requirements.availableTimeSlots.Any(a => a.Includes(windowTimeSlot))))
                        {
                            TimeSlot.RemoveTimeSlotFromAvailability(room.availability, windowTimeSlot);
                            foreach (var group in subject.GetGroups())
                            {
                                TimeSlot.RemoveTimeSlotFromAvailability(groupAvailabilities[group][dayOfWeek], windowTimeSlot);
                            }
                            currentSolution.AddLast(new ScheduledTimeSlot(subject, room, windowTimeSlot, subject.GetGroups()));

                            if (!FindSolutions(subjects.Skip(1)))
                            {
                                return false;
                            }

                            currentSolution.RemoveLast();
                            foreach (var group in subject.GetGroups())
                            {
                                TimeSlot.AddTimeSlotToAvailability(groupAvailabilities[group][(int)windowTimeSlot.Day - 1], windowTimeSlot);
                            }
                            TimeSlot.AddTimeSlotToAvailability(room.availability, windowTimeSlot);
                        }
                    }
                }
            }

            return true;
        }
 private ScheduledTimeSlot[] GetCurrentSolutionArray()
 {
     ScheduledTimeSlot[] copy = new ScheduledTimeSlot[currentSolution.Count];
     currentSolution.CopyTo(copy, 0);
     return copy;
 }