def room_limit_naive(individual, exams, periods, rooms, pb=1.0):
    mapping = get_period_to_room_to_exam_mapping(individual)
    stack = []
    for _ in range(2):
        for period_i in range(len(periods)):
            for room_i in range(len(rooms)):
                total_students = 0
                # Remove exams from busy rooms
                if period_i in mapping and room_i in mapping[period_i] and random() < pb:
                    exam_list = mapping[period_i][room_i]
                    exam_sizes = list(map(lambda exam_i: len(exams[exam_i].students), exam_list))
                    total_students = sum(exam_sizes)
                    while total_students > rooms[room_i].capacity:
                        removed_exam = exam_list.pop()
                        removed_exam_size = len(exams[removed_exam].students)
                        total_students -= removed_exam_size
                        stack.append(removed_exam)
                # Add exams to empty rooms
                stack_remove = []
                for i in range(len(stack)):
                    if total_students + len(exams[stack[i]].students) < rooms[room_i].capacity:
                        added_exam = stack[i]
                        added_exam_size = len(exams[added_exam].students)
                        total_students += added_exam_size
                        individual[added_exam] = (room_i, period_i)
                        stack_remove.append(i)
                # Remove placed exams from stack
                for i in sorted(stack_remove, reverse=True):
                    del stack[i]

    return individual
def room_limit_naive(individual, exams, periods, rooms, pb=1.0):
    mapping = get_period_to_room_to_exam_mapping(individual)
    stack = []
    for _ in range(2):
        for period_i in range(len(periods)):
            for room_i in range(len(rooms)):
                total_students = 0
                # Remove exams from busy rooms
                if period_i in mapping and room_i in mapping[
                        period_i] and random() < pb:
                    exam_list = mapping[period_i][room_i]
                    exam_sizes = list(
                        map(lambda exam_i: len(exams[exam_i].students),
                            exam_list))
                    total_students = sum(exam_sizes)
                    while total_students > rooms[room_i].capacity:
                        removed_exam = exam_list.pop()
                        removed_exam_size = len(exams[removed_exam].students)
                        total_students -= removed_exam_size
                        stack.append(removed_exam)
                # Add exams to empty rooms
                stack_remove = []
                for i in range(len(stack)):
                    if total_students + len(
                            exams[stack[i]].students) < rooms[room_i].capacity:
                        added_exam = stack[i]
                        added_exam_size = len(exams[added_exam].students)
                        total_students += added_exam_size
                        individual[added_exam] = (room_i, period_i)
                        stack_remove.append(i)
                # Remove placed exams from stack
                for i in sorted(stack_remove, reverse=True):
                    del stack[i]

    return individual
def room_limit_repair(individual, exams, rooms):
    period_to_room_to_exam_mapping = get_period_to_room_to_exam_mapping(
        individual)
    leftover_exams = []
    leftover_room = dict()
    for period_i, room_to_exams_mapping in period_to_room_to_exam_mapping.items(
    ):
        # print('period_i: {}'.format(period_i))
        # print('room_to_exams: {}'.format(room_to_exams_mapping))
        for room_i, exam_is in room_to_exams_mapping.items():
            # print('Exams: {}'.format(exam_is))
            limit = rooms[room_i].capacity
            count = 0
            for exam_i in exam_is:
                count += len(exams[exam_i].students)
                print('Success')

            if count > limit:
                diff = count - limit
                print('{} students and only a capacity of {}'.format(
                    count, limit))
                print('Exams: {}'.format(exam_is))
                print('Exams sizes: {}'.format(
                    list(map(lambda x: len(exams[x].students), exam_is))))
    return
def room_limit_repair(individual, exams, rooms):
    period_to_room_to_exam_mapping = get_period_to_room_to_exam_mapping(individual)
    leftover_exams = []
    leftover_room = dict()
    for period_i, room_to_exams_mapping in period_to_room_to_exam_mapping.items():
        # print('period_i: {}'.format(period_i))
        # print('room_to_exams: {}'.format(room_to_exams_mapping))
        for room_i, exam_is in room_to_exams_mapping.items():
            # print('Exams: {}'.format(exam_is))
            limit = rooms[room_i].capacity
            count = 0
            for exam_i in exam_is:
                count += len(exams[exam_i].students)
                print('Success')

            if count > limit:
                diff = count - limit
                print('{} students and only a capacity of {}'.format(count, limit))
                print('Exams: {}'.format(exam_is))
                print('Exams sizes: {}'.format(list(map(lambda x: len(exams[x].students), exam_is))))
    return