localdata.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. package schedule
  2. import (
  3. "os"
  4. "sort"
  5. "time"
  6. // "errors"
  7. "math/rand"
  8. "encoding/json"
  9. )
  10. func init() {
  11. rand.Seed(time.Now().UnixNano())
  12. }
  13. func (gen *Generator) tryGenerate(
  14. subgroup SubgroupType,
  15. subjtype SubjectType,
  16. group *Group,
  17. subject *Subject,
  18. schedule *Schedule,
  19. countl *Subgroup,
  20. template []*Schedule,
  21. ) {
  22. var (
  23. indexGroup = -1
  24. flag = false
  25. )
  26. if template != nil {
  27. for i, sch := range template {
  28. if sch.Group == group.Name {
  29. indexGroup = i
  30. }
  31. }
  32. if indexGroup == -1 {
  33. return
  34. }
  35. }
  36. startAgain:
  37. nextLesson: for lesson := uint(0); lesson < NUM_TABLES; lesson++ {
  38. // Если лимит пар на день окончен, тогда прекратить ставить пары группе.
  39. if gen.isLimitLessons(subgroup, countl) {
  40. break nextLesson
  41. }
  42. // Если это полная группа и у неё не осталось теоретических занятий, тогда пропустить этот предмет.
  43. if subjtype == THEORETICAL && !gen.haveTheoreticalLessons(subject) {
  44. break nextLesson
  45. }
  46. // Если это подгруппа и у неё не осталось практических занятий, тогда пропустить этот предмет.
  47. if subjtype == PRACTICAL && !gen.havePracticalLessons(subgroup, subject) {
  48. break nextLesson
  49. }
  50. // Если учитель заблокирован (не может присутствовать на занятиях) или
  51. // лимит пар на текущую неделю для предмета завершён, тогда пропустить этот предмет.
  52. if gen.notHaveWeekLessons(subgroup, subject) { // gen.inBlocked(subject.Teacher) ||
  53. break nextLesson
  54. }
  55. isAfter := false
  56. savedLesson := lesson
  57. // [ I ] Первая проверка.
  58. switch subgroup {
  59. case ALL:
  60. // Если две подгруппы стоят друг за другом, тогда исключить возможность добавления полной пары.
  61. for i := uint(0); i < NUM_TABLES-1; i++ {
  62. if gen.cellIsReserved(A, schedule, i) && !gen.cellIsReserved(B, schedule, i) &&
  63. gen.cellIsReserved(B, schedule, i+1) && !gen.cellIsReserved(A, schedule, i+1) ||
  64. gen.cellIsReserved(B, schedule, i) && !gen.cellIsReserved(A, schedule, i) &&
  65. gen.cellIsReserved(A, schedule, i+1) && !gen.cellIsReserved(B, schedule, i+1) {
  66. break nextLesson
  67. }
  68. }
  69. // Если между двумя разными подгруппами находятся окна, тогда посчитать сколько пустых окон.
  70. // Если их количество = 1, тогда попытаться подставить полную пару под это окно.
  71. // Если не получается, тогда не ставить полную пару.
  72. cellSubgroupReserved := false
  73. indexNotReserved := uint(0)
  74. cellIsNotReserved := 0
  75. for i := uint(0); i < NUM_TABLES; i++ {
  76. if gen.cellIsReserved(A, schedule, i) && !gen.cellIsReserved(B, schedule, i) ||
  77. gen.cellIsReserved(B, schedule, i) && !gen.cellIsReserved(A, schedule, i) {
  78. if cellIsNotReserved != 0 {
  79. if cellIsNotReserved == 1 {
  80. lesson = indexNotReserved
  81. goto tryAfter
  82. }
  83. break nextLesson
  84. }
  85. cellSubgroupReserved = true
  86. }
  87. if !gen.cellIsReserved(A, schedule, i) && !gen.cellIsReserved(B, schedule, i) && cellSubgroupReserved {
  88. if cellIsNotReserved == 0 {
  89. indexNotReserved = i
  90. }
  91. cellIsNotReserved += 1
  92. }
  93. }
  94. switch {
  95. case lesson > 1 && (gen.cellIsReserved(A, schedule, lesson-1) || gen.cellIsReserved(B, schedule, lesson-1)) &&
  96. !(gen.cellIsReserved(A, schedule, lesson+1) || gen.cellIsReserved(B, schedule, lesson+1)): // pass
  97. default:
  98. // "Подтягивать" полные пары к уже существующим [перед].
  99. for i := uint(0); i < NUM_TABLES-1; i++ {
  100. if (gen.cellIsReserved(A, schedule, i+1) || gen.cellIsReserved(B, schedule, i+1)) &&
  101. (!gen.cellIsReserved(A, schedule, i) && !gen.cellIsReserved(B, schedule, i)) {
  102. lesson = i
  103. break
  104. }
  105. }
  106. }
  107. default:
  108. switch {
  109. case lesson > 1 && gen.cellIsReserved(subgroup, schedule, lesson-1) &&
  110. !gen.cellIsReserved(subgroup, schedule, lesson+1): // pass
  111. default:
  112. // "Подтягивать" неполные пары к уже существующим [перед].
  113. for i := uint(0); i < NUM_TABLES-1; i++ {
  114. if !gen.cellIsReserved(subgroup, schedule, i) && gen.cellIsReserved(subgroup, schedule, i+1) {
  115. lesson = i
  116. break
  117. }
  118. }
  119. }
  120. }
  121. tryAfter:
  122. if isAfter {
  123. switch subgroup {
  124. case ALL:
  125. // "Подтягивать" полные пары к уже существующим [после].
  126. for i := uint(0); i < NUM_TABLES-1; i++ {
  127. if (gen.cellIsReserved(A, schedule, i) || gen.cellIsReserved(B, schedule, i)) &&
  128. (!gen.cellIsReserved(A, schedule, i+1) && !gen.cellIsReserved(B, schedule, i+1)) {
  129. lesson = i+1
  130. break
  131. }
  132. }
  133. default:
  134. // "Подтягивать" неполные пары к уже существующим [после].
  135. for i := uint(0); i < NUM_TABLES-1; i++ {
  136. if (gen.cellIsReserved(ALL, schedule, i) || gen.cellIsReserved(subgroup, schedule, i)) &&
  137. !gen.cellIsReserved(subgroup, schedule, i+1) {
  138. lesson = i+1
  139. break
  140. }
  141. }
  142. }
  143. }
  144. var (
  145. cabinet = ""
  146. cabinet2 = ""
  147. )
  148. // Если ячейка уже зарезервирована или учитель занят, или кабинет зарезервирован, или
  149. // если это полная пара и ячейка занята либо первой, либо второй подгруппой, или
  150. // если это двойная пара и кабинеты второго учителя зарезервированы, или
  151. // если это двойная пара и второй учитель занят: попытаться сдвинуть пары к уже существующим.
  152. // Если не получается, тогда не ставить этот урок.
  153. if gen.cellIsReserved(subgroup, schedule, lesson) ||
  154. gen.teacherIsReserved(subject.Teacher, lesson) ||
  155. gen.cabinetIsReserved(subgroup, subject, subject.Teacher, lesson, &cabinet) ||
  156. (subgroup == ALL && (gen.cellIsReserved(A, schedule, lesson) || gen.cellIsReserved(B, schedule, lesson))) ||
  157. (gen.withSubgroups(group.Name) && gen.isDoubleLesson(group.Name, subject.Name) && gen.teacherIsReserved(subject.Teacher2, lesson)) ||
  158. (gen.withSubgroups(group.Name) && gen.isDoubleLesson(group.Name, subject.Name) && gen.cabinetIsReserved(subgroup, subject, subject.Teacher2, lesson, &cabinet2)) {
  159. if isAfter {
  160. break nextLesson
  161. }
  162. if lesson != savedLesson {
  163. isAfter = true
  164. goto tryAfter
  165. }
  166. continue nextLesson
  167. }
  168. // Если существует шаблон расписания, тогда придерживаться его структуры.
  169. if template != nil && template[indexGroup].Table[lesson].Subject[A] == "" && template[indexGroup].Table[lesson].Subject[B] == "" {
  170. if (gen.cellIsReserved(A, schedule, lesson) && !gen.cellIsReserved(B, schedule, lesson)) ||
  171. (gen.cellIsReserved(B, schedule, lesson) && !gen.cellIsReserved(A, schedule, lesson)) {
  172. goto passTemplate
  173. }
  174. lesson = savedLesson
  175. continue nextLesson
  176. }
  177. passTemplate:
  178. // Полный день - максимум 7 пар.
  179. // lesson начинается с нуля!
  180. if (gen.Day != WEDNESDAY && gen.Day != SATURDAY) && lesson >= 7 {
  181. break nextLesson
  182. }
  183. // В среду и субботу - 5-6 пары должны быть свободны.
  184. // lesson начинается с нуля!
  185. if (gen.Day == WEDNESDAY || gen.Day == SATURDAY) && (lesson == 4 || lesson == 5) {
  186. lesson = savedLesson // Возобновить сохранённое занятие.
  187. continue nextLesson // Перейти к следующей ячейке.
  188. }
  189. // [ II ] Вторая проверка.
  190. switch subgroup {
  191. case ALL:
  192. // Если уже существует полная пара, которая стоит за парами с подгруппами, тогда
  193. // перейти на новую ячейку расписания группы.
  194. for i := lesson; i < NUM_TABLES-1; i++ {
  195. if gen.cellIsReserved(A, schedule, i) && !gen.cellIsReserved(B, schedule, i) && gen.cellIsReserved(ALL, schedule, i+1) ||
  196. gen.cellIsReserved(B, schedule, i) && !gen.cellIsReserved(A, schedule, i) && gen.cellIsReserved(ALL, schedule, i+1) {
  197. lesson = savedLesson
  198. continue nextLesson
  199. }
  200. }
  201. default:
  202. // Если у одной подгруппы уже имеется пара, а у второй стоит пара
  203. // в это же время, тогда пропустить проверку пустых окон.
  204. if gen.cellIsReserved(A, schedule, lesson) && A != subgroup ||
  205. gen.cellIsReserved(B, schedule, lesson) && B != subgroup {
  206. goto passCheck
  207. }
  208. // Если стоит полная пара, а за ней идёт подгруппа неравная проверяемой, тогда
  209. // прекратить ставить пары у проверяемой подгруппы.
  210. fullLessons := false
  211. for i := uint(0); i < lesson; i++ {
  212. if gen.cellIsReserved(ALL, schedule, i) {
  213. fullLessons = true
  214. continue
  215. }
  216. if (fullLessons && gen.cellIsReserved(A, schedule, i) && A != subgroup) ||
  217. (fullLessons && gen.cellIsReserved(B, schedule, i) && B != subgroup) {
  218. break nextLesson
  219. }
  220. }
  221. }
  222. passCheck:
  223. // [ III ] Третья проверка.
  224. // Если нет возможности добавить новые пары без создания окон, тогда не ставить пары.
  225. if lesson > 1 {
  226. switch subgroup {
  227. case ALL:
  228. for i := uint(0); i < lesson-1; i++ {
  229. if (gen.cellIsReserved(A, schedule, i) && !gen.cellIsReserved(A, schedule, lesson-1)) ||
  230. (gen.cellIsReserved(B, schedule, i) && !gen.cellIsReserved(B, schedule, lesson-1)) {
  231. break nextLesson
  232. }
  233. }
  234. default:
  235. for i := uint(0); i < lesson-1; i++ {
  236. if gen.cellIsReserved(subgroup, schedule, i) && !gen.cellIsReserved(subgroup, schedule, lesson-1) {
  237. break nextLesson
  238. }
  239. }
  240. }
  241. }
  242. gen.Reserved.Teachers[subject.Teacher][lesson] = true
  243. gen.Reserved.Cabinets[cabinet][lesson] = true
  244. switch subgroup {
  245. case A:
  246. gen.Groups[group.Name].Subjects[subject.Name].Lessons.Week.A -= 1
  247. gen.Groups[group.Name].Subjects[subject.Name].Lessons.Practice.A -= 1
  248. countl.A += 1
  249. case B:
  250. gen.Groups[group.Name].Subjects[subject.Name].Lessons.Week.B -= 1
  251. gen.Groups[group.Name].Subjects[subject.Name].Lessons.Practice.B -= 1
  252. countl.B += 1
  253. case ALL:
  254. gen.Groups[group.Name].Subjects[subject.Name].Lessons.Week.A -= 1
  255. gen.Groups[group.Name].Subjects[subject.Name].Lessons.Week.B -= 1
  256. countl.A += 1
  257. countl.B += 1
  258. switch subjtype {
  259. case THEORETICAL:
  260. gen.Groups[group.Name].Subjects[subject.Name].Lessons.Theory -= 1
  261. case PRACTICAL:
  262. gen.Groups[group.Name].Subjects[subject.Name].Lessons.Practice.A -= 1
  263. gen.Groups[group.Name].Subjects[subject.Name].Lessons.Practice.B -= 1
  264. }
  265. }
  266. if subgroup == ALL {
  267. schedule.Table[lesson].Teacher = [ALL]string{
  268. subject.Teacher,
  269. subject.Teacher,
  270. }
  271. schedule.Table[lesson].Subject = [ALL]string{
  272. subject.Name,
  273. subject.Name,
  274. }
  275. schedule.Table[lesson].Cabinet = [ALL]string{
  276. cabinet,
  277. cabinet,
  278. }
  279. // Если это двойная пара и группа делимая, тогда поставить пару с разными преподавателями.
  280. if gen.isDoubleLesson(group.Name, subject.Name) && gen.withSubgroups(group.Name) {
  281. gen.Reserved.Teachers[subject.Teacher2][lesson] = true
  282. gen.Reserved.Cabinets[cabinet2][lesson] = true
  283. schedule.Table[lesson].Teacher[B] = subject.Teacher2
  284. schedule.Table[lesson].Cabinet[B] = cabinet2
  285. }
  286. lesson = savedLesson
  287. continue nextLesson
  288. }
  289. schedule.Table[lesson].Teacher[subgroup] = subject.Teacher
  290. schedule.Table[lesson].Subject[subgroup] = subject.Name
  291. schedule.Table[lesson].Cabinet[subgroup] = cabinet
  292. lesson = savedLesson
  293. }
  294. if template != nil && !flag {
  295. flag = true
  296. goto startAgain
  297. }
  298. }
  299. func (gen *Generator) isLimitLessons(subgroup SubgroupType, countl *Subgroup) bool {
  300. switch subgroup {
  301. case ALL:
  302. if countl.A >= MAX_COUNT_LESSONS_IN_DAY && countl.B >= MAX_COUNT_LESSONS_IN_DAY {
  303. return true
  304. }
  305. case A:
  306. if countl.A >= MAX_COUNT_LESSONS_IN_DAY {
  307. return true
  308. }
  309. case B:
  310. if countl.B >= MAX_COUNT_LESSONS_IN_DAY {
  311. return true
  312. }
  313. }
  314. return false
  315. }
  316. func (gen *Generator) withSubgroups(group string) bool {
  317. if gen.Groups[group].Quantity > MAX_COUNT_WITHOUT_SUBGROUPS {
  318. return true
  319. }
  320. return false
  321. }
  322. // func (gen *Generator) blockTeacher(teacher string) error {
  323. // if !gen.inTeachers(teacher) {
  324. // return errors.New("teacher undefined")
  325. // }
  326. // gen.Blocked[teacher] = true
  327. // return nil
  328. // }
  329. // func (gen *Generator) inBlocked(teacher string) bool {
  330. // if _, ok := gen.Blocked[teacher]; !ok {
  331. // return false
  332. // }
  333. // return true
  334. // }
  335. func (gen *Generator) inGroups(group string) bool {
  336. if _, ok := gen.Groups[group]; !ok {
  337. return false
  338. }
  339. return true
  340. }
  341. func (gen *Generator) inTeachers(teacher string) bool {
  342. if _, ok := gen.Teachers[teacher]; !ok {
  343. return false
  344. }
  345. return true
  346. }
  347. // func (gen *Generator) unblockTeacher(teacher string) error {
  348. // if !gen.inBlocked(teacher) {
  349. // return errors.New("teacher undefined")
  350. // }
  351. // delete(gen.Blocked, teacher)
  352. // return nil
  353. // }
  354. func packJSON(data interface{}) []byte {
  355. jsonData, err := json.MarshalIndent(data, "", "\t")
  356. if err != nil {
  357. return nil
  358. }
  359. return jsonData
  360. }
  361. func unpackJSON(data []byte, output interface{}) error {
  362. err := json.Unmarshal(data, output)
  363. return err
  364. }
  365. func writeJSON(filename string, data interface{}) error {
  366. return writeFile(filename, string(packJSON(data)))
  367. }
  368. func (gen *Generator) subjectInGroup(subject string, group string) bool {
  369. if !gen.inGroups(group) {
  370. return false
  371. }
  372. if _, ok := gen.Groups[group].Subjects[subject]; !ok {
  373. return false
  374. }
  375. return true
  376. }
  377. func (gen *Generator) isDoubleLesson(group string, subject string) bool {
  378. if !gen.inGroups(group) {
  379. return false
  380. }
  381. if _, ok := gen.Groups[group].Subjects[subject]; !ok {
  382. return false
  383. }
  384. if gen.Groups[group].Subjects[subject].Teacher2 == "" {
  385. return false
  386. }
  387. return true
  388. }
  389. func shuffle(slice interface{}) interface{}{
  390. switch slice.(type) {
  391. case []*Group:
  392. result := slice.([]*Group)
  393. for i := len(result)-1; i > 0; i-- {
  394. j := rand.Intn(i+1)
  395. result[i], result[j] = result[j], result[i]
  396. }
  397. return result
  398. case []*Subject:
  399. result := slice.([]*Subject)
  400. for i := len(result)-1; i > 0; i-- {
  401. j := rand.Intn(i+1)
  402. result[i], result[j] = result[j], result[i]
  403. }
  404. return result
  405. }
  406. return nil
  407. }
  408. func (gen *Generator) cellIsReserved(subgroup SubgroupType, schedule *Schedule, lesson uint) bool {
  409. if lesson >= NUM_TABLES {
  410. return false
  411. }
  412. switch subgroup {
  413. case A:
  414. if schedule.Table[lesson].Subject[A] != "" {
  415. return true
  416. }
  417. case B:
  418. if schedule.Table[lesson].Subject[B] != "" {
  419. return true
  420. }
  421. case ALL:
  422. if schedule.Table[lesson].Subject[A] != "" && schedule.Table[lesson].Subject[B] != "" {
  423. return true
  424. }
  425. }
  426. return false
  427. }
  428. func (gen *Generator) cabinetIsReserved(subgroup SubgroupType, subject *Subject, teacher string, lesson uint, cabinet *string) bool {
  429. if !gen.inTeachers(teacher) {
  430. return true
  431. }
  432. // Основные кабинеты преподавателя.
  433. for _, cab := range gen.Teachers[teacher].Cabinets {
  434. gen.cabinetToReserved(cab.Name)
  435. // Если это не компьютерный кабинет, а предмет предполагает практику в компьютерных кабинетах и идёт время практики,
  436. // тогда посмотреть другой кабинет преподавателя.
  437. if subject.IsComputer && !cab.IsComputer &&
  438. gen.havePracticalLessons(subgroup, subject) &&
  439. !gen.haveTheoreticalLessons(subject) {
  440. continue
  441. }
  442. // Если кабинет не зарезирвирован, тогда занять кабинет.
  443. if _, ok := gen.Reserved.Cabinets[cab.Name]; ok && !gen.Reserved.Cabinets[cab.Name][lesson] {
  444. *cabinet = cab.Name
  445. return false
  446. }
  447. }
  448. // Все другие кабинеты. Могут быть использованы в случае, если все основные кабинеты преподавателя были заняты.
  449. for _, cab := range gen.Cabinets {
  450. gen.cabinetToReserved(cab.Name)
  451. // Если это не компьютерный кабинет, а предмет предполагает практику в компьютерных кабинетах и идёт время практики,
  452. // тогда посмотреть другой кабинет преподавателя.
  453. if subject.IsComputer && !cab.IsComputer &&
  454. gen.havePracticalLessons(subgroup, subject) &&
  455. !gen.haveTheoreticalLessons(subject) {
  456. continue
  457. }
  458. // Если кабинет не зарезирвирован, тогда занять кабинет.
  459. if _, ok := gen.Reserved.Cabinets[cab.Name]; ok && !gen.Reserved.Cabinets[cab.Name][lesson] {
  460. *cabinet = cab.Name
  461. return false
  462. }
  463. }
  464. return true
  465. }
  466. func (gen *Generator) teacherIsReserved(teacher string, lesson uint) bool {
  467. gen.teacherToReserved(teacher)
  468. if value, ok := gen.Reserved.Teachers[teacher]; ok {
  469. return value[lesson] == true
  470. }
  471. return false
  472. }
  473. func (gen *Generator) teacherToReserved(teacher string) {
  474. if _, ok := gen.Reserved.Teachers[teacher]; ok {
  475. return
  476. }
  477. gen.Reserved.Teachers[teacher] = make([]bool, NUM_TABLES)
  478. }
  479. func (gen *Generator) cabinetToReserved(cabnum string) {
  480. if _, ok := gen.Reserved.Cabinets[cabnum]; ok {
  481. return
  482. }
  483. gen.Reserved.Cabinets[cabnum] = make([]bool, NUM_TABLES)
  484. }
  485. func (gen *Generator) notHaveWeekLessons(subgroup SubgroupType, subject *Subject) bool {
  486. switch subgroup {
  487. case A:
  488. if subject.Lessons.Week.A == 0 {
  489. return true
  490. }
  491. case B:
  492. if subject.Lessons.Week.B == 0 {
  493. return true
  494. }
  495. case ALL:
  496. if subject.Lessons.Week.A == 0 && subject.Lessons.Week.B == 0 {
  497. return true
  498. }
  499. }
  500. return false
  501. }
  502. func (gen *Generator) haveTheoreticalLessons(subject *Subject) bool {
  503. if subject.Lessons.Theory == 0 {
  504. return false
  505. }
  506. return true
  507. }
  508. func (gen *Generator) havePracticalLessons(subgroup SubgroupType, subject *Subject) bool {
  509. switch subgroup {
  510. case A:
  511. if subject.Lessons.Practice.A == 0 {
  512. return false
  513. }
  514. case B:
  515. if subject.Lessons.Practice.B == 0 {
  516. return false
  517. }
  518. case ALL:
  519. if subject.Lessons.Practice.A == 0 && subject.Lessons.Practice.B == 0 {
  520. return false
  521. }
  522. }
  523. return true
  524. }
  525. func getGroups(groups map[string]*Group) []*Group {
  526. var list []*Group
  527. for _, group := range groups {
  528. list = append(list, group)
  529. }
  530. return shuffle(list).([]*Group)
  531. }
  532. func getSubjects(subjects map[string]*Subject) []*Subject {
  533. var list []*Subject
  534. for _, subject := range subjects {
  535. list = append(list, subject)
  536. }
  537. return shuffle(list).([]*Subject)
  538. }
  539. func sortSchedule(schedule []*Schedule) []*Schedule {
  540. sort.SliceStable(schedule, func(i, j int) bool {
  541. return schedule[i].Group < schedule[j].Group
  542. })
  543. return schedule
  544. }
  545. func colWidthForCabinets(index int) (int, int, float64) {
  546. var col = (index+1)*3+1
  547. return col, col, COL_W_CAB
  548. }
  549. // Returns [min:max] value.
  550. func random(min, max int) int {
  551. return rand.Intn(max - min + 1) + min
  552. }
  553. func readFile(filename string) string {
  554. file, err := os.Open(filename)
  555. if err != nil {
  556. return ""
  557. }
  558. defer file.Close()
  559. var (
  560. buffer []byte = make([]byte, BUFFER)
  561. data string
  562. )
  563. for {
  564. length, err := file.Read(buffer)
  565. if length == 0 || err != nil { break }
  566. data += string(buffer[:length])
  567. }
  568. return data
  569. }
  570. func writeFile(filename, data string) error {
  571. file, err := os.Create(filename)
  572. if err != nil {
  573. return err
  574. }
  575. file.WriteString(data)
  576. file.Close()
  577. return nil
  578. }