/// <summary>
        /// Generates a new seed.
        /// </summary>
        public int GenerateSeed(UserQuestionData userQuestionData, int numSeeds)
        {
            var existingSeeds = userQuestionData.Submissions
                                ?.Where(uqs => uqs.Seed.HasValue && uqs.Seed < numSeeds)
                                ?.GroupBy(uqs => uqs.Seed.Value)
                                ?.ToDictionary(g => g.Key, g => g.Count())
                                ?? new Dictionary <int, int>();

            int newSeed;

            if (existingSeeds.Count >= numSeeds)
            {
                newSeed = existingSeeds
                          .MinBy(kvp => kvp.Value)
                          .Key;
            }
            else
            {
                do
                {
                    newSeed = _randomNumberProvider.NextInt() % numSeeds;
                } while (existingSeeds.ContainsKey(newSeed));
            }

            return(newSeed);
        }
        /// <summary>
        /// Returns the next question ID to use.
        /// </summary>
        public int GetNextQuestionId(
            UserQuestionData userQuestionData,
            IList <int> availableQuestionIds)
        {
            var seenQuestionIds = userQuestionData
                                  ?.Submissions
                                  ?.Where(uqs => uqs.Seed.HasValue)
                                  ?.GroupBy(uqs => uqs.Seed.Value)
                                  ?.ToDictionary(g => g.Key, g => g.Count())
                                  ?? new Dictionary <int, int>();

            var validQuestionIds = new HashSet <int>(availableQuestionIds);

            var unseenQuestionIds = validQuestionIds
                                    .Except(seenQuestionIds.Keys)
                                    .ToList();

            if (unseenQuestionIds.Any())
            {
                var randomIndex = _randomNumberProvider.NextInt() % unseenQuestionIds.Count;

                return(unseenQuestionIds[randomIndex]);
            }
            else
            {
                return(seenQuestionIds
                       .Where(kvp => validQuestionIds.Contains(kvp.Key))
                       .MinBy(kvp => kvp.Value)
                       .Key);
            }
        }
Exemplo n.º 3
0
        public Dictionary <Student, Project> AllocateProjects(State state)
        {
            if (state.Students.Count > state.Supervisors.Sum(supervisor => supervisor.Capacity))
            {
                throw new ArgumentException($"Not enough capacity for the student list provided. Capacity = '{state.Supervisors.Sum(supervisor => supervisor.Capacity)}', Student count = '{state.Students.Count}'", nameof(state));
            }

            // Assign based on preferences. Highest GPA -> lowest. GPA clashes resolved by random number
            var studentsByGpa = state.Students
                                .Where(student => student.ProjectInterests.Count > 0)
                                .OrderByDescending(student => student.Gpa)
                                .ThenBy(student => _randomNumberProvider.NextInt(state.Students.Count));

            _logger.LogInformation("Assigning students to projects based on their preferences, ordered by GPA.");

            foreach (var student in studentsByGpa)
            {
                _logger.LogTrace("Trying to assign a project to student '{0}'", student.Id);
                var project = student.ProjectInterests.FirstOrDefault(projectInterest => projectInterest.HasSpaceRemaining);

                if (project == null)
                {
                    _logger.LogInformation("None of student '{0}'s preferences have space remaining. Skipping for now.", student.Id);
                    continue;
                }

                _logger.LogTrace("Student '{0}'s preference #{1} is still available. Assigning...", student.Id, student.ProjectInterests.IndexOf(project) + 1);
                _studentRepository.AssignProject(student, project);
            }

            _logger.LogInformation("All student preferences assigned (where available)");

            // Randomly assign remaining students
            var projectsLeft = state.Projects
                               .Where(project => project.HasSpaceRemaining)
                               .ToList();
            var studentsLeft = state.Students
                               .Where(student => !student.HasProject)
                               .ToList();

            _logger.LogInformation("Assigning remaining {0} students a project at random.", studentsLeft.Count);

            foreach (var student in studentsLeft)
            {
                var project = projectsLeft[_randomNumberProvider.NextInt(projectsLeft.Count)];

                _studentRepository.AssignProject(student, project);

                if (!project.HasSpaceRemaining)
                {
                    projectsLeft.Remove(project);
                }
                if (!project.Supervisor.HasSpaceRemaining)
                {
                    foreach (var supervisorProject in project.Supervisor.Projects)
                    {
                        if (projectsLeft.Contains(supervisorProject))
                        {
                            projectsLeft.Remove(supervisorProject);
                        }
                    }
                }
            }

            return(state.Students.ToDictionary(
                       student => student,
                       student => student.Project
                       ));
        }