Распределение студентов по преподавателям

Есть определённое количество курсов, каждый курс ведёт несколько преподавателей, у каждого есть ограниченное количество студентов, которые он может принять в подгруппу.

Пример файла с настройками курса:

{"title":"Выбор практиков ОМ-3", 
"students":30, 
"subjects":[
{"name":"ТФКЗ", "teachers":[
    {"name":"Оноцкий", "cap":"15"},
    {"name":"Молодцов", "cap":"15"}]
},
{"name":"Матфиз", "teachers":[
    {"name":"Кузьмин", "cap":"auto"},
    {"name":"Кашпур", "cap":"16"}]
},
{"name":"Методы вычислений", "teachers":[
    {"name":"Рыженко"},
    {"name":"Тимошенко"}]
},
{"name":"Теория управления", "teachers":[
    {"name":"Волощук"},
    {"name":"Пичкур"}]
}]}

Есть перечень студентов, каждый из которых выбрал на каждый курс предпочтительного из практиков, к которому он хотел бы попасть. И для каждого курса он определяет важность (приоритетность) того, чтобы именно этого практика забрать себе. Важность определяется порядком перечисления учителей.

Пример входных данных: Никитенко: Пичкур, Тимошенко, Кузьмин, Оноцкий

Система пытается удовлетворить в первую очередь те пожелания, которые были названы первыми. В приведённом примере наибольшее желание студента — попасть на Теории управления к Пичкур, а не к Волощук. А разница между Оноцкий и Молодцов для него не так важна.

Установка

pip install nltk (применяется для парсинга запросов студентов, исправления опечаток в фамилиях и прочее)

Запуск

python main.py

В main.py идёт перечисление входных данных (TODO: вынести как аргументы командной строки)

teachers_file = "teachersOM3.json"
students_file = "studentsOM3.txt"
randomSeed = "abHkk1o3Ac-BKVup"

Структура проекта

... отвратительна и ужасна по причине того, что у меня нет времени привести его в сколь-нибудь читаемый вид.

Вся логика в poll.py Реализованы сущности Student, Teacher, Subject, Poll.

[В идеале должно быть, что всё] взаимодействие производится через сущность Poll: импорт предметов и учителей, добавление голосов студентов, их проверка, экспорт результатов голосования.

Непосредственно логика формирования итоговых списков происходит в Subject.formList. Сам алгоритм работает для каждого предмета независимо: сначала удовлетворяются все запросы студентов с максимальными приоритетами (которые поставили преподавателя на первое место). Когда места в подгруппу заканчиваются, то все студенты с таким же приоритетом, как и у последнего студента помещающегося в подгруппу случайно перемешиваются и добавляется столько, сколько может. Остальные переходят к другим практикам.