momente şi schiţe de informatică şi matematică
To attain knowledge, write. To attain wisdom, rewrite.

De la încadrarea profesorilor la orarul şcolii, folosind R (II)

limbajul R | orar şcolar
2021 mar

Cuplările de ore – la sfârşit!

În [1] am adăugat în încadrare profesori fictivi, pe acele ore care trebuie partajate de câte doi profesori; m-am chinuit apoi, după ce am generat orarele zilnice, să plasez orele astfel încât profesorii cuplaţi, pe lângă orele proprii fiecăruia, să poată intra împreună (şi fără ferestre) în orele acelui profesor fictiv care îi cuplează. Interesant desigur, dar… chinuit (şi nu voi mai repeta cred, un asemenea experiment).

Oare de ce sunt necesare cuplajele, în şcolile noastre? Păi numai din motive politico-administrative, nu din raţiuni proprii unui sistem de învăţământ coerent; împarţi o clasă în două fiindcă sunt prea mulţi elevi în fiecare clasă, iar unii sunt „Engleză-avansaţi”, ceilalţi sunt „Engleză-începători” (de exemplu); împarţi o clasă în două fiindcă este greu de lucrat cu prea mulţi elevi într-un acelaşi laborator; împarţi clasele în câte două părţi fiindcă obiecte ca "Desen" şi "Muzică" fie că nu-s importante, fie că nu-s destui profesori – încât li se rezervă câte o jumătate de oră pe săptămână şi numai la anumite clase (spre deosebire de "Religie", care a devenit un obiect de maximă importanţă – toate clasele au câte o oră pe săptămână, iar cabinetele oficiale sunt doldora de icoane).

În mod normal, cuplajele nu sunt necesare şi ar trebui tratate ca atare – la sfârşitul lucrurilor! (dar abandonăm aici, disecarea formulei „în mod normal”)

În fond, avem cuplaje doar pe două-trei discipline, numai la câteva clase, iar numărul de ore cuplate este relativ mic (sub 5% din totalul orelor). Soluţia firească (şi comodă) pentru tratarea cuplajelor constă în… ignorarea lor, în baza unui anumit „plan de ignorare”: mai întâi, eliminăm din încadrare cele cel mult 5% ore cuplate şi – prin programul "distribute_by_days.R" din [1] – repartizăm pe zilele de lucru orele rămase; apoi – prin aplicaţia interactivă recast – mutăm ore dintr-o zi în alta astfel încât să fie posibilă anexarea orelor cuplate la sfârşitul zilei (sau la început), după ce vom fi generat – prin "set_hours_day.R" din [1] – orarul zilei.

Şi distribuţia orelor pe zilele de lucru şi orarele propriu-zise ale zilelor vor fi generate astfel mult mai rapid, iar cele două intervenţii interactive necesare (prin aplicaţiile /Recast/ şi /dayRecast/) sunt realmente mai uşoare, decât în cazul când foloseam „profesori fictivi”; dificultatea constă în alegerea unui plan „de ignorare”: la care clase şi în care zile, să reducem cu 1 sau 2 (sau poate chiar cu 3) numărul de ore pe zi (crescându-l în alte zile) pentru a face loc orelor ce vor trebui anexate în final.

Încadrarea redusă (fără cuplaje) şi repartizarea ei pe zile

Eliminând de pe încadrarea considerată în [1] toate cuplajele (în total, 38 de ore), obţinem acest tabel de încadrare (de fapt, am eliminat cele 6 linii de profesori fictivi, din fişierul "incadrare.csv" obţinut în [1], iar aici am tabelat cumva, datele respective):

      10_________ 11_________ 12_________         9__________
