瀏覽代碼

fix in port arg and xlsx

Dasflugen 5 年之前
父節點
當前提交
46780de61c
共有 5 個文件被更改,包括 183 次插入244 次删除
  1. 1 0
      .gitignore
  2. 37 164
      schedule/generator.go
  3. 84 58
      schedule/localdata.go
  4. 60 21
      schedule/models.go
  5. 1 1
      schedule/settings.go

+ 1 - 0
.gitignore

@@ -3,6 +3,7 @@
 *.o
 *.a
 *.so
+*.log
 
 # Folders
 _obj

+ 37 - 164
schedule/generator.go

@@ -2,7 +2,6 @@ package schedule
 
 import (
     "fmt"
-    "strconv"
     "encoding/json"
     "github.com/tealeg/xlsx"
 )
@@ -13,7 +12,8 @@ func NewGenerator(data *Generator) *Generator {
         Debug: data.Debug,
         Groups: data.Groups,
         Teachers: data.Teachers,
-        Blocked: make(map[string]bool),
+        Cabinets: data.Cabinets,
+        // Blocked: make(map[string]bool),
         Reserved: Reserved{
             Teachers: make(map[string][]bool),
             Cabinets: make(map[string][]bool),
@@ -55,14 +55,16 @@ func ReadGroups(filename string) map[string]*Group {
                 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,
+                Lessons: Lessons{
+                    Theory: sb.Lessons.Theory,
+                    Practice: Subgroup{
+                        A: sb.Lessons.Practice,
+                        B: sb.Lessons.Practice,
+                    },
+                    Week: Subgroup{
+                        A: sb.Lessons.Week,
+                        B: sb.Lessons.Week,
+                    },
                 },
             }
         }
@@ -89,6 +91,25 @@ func ReadTeachers(filename string) map[string]*Teacher {
     return teachers
 }
 
+func ReadCabinets(filename string) map[string]*Cabinet {
+    var (
+        cabinets = make(map[string]*Cabinet)
+        cabinetsList []Cabinet
+    )
+    data := readFile(filename)
+    err := json.Unmarshal([]byte(data), &cabinetsList)
+    if err != nil {
+        return nil
+    }
+    for _, cb := range cabinetsList {
+        cabinets[cb.Name] = &Cabinet{
+            Name: cb.Name,
+            IsComputer: cb.IsComputer,
+        }
+    }
+    return cabinets
+}
+
 const (
     OUTDATA = "output/"
 )
@@ -103,14 +124,15 @@ func (gen *Generator) Template() [][]*Schedule {
     if gen.Debug {
         file, name = CreateXLSX(OUTDATA + "template.xlsx")
     }
-    for i := generator.Day; i < generator.Day+7; i++ {
+    day := generator.Day
+    for i := day; i < day+7; i++ {
         weekLessons[i % 7] = generator.Generate(nil)
         if gen.Debug {
             generator.WriteXLSX(
                 file,
                 name,
-                weekLessons[i],
-                int(i),
+                weekLessons[i % 7],
+                int(i % 7),
             )
         }
     }
@@ -138,8 +160,8 @@ func (gen *Generator) Generate(template [][]*Schedule) []*Schedule {
             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
+                gen.Groups[group.Name].Subjects[subject.Name].Lessons.Week.A = saved
+                gen.Groups[group.Name].Subjects[subject.Name].Lessons.Week.B = saved
             }
             continue
         }
@@ -185,155 +207,6 @@ func (gen *Generator) Generate(template [][]*Schedule) []*Schedule {
     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))
 }

+ 84 - 58
schedule/localdata.go

@@ -4,7 +4,7 @@ import (
     "os"
     "sort"
     "time"
-    "errors"
+    // "errors"
     "math/rand"
     "encoding/json"
 )
