Gépi órarendkészítő demonstrációs
program
Az Órarend menüpontban említettem, hogy
a TANFORDI több gépi órarendkészítő rutinnal is rendelkezik. Ebben a
demonstrációs programban ízelítőt kaphatunk a gépi órarend-generálás
nehézségeiből. A program a tantárgyfelosztást és az órarendet is automatikusan
készíti. Ebből adódóan nem valószínű, hogy az előállított órarend egy valós
esetre, egy az egyben alkalmazható lenne. Nem is ez a program célja, hanem az,
hogy egy olyan algoritmust mutasson be, melyet finomítva, gyakorlati
órarendkészítésre is alkalmassá tehetünk.
Először a program paramétereit
ismertetném. Mint már említettem, magát a tantárgyfelosztást is a gép készíti.
Az osztályok száma
A program minden osztálynak 30 órát generál: egy
5-órás, kettő 4-órás, három 3-órás és négy 2-órás tantárggyal. Az osztályokban
minden tantárgyat más-más pedagógus tanít, ebből adódóan a tantárgyakat a
pedagógusok neve helyettesítheti, azaz a program nem tartalmaz tantárgyneveket.
Ugyancsak nincs a programban tanterem (minden osztály a saját tantermében
tartja óráit), nincs csoportbontás és csoportösszevonás sem (mint általában az
5.-8. évfolyamon). Az alkalmazott rendező algoritmus hatékonyságát mindezek
természetesen befolyásolják, úgy gondolom, hogy könnyítik, de használhatatlanná
nem teszik. Ha a valós esetnek megfelelő részek is bekerülnek, akkor az
algoritmus több lépésre kényszerül, de a végső megoldáshoz elég jól konvergál
akkor is. A látszólag gyengébb feltételek mellett van egy nagyon szigorú is:
csak teljesen tömör órarendet fogad el megoldásnak, azaz a 32 osztály 960
óráját öt napra, napi 6 órában helyezi el (vagyis nem lehet sem lyukasóra, sem
hetedik).
Az algoritmus leírásában előforduló
fogalmak részletes magyarázatára térnék át. Először az órarendfeltöltést
irányító paraméterekről essen szó. Az alapértékek feltöltése után minden
továbbit hozzáadjuk a már benne lévőkhöz:
-
Lehetőségvektor: a napi paramétereket ide töltjük be. Az órák betöltési
időpontjának kiválasztása a lehetőségvektor napi maximumai közül történik.
-
Napi paraméterek: a hét minden órájához tartozik egy paraméter, mely a harmadik
órára a legnagyobb
-
Hétvége paraméter: gyakorlatilag egy 5 elemű vektor, mely a hét első és utolsó
napjára nullát, a többi napra egy pozitív értéket tartalmaz.
-
Periodicitás paraméter: a tantárgy heti óraszámának megfelelő eltolást hoz
létre. Heti egy és négy óra esetén véletlenül választ a hét napjai közül, három
órás tárgynál hétfőt, szerdát és pénteket helyezi előtérbe, kétórásnál keddet
és csütörtököt.
-
Szomszédossági paraméter: a pedagógusok tömörebb órarendjének létrehozását
segíti. Ha egy pedagógusnak van valahol már órája, akkor a következőt a
meglévők mellé szeretné tenni.
-
Óraszám kiegyenlítés: mivel minden pillanatban 32 órát kell ellátni, igyekezni
kell a betöltés menete közben is az órák egyenletes eloszlására. Ez a paraméter
ezt hivatott szolgálni.
-
Kritikus időpont kiemelése: mivel minden osztálynak, minden időpontban kell
órájának lenni, az algoritmus megkeresi az e tekintetben legkritikusabb
időpontot és osztályt, majd erre az időpontra a lehetőségvektorban nagyon magas
értéket állít be, hogy minél nagyobb valószínűséggel az időpont kiválasztódjon
a betöltéshez.
Az algoritmus kiválasztási eljárásában
nagyon fontos a tétel heti óraszáma. Minél több óra van a héten egy tantárgyból,
annál fontosabbnak tartja és a betöltéskor, ha lehet, mindig a magasabb
óraszámút választja. A másik tétel kiválasztási elv alapja a relatív
betöltöttség. Ezek pedagógusokra és osztályokra értelmezett, a betöltési
folyamat során folyamatosan csökkenő értékű paraméterek (természetesen tétel
törlésekor nőhetnek). A relatív betöltöttség a betöltendő órák száma osztva, a
betöltési lehetőségek számával. Ez az érték induláskor mindig kisebb, mint egy,
és minden betöltési lépés után csökken, végül nulla lesz. Minél magasabb a
relatív betöltöttsége egy pedagógusnak vagy osztálynak, annál nehezebb az órák
elhelyezése. A tételek kiválasztásakor ezért mindig a lehető legnagyobb relatív
betöltöttség szerinti pedagógust illetve osztályt választja a program.
A tétel kiválasztási rendet öt
szakaszra osztottam, melyet a lépésszám 5-ös modulusával vezérlek.
-
0-ra: a legnagyobb relatív betöltöttségű osztályt választjuk,
-
1-re: a legnagyobb relatív betöltöttségű pedagógust választjuk,
-
2-re: kritikus osztály időpontot keresünk,
-
3-ra: azt a pedagógust, aki miatt a legtöbbször kellett az órarendet törölni,
-
4-re: azt az osztályt, amelyik miatt a legtöbbször kellett az órarendet
törölni.
Az algoritmus olyan, hogy a kiválasztás
után mindenképp beírja az órarendbe a tanítási tételt. Utána ellenőrzi, hogy
nem került-e hetedik órára. Ha igen, akkor az érintett osztály teljes
órarendjét törli. Így nem képzelhető el, hogy hetedik óra maradjon az
órarendben. A törlést felváltva könyveli egyszer a pedagógusnak, egyszer az osztálynak.
A program a betöltés közben számolja,
hogy az egyes osztályok és pedagógusok hányszor szerepeltek betöltésben. Azért,
hogy az algoritmus ne ragadjon bent egy állandóan (újra meg újra) kiválasztott
pedagógusnál vagy osztálynál, teljes törlést hajt végre az órarendre. Ezt akkor
teszi, ha pedagógusnál a kezelési szám meghaladja az osztályok számának a
négyzetét, osztályoknál pedig az osztályok száma négyzetének a kétszeresét.
Természetesen a paraméterekkel
kísérletezhetünk. Ha egy feltételt fontosabbnak tartunk, akkor a listában lévő
értéktől nagyobbat adatunk neki. Hasonlóan módosíthatjuk a pedagógusok, illetve
a pedagógusok heti maximális óraszámát is. Ha a pedagógusok számát csökkentjük,
akkor a keresési lépésszám növekedni kezd. Ezzel a változatással óvatosan
bánjunk, a programba nincs beépítve a lehetetlen tantárgyfelosztás esete, és
végtelen ciklusba eshet a program. Ne állítsunk be például 20 pedagógust, mert
azok nem tudnak 960 órát megtartani. Ha az előző futtatáshoz képest a
pedagógusok számát módosítottuk, akkor a TFO.DAT
állományt a futtatási mappából el kell távolítani, hiszen a megváltozott
rekordszám miatt az állományt nem tudja a program elolvasni. Arra az esetre, ha
a program nagyon hosszú időt venne igénybe a feltöltéshez, egy 2000*(osztályok
száma) limit van beállítva a maximális lépésszámra, mely természetesen szintén
módosítható.
Futtatás után a program a teljes
pedagógus tantárgyfelosztást és órarendet lemezre menti, melyet a következő
futtatáskor betölt. A képernyőn váltani lehet a pedagógus tantárgyfelosztás,
pedagógus órarend és osztály órarend látványa közül. Órarend generálásakor
valamelyik órarend és a relatív betöltöttségek látszanak. A gyorsabb futás
érdekében csak minden századik lépésre frissül a képernyő. A listabeli
értékekre a betöltési lépésszám 1600-16000 között van, egy közepes
teljesítményű
A program formja tervező nézetben:
A program futási képei. Pedagógus
tantárgyfelosztás:
Elkészült pedagógus órarend:
Elkészült osztályórarend:
A program listája:
{**********************************************
** **
** Gépi órarendkészítő demonstrációs program **
** Készítette: Görbe Mihály (GM-Soft) **
** 2010. Július **
** **
**********************************************}
unit UGOD;
interface
uses
Windows, Messages, SysUtils, Variants, Classes,
Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids, ExtCtrls;
Const OSz= 32; //osztályok száma
type
TfmGOD = class(TForm)
btKilepes: TButton;
btTFGeneral: TButton;
sgTF: TStringGrid;
btTFOR: TButton;
sgOR: TStringGrid;
btFeltolt: TButton;
edLepes: TEdit;
btOrarendTorlo: TButton;
edReset: TEdit;
lbLepes: TLabel;
lbRestart: TLabel;
Procedure Lemezrol;
Procedure Lemezre;
Procedure OTFeORTolt;
Procedure OraTorlo;
Procedure PTFKepre;
Procedure PedORKepre;
Procedure OszORKepre;
Function PRelBet(P: Word): Real;
Function MaxPRelBet: Word;
Function ORelBet(O: Word): Real;
Function MaxORelBet: Word;
Function OszMaxP(O: Word): Word;
Function PedMaxO(P: Word): Word;
Procedure OPLehetoseg;
Procedure OPLMin(Var O, D, H: Word);
Function MaxPORelBet(O, D, H: Word): Word;
Procedure OTorlo(O: Word);
Function MaxPUjra: Word;
Function MaxOUjra: Word;
Procedure ReStart;
Procedure GepiBetolto;
procedure btKilepesClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure btTFGeneralClick(Sender: TObject);
procedure btTFORClick(Sender: TObject);
procedure btFeltoltClick(Sender: TObject);
procedure btOrarendTorloClick(Sender: TObject);
procedure sgORDrawCell(Sender: TObject; Col, Row: Integer;
Rect: TRect; State: TGridDrawState);
procedure sgTFDrawCell(Sender: TObject; Col, Row: Integer;
Rect: TRect; State: TGridDrawState);
procedure sgTFClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
St1=String[1]; //1 karakter hosszú string típus
St3=String[3]; //3 karakter hosszú string típus
TTTetel=Record //tanítási tétel
OSza: Word; //óraszám
Beir: Boolean; //beírt esetén TRUE egyébként FALSE
End;
TPTFO=Record //pedagógus tant.-felosztása és órarendje
PRov: St1; //pedagógus névrövidítése
PTFe: Array[1..OSz] Of TTTetel; //pedagógus tantárgyfelosztása
POra: Array[1..5,1..7] Of Word; //pedagógus órarendje
End;
Const PSz= 50; //pedagógusok száma
POMax= 26; //pedagógusok maximális heti óraszáma
Oszt: Array[1..Osz] Of St3= //alapértelmezett osztálynevek
('1.a','1.b','1.c','1.d','1.e','
'2.a','2.b','2.c','2.d','2.e','
'3.a','3.b','3.c','3.d','3.e','
'4.a','4.b','4.c','4.d','4.e','
PedN: String[PSz]= //alapértelmezett pedagógusnevek
'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy';
NPar: Array[1..7] Of Word= //napi paraméterek
(2600,2900,3100,2900,2400,2000,100);
PerP= 300; //periodicitás paraméter
SzoP= 150; //szomszédossági paraméter
HVeg= 100; //hétvége paraméter
OKie= 50; //Napi óraszámkiegyenlítő paraméter
HetN= 'HKSCP'; //a hét napjai
var
fmGOD: TfmGOD;
ACol,ARow: Integer;
PTFO: Array[1..PSz] Of TPTFO; //az adatállomány
DNev: String; //az adatállomány OS-beli neve
FNev: File Of TPTFO; //az adatállomány logikai neve
TFPOROOR: Word; //1: TF, 2: POR, 3: OOR látható
POSza: Array[1..PSz] Of Word; //pedagógusok heti óraszáma
OOSza: Array[1..OSz] Of Word; //osztályok heti óraszáma
PRelB: Array[1..PSz] Of Real; //pedagógus relatív betöltöttség
ORelB: Array[1..OSz] Of Real; //osztály relatív betöltöttség
OTFe: Array[1..OSz,1..PSz] Of TTTetel; //osztály tantárgyfelosztás
OOra: Array[1..OSz,1..5,1..7] Of Word; //osztály órarend
LVekt: Array[1..5,1..7] Of Word; //lehetőségvektor
OPLeh: Array[1..OSz,1..5,1..7] Of Word; //osztály-pedagógus lehetőségek
Faz: Word; //fázis: 0-4 értékek egyike
Lep: LongInt; //a gépi betöltő hívási száma
Veg: Boolean; //betöltést leállító
Res: Word; //teljes újraindítások száma
OKsz: Array[1..OSz] Of Word; //osztály kiválasztási szám
OUjr: Array[1..OSz] Of Word; //osztály újraindítási szám
PKsz: Array[1..PSz] Of Word; //pedagógus kiválasztási szám
PUjr: Array[1..PSz] Of Word; //pedagógus újraindítási szám
implementation
{$R *.dfm}
Procedure TfmGOD.Lemezrol; //adatok betöltése lemezről
Var I: Word;
Begin
I:= 0;
AssignFile(FNev,DNev); {$I-}Reset(FNev);{$I+}
If IOResult<>0 Then ReWrite(FNev) Else
While Not EOF(FNev) Do Begin Inc(I); Read(FNev,PTFO[I]) End;
CloseFile(FNev);
End;
Procedure TfmGOD.Lemezre; //adatok lemezre írása
Var I: Word;
Begin
AssignFile(FNev,DNev); ReWrite(FNev);
For I:= 1 To PSz Do Write(FNev,PTFO[I]);
CloseFile(FNev);
End;
Procedure TfmGOD.OTFeORTolt; //osztályórarendek feltöltése
Var I, J, K: Word;
Begin
For I:= 1 To OSz Do For J:= 1 To PSz Do With OTFe[I,J] Do
Begin OSza:= 0; Beir:= False End;
For K:= 1 To PSz Do With PTFO[K] Do
Begin
For I:= 1 To OSz Do With PTFe[I] Do If OSza<>0 Then
Begin
OTFe[I,K].OSza:= OSza;
OTFe[I,K].Beir:= Beir;
End;
For I:= 1 To 5 Do For J:= 1 To 7 Do If POra[I,J]<>0 Then
OOra[POra[I,J],I,J]:= K;
PRelBet(K);
End;
For I:= 1 To OSz Do ORelBet(I);
End;
Procedure TfmGOD.OraTorlo; //órarendek törlése
Var I, J, K: Word;
Begin
For K:= 1 To PSz Do With PTFO[K] Do
Begin
For I:= 1 To 5 Do For J:= 1 To 7 Do POra[I,J]:= 0;
For I:= 1 To OSz Do PTFe[I].Beir:= False;
End;
For K:= 1 To OSz Do
Begin
For I:= 1 To 5 Do For J:= 1 To 7 Do OOra[K,I,J]:= 0;
For I:= 1 To PSz Do OTFe[K,I].Beir:= False;
End;
With sgOR Do Cells[ColCount-1,0]:= '';
For I:= 1 To PSz Do PRelBet(I);
For I:= 1 To OSz Do ORelBet(I);
For I:= 1 To PSz Do PUjr[I]:= 0;
For I:= 1 To OSz Do OUjr[I]:= 0;
End;
procedure TfmGOD.btKilepesClick(Sender: TObject); //kilépés a programból
begin
Lemezre;
Close;
end;
Procedure TfmGOD.PTFKepre; //pedagógus tantárgyfelosztás képernyőre
Var I, J, N: Word;
Begin
For I:= 1 To OSz Do OOSza[I]:= 0;
With sgTF Do
Begin
For I:= 1 To ColCount-1 Do For J:= 1 To RowCount-1 Do Cells[I,J]:= '';
For I:= 1 To PSz Do With PTFO[I] Do
Begin
Cells[0,I]:= PRov; N:= 0;
For J:= 1 To OSz Do With PTFe[J] Do
Begin
Inc(N,OSza); Inc(OOSza[J],OSza);
If OSza<>0 Then Cells[J,I]:= IntToStr(OSza);
End;
Cells[ColCount-1,I]:= IntToStr(N); POsza[I]:= N;
End;
For I:= 1 To OSz Do Cells[I,RowCount-1]:= IntToStr(OOSza[I]);
End;
For I:= 1 To PSz Do PRelBet(I);
For I:= 1 To OSz Do ORelBet(I);
End;
Procedure TfmGOD.PedORKepre; //pedagógus órarend képernyőre
Var I, J, K: Word;
Begin
With sgOR Do
Begin
sgTF.Visible:= False; Visible:= True;
Cells[0,0]:= 'POR';
For I:= 0 To ColCount-1 Do For J:= 1 To RowCount-1 Do Cells[I,J]:= '';
For K:= 1 To PSz Do With PTFO[K] Do
Begin
Cells[0,K]:= PRov; Cells[ColCount-1,K]:= FloatToStr(PRelB[K]);
For I:= 1 To 5 Do For J:= 1 To 7 Do If POra[I,J]<>0 Then
Cells[7*(I-1)+J,K]:= Oszt[POra[I,J]];
End;
End;
End;
Procedure TfmGOD.OszORKepre; //osztály órarend képernyőre
Var I, J, K: Word;
Begin
With sgOR Do
Begin
sgTF.Visible:= False; Visible:= True;
Cells[0,0]:= 'OOR';
For I:= 0 To ColCount-1 Do For J:= 1 To RowCount-1 Do Cells[I,J]:= '';
For K:= 1 To OSz Do
Begin
Cells[0,K]:= Oszt[K]; Cells[ColCount-1,K]:= FloatToStr(ORelB[K]);
For I:= 1 To 5 Do For J:= 1 To 7 Do If OOra[K,I,J]<>0 Then
Cells[7*(I-1)+J,K]:= PTFO[OOra[K,I,J]].PRov;
End;
End;
End;
Function TfmGOD.PRelBet(P: Word): Real; //P pedagógus relativ betöltöttsége
Var I, J, K, Bs, Ls: Word; Pr: Real; //Bs: beírt, Ls: lehetőségek száma
Lv: Array[1..5,1..7] Of Word;
Begin
PRelBet:= 0; If P=0 Then Exit;
Bs:= 0; Ls:= 0; For I:= 1 To 5 Do For J:= 1 To 7 Do Lv[I,J]:= 0;
With PTFO[P] Do
Begin
For I:= 1 To OSz Do //beírt órák száma
If PTFe[I].Beir Then Inc(Bs, PTFe[I].OSza);
For K:= 1 To OSz Do //lehetőségek száma
If (PTFe[K].OSza>0) And Not PTFe[K].Beir Then
For I:= 1 To 5 Do For J:= 1 To 7 Do
If (OOra[K,I,J]=0) And (POra[I,J]=0) Then Inc(Lv[I,J]);
For I:= 1 To 5 Do For J:= 1 To 7 Do If Lv[I,J]>0 Then Inc(Ls);
Pr:= 0;
End;
If Ls>0 Then Pr:= Round(10000*(POSza[P]-Bs)/Ls)/10000;
PRelB[P]:= Pr; PRelBet:= Pr;
//PRelBet:= be nem irt órák száma/ahány helyen még be tud menni osztályba
End;
Function TfmGOD.ORelBet(O: Word): Real; //O osztály relatív betöltöttsége
Var I, J, K, Bs, Ls: Word; Pr: Real;
Lv: Array[1..5,1..7] Of Word;
Begin
ORelBet:= 0; If O=0 Then Exit;
Bs:= 0; Ls:= 0; For I:= 1 To 5 Do For J:= 1 To 7 Do Lv[I,J]:= 0;
For I:= 1 To PSz Do //beírt órák száma
If OTFe[O,I].Beir Then Inc(Bs,OTFe[O,I].OSza);
For K:= 1 To PSz Do //lehetőségek száma
If Not OTFe[O,K].Beir Then With PTFO[K] Do
For I:= 1 To 5 Do For J:= 1 To 7 Do
If (OOra[O,I,J]=0) And (POra[I,J]=0) Then Inc(Lv[I,J]);
For I:= 1 To 5 Do For J:= 1 To 7 Do If Lv[I,J]>0 Then Inc(Ls); Pr:= 0;
If Ls>0 Then Pr:= Round(1000*(OOSza[O]-Bs)/Ls)/1000;
ORelB[O]:= Pr; ORelBet:= Pr;
//ORelBet:= be nem irt órák száma/ahány helyen még ráérnek pedagógusok
End;
procedure TfmGOD.FormCreate(Sender: TObject); //rendszer-start
Var I, J: Word;
begin
With sgTF Do
Begin
Top:= 40;
Left:= 8;
Width:= 881;
Height:= 666;
ColCount:= 34;
RowCount:= 52;
ColWidths[0]:= 32;
ColWidths[ColCount-1]:= 28;
Cells[0,0]:= 'PTF';
Cells[ColCount-1,0]:= 'Osz';
For I:= 1 To OSz Do Cells[I,0]:= Oszt[I];
Visible:= True;
End;
ACol:= 1; ARow:= 1;
With sgOR Do
Begin
Top:= 40;
Left:= 8;
Width:= 881;
Height:= 666;
ColCount:= 37;
RowCount:= 51;
ColWidths[0]:= 32;
ColWidths[36]:= 55;
For I:= 1 To 5 Do For J:= 1 To 7 Do
Cells[7*(I-1)+J,0]:= HetN[I]+IntToStr(J);
Visible:= False;
End;
DNev:= 'TFO.dat';
Lemezrol;
Randomize;
TFPOROOR:= 1;
OTFeORTolt;
PTFKepre;
end;
procedure TfmGOD.btTFGeneralClick(Sender: TObject); //TF generálása
Var I, J, K, L, N, P: Word;
begin
btOrarendTorloClick(Sender);
If TFPOROOR>1 Then Begin TFPOROOR:= 3; btTFORClick(Sender) End;
For I:= 1 To PSz Do With PTFO[I] Do//pedagógus tantárgyfelosztás törlése
For J:= 1 To OSz Do With PTFe[J] Do Begin OSza:= 0; Beir:= False End;
For I:= 1 To PSz Do POSza[I]:= 0; //pedagógusok óraszámának törlése
For I:= 1 To OSz Do OOSza[I]:= 0; //osztályok óraszámának törlése
For I:= 1 To OSz //osztály tantárgyfelosztás törlése
Do For J:= 1 To PSz Do With OTFe[I,J] Do Begin OSza:= 0; Beir:= False End;
For I:= 1 To PSz Do PUjr[I]:= 0; //újraindítási számok törlése
For I:= 1 To OSz Do OUjr[I]:= 0;
For I:= 1 To PSz Do PKSz[I]:= 0; //kezelési számok törlése
For I:= 1 To OSz Do OKSz[I]:= 0;
For I:= 1 To PSz Do PTFO[I].PRov:= PedN[I]; //pedagógus névrövidítés töltése
//a tantárgyfelosztás generálása, minden osztályban:
//5+4+4+3+3+3+2+2+2+2=30 óra van, 10 tétel, összesen 320 tétel
For I:= 1 To OSz Do For J:= 1 To 4 Do For K:= 1 To J Do
Begin //egy osztályban egy pedagógus
Repeat //legfeljebb egy tárgyat taníthat
P:= Random(PSz)+1;
N:= 0; For L:= 1 To OSz Do Inc(N,PTFO[P].PTFe[L].OSza);
Until (PTFO[P].PTFe[I].OSza=0) And (N+(6-J)<=POMax);
PTFO[P].PTFe[I].OSza:= 6-J;
End;
For I:= 1 To PSz Do With PTFO[I] Do//áttöltés az osztály-tantárgyfelosztásba
For J:= 1 To OSz Do With PTFe[J] Do OTFe[J,I].OSza:= OSza;
For I:= 1 To PSz Do With PTFO[I] Do//pedagógusok óraszáma
For J:= 1 To OSz Do Inc(POSza[I],PTFe[J].OSza);
For I:= 1 To OSz Do //osztályok óraszáma
For J:= 1 To PSz Do Inc(OOsza[I],OTFe[I,J].OSza);
For I:= 1 To PSz Do PRelBet(I); //relatív betöltöttségek
For I:= 1 To OSz Do ORelBet(I);
PTFKepre;
end;
procedure TfmGOD.btTFORClick(Sender: TObject); //váltás TF és OR képek között
begin
Inc(TFPOROOR); If TFPOROOR>3 Then TFPOROOR:= 1;
Case TFPOROOR Of
1: Begin sgTF.Visible:= True; sgOR.Visible:= False End;
2: PedORKepre;
3: OszORKepre;
End;
end;
Function TfmGOD.MaxORelBet: Word; //maximális relatív betöltöttségű osztály
Var I, J, Ao: Word;
Rb: Real;
Begin
J:= Random(OSz)+1; Rb:= 0; Ao:= 0;
For I:= J To OSz Do If ORelB[I]>Rb Then Begin Rb:= ORelB[I]; Ao:= I End;
For I:= 1 To J-1 Do If ORelB[I]>Rb Then Begin Rb:= ORelB[I]; Ao:= I End;
MaxORelBet:= Ao;
End;
Function TfmGOD.OszMaxP(O: Word): Word; //osztályhoz max. óraszámú pedagógus
Var I, J, Sp, Pp: Word;
Begin
OszMaxP:= 0; If O=0 Then Exit;
Sp:=0; Pp:= 0;
J:= Random(PSz)+1;
For I:= J To PSz Do IF Not OTFe[O,I].Beir And (OTFe[O,I].OSza>Sp) Then
Begin Sp:= OTFe[O,I].OSza; Pp:= I End;
For I:= 1 To J-1 Do IF Not OTFe[O,I].Beir And (OTFe[O,I].OSza>Sp) Then
Begin Sp:= OTFe[O,I].OSza; Pp:= I End;
OszMaxP:= Pp;
End;
Function TfmGOD.MaxPRelBet: Word; //legnagyobb relatív betöltöttségű ped.
Var I, J, Ap: Word; Rb: Real;
Begin
J:= Random(PSz)+1; Rb:= 0; AP:= 0;
For I:= J To PSz Do If PRelB[I]>Rb Then Begin Rb:= PRelB[I]; Ap:= I End;
For I:= 1 To J-1 Do If PRelB[I]>Rb Then Begin Rb:= PRelB[I]; Ap:= I End;
MaxPRelBet:= Ap;
End;
Function TfmGOD.PedMaxO(P: Word): Word; //pedagógus még be nem írt,
Var I, J, Sp, Op: Word; //maximális óraszámú osztálya
Begin
PedMaxO:= 0; If P=0 Then Exit;
Sp:= 0; Op:= 0;
With PTFO[P] Do
Begin
J:= Random(OSz)+1;
For I:= J To OSz Do IF Not PTFe[I].Beir And (PTFe[I].OSza>Sp) Then
Begin Sp:= PTFe[I].OSza; Op:= I End;
For I:= 1 To J-1 Do IF Not PTFe[I].Beir And (PTFe[I].OSza>Sp) Then
Begin Sp:= PTFe[I].OSza; Op:= I End;
End;
PedMaxO:= Op;
End;
Procedure TfmGOD.OPLehetoseg; //az osztályokban óránként,
Var I, J, K, L: Word; //hány pedagógus tudna órát tartani
Begin
For K:= 1 To OSz Do For I:= 1 To 5 Do For J:= 1 To 7 Do OPleh[K,I,J]:= 0;
For K:= 1 To OSz Do For L:= 1 To PSz Do With OTFe[K,L] Do
If (OSza>0) And Not Beir Then For I:= 1 To 5 Do For J:= 1 To 7 Do
If (PTFO[L].POra[I,J]=0) And (OOra[K,I,J]=0) Then Inc(OPLeh[K,I,J]);
End;
Procedure TfmGOD.OPLMin(Var O, D, H: Word); //OPLeh minimuma
Var I, J, K, L, Pm: Word;
Begin
O:= 0; D:= 0; H:= 0; //D: nap, H: óra
L:= Random(OSz)+1; Pm:= 65535;
For K:= L To OSz Do For I:= 1 To 5 Do For J:= 1 To 7 Do
If (OPLeh[K,I,J]>0) And (OPLeh[K,I,J]<Pm) Then
Begin O:= K; D:= I; H:= J; Pm:= OPLeh[K,I,J]; End;
For K:= 1 To L-1 Do For I:= 1 To 5 Do For J:= 1 To 7 Do
If (OPLeh[K,I,J]>0) And (OPLeh[K,I,J]<Pm) Then
Begin O:= K; D:= I; H:= J; Pm:= OPLeh[K,I,J]; End;
End;
Function TfmGOD.MaxPORelBet(O, D, H: Word): Word;
Var I, J: Word; //osztályhoz és kritikus időponthoz
Pm: Real; //max. rel. betöltöttségű pedagógus
Begin
MaxPORelBet:= 0; If O=0 Then Exit;
J:= Random(PSz)+1; Pm:= 0;
For I:= J To PSz Do
If (OTFe[O,I].OSza>0) And Not OTFe[O,I].Beir And (PRelBet(I)>Pm) And
(PTFO[I].POra[D,H]=0) Then Begin Pm:= PRelBet(I); MaxPORelBet:= I End;
For I:= 1 To J-1 Do
If (OTFe[O,I].OSza>0) And Not OTFe[O,I].Beir And (PRelBet(I)>Pm) And
(PTFO[I].POra[D,H]=0) Then Begin Pm:= PRelBet(I); MaxPORelBet:= I End;
End;
Procedure TfmGOD.OTorlo(O: Word); //egy osztály óráinak törlése
Var I, J, K: Word;
Begin
If O=0 Then Exit;
Inc(OUjr[O]);
For K:= 1 To PSz Do If OTFe[O,K].OSza>0 Then
Begin
OTFe[O,K].Beir:= False; PTFO[K].PTFe[O].Beir:= False;
With PTFO[K] Do For I:= 1 To 5 Do For J:= 1 To 7 Do
If POra[I,J]=O Then Begin POra[I,J]:= 0; OOra[O,I,J]:= 0 End;
PRelBet(K);
End;
ORelBet(O);
End;
Function TfmGOD.MaxPUjra: Word; //pedagógus aki miatt a legtöbb restart
Var I, J, P, Pm: Word;
Begin
P:= 0; Pm:= 0;
J:= Random(PSz)+1;
For I:= J To PSz Do If PRelB[I]>0 Then If PUjr[I]>=Pm Then
Begin P:= I; Pm:= PUjr[I] End;
For I:= 1 To J-1 Do If PRelB[I]>0 Then If PUjr[I]>=Pm Then
Begin P:= I; Pm:= PUjr[I] End;
MaxPUjra:= P;
End;
Function TfmGOD.MaxOUjra: Word; //osztály amely miatt a legtöbb restart
Var I, J, O, Om: Word;
Begin
O:= 0; Om:= 0;
J:= Random(OSz)+1;
For I:= J To OSz Do If ORelB[I]>0 Then If OUjr[I]>=Om Then
Begin O:= I; Om:= OUjr[I] End;
For I:= 1 To J-1 Do If ORelB[I]>0 Then If OUjr[I]>=Om Then
Begin O:= I; Om:= OUjr[I] End;
MaxOUjra:= O;
End;
Procedure TfmGOD.ReStart; //betöltés előlről, teljes törlés után
Var I, J, K: Word;
Begin
Inc(Res); edReset.Text:= IntToStr(Res);
For I:= 1 To OSz Do For J:= 1 To PSz Do OTFe[I,J].Beir:= False;
For I:= 1 To PSz Do For J:= 1 To OSz Do PTFO[I].PTFe[J].Beir:= False;
For K:= 1 To OSz Do For I:= 1 To 5 Do For J:= 1 To 7 Do OOra[K,I,J]:= 0;
For K:= 1 To PSz Do For I:= 1 To 5 Do For J:= 1 To 7 Do PTFO[K].POra[I,J]:= 0;
For I:= 1 To OSz Do ORelBet(I);
For I:= 1 To PSz Do PRelBet(I);
For I:= 1 To OSz Do OKSz[I]:= 0;
For I:= 1 To PSz Do PKSz[I]:= 0;
End;
Procedure TfmGOD.GepiBetolto; //gépi betöltő
Var I, J, O, P, K, L, M, Ap, Ao, Nm, Pm, V, W, D, H: Word;
Vt: Array[1..5,1..2] Of Word;
Begin
Inc(Faz); Faz:= Faz Mod 5; Ao:= 0; Ap:= 0;
Case Faz Of
0: Begin //max relatív betöltöttségű osztály
Ao:= MaxORelBet; Ap:= OszMaxP(Ao);
End;
1: Begin //max relatív betöltöttségű pedagógus
Ap:= MaxPRelBet; Ao:= PedMaxO(Ap);
End;
2: Begin //kritikus osztályidőpont
OPLehetoseg; OPLMin(Ao,D,H); Ap:= MaxPORelBet(Ao,D,H);
End;
3: Begin //pedagógus miatt legtöbbször újraindít
Ap:= MaxPUjra; Ao:= PedMaxO(Ap);
End;
4: Begin //osztály miatt legtöbbször újraindít
Ao:= MaxOUjra; Ap:= OszMaxP(Ao);
End;
End;
If Ao*AP=0 Then Begin Veg:= True; Exit End;
//lehetőségvektor alapértékei
For I:= 1 To 5 Do For J:= 1 To 7 Do LVekt[I,J]:= NPar[J];
//hétvége paraméterek
For I:= 2 To 4 Do For J:= 1 To 6 Do Inc(LVekt[I,J], HVeg);
//periodicitás
Case PTFO[Ap].PTFe[Ao].OSza Of //5-re minden napra kell egy óra
1: Begin //1
Pm:= Random(5)+1; For I:= 1 To 5 Do For J:= 1 To 7 Do
If I=Pm Then Inc(LVekt[I,J], PerP);
End;
2: For I:= 1 To 7 Do //2
Begin Inc(LVekt[2,I], PerP); Inc(LVekt[4,I], PerP) End;
3: For I:= 1 To 7 Do //3
Begin
Inc(LVekt[1,I], PerP); Inc(LVekt[3,I], PerP); Inc(LVekt[5,I], PerP)
End;
4: Begin //4
Pm:= Random(5)+1; For I:= 1 To 5 Do For J:= 1 To 7 Do
If I<>Pm Then Inc(LVekt[I,J], PerP);
End;
End;
//szomszédossági paraméter
With PTFO[Ap] Do
For I:= 1 To 5 Do For J:= 2 To 5 Do
Begin
If POra[I,J-1]>0 Then Inc(LVekt[I,J],SzoP);
If POra[I,J+1]>0 Then Inc(LVekt[I,J],SzoP);
End;
//óraszámkiegyenlítés
For I:= 1 To 5 Do
Begin
Nm:= 0; For J:= 1 To 7 Do If OOra[Ao,I,J]>0 Then Inc(Nm);
For J:= 1 To 7 Do Inc(LVekt[I,J],(7-Nm)*OKie);
End;
//törlések a pedagógus és az osztály foglaltsága alapján
With PTFO[Ap] Do
For I:= 1 To 5 Do For J:= 1 To 7 Do If POra[I,J]>0 Then LVekt[I,J]:= 0;
For I:= 1 To 5 Do For J:= 1 To 7 Do If OOra[Ao,I,J]>0 Then LVekt[I,J]:= 0;
//kritikus időpont kiemelése
If (Faz=2) And (LVekt[D,H]<>0) Then LVekt[D,H]:= 30000;
//aktuális óraszámszor kiválasztjuk a legnagyobbat
For I:= 1 To 5 Do For J:= 1 To 2 Do Vt[I,J]:= 0; M:= 1;
For K:= 1 To PTFO[Ap].PTFe[Ao].OSza Do
Begin
V:= 1; W:= 1; Nm:= LVekt[V,W]; //V: Nap, W: óra, Nm: Max érték
For I:= 1 To 5 Do For J:= 1 To 7 Do If LVekt[I,J]>Nm Then
Begin Nm:= LVekt[I,J]; V:= I; W:= J End;
Vt[M,1]:= V; Vt[M,2]:= W; Inc(M); For L:= 1 To 7 Do LVekt[V,L]:= 0;
End;
For I:= 1 To 5 Do For J:= 1 To 7 Do LVekt[I,J]:= 0; M:= 1;
While (M<6) And (Vt[M,1]<>0) Do Begin LVekt[Vt[M,1],Vt[M,2]]:= 1; Inc(M) End;
//beírás az órarendekbe
PTFO[Ap].PTFe[Ao].Beir:= True; OTFe[Ao,Ap].Beir:= True;
For I:= 1 To 5 Do For J:= 1 To 7 Do If LVekt[I,J]>0 Then
Begin
PTFO[Ap].POra[I,J]:= Ao; OOra[Ao,I,J]:= Ap; Inc(OKSz[Ao]); Inc(PKSz[Ap]);
PRelBet(Ap); ORelBet(Ao);
End;
//hetedik óra miatti törlés
For I:= 1 To 5 Do If OOra[Ao,I,7]<>0 Then
Begin OTorlo(Ao); If Odd(Faz) Then Inc(PUjr[Ap]) Else Inc(OUjr[Ao]) End;
//magas osztály-kezelési szám miatti újrakezdés
If (OKSz[Ao]>2*OSz*OSz) And (PKSz[AP]>OSz*OSz) Then
Begin ReStart; Inc(OUjr[Ao]) End;
//magas pedagógus-kezelési szám miatti újrakezdés
If (PKSz[Ap]>2*OSz*OSz) And (OKSz[Ao]>OSz*OSz) Then
Begin ReStart; Inc(PUjr[Ap]) End;
End;
procedure TfmGOD.btFeltoltClick(Sender: TObject); //gépi betöltő indítója
Var I, J, K, S: Word;
begin
btOrarendTorloClick(Sender);
Lep:= 0; Faz:= 0; Lep:= 0; Res:= 0; Veg:= False;
btTFGeneral.Enabled:= False; btTFOR.Enabled:= False;
For I:= 1 To PSz Do PRelBet(I);
For I:= 1 To OSz Do ORelBet(I);
For I:= 1 To PSz Do PKSz[I]:= 0;
For I:= 1 To OSz Do OKSz[I]:= 0;
For I:= 1 To PSz Do PRelBet(I);
For I:= 1 To OSz Do ORelBet(I);
For I:= 1 To PSz Do PUjr[I]:= 0;
For I:= 1 To OSz Do OUjr[I]:= 0;
If TFPOROOR=1 Then btTFORClick(Sender);
Repeat
Begin
GepiBetolto; Inc(Lep); edLepes.Text:= IntToStr(Lep);
If Lep Mod 100=0 Then Repaint;
Case TFPOROOR Of
2: PedORKepre;
3: OszORKepre;
End;
End;
Until Veg Or (Lep>2000*OSz);
S:= 0; For K:= 1 To OSz Do For I:= 1 To 5 Do For J:= 1 To 7 Do
If OOra[K,I,J]<>0 Then Inc(S); With sgOR Do Cells[ColCount-1,0]:= IntToStr(S);
btTFGeneral.Enabled:= True;
btTFOR.Enabled:= True;
end;
procedure TfmGOD.btOrarendTorloClick(Sender: TObject);
begin
OraTorlo;
If TFPOROOR=1 Then btTFORClick(Sender);
Case TFPOROOR Of
2: PedORKepre;
3: OszORKepre;
End;
end;
procedure TfmGOD.sgORDrawCell(Sender: TObject; Col, Row: Integer;
Rect: TRect; State: TGridDrawState);
begin
With sgOR.Canvas.Brush Do
If gdSelected In State Then Color:= clYellow
Else If gdFixed In State Then Color:= clBtnFace Else
Begin
Case Col Of
7, 14, 21, 28, 35,36: Color:= clWindow;
1..6, 8..13, 15..20, 22..27, 29..34: Color:= clAqua;
End;
End;
sgOR.Canvas.TextRect(Rect,Rect.Left+1,Rect.Top+1,sgOR.Cells[Col,Row]);
If gdFocused In State Then sgOR.Canvas.DrawFocusRect(Rect);
end;
procedure TfmGOD.sgTFClick(Sender: TObject);
begin
With sgTF Do Begin ACol:= Col; ARow:= Row; RePaint End;
end;
procedure TfmGOD.sgTFDrawCell(Sender: TObject; Col, Row: Integer;
Rect: TRect; State: TGridDrawState);
begin
With sgTF.Canvas.Brush Do
Begin
If (gdFixed In State) And ((Col=ACol) Or (Row=ARow))
Then Color:= clYellow Else Color:= clBtnFace;
If gdSelected In State Then Color:= clLime;
If Not((gdSelected In State) Or (gdFixed In State)) Then
//ha nincs beírva a tétel, akkor a cella clAqua színű
If (Col<sgTF.ColCount-1) And (Pos(sgTF.Cells[Col,Row],'123456789')>0) And
Not OTFe[Col,Row].Beir Then Color:= clAqua Else Color:= clWindow;
End;
sgTF.Canvas.TextRect(Rect,Rect.Left+1,Rect.Top+1,sgTF.Cells[Col,Row]);
With sgTF Do If gdFocused In State Then Canvas.DrawFocusRect(Rect);
end;
end.