prof  A B C D E F A B C D E F A B C D E F 5 6 7 8 A B C D E F
  P01 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
  P04 . . 1 3 . . . . . 2 2 1 . 1 . 5 5 3 . . . . . . . 2 . 2
  P06 . . 2 . 1 1 . 2 2 . 2 . . . . 1 1 1 . . 1 1 . 3 3 2 2 2
  P07 . 4 . . . . . . . . . . 4 . . . 2 . . . 6 . . 4 4 . . 2
  P08 . . 4 . . . 5 4 . . . . . 5 . . . . . . . 4 4 . . . . .
  P11 . . . 2 2 . . 3 . . . . . . 3 . . . . . . 2 . 3 4 2 . 2
  P12 . 2 . 2 . . . 2 2 2 . . 2 . . 5 . . . . . . 2 . . 4 . .
  P05 . . 3 . 2 3 . 2 . . . . 2 2 . . . . . 2 . . 2 2 . 2 . .
  P09 . 2 . . . . . . . 2 6 . . . . . . 4 2 . . 2 . . . . . 4
  P14 2 . 3 . . . 1 4 3 . . . 1 . . . . . . . 2 2 2 . . 1 . 1
  P15 . . . . 6 . 2 . . . . . . 2 2 . 2 3 . 2 . 2 . . . . . .
  P16 . . . 2 3 2 . . . 2 2 . . . 4 2 . . . . . . . . . 2 2 .
  P17 2 2 . . 1 . . 3 3 . . 1 1 . . . . 1 . . . . . 4 3 . . .
  P18 . . 3 . . . . . . . . . 4 . . . 4 . . . . 5 . . . . 5 .
  P13 2 . 2 . . 3 . . . . . 3 . . . . . . 2 . 2 . . 2 2 . 2 .
  P19 2 . . . . . . . 1 2 1 2 2 . . . . 1 . . 2 2 1 1 1 . 1 1
  P20 3 . . . . . . 4 . 5 . . . . . 4 . . . . . . . 4 . . . .
  P21 . 3 . . . . . . 4 . 4 . . . 4 . . . . . . . . . . 5 . .
  P22 . . . 4 . . . . . 4 . . 1 . . . 5 3 . . . . . . . . 2 .
  P23 . 2 2 1 1 1 1 1 . . . . . 1 1 1 1 . 3 2 . . . . . 1 . .
  P24 . . . . . . . . . . 4 . . . . 4 . . 2 2 . . 1 1 1 2 . 2
  P25 . . . 4 . . . . . . . 6 . 4 . . . 5 . . . . . . . . . .
  P26 . . 2 1 . 1 1 . . . . . . 4 3 . . . . 2 . 1 2 . . 1 1 .
  P27 1 1 1 . 3 4 1 1 1 . . 3 . 1 1 . . . . . . . . . . . . .
  P28 1 1 1 2 . . 1 . . . . . 1 1 . 2 . . 1 . . 3 1 . . 2 . .
  P29 . 2 . 1 1 1 . . . . . . . 3 4 . . . . . . . . 2 2 . 1 .
  P30 . 3 3 . . 2 . . 4 . . . . 3 . . . . . . . . . . . . 2 .
  P10 . . . . . . . . . 1 1 1 . . . 1 1 2 1 1 1 1 . . . 1 1 2
  P33 . . . 3 . . . . 2 . . 3 . . 2 2 . . . . . . . . 2 . . .
  P02 2 . . . . . 4 . . . . 1 . 1 . . . . 1 . . . 4 . . . . .
  P03 . 3 . 1 . . . . . 2 . . 4 . 2 . . . . 1 . . . . . . . .
  P34 . . . . . . . . . . . . . . . . . . . 5 . . . . 4 . . 4
  P35 . . . . 4 4 4 . . . . . . . . . . . . . . . . . . . . .
  P36 3 . . . . . 3 . . . . . 3 . . . . . . . . . 3 . . . . .
  P37 . . . . . 2 . . . . 2 2 . . . . . . . . . . . . . . 2 2
  P38 . . . 1 1 1 . . . . . 2 . . . . . 1 . . 1 . . . . 1 1 1
  P40 . . . . 2 . . . 1 . . . . . 1 . 2 . . . . . . 1 . . . 2
  P41 . . . . . . . . 4 . . . . . . . . . 5 . . . . . . . . .
  P42 1 1 1 1 1 1 1 1 . . . . . . . . . . . . . . . . . . . .
  P43 . . . . . . . . . . . . . . . . . . . . 4 . 4 . . . . .
  P44 4 . . . . . . . . . . . . . . . . . . 4 . . . . . . . .
  P31 . . . . . . . . . . . . . . . . . . 1 1 1 1 . . . 1 1 1
  P45 1 1 . . . . . . . . . . . . . . . . . . . . 1 1 1 . 2 .
  P46 . . . . . . . . 1 2 2 1 . . . . . . . . . 1 . . . . . .
  P47 . . . . . . . 1 . 3 . . . . . . . 2 . . . . . . 1 . . .
  P32 2 . . . . . . . . . . . . . . . 1 . . . . . . . . . 1 .
  P39 . . . . . . 2 . . . . . . . . . . . . . 2 . . . . . . .
  P50 . . . . . . . . . . . . . . . . . . 1 . 2 . . . . . . 1
  P51 . . . . . . . . . . . . . . . . . . . 2 2 . . . . . . .
  P52 . . . . 2 2 . . . . . . . . . . . . . . . . . . . . . .
  P53 . . . . . . . . . . . . . . . . . . 4 . . . . . . . . .
  P54 . . . . . . . . . 1 . 1 . . . 1 . 1 . . . . . . . . . .
  P55 . . . . . . . . . . . . . . . . . . . . 1 2 . . . . . .
  P56 . . . . . . . . . . . . . . . . . . 1 1 1 . . . . . . .
  P57 . . . . . . . . . . . . . . . . . . 1 . 1 1 . . . . . .
  P58 . . . . . . . . . . . . . . . . . . . 1 1 . . . . . . .
  P59 . . . . . . . . . . . 1 . . . . . 1 . . . . . . . . . .
  P60 . . . . . . . . . . . . 1 . 1 . . . . . . . . . . . . .
  P61 . . . . . . . . . . . . . . . . . . . 1 . . . . . . . .
 prof A B C D E F A B C D E F A B C D E F 5 6 7 8 A B C D E F
      10_________ 11_________ 12_________         9__________  