@@ -22,7 +22,20 @@ func (gen *Generator) tryGenerate(
     countl *Subgroup, 
     template []*Schedule,
 ) {
-    flag := false
+    var (
+        indexGroup = -1
+        flag       = false
+    )
+    if template != nil {
+        for i, sch := range template {
+            if sch.Group == group.Name {
+                indexGroup = i
+            }
+        }
+        if indexGroup == -1 {
+            return
+        }
+    }
 startAgain:
     nextLesson: for lesson := uint(0); lesson < NUM_TABLES; lesson++ {
         // Если лимит пар на день окончен, тогда прекратить ставить пары группе.
@@ -42,7 +55,7 @@ startAgain:
 
         // Если учитель заблокирован (не может присутствовать на занятиях) или
         // лимит пар на текущую неделю для предмета завершён, тогда пропустить этот предмет.
-        if gen.inBlocked(subject.Teacher) || gen.notHaveWeekLessons(subgroup, subject) {
+        if gen.notHaveWeekLessons(subgroup, subject) { // gen.inBlocked(subject.Teacher) || 
             break nextLesson
         }
 
@@ -167,22 +180,16 @@ tryAfter:
         }
 
         // Если существует шаблон расписания, тогда придерживаться его структуры.
-        if template != nil {
-            for _, sch := range template {
-                if sch.Group == group.Name {
-                    if sch.Table[lesson].Subject[A] == "" && sch.Table[lesson].Subject[B] == "" {
-                        if  (gen.cellIsReserved(A, schedule, lesson) && !gen.cellIsReserved(B, schedule, lesson)) ||
-                            (gen.cellIsReserved(B, schedule, lesson) && !gen.cellIsReserved(A, schedule, lesson)) {
-                                break
-                        }
-                        lesson = savedLesson
-                        continue nextLesson
-                    }
-                    break
-                }
+        if template != nil && template[indexGroup].Table[lesson].Subject[A] == "" && template[indexGroup].Table[lesson].Subject[B] == "" {
+            if  (gen.cellIsReserved(A, schedule, lesson) && !gen.cellIsReserved(B, schedule, lesson)) ||
+                (gen.cellIsReserved(B, schedule, lesson) && !gen.cellIsReserved(A, schedule, lesson)) {
+                    goto passTemplate
             }
+            lesson = savedLesson
+            continue nextLesson
         }
 
+passTemplate:
         // Полный день - максимум 7 пар.
         // lesson начинается с нуля!
         if (gen.Day != WEDNESDAY && gen.Day != SATURDAY) && lesson >= 7 {
@@ -213,7 +220,7 @@ tryAfter:
             // в это же время, тогда пропустить проверку пустых окон.
             if  gen.cellIsReserved(A, schedule, lesson) && A != subgroup || 
                 gen.cellIsReserved(B, schedule, lesson) && B != subgroup {
-                    goto passcheck
+                    goto passCheck
             }
             // Если стоит полная пара, а за ней идёт подгруппа неравная проверяемой, тогда
             // прекратить ставить пары у проверяемой подгруппы.
@@ -230,7 +237,7 @@ tryAfter:
             }
         }
 
-passcheck:
+passCheck:
         // [ III ] Третья проверка.
         // Если нет возможности добавить новые пары без создания окон, тогда не ставить пары.
         if lesson > 1 {
@@ -256,24 +263,24 @@ passcheck:
 
         switch subgroup {
         case A:
-            gen.Groups[group.Name].Subjects[subject.Name].WeekLessons.A -= 1
-            gen.Groups[group.Name].Subjects[subject.Name].Practice.A -= 1
+            gen.Groups[group.Name].Subjects[subject.Name].Lessons.Week.A -= 1
+            gen.Groups[group.Name].Subjects[subject.Name].Lessons.Practice.A -= 1
             countl.A += 1
         case B:
-            gen.Groups[group.Name].Subjects[subject.Name].WeekLessons.B -= 1
-            gen.Groups[group.Name].Subjects[subject.Name].Practice.B -= 1
+            gen.Groups[group.Name].Subjects[subject.Name].Lessons.Week.B -= 1
+            gen.Groups[group.Name].Subjects[subject.Name].Lessons.Practice.B -= 1
             countl.B += 1
         case ALL:
-            gen.Groups[group.Name].Subjects[subject.Name].WeekLessons.A -= 1
-            gen.Groups[group.Name].Subjects[subject.Name].WeekLessons.B -= 1
+            gen.Groups[group.Name].Subjects[subject.Name].Lessons.Week.A -= 1
+            gen.Groups[group.Name].Subjects[subject.Name].Lessons.Week.B -= 1
             countl.A += 1
             countl.B += 1
             switch subjtype {
             case THEORETICAL:
-                gen.Groups[group.Name].Subjects[subject.Name].Theory -= 1
+                gen.Groups[group.Name].Subjects[subject.Name].Lessons.Theory -= 1
             case PRACTICAL:
-                gen.Groups[group.Name].Subjects[subject.Name].Practice.A -= 1
-                gen.Groups[group.Name].Subjects[subject.Name].Practice.B -= 1
+                gen.Groups[group.Name].Subjects[subject.Name].Lessons.Practice.A -= 1
+                gen.Groups[group.Name].Subjects[subject.Name].Lessons.Practice.B -= 1
             }
         }
 
@@ -338,20 +345,20 @@ func (gen *Generator) withSubgroups(group string) bool {
     return false
 }
 
-func (gen *Generator) blockTeacher(teacher string) error {
-    if !gen.inTeachers(teacher) {
-        return errors.New("teacher undefined")
-    }
-    gen.Blocked[teacher] = true
-    return nil
-}
-
-func (gen *Generator) inBlocked(teacher string) bool {
-    if _, ok := gen.Blocked[teacher]; !ok {
-        return false
-    }
-    return true
-}
+// func (gen *Generator) blockTeacher(teacher string) error {
+//     if !gen.inTeachers(teacher) {
+//         return errors.New("teacher undefined")
+//     }
+//     gen.Blocked[teacher] = true
+//     return nil
+// }
+
+// func (gen *Generator) inBlocked(teacher string) bool {
+//     if _, ok := gen.Blocked[teacher]; !ok {
+//         return false
+//     }
+//     return true
+// }
 
 func (gen *Generator) inGroups(group string) bool {
     if _, ok := gen.Groups[group]; !ok {
@@ -367,13 +374,13 @@ func (gen *Generator) inTeachers(teacher string) bool {
     return true
 }
 
-func (gen *Generator) unblockTeacher(teacher string) error {
-    if !gen.inBlocked(teacher) {
-        return errors.New("teacher undefined")
-    }
-    delete(gen.Blocked, teacher)
-    return nil
-}
+// func (gen *Generator) unblockTeacher(teacher string) error {
+//     if !gen.inBlocked(teacher) {
+//         return errors.New("teacher undefined")
+//     }
+//     delete(gen.Blocked, teacher)
+//     return nil
+// }
 
 func packJSON(data interface{}) []byte {
     jsonData, err := json.MarshalIndent(data, "", "\t")
@@ -457,10 +464,11 @@ func (gen *Generator) cellIsReserved(subgroup SubgroupType, schedule *Schedule,
 }
 
 func (gen *Generator) cabinetIsReserved(subgroup SubgroupType, subject *Subject, teacher string, lesson uint, cabinet *string) bool {
-    var result = true
     if !gen.inTeachers(teacher) {
-        return result
+        return true
     }
+
+    // Основные кабинеты преподавателя.
     for _, cab := range gen.Teachers[teacher].Cabinets {
         gen.cabinetToReserved(cab.Name)
         // Если это не компьютерный кабинет, а предмет предполагает практику в компьютерных кабинетах и идёт время практики,
@@ -476,7 +484,25 @@ func (gen *Generator) cabinetIsReserved(subgroup SubgroupType, subject *Subject,
             return false
         }
     }
-    return result
+
+    // Все другие кабинеты. Могут быть использованы в случае, если все основные кабинеты преподавателя были заняты.
+    for _, cab := range gen.Cabinets {
+        gen.cabinetToReserved(cab.Name)
+        // Если это не компьютерный кабинет, а предмет предполагает практику в компьютерных кабинетах и идёт время практики,
+        // тогда посмотреть другой кабинет преподавателя.
+        if   subject.IsComputer && !cab.IsComputer &&
+             gen.havePracticalLessons(subgroup, subject) &&
+            !gen.haveTheoreticalLessons(subject) {
+                continue
+        }
+        // Если кабинет не зарезирвирован, тогда занять кабинет.
+        if _, ok := gen.Reserved.Cabinets[cab.Name]; ok && !gen.Reserved.Cabinets[cab.Name][lesson] {
+            *cabinet = cab.Name
+            return false
+        }
+    }
+
+    return true
 }
 
 func (gen *Generator) teacherIsReserved(teacher string, lesson uint) bool {
@@ -504,15 +530,15 @@ func (gen *Generator) cabinetToReserved(cabnum string) {
 func (gen *Generator) notHaveWeekLessons(subgroup SubgroupType, subject *Subject) bool {
     switch subgroup {
     case A:
-        if subject.WeekLessons.A == 0 {
+        if subject.Lessons.Week.A == 0 {
             return true
         }
     case B:
-        if subject.WeekLessons.B == 0 {
+        if subject.Lessons.Week.B == 0 {
             return true
         }
     case ALL:
-        if subject.WeekLessons.A == 0 && subject.WeekLessons.B == 0 {
+        if subject.Lessons.Week.A == 0 && subject.Lessons.Week.B == 0 {
             return true
         }
     }
@@ -520,7 +546,7 @@ func (gen *Generator) notHaveWeekLessons(subgroup SubgroupType, subject *Subject
 }
 
 func (gen *Generator) haveTheoreticalLessons(subject *Subject) bool {
-    if subject.Theory == 0 {
+    if subject.Lessons.Theory == 0 {
         return false
     }
     return true
@@ -529,15 +555,15 @@ func (gen *Generator) haveTheoreticalLessons(subject *Subject) bool {
 func (gen *Generator) havePracticalLessons(subgroup SubgroupType, subject *Subject) bool {
     switch subgroup {
     case A:
-        if subject.Practice.A == 0 {
+        if subject.Lessons.Practice.A == 0 {
             return false
         }
     case B:
-        if subject.Practice.B == 0 {
+        if subject.Lessons.Practice.B == 0 {
             return false
         }
     case ALL:
-        if subject.Practice.A == 0 && subject.Practice.B == 0 {
+        if subject.Lessons.Practice.A == 0 && subject.Lessons.Practice.B == 0 {
             return false
         }
     }

+ 60 - 21
schedule/models.go

@@ -1,5 +1,39 @@
 package schedule
 
+type TypeRow uint8
+const (
+	IsCycleTR = 0
+	IsStartTR = 1
+	IsPmTR    = 2
+	IsSubTR   = 3
+)
+
+type PlanXLSX struct {
+	ProgramCode   string     `json:"program_code"`
+	NameCode      string     `json:"name_code"`
+	PeriodOfStudy string     `json:"period_of_study"`
+	GroupNumber   string     `json:"group_number"`
+	Lines         []LineXLSX `json:"lines"`
+}
+
+type LineXLSX struct {
+	ID        string        `json:"id"`
+	Name      string        `json:"name"`
+	CertForm  string        `json:"cert_form"`
+	StudyLoad StudyLoadXLSX `json:"study_load"`
+	Course    [4][2]int     `json:"course"`
+	TypeRow   TypeRow       `json:"typerow"`
+}
+
+type StudyLoadXLSX struct {
+	Max       int `json:"max"`
+	SelfStudy int `json:"self_study"`
+	AllStudy  int `json:"all_study"`
+	Lectures  int `json:"lectures"`
+	Labs      int `json:"labs"`
+	Projects  int `json:"projects"`
+}
+
 type DayType uint8
 const (
 	SUNDAY 		DayType = 0
@@ -25,11 +59,12 @@ const (
 )
 
 type Generator struct {
-	Day DayType
-	Debug bool
-	Groups map[string]*Group
+	Day      DayType
+	Debug    bool
+	Groups   map[string]*Group
 	Teachers map[string]*Teacher
-	Blocked map[string]bool
+	Cabinets map[string]*Cabinet
+	// Blocked map[string]bool
 	Reserved Reserved
 }
 
@@ -39,7 +74,7 @@ type Reserved struct {
 }
 
 type Schedule struct {
-	Day DayType
+	Day   DayType
 	Group string
 	Table []Row
 }
@@ -51,30 +86,34 @@ type Row struct {
 }
 
 type Teacher struct {
-	Name string `json:"name"`
+	Name     string    `json:"name"`
 	Cabinets []Cabinet `json:"cabinets"`
 }
 
 type Cabinet struct {
-	Name string `json:"name"`
-	IsComputer bool `json:"is_computer"`
+	Name       string `json:"name"`
+	IsComputer bool   `json:"is_computer"`
 }
 
 type Group struct {
-	Name string
+	Name     string
 	Quantity uint // students count
 	Subjects map[string]*Subject
 }
 
 type Subject struct {
-	Name string
-	Teacher string
-	Teacher2 string
+	Name       string
 	IsComputer bool
-	SaveWeek uint
-	Theory uint
+	Teacher    string
+	Teacher2   string
+	SaveWeek   uint
+	Lessons    Lessons
+}
+
+type Lessons struct {
+	Theory   uint
 	Practice Subgroup
-	WeekLessons Subgroup
+	Week     Subgroup
 }
 
 type Subgroup struct {
@@ -83,20 +122,20 @@ type Subgroup struct {
 }
 
 type GroupJSON struct {
-	Name string `json:"name"`
+	Name     string `json:"name"`
 	Quantity uint `json:"quantity"`
 	Subjects []SubjectJSON `json:"subjects"`
 }
 
 type SubjectJSON struct {
-	Name string `json:"name"`
-	Teacher string `json:"teacher"`
+	Name       string `json:"name"`
+	Teacher    string `json:"teacher"`
 	IsComputer bool `json:"is_computer"`
-	Lessons LessonsJSON `json:"lessons"`
+	Lessons    LessonsJSON `json:"lessons"`
 }
 
 type LessonsJSON struct {
-	Theory uint `json:"theory"`
+	Theory   uint `json:"theory"`
 	Practice uint `json:"practice"`
-	Week uint `json:"week"`
+	Week     uint `json:"week"`
 }

+ 1 - 1
schedule/settings.go

@@ -7,7 +7,7 @@ const (
 const (
 	NUM_TABLES = 11
 	MAX_COUNT_LESSONS_IN_DAY = 3
-	MAX_COUNT_WITHOUT_SUBGROUPS = 16
+	MAX_COUNT_WITHOUT_SUBGROUPS = 20
 )
 
 // For XLSX.