Esempio n. 1
0
 /**
  * Distribute seats for several courses in a course set using the given
  * user priorities.
  *
  * @param CourseSet $courseSet The course set containing the courses
  * that seats shall be distributed for.
  * @see CourseSet
  */
 private function distributeByPriorities($courseSet)
 {
     Log::DEBUG('start seat distribution for course set: ' . $courseSet->getId());
     $limited_admission = $courseSet->getAdmissionRule('LimitedAdmission');
     //all users with their priorities
     $claiming_users = AdmissionPriority::getPriorities($courseSet->getId());
     //all users which have bonus/malus
     $factored_users = $courseSet->getUserFactorList();
     //all users with their max number of courses
     $max_seats_users = array_combine(array_keys($claiming_users), array_map(function ($u) use($limited_admission) {
         return $limited_admission->getMaxNumberForUser($u);
     }, array_keys($claiming_users)));
     //unlucky users get a bonus for the next round
     $bonus_users = array();
     //users / courses für later waitlist distribution
     $waiting_users = array();
     //number of already distributed seats for users
     $distributed_users = array();
     $prio_mapper = function ($users, $course_id) use($claiming_users) {
         $mapper = function ($u) use($course_id) {
             return isset($u[$course_id]) ? $u[$course_id] : null;
         };
         return array_filter(array_map($mapper, array_intersect_key($claiming_users, array_flip($users))));
     };
     //sort courses by highest count of prio 1 applicants
     $stats = AdmissionPriority::getPrioritiesStats($courseSet->getId());
     $courses = array_map(function ($a) {
         return $a['h'];
     }, $stats);
     arsort($courses, SORT_NUMERIC);
     $max_prio = AdmissionPriority::getPrioritiesMax($courseSet->getId());
     //count already manually distributed places
     $distributed_users = $this->countParticipatingUsers(array_keys($courses), array_keys($claiming_users));
     Log::DEBUG('already distributed users: ' . print_r($distributed_users, 1));
     //walk through all prios with all courses
     foreach (range(1, $max_prio) as $current_prio) {
         foreach (array_keys($courses) as $course_id) {
             $current_claiming = array();
             $course = Course::find($course_id);
             $free_seats = $course->getFreeSeats();
             //find users with current prio for this course, if they still need a place
             foreach ($claiming_users as $user_id => $prio_courses) {
                 if ($prio_courses[$course_id] == $current_prio && $distributed_users[$user_id] < $max_seats_users[$user_id]) {
                     //exclude participants
                     if (!$course->getParticipantStatus($user_id)) {
                         $current_claiming[$user_id] = 1;
                         if (isset($factored_users[$user_id])) {
                             $current_claiming[$user_id] *= $factored_users[$user_id];
                         }
                     } else {
                         Log::DEBUG(sprintf('user %s is already %s in course %s, ignoring', $user_id, $course->getParticipantStatus($user_id), $course->id));
                     }
                 }
             }
             //give maximum bonus to users which were unlucky before
             foreach (array_keys($current_claiming) as $user_id) {
                 if ($bonus_users[$user_id] > 0) {
                     $current_claiming[$user_id] = $bonus_users[$user_id] * count($current_claiming) + 1;
                     $bonus_users[$user_id]--;
                 }
             }
             Log::DEBUG(sprintf('distribute %s seats on %s claiming with prio %s in course %s', $free_seats, count($current_claiming), $current_prio, $course->id));
             Log::DEBUG('users to distribute: ' . print_r($current_claiming, 1));
             $current_claiming = $this->rollTheDice($current_claiming);
             Log::DEBUG('the die is cast: ' . print_r($current_claiming, 1));
             $chosen_ones = array_slice(array_keys($current_claiming), 0, $free_seats);
             Log::DEBUG('chosen ones: ' . print_r($chosen_ones, 1));
             $this->addUsersToCourse($chosen_ones, $course, $prio_mapper($chosen_ones, $course->id));
             foreach ($chosen_ones as $one) {
                 $distributed_users[$one]++;
             }
             if ($free_seats < count($current_claiming)) {
                 $remaining_ones = array_slice(array_keys($current_claiming), $free_seats);
                 foreach ($remaining_ones as $one) {
                     $bonus_users[$one]++;
                     $waiting_users[$current_prio][$course_id][] = $one;
                 }
             }
         }
     }
     //distribute to waitlists if applicable
     Log::DEBUG('waiting list: ' . print_r($waiting_users, 1));
     foreach ($waiting_users as $current_prio => $current_prio_waiting_courses) {
         foreach ($current_prio_waiting_courses as $course_id => $users) {
             $users = array_filter($users, function ($user_id) use($distributed_users, $max_seats_users) {
                 return $distributed_users[$user_id] < $max_seats_users[$user_id];
             });
             $course = Course::find($course_id);
             Log::DEBUG(sprintf('distribute waitlist of %s with prio %s in course %s', count($users), $current_prio, $course->id));
             if (!$course->admission_disable_waitlist) {
                 if ($course->admission_waitlist_max) {
                     $free_seats_waitlist = $course->admission_waitlist_max - $course->getNumWaiting();
                     $free_seats_waitlist = $free_seats_waitlist < 0 ? 0 : $free_seats_waitlist;
                 } else {
                     $free_seats_waitlist = count($users);
                 }
                 $waiting_list_ones = array_slice($users, 0, $free_seats_waitlist);
                 Log::DEBUG('waiting list ones: ' . print_r($waiting_list_ones, 1));
                 $this->addUsersToWaitlist($waiting_list_ones, $course, $prio_mapper($waiting_list_ones, $course->id));
                 foreach ($waiting_list_ones as $one) {
                     $distributed_users[$one]++;
                 }
             } else {
                 $free_seats_waitlist = 0;
             }
             if ($free_seats_waitlist < count($users)) {
                 $remaining_ones = array_slice($users, $free_seats_waitlist);
                 Log::DEBUG('remaining ones: ' . print_r($remaining_ones, 1));
                 $this->notifyRemainingUsers($remaining_ones, $course, $prio_mapper($remaining_ones, $course->id));
             }
         }
     }
 }