Prin următorul program normalizăm datele încadrării, obţinând în "frame.RDS" un obiect tibble care înregistrează fiecare oră prin prof|cls (în total, 801 linii), unde $prof este factor ordonat (descrescător după numărul de ore pe săptămână); am avut acum grijă (faţă de [1]) să uniformizăm din start, denumirile claselor ("5" → "5G", etc.):

# cdr_norm.R  # normalizarea încadrării
library(tidyverse)
fram <- read_csv("incadrare.csv", na = '.') %>% 
        gather("cls", "nore", 2:29) %>%
        filter(! is.na(nore)) %>% 
        mutate(nore = as.integer(nore)) %>%  
        uncount(nore)  # 'prof' | 'cls' (cu linii identice de câte 'nore' ori)
srt <- sort(table(fram$prof), decreasing=TRUE)
fram$prof <- factor(fram$prof, levels = names(srt), ordered=TRUE)
for(k in 5:8) {  # clasa 5 --> "5G", etc.
    kg <- as.character(k)
    fram[fram$cls == kg, ]$cls <- paste0(kg, "G")
}
fram  %>%  arrange(prof, cls)  %>%
      saveRDS(., "frame.RDS")  # 801,  <ord>prof  <chr>cls 

Din "frame.RDS" obţinem (în 1-2 minute) o distribuţie (cvasi-omogenă) pe zile a încadrării, folosind distributeByDays.R; desigur, am avut grijă ca în prelabil, să redefinim lista 'prOf' – ţinând seama că acum profesorii cu măcar 10 ore pe săptămână sunt cei aflaţi deasupra lui "P40" (v. tabelul de încadrare de mai sus).

Continuăm ca în [1], prin disToRecast.R (dar excluzând secvenţa prin care formulam fişierul "together.txt", dat fiind că acum ne-am lipsit de cuplaje) – obţinând fişierul CSV pe care urmează să-l modificăm prin aplicaţia /recast/.

Planul anexării cuplajelor

Putem scăpa uşor de 15 dintre cele 38 de ore care vor trebui anexate: sunt 5 clase „de informatică”, la care doi profesori sunt cuplaţi pe câte 3 ore; fiindcă aceste ore se desfăşoară în câte un „Laborator de Informatică”, ar fi chiar potrivit ca ele să fie plasate într-o aceeaşi zi, pentru fiecare clasă.

