Составлен план работ + выполнен этап 1

This commit is contained in:
ki.sagidullin
2026-04-05 11:51:06 +05:00
parent 018e2a860e
commit a8f47d29f6
5 changed files with 352 additions and 89 deletions

159
main.py
View File

@@ -1,101 +1,82 @@
from ortools.sat.python import cp_model
"""
main.py - Основ
ный скрипт для создания графика смен
Использует модуль models.py для создания и решения модели
"""
from models import create_model, solve_model, get_solution, SHIFTS, OPERATORS
import csv
# Определяем даты апреля 2026 года
days = [
"2026-04-{:02d}".format(i) for i in range(1, 31)
]
# Смены
shifts = [
(6, 14.5), # с 06:00 до 14:30
(8, 16.5), # с 08:00 до 16:30
(11.5, 20), # с 11:30 до 20:00
(12.5, 21) # с 12:30 до 21:00
]
# Операторы и их пожелания
operators = [
"Иванов",
"Алексеев",
"Сидоров",
"Козобородов",
"Трудяшкина",
"Петрова"
]
operator_preferences = {
"Иванов": ["2026-04-10", "2026-04-13"],
"Алексеев": [(i, 0) for i in days if (int(i[-2:]) - 1) % 7 == 0], # Понедельники
"Сидоров": ["2026-04-25", "2026-04-26"],
"Козобородов": [(i, 2) for i in days], # Предпочитает смену 11:3020:00
"Трудяшкина": ["2026-04-04"],
"Петрова": ["2026-04-08", "2026-04-29"]
}
# Создаем модель
model = cp_model.CpModel()
# Переменные: определяем, работает ли оператор на смене в день
works = {}
for day in days:
for shift_idx in range(len(shifts)):
for op in operators:
works[(day, shift_idx, op)] = model.NewBoolVar(f"{op}_{day}_shift_{shift_idx}")
# # Пожелания операторов
for op, prefs in operator_preferences.items():
if isinstance(prefs, list):
for pref in prefs:
if isinstance(pref, tuple):
day, shift = pref
model.AddHint(works[day, shift, op], 1)
else:
day = pref
model.Add(sum(works[day, shift_idx, op] for shift_idx in range(len(shifts))) == 0)
# Условие 1: На каждую смену должен быть назначен оператор
for day in days:
for shift_idx in range(len(shifts)):
model.Add(sum(works[day, shift_idx, op] for op in operators) == 1)
# Условие 2: У каждого оператора должно быть 8 выходных
for op in operators:
model.Add(sum(works[day, shift_idx, op] for day in days for shift_idx in range(len(shifts))) == 20 )
# Условие 3: Оператор не должен работать больше 5 дней подряд
for op in operators:
for day_idx in range(len(days) - 4):
model.Add(sum(works[days[day_idx + i], shift_idx, op] for i in range(5) for shift_idx in range(len(shifts))) <= 4)
# Условие 4: В день оператор может работать только одну смену
for day in days:
for op in operators:
model.Add(sum(works[day, shift_idx, op] for shift_idx in range(len(shifts))) <= 1)
# Решаем модель
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status != cp_model.OPTIMAL and status != cp_model.FEASIBLE:
print("Невозможно составить график")
else:
# Создаем CSV файл с результатами
with open('shift_schedule.csv', 'w', newline='', encoding='utf-8') as file:
def generate_csv_report(schedule: dict, filename: str = 'shift_schedule.csv'):
"""
Генерирует CSV-отчет на основе расписания.
Аргументы:
schedule: словарь расписания из get_solution()
filename: имя файла для вывода CSV
Возвращает:
True если файл создан успешно
"""
with open(filename, 'w', newline='', encoding='utf-8') as file:
writer = csv.writer(file)
writer.writerow(['Day'] + [f'{i+1} shift' for i in range(len(shifts))])
# Заголовок
writer.writerow(['День'] + [f'Смена {i+1}' for i in range(len(SHIFTS))])
for day in days:
for day, day_shifts in schedule.items():
row = [day]
for shift_idx in range(len(shifts)):
for shift_idx in range(len(SHIFTS)):
op = None
for op_name in operators:
if solver.Value(works[day, shift_idx, op_name]) == 1:
for op_name in OPERATORS:
if schedule[day][shift_idx].get(op_name, False):
op = op_name
break
row.append(op)
writer.writerow(row)
print(f"График успешно составлен и сохранен в '{filename}'")
return True
print("График успешно составлен и сохранен в 'shift_schedule.csv'")
def main():
"""
Главная функция: создает и решает модель, затем генерирует CSV-отчет.
"""
print("=" * 60)
print("Создание графика смен")
print("=" * 60)
# Шаг 1: Создаем модель
print("\n[1] Создание модели...")
model, variables, operators_set = create_model()
print(f" Модель создана с {len(variables)} переменными")
print(f" Операторы: {', '.join(operators_set)}")
# Шаг 2: Решаем модель
print("\n[2] Решение модели...")
success = solve_model()
if success:
print(" ✅ Модель решена успешно!")
# Шаг 3: Получаем решение
print("\n[3] Получение решения...")
schedule = get_solution()
print(f" Решение получено для {len(schedule)} дней")
# Шаг 4: Генерируем CSV-отчет
print("\n[4] Генерация CSV-отчета...")
generate_csv_report(schedule, 'shift_schedule.csv')
else:
print("Не удалось составить график!")
print(" Проверьте ограничения и предпочтения операторов.")
return False
print("\n" + "=" * 60)
print("Готово!")
print("=" * 60)
return True
if __name__ == '__main__':
main()