Esempio n. 2
0
 /**
  * Gets courses fulfilling the given condition.
  *
  * @param String $seminare_condition SQL condition
  */
 function get_courses($seminare_condition)
 {
     global $perm, $user;
     list($institut_id, $all) = explode('_', $this->current_institut_id);
     // Prepare count statements
     $query = "SELECT count(*)\n                FROM seminar_user\n                WHERE seminar_id = ? AND status IN ('user', 'autor')";
     $count0_statement = DBManager::get()->prepare($query);
     $query = "SELECT SUM(status = 'accepted') AS count2,\n                SUM(status = 'awaiting') AS count3\n                FROM admission_seminar_user\n                WHERE seminar_id = ?\n                GROUP BY seminar_id";
     $count1_statement = DBManager::get()->prepare($query);
     $parameters = array();
     $sql = "SELECT seminare.seminar_id,seminare.Name as course_name,seminare.VeranstaltungsNummer as course_number,\n                admission_prelim, admission_turnout,seminar_courseset.set_id\n                FROM seminar_courseset\n                INNER JOIN courseset_rule csr ON csr.set_id=seminar_courseset.set_id AND csr.type='ParticipantRestrictedAdmission'\n                INNER JOIN seminare ON seminar_courseset.seminar_id=seminare.seminar_id\n                ";
     if ($institut_id == 'all' && $perm->have_perm('root')) {
         $sql .= "WHERE 1 {$seminare_condition} ";
     } elseif ($all == 'all') {
         $sql .= "INNER JOIN Institute USING (Institut_id)\n            WHERE Institute.fakultaets_id = ? {$seminare_condition}\n            ";
         $parameters[] = $institut_id;
     } else {
         $sql .= "WHERE seminare.Institut_id = ? {$seminare_condition}\n            ";
         $parameters[] = $institut_id;
     }
     $sql .= "GROUP BY seminare.Seminar_id ORDER BY seminar_courseset.set_id, seminare.Name";
     $statement = DBManager::get()->prepare($sql);
     $statement->execute($parameters);
     while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
         $seminar_id = $row['seminar_id'];
         $ret[$seminar_id] = $row;
         $count0_statement->execute(array($seminar_id));
         $count = $count0_statement->fetchColumn();
         $ret[$seminar_id]['count_teilnehmer'] = $count;
         $count1_statement->execute(array($seminar_id));
         $counts = $count1_statement->fetch(PDO::FETCH_ASSOC);
         $ret[$seminar_id]['count_prelim'] = (int) $counts['count2'];
         $ret[$seminar_id]['count_waiting'] = (int) $counts['count3'];
         $cs = new CourseSet($row['set_id']);
         $ret[$seminar_id]['cs_name'] = $cs->getName();
         $ret[$seminar_id]['distribution_time'] = $cs->getSeatDistributionTime();
         if ($ta = $cs->getAdmissionRule('TimedAdmission')) {
             $ret[$seminar_id]['start_time'] = $ta->getStartTime();
             $ret[$seminar_id]['end_time'] = $ta->getEndTime();
         }
         if (!$cs->hasAlgorithmRun()) {
             $ret[$seminar_id]['count_claiming'] = $cs->getNumApplicants();
         }
     }
     return $ret;
 }