123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- package schedule
- import (
- "fmt"
- "strconv"
- "encoding/json"
- "github.com/tealeg/xlsx"
- )
- func NewGenerator(data *Generator) *Generator {
- return &Generator{
- Day: data.Day,
- Debug: data.Debug,
- Groups: data.Groups,
- Teachers: data.Teachers,
- Blocked: make(map[string]bool),
- Reserved: Reserved{
- Teachers: make(map[string][]bool),
- Cabinets: make(map[string][]bool),
- },
- }
- }
- func (gen *Generator) NewSchedule(group string) *Schedule {
- return &Schedule{
- Day: gen.Day,
- Group: group,
- Table: make([]Row, NUM_TABLES),
- }
- }
- func ReadGroups(filename string) map[string]*Group {
- var (
- groups = make(map[string]*Group)
- groupsList []GroupJSON
- )
- data := readFile(filename)
- err := json.Unmarshal([]byte(data), &groupsList)
- if err != nil {
- return nil
- }
- for _, gr := range groupsList {
- groups[gr.Name] = &Group{
- Name: gr.Name,
- Quantity: gr.Quantity,
- }
- groups[gr.Name].Subjects = make(map[string]*Subject)
- for _, sb := range gr.Subjects {
- if _, ok := groups[gr.Name].Subjects[sb.Name]; ok {
- groups[gr.Name].Subjects[sb.Name].Teacher2 = sb.Teacher
- continue
- }
- groups[gr.Name].Subjects[sb.Name] = &Subject{
- Name: sb.Name,
- Teacher: sb.Teacher,
- IsComputer: sb.IsComputer,
- SaveWeek: sb.Lessons.Week,
- Theory: sb.Lessons.Theory,
- Practice: Subgroup{
- A: sb.Lessons.Practice,
- B: sb.Lessons.Practice,
- },
- WeekLessons: Subgroup{
- A: sb.Lessons.Week,
- B: sb.Lessons.Week,
- },
- }
- }
- }
- return groups
- }
- func ReadTeachers(filename string) map[string]*Teacher {
- var (
- teachers = make(map[string]*Teacher)
- teachersList []Teacher
- )
- data := readFile(filename)
- err := json.Unmarshal([]byte(data), &teachersList)
- if err != nil {
- return nil
- }
- for _, tc := range teachersList {
- teachers[tc.Name] = &Teacher{
- Name: tc.Name,
- Cabinets: tc.Cabinets,
- }
- }
- return teachers
- }
- const (
- OUTDATA = "output/"
- )
- func (gen *Generator) Template() [][]*Schedule {
- var (
- weekLessons = make([][]*Schedule, 7)
- generator = new(Generator)
- file *xlsx.File
- name string
- )
- unpackJSON(packJSON(gen), generator)
- if gen.Debug {
- file, name = CreateXLSX(OUTDATA + "template.xlsx")
- }
- for i := generator.Day; i < generator.Day+7; i++ {
- weekLessons[i % 7] = generator.Generate(nil)
- if gen.Debug {
- generator.WriteXLSX(
- file,
- name,
- weekLessons[i],
- int(i),
- )
- }
- }
- return weekLessons
- }
- func (gen *Generator) Generate(template [][]*Schedule) []*Schedule {
- var (
- list []*Schedule
- templt []*Schedule
- groups = getGroups(gen.Groups)
- )
- if template == nil {
- templt = nil
- } else {
- templt = template[gen.Day]
- }
- for _, group := range groups {
- var (
- schedule = gen.NewSchedule(group.Name)
- subjects = getSubjects(group.Subjects)
- countLessons = new(Subgroup)
- )
- if gen.Day == SUNDAY {
- list = append(list, schedule)
- for _, subject := range subjects {
- saved := gen.Groups[group.Name].Subjects[subject.Name].SaveWeek
- gen.Groups[group.Name].Subjects[subject.Name].WeekLessons.A = saved
- gen.Groups[group.Name].Subjects[subject.Name].WeekLessons.B = saved
- }
- continue
- }
- for _, subject := range subjects {
- switch {
- case gen.haveTheoreticalLessons(subject):
- if gen.Debug {
- fmt.Println(group.Name, subject.Name, ": not splited THEORETICAL;")
- }
- gen.tryGenerate(ALL, THEORETICAL, group, subject, schedule, countLessons, templt)
- // Практические пары начинаются только после завершения всех теоретических.
- default:
- // Если подгруппа неделимая, тогда провести практику в виде полной пары.
- // Иначе разделить практику на две подгруппы.
- if !gen.withSubgroups(group.Name) {
- if gen.Debug {
- fmt.Println(group.Name, subject.Name, ": not splited PRACTICAL;")
- }
- gen.tryGenerate(ALL, PRACTICAL, group, subject, schedule, countLessons, templt)
- } else {
- switch RandSubgroup() {
- case A:
- if gen.Debug {
- fmt.Println(group.Name, subject.Name, ": splited (A -> B);")
- }
- gen.tryGenerate(A, PRACTICAL, group, subject, schedule, countLessons, templt)
- gen.tryGenerate(B, PRACTICAL, group, subject, schedule, countLessons, templt)
- case B:
- if gen.Debug {
- fmt.Println(group.Name, subject.Name, ": splited (B -> A);")
- }
- gen.tryGenerate(B, PRACTICAL, group, subject, schedule, countLessons, templt)
- gen.tryGenerate(A, PRACTICAL, group, subject, schedule, countLessons, templt)
- }
- }
- }
- }
- list = append(list, schedule)
- }
- gen.Reserved.Teachers = make(map[string][]bool)
- gen.Reserved.Cabinets = make(map[string][]bool)
- gen.Day = (gen.Day + 1) % 7
- return sortSchedule(list)
- }
- func CreateXLSX(filename string) (*xlsx.File, string) {
- file := xlsx.NewFile()
- _, err := file.AddSheet("Init")
- if err != nil {
- return nil, ""
- }
- err = file.Save(filename)
- if err != nil {
- return nil, ""
- }
- return file, filename
- }
- func (gen *Generator) WriteXLSX(file *xlsx.File, filename string, schedule []*Schedule, iter int) error {
- const (
- colWidth = 30
- rowHeight = 30
- )
- var (
- MAXCOL = uint(3)
- )
- rowsNext := uint(len(schedule)) / MAXCOL
- if rowsNext == 0 || uint(len(schedule)) % MAXCOL != 0 {
- rowsNext += 1
- }
- var (
-
- colNum = uint(NUM_TABLES + 2)
-
- row = make([]*xlsx.Row, colNum * rowsNext) // * (rowsNext + 1)
- cell *xlsx.Cell
- dayN = gen.Day
- day = ""
- )
- if dayN == SUNDAY {
- dayN = SATURDAY
- } else {
- dayN -= 1
- }
- switch dayN {
- case SUNDAY: day = "Sunday"
- case MONDAY: day = "Monday"
- case TUESDAY: day = "Tuesday"
- case WEDNESDAY: day = "Wednesday"
- case THURSDAY: day = "Thursday"
- case FRIDAY: day = "Friday"
- case SATURDAY: day = "Saturday"
- }
- sheet, err := file.AddSheet(day + "-" + strconv.Itoa(iter))
- if err != nil {
- return err
- }
- sheet.SetColWidth(2, int(MAXCOL)*3+1, COL_W)
- for r := uint(0); r < rowsNext; r++ {
- for i := uint(0); i < colNum; i++ {
- row[(r*colNum)+i] = sheet.AddRow() // (r*rowsNext)+
- row[(r*colNum)+i].SetHeight(ROW_H)
- cell = row[(r*colNum)+i].AddCell()
- if i == 0 {
- cell.Value = "Пара"
- continue
- }
- cell.Value = strconv.Itoa(int(i-1))
- }
- }
- index := uint(0)
- exit: for r := uint(0); r < rowsNext; r++ {
- for i := uint(0); i < MAXCOL; i++ {
- if uint(len(schedule)) <= index {
- break exit
- }
- savedCell := row[(r*colNum)+0].AddCell()
- savedCell.Value = "Группа " + schedule[index].Group
- cell = row[(r*colNum)+0].AddCell()
- cell = row[(r*colNum)+0].AddCell()
- savedCell.Merge(2, 0)
- cell = row[(r*colNum)+1].AddCell()
- cell.Value = "Предмет"
- cell = row[(r*colNum)+1].AddCell()
- cell.Value = "Преподаватель"
- cell = row[(r*colNum)+1].AddCell()
- cell.Value = "Кабинет"
- for j, trow := range schedule[index].Table {
- cell = row[(r*colNum)+uint(j)+2].AddCell()
- if trow.Subject[A] == trow.Subject[B] {
- cell.Value = trow.Subject[A]
- } else {
- if trow.Subject[A] != "" {
- cell.Value = trow.Subject[A] + " (A)"
- }
- if trow.Subject[B] != "" {
- cell.Value += "\n" + trow.Subject[B] + " (B)"
- }
- }
- cell = row[(r*colNum)+uint(j)+2].AddCell()
- if trow.Teacher[A] == trow.Teacher[B] {
- cell.Value = trow.Teacher[A]
- } else {
- if trow.Teacher[A] != "" {
- cell.Value = trow.Teacher[A]
- }
- if trow.Teacher[B] != "" {
- cell.Value += "\n" + trow.Teacher[B]
- }
- }
- sheet.SetColWidth(colWidthForCabinets(int(j)))
- cell = row[(r*colNum)+uint(j)+2].AddCell()
- if trow.Cabinet[A] == trow.Cabinet[B] {
- cell.Value = trow.Cabinet[A]
- } else {
- if trow.Cabinet[A] != "" {
- cell.Value = trow.Cabinet[A]
- }
- if trow.Cabinet[B] != "" {
- cell.Value += "\n" + trow.Cabinet[B]
- }
- }
- }
- index++
- }
- }
- err = file.Save(filename)
- if err != nil {
- return err
- }
- return nil
- }
- func RandSubgroup() SubgroupType {
- return SubgroupType(random(0, 1))
- }
- func Load(filename string) *Generator {
- var generator = new(Generator)
- jsonData := readFile(filename)
- err := json.Unmarshal([]byte(jsonData), generator)
- if err != nil {
- return nil
- }
- return generator
- }
- func (gen *Generator) Dump(filename string) error {
- return writeJSON(filename, gen)
- }
|