Nu mai căutăm motive de a prefera o zi sau alta, pentru o clasă sau alta – vom proceda arbitrar: rezervăm ziua Lu pentru clasa 10A, ziua Ma pentru 10B, ş.a.m.d.
10A, 10B şi 9A aveau iniţial următoarea distribuţie pe zile a orelor: (6 6 6 5 5); la 10A mutăm 2 ore din ziua Lu, la 10B mutăm 2 ore din ziua Ma, iar la 9A eliberăm 2 ore în ziua Mi (mutându-le prin /recast/ în cele câte două zile cu câte 5 ore); de exemplu, pentru 10A va rezulta distribuţia (4 6 6 6 6) – încât cele 3 ore de „Laborator” la 10A se vor desfăşura în orele 5-6-7 ale zilei de Lu; pentru 10B va rezulta distribuţia (6 4 6 6 6) şi vom anexa cele 3 ore de laborator în orele 5-6-7 ale zilei Ma; ş.a.m.d.

Cei doi profesori cuplaţi pe aceste ore ("P02" şi "P03") ar fi astfel în situaţia de a „închide şcoala” în fiecare zi; dar în cazul de faţă, ei au multe ore pe săptămână – 15 ore împreună şi câte 13 ore fiecare (şi deci oricum ies cam ultimii din şcoală, mai în fiecare zi). Cam la fel stau lucrurile şi pentru profesorii de limbi străine.

Dintre cele 38-15=23 ore cuplate rămase, 14 ore ţin de limbi străine; la 9E vor fi de anexat 6 ore (5 pentru "P32"+"P39" şi una pentru "P32"+"P05") – încât prin SWAP vom lăsa distribuţia (6 6 4 6 5), anexând în final cele 6 ore cuplate, ca a 7-a oră în zilele Lu, Ma şi Jo, respectiv a 5-a şi a 6-a oră în ziua Mi şi a 6-a oră Vi.
Regizând astfel, am ţinut seama şi de faptul că "P32" şi "P05" sunt cuplaţi nu numai pe 9E, dar şi pe clasa 12E – anume, pe 5 ore; distribuţia iniţială pentru 12E este (5 5 5 5 5), deci ora cuplată va fi anexată ca a 6-a oră în fiecare zi; astfel, "P32"+"P05" intră Lu ora a 6-a la 12E şi apoi intră în ora a 7-a la 9E.
Încă 3 ore sunt cuplate, la clasa 11E, dar cu alţi profesori decât cei menţionaţi mai sus – încât şi acestea pot fi anexate ca ultima oră din zi, la clasa respectivă.

Cele 23-14=9 ore care mai sunt de anexat, ţin de "Muzică/Desen", la clasele 10A-F şi 9ABC, cu "P31"+"P10"; n-ar fi greu să introducem totuşi un „profesor fictiv” pentru aceste 9 ore, încât să evităm măcar pentru acest caz plasarea lor la sfârşitul zilei – totuşi am preferat să procedăm la fel ca mai sus, vizând anexarea acestor 9 ore ca a 6-a şi a 7-a oră la câte două dintre clasele respective, în fiecare zi.

Modificarea distribuţiei pe zile a încadrării

Ducând în /recast/ fişierul CSV rezultat mai sus prin distributeByDays.R şi folosind în principal operaţiile Mark şi SWAP, am ajuns la redistribuirea redată în tabelul următor – asigurând conform planului sugerat mai sus anexarea ulterioară a celor 38 de ore cuplate şi pe de altă parte, omogenizând mai bine distribuţiile individuale pentru profesorii cu măcar 10 ore pe săptămână şi reducând numărul de zile de lucru celor cu puţine ore.

profLuMaMiJoVi
P0110A 10B 11B 7G 9A 10A 10C 12B 12F 5G 9C 11A 11C 12D 12E 6G 9B 10D 10E 11D 12A 9E 9F 10F 11E 12C 8G 9D 11F
P0410D 11D 12D 12E 9F 10D 11D 11F 12D 12E 9F 11E 12D 12E 12F 9D 11E 12B 12D 12E 12F 9D 10C 10D 12D 12E 12F
P0610E 10F 11E 9B 9C 11B 11E 9B 9D 9F 10C 11B 12E 9E 9F 10C 11C 8G 9C 9E 7G 11C 12D 9B 9C 9D 12F
P0712A 7G 7G 9B 10B 10B 7G 9B 9C 9F 10B 12A 7G 9C 9F 10B 12E 7G 9B 9C 12A 12A 12E 7G 9B 9C
P0810C 11A 11B 12B 8G 10C 11A 12B 8G 9A 10C 11A 11B 12B 8G 9A 11A 12B 8G 9A 11B 10C 11A 11B 12B 9A
P1110E 11B 12C 9B 9C 10D 10E 8G 9B 9D 10D 8G 9B 9C 9D 11B 12C 9C 9F 11B 12C 9C 9F
P1210D 11D 12D 9D 10B 11C 12A 12D 11B 11C 12A 12D 9D 11B 12D 9A 9D 10B 10D 11D 12D 9D 9A
P0510E 10F 12A 6G 9D 10F 11B 12A 9D 10C 11B 12B 9A 10C 12B 9A 9B 10C 10E 6G 9B 10F
P0911E 12F 5G 9F 11E 11E 12F 5G 10B 11D 11E 12F 9F 10B 11D 11E 8G 9F 11E 12F 8G 9F
P1410C 11A 11B 11C 9A 10C 11B 8G 9A 9F 10A 10C 11B 8G 10A 11C 7G 9D 11B 11C 12A 7G
P1510E 12E 12F 6G 8G 10E 12C 12E 12F 10E 12B 12C 12F 10E 11A 12B 6G 10E 10E 11A 8G
P1610F 11E 9D 9E 10D 10E 12C 9E 10D 10E 11D 12C 10E 12C 12D 11D 10F 11E 12D 9D 12C
P1710B 11B 9B 11B 11C 9B 10E 10A 11B 11C 9B 9C 11C 12A 12F 9C 11F 10A 10B 9B 9C
P1810C 12A 12E 8G 9E 12A 12E 8G 9E 12A 8G 9E 10C 10C 12E 8G 9E 12A 12E 8G 9E
P1310F 11F 9B 9E 10A 10C 9B 7G 10A 10C 9C 7G 10F 11F 5G 9C 10F 11F 5G 9E
P1912A 7G 8G 9C 11D 11F 8G 9E 11D 11F 9A 10A 11C 12F 9F 10A 11E 12A 7G 9B
P2011B 11D 12D 9B 10A 11D 12D 9B 10A 11D 9B 11B 11B 11D 12D 9B 11B 11D 12D 10A
P2111C 11E 12C 9D 11C 11E 12C 9D 10B 11C 11E 9D 10B 11E 12C 9D 11C 12C 9D 10B
P2210D 12E 12F 9E 11D 12E 9E 10D 11D 12A 12E 10D 11D 12E 12F 10D 12E 12F 11D
P2310B 12C 5G 6G 10C 10D 11A 11B 10F 12B 12E 9D 10E 12D 5G 10B 5G 6G 10C
P2411E 12D 9C 9F 11E 12D 6G 9D 11E 12D 9D 11E 12D 5G 9B 5G 9A 9F 6G
P2510D 11F 12B 12F 11F 12B 12F 10D 11F 12F 12B 10D 11F 11F 12F 11F 12B 12F 10D
P2612B 12C 8G 9A 11A 12B 12C 9A 10D 12B 6G 10C 10F 6G 9D 12B 12C 9E 10C
P2710C 10E 11A 11F 10B 10E 10F 11F 10E 10F 12C 10A 10F 11B 12B 10F 11C 11F
P2810D 12D 9D 10C 12D 9D 10B 11A 8G 12A 8G 12B 5G 10A 10D 8G 9A
P2912B 12C 9C 10F 12B 9C 9E 10D 12C 9B 10B 12C 9B 10B 10E 12B 12C
P3010C 11C 12B 10B 11C 12B 10B 11C 9E 10C 10F 11C 9E 10C 12B 10F 10B
P1012F 9D 9F 12E 6G 9F 11F 12D 5G 11E 8G 7G 11D 12F 9E
P3310D 11F 11C 12D 9C 11C 12C 9C 10D 11F 12C 10D 11F 12D
P0210A 12B 11A 11F 9A 11A 5G 9A 11A 9A 10A 11A 9A
P0310B 11D 12A 12A 12C 6G 12A 12C 10B 10D 12A 10B 11D
P346G 9F 6G 9C 6G 9C 9F 6G 9C 9F 6G 9C 9F
P3510E 10F 10F 11A 10E 10F 11A 10E 10F 11A 10E 11A
P3611A 12A 9A 12A 9A 10A 11A 12A 10A 9A 10A 11A
P3710F 9E 10F 11E 11E 11F 11F 9F 9E 9F
P3811F 12F 10D 9F 10E 10F 9D 9E 11F 7G
P4010E 11C 9F 9F 10E 12C 12E 12E 9B
P4111C 5G 11C 5G 5G 11C 5G 11C 5G
P4210A 11A 10B 10F 10C 10D 10E 11B
P439A 7G 7G 9A 7G 9A 7G 9A
P4410A 6G 10A 6G 10A 6G 10A 6G
P315G 6G 7G 9E 9D 9F 8G
P4510A 9A 9C 9E 10B 9B 9E
P4611E 8G 11D 11F 11E 11D 11C
P4711D 9C 12F 11D 11B 11D 12F
P3212E 9E 10A 10A
P3911A 7G 11A 7G
P505G 7G 7G 9F
P517G 6G 7G 6G
P5210E 10F 10F 10E
P535G 5G 5G 5G
P5412F 11D 11F 12D
P558G 7G 8G
P567G 6G 5G
P575G 8G 7G
P587G 6G
P5912F 11F
P6012C 12A
P616G

Bineînţeles că acest tabel HTML a fost preluat direct din aplicaţia /recast/ (folosind instrumentul Inspector al browser-ului, v. [1]); doar am eliminat cele 801 <div>-uri în care erau ambalate clasele (aici nemaifiind necesar să păstrez şi handler-ele de click ale aplicaţiei, montate pe aceste <div>-uri).

Cele 801 ore sunt repartizate aproape omogen pe zile: (160 162 159 161 159); bineînţeles că după ce vom anexa şi cele 38 de ore cuplate, numărul total de ore va creşte cu 7 sau 8, în fiecare zi.

Întrebare: cum se explică diferenţa între distribuţiile orelor la "P55" şi "P56"? Aceştia au numai câte 3 ore (şi nu intră în vreun cuplaj); în mod normal le-am plasa într-o singură zi, dar numai dacă ar fi la clase diferite (două dintre cele 3 ore ale lui "P55" sunt la o aceeaşi clasă).

Generarea orarelor zilnice

După ce am obţinut prin /recast/ distribuţia pe zile redată în tabelul HTML de mai sus, o salvăm prin "Export" în fişierul "disRecast.csv" (păstrăm aici denumirile din [1]), pe care apoi îl transformăm prin csv2df.R (v. [1]) în disPeZile.RDS – obiect tibble de 801 linii cu 3 variabile: $prof (factor ordonat), $cls şi $zl (factor ordonat).

Din disPeZile.RDS separăm distribuţia corespunzătoare fiecărei zile, rezultând dis_{zi}.RDS, unde "{zi}" este Lu, Ma, etc. (v. [1]). Aplicând pe dis_{zi}.RDS funcţia mountHtoDay() din programul set_hours_day.R, obţinem câte un orar orar_{zi}.RDS pentru fiecare zi (cam în câte 2 minute).

Prin aplicaţia /dayRecast vom putea rearanja distribuţia pe orele zilei existentă în orar_{zi}.RDS, astfel încât să reducem numărul de ferestre şi să facem posibilă anexarea orelor cuplate. Dar avem de transformat „formatul” prof|cls|ora specific pentru orar_{zi}.RDS, într-un fişier CSV cu structura "prof, ora1, ora2, ..., ora7" (care să fie apoi „pastat” în elementul <textarea> al aplicaţiei). Dar ca şi în [1], vrem ceva mai mult: să reordonăm liniile încât cele corespunzătoare profesorilor cărora urmează să le anexăm orele cuplate, să fie grupate la începutul tabelului (astfel, ne vom uşura intervenţia interactivă prin operaţiile SWAP):

# rds2csv.R  (adaptat din [1])
library(tidyverse)
file <- "orar_"
# Zile <- c("Lu", "Ma", "Mi", "Jo", "Vi")
format_csv <- function(zi) {
    readRDS(paste0(file, zi, ".RDS")) %>%
    arrange(prof) %>%
    split(.$prof) %>%
    map_df(., function(Q) spread(Q, ora, cls))
}
rds2csv <- function(zi) {
    orz <- format_csv(zi)
    cplv <- c("P02", "P03", "P31", "P10","P32","P39","P05")
  # vectorul profesorilor din acea 'zi', începând cu cei cuplaţi
    ord_pr <- c(cplv, setdiff(orz$prof, cplv))
  # indecşii liniilor din 'orz', în ordinea dată de 'ord_pr'
    row_ids <- unlist(lapply(ord_pr, function(pr, D) { 
                                         which(D$prof == pr) 
                                     }, D = orz))
    orz <- orz[row_ids, ]  # pe primele linii avem cuplurile din acea zi
    write_csv(orz, file=paste0(file, zi, ".csv"), na = "-", col_names=TRUE)
}

Prin rds2csv() obţinem fişierele orar_{zi}.csv, cerute în /dayRecast/.

Finalizarea interactivă a orarului zilei

Înainte de a ne apuca de lucru asupra orarului unei zile, adăugăm în "dayRecast.js" o nouă operaţie, "markStruct" să-i zicem, prin care să marcăm cumva, la un moment sau altul, structura distribuţiilor orare de pe primele linii:

        bar.find('button:contains(markStruct)').on('click', function(event) {
            let nrows = $(this).prev().val();
            let ks = got.find('tr').slice(0, nrows);
            ks.find("td:contains('-')").toggleClass("toKeepStruc");
        });

'bar' şi 'got' referă bara butoanelor aplicaţiei şi respectiv, tabelul HTML în care este redat (dinamic) orarul zilei. În fişierul dayRecast.css am adăugat definiţia .toKeepStruc {background:LightBlue}; la click pe "markStruct", pe primele linii ale tabelului – atâtea cât se indică în elementul <input> care precede butonul – se vor marca locurile „goale”, adică acele <div>-uri care conţin nu o clasă, ci "-".

După ce, folosind SWAP, vom ajunge la un orar care să permită anexarea ulterioară a orelor cuplate (la profesorii aflaţi pe primele linii ale tabelului) – este de dorit ca operaţiile SWAP ulterioare (prin care să continuăm reducerea ferestrelor existente) să nu „deranjeze” structura existentă pe primele linii (adică pe aceste linii să nu apară vreo clasă în zona marcată anterior prin markStruct).

De exemplu, pentru ziua Lu existau iniţial (în orar_Lu.csv, transferat aplicaţiei) 40 de ferestre; după câteva operaţii SWAP am stabilizat convenabil structura primelor 7 linii (corespunzătoare cuplajelor de anexat ulterior) şi am continuat cu SWAP pentru a reduce cât mai mult ferestrele, iar markStruct s-a dovedit foarte util, atenţionând vizual atunci când operaţia SWAP curentă perturbă structura stabilită pe primele linii (caz în care putem folosi "Undo", sau putem angaja operaţii SWAP care să reconstituie structura convenită):

Aplicaţia înregistrează operaţiile SWAP efectuate – într-o listă "History", pe care ulterior "applyHIST" o poate reparcurge – şi în final, am constatat că mi-au trebuit 125 de operaţii SWAP pentru a reduce numărul de ferestre la 11 (desigur, cineva mai inspirat ar putea ajunge probabil pe la 6 ferestre, cu numai vreo 60 de operaţii SWAP; eu am procedat mai degrabă mecanic, nu inspirat şi n-am insistat mai mult de vreo oră).

Am avut în vedere următorul plan de anexare a orelor cuplate (pentru ziua Lu): "P02" şi "P03" – imediat după ce-şi fac orele proprii, cum se vede pe panoul din dreapta – intră împreună la clasa 10A, în orele 5, 6 şi 7; "P31" şi "P10" – imediat după ce-şi fac orele proprii (v. liniile 3 şi 4 pe panoul redat mai sus, în dreapta) – intră împreună ora a 6-a la clasa 10C şi ora a 7-a la clasa 10B; "P32" intră împreună cu "P05" în ora a 6-a la clasa 12E, apoi intră împreună cu "P39" în ora a 7-a la clasa 9E.
Deci după anexarea orelor astfel cuplate, pe primele 7 linii vom avea:

La profesorii cuplaţi nu avem nicio fereastră, ceea ce compensează cumva faptul că ei „închid şcoala”; cele 11 ferestre sunt toate, de câte o singură oră, numai la profesori cu 5 sau cu 4 ore în ziua respectivă (iar aceste reguli sunt păstrate şi pe orarele celorlalte zile, la care nu ne mai referim aici).

vezi Cărţile mele (de programare)

docerpro | Prev | Next