with Sem95; use Sem95;
with Ekran; use Ekran;
with Randompackage;
use Randompackage;
with Gnat.Io;-- cale with i use pozwalaja na korzystanie z zewnetrznych pakietow
use Gnat.Io;
with Winconsoleex;
use Winconsoleex;
-- przy zmiennych bedacych talbiacami, lub wsakznikami na nie (x,y) to indeksowanie po eleementach ,jak w c []
procedure Main is-- glowny program poniezej deklaracja zmiennych
Random_Sem: Semafor_Binarny(1);--semafor dostepu do generatora liczb pseudo losowych
procedure Getrandom( Wynik : out Integer ; Max : in Integer) is--procedura zwracaja liczbe preuso losowa w zakresie 1..max (lacznie)
begin --out przy parametrze oznacza ,ze zapis do tej zmiennej jest zapisywany na zewnatrz, czyli tak jakbysmy w c++ referencje dali
Pb(Random_Sem);--czekaj na semaforze
Wynik := Randomint(Max);
Vb(Random_Sem);--zwolnij semafor
end Getrandom;
Ekran : Screen;--nasz obiekt do rysowania po ekranie
task type Person ;-- deklaracja zapowiadajaca typu person
type Personptr is access Person;-- deklaracja wskaznika na person
type Personarray is array(Integer range <>) of Personptr;--deklaracja tablicy wskaznikow na person
type Personaptr is access Personarray;--deklaracja wsakznika na tablice wskanikow na person,
task type Elevator(Id :Integer) ;--tu podobnie jak wyzej, id to numer windy, bedzie to znmienna dostapna w obiekcie windy
type Elevatorptr is access Elevator;
type Elevatorarray is array(Integer range <>) of Elevatorptr;
type Elevatoraptr is access Elevatorarray;
type Integerarray is array( Integer range <>) of Integer;
type Integeraptr is access Integerarray;
type Integer2darray is array( Integer range <>,Integer range<>) of Integer;--tablica 2 wymiarowa
type Integer2daptr is access Integer2darray;
Queue_Sem : Semafor_Binarny(1);--semafor dostepu do kolejki
type Queue is--deklaracja typu kolejki jak struct w c
record
Czeka : Integer :=0;-- liczba osob dczekajacyh w kolejce
Zwolniono: Integer :=0;-- liczba osob ktore moga oposcic kolejke
Ypos,Xpos: Integer;--polozenie gdzie bedzie wystielana liczba osob czekajacych
end record;
type Queue2darray is array( Integer range <>,Integer range<>) of Queue;
type Queue2daptr is access Queue2darray;
Kolejkaup :Queue2daptr ;-- kolejki up down out jak w javie
Kolejkadown : Queue2daptr ;
Kolejkaout : Queue2daptr ;
procedure Qget(Qtype ,X,Y :Integer; Val : out Integer) is-- procedura zwraca liczbe osob czekajacch ,x - numer windy, y- numer pietra, qtype okresla ktora kolejka 0 - kolejka up, 1 down 2 out
begin--mialem napisane bardizej czytelne procedury,ale nei dzialaly do konca, wiec taki koszmarny kod jest, ogolnie to wszedzie jest sprawdzane jaki qtyle jest i odwoluywane jest do kolejkaup, down lub out
Pb(Queue_Sem);
if Qtype = 0 then
Val:= Kolejkaup(X,Y).Czeka;
else
if Qtype = 1 then
Val:= Kolejkadown(X,Y).Czeka;-- ogolnie tu nam tylko zwraca wartosc czekajacyh w k olejce
else
Val:= Kolejkaout(X,Y).Czeka;
end if;
end if;
Vb(Queue_Sem);
end Qget;
procedure Qrelease(Qtype ,X,Y :Integer) is-- zwalnia jedna osobe w kolejce
begin
Pb(Queue_Sem);
if Qtype = 0 then
Kolejkaup(X,Y).Zwolniono:= Kolejkaup(X,Y).Zwolniono +1;-- ustawia ze moze wyjsc jedna osoba wiecej
else
if Qtype = 1 then
Kolejkadown(X,Y).Zwolniono:= Kolejkadown(X,Y).Zwolniono +1;
else
Kolejkaout(X,Y).Zwolniono:= Kolejkaout(X,Y).Zwolniono +1;
end if;
end if;
Vb(Queue_Sem);
end Qrelease;
procedure Qreleaseall(Qtype ,X,Y :Integer) is-- zwalnia wszyskie osoby w kolejce, wtedy zwolniono = tyle co czeka
begin
Pb(Queue_Sem);
if Qtype = 0 then
Kolejkaup(X,Y).Zwolniono:= Kolejkaup(X,Y).Czeka ;
else
if Qtype = 1 then
Kolejkadown(X,Y).Zwolniono:= Kolejkadown(X,Y).Czeka ;
else
Kolejkaout(X,Y).Zwolniono:= Kolejkaout(X,Y).Czeka ;
end if;
end if;
Vb(Queue_Sem);
end Qreleaseall;
procedure Qenter(Qtype ,X,Y :Integer) is--wejscie do kolejki ,wyswietla zmiany na ekranie wartosci czeka
begin
Pb(Queue_Sem);
if Qtype = 0 then
Kolejkaup(X,Y).Czeka:= Kolejkaup(X,Y).Czeka+1 ;--zwieksza w kolejce liczbe czekajacych o 1
Ekran.Putati(Kolejkaup(X,Y).Ypos,Kolejkaup(X,Y).Xpos,Kolejkaup(X,Y).Czeka);
else
if Qtype = 1 then
Kolejkadown(X,Y).Czeka:= Kolejkadown(X,Y).Czeka+1 ;
Ekran.Putati(Kolejkadown(X,Y).Ypos,Kolejkadown(X,Y).Xpos,Kolejkadown(X,Y).Czeka);
else
Kolejkaout(X,Y).Czeka:= Kolejkaout(X,Y).Czeka +1;
Ekran.Putati(Kolejkaout(X,Y).Ypos,Kolejkaout(X,Y).Xpos,Kolejkaout(X,Y).Czeka);
end if;
end if;
-- Ekran.Putati(Q.Ypos,Q.Xpos,Q.Czeka);
Vb(Queue_Sem);
loop-- teraz w petli sprawdza czy moze wyjsc( liczba osob do zwolnienia jest >0 ) wtedy zminejsza liczbe ktora moze wyjsc o 1 i wychodzi z petli (exit)
Pb(Queue_Sem);
-- Ekran.putati(q.ypos,q.xpos+2,Q.zwolniono);
if Qtype = 0 then
if Kolejkaup(X,Y).Zwolniono >0 then
Kolejkaup(X,Y).Zwolniono := Kolejkaup(X,Y).Zwolniono -1;
Vb(Queue_Sem);
exit;
end if;
else
if Qtype = 1 then
if Kolejkadown(X,Y).Zwolniono >0 then
Kolejkadown(X,Y).Zwolniono := Kolejkadown(X,Y).Zwolniono -1;
Vb(Queue_Sem);
exit;
end if;
else
if Kolejkaout(X,Y).Zwolniono >0 then
Kolejkaout(X,Y).Zwolniono := Kolejkaout(X,Y).Zwolniono -1;
Vb(Queue_Sem);
exit;
end if;
end if;
end if;
Vb(Queue_Sem);
end loop;
Pb(Queue_Sem);
if Qtype = 0 then
Kolejkaup(X,Y).Czeka:= Kolejkaup(X,Y).Czeka-1 ;-- a tu teraz mniejsza liczbe osob czekajacych w kolejce
Ekran.Putati(Kolejkaup(X,Y).Ypos,Kolejkaup(X,Y).Xpos,Kolejkaup(X,Y).Czeka);
else
if Qtype = 1 then
Kolejkadown(X,Y).Czeka:= Kolejkadown(X,Y).Czeka-1 ;
Ekran.Putati(Kolejkadown(X,Y).Ypos,Kolejkadown(X,Y).Xpos,Kolejkadown(X,Y).Czeka);
else
Kolejkaout(X,Y).Czeka:= Kolejkaout(X,Y).Czeka-1 ;
Ekran.Putati(Kolejkaout(X,Y).Ypos,Kolejkaout(X,Y).Xpos,Kolejkaout(X,Y).Czeka);
end if;
end if;
Vb(Queue_Sem);
end Qenter;
Elevatorcount : Integer;--liczba wind
Personcount : Integer;-- liczba osob
Floorcount : Integer;--jak w javie :)
Elevatorcapacity : Integer:=3;
Canenter : Integer2daptr;--tablica okreslajace ile osob moze wejsc do windy na danym pietrze
Canmove : Integeraptr;--w javie robiliscmy signal do sygnalizowania windzie ze moze ruszyc,teraz canMove(numer_windy) = 1 to winda rusza
W_Windzie: Integeraptr;--liczba osob w danej windzie
-- Changeq_Sem : Semafor_Binarny(1);--semafor ,cos nei potrzebny :D
Canenter_Sem : Semafor_Binarny(1);-- semafor dostepu do zmiennych canEnter
Elevator_Sem :Semafor_Binarny(1);--semafor dostepu do danych windy
-- Test: Queue ;-- tylko do mych testow
------------------------------------------------------------------------
task body Person is--typ osoby definicja
X,Y : Integer;--aktualna pozycja
Oldx,Oldy : Integer;--stara pozycja przed ruchem, potrzebne przy rysowania znaku osoby, w starym miejscu jest czyszczone
Btemp : Boolean ;--zmiena tymczasowa uzywana,lub nie poxniej
Dir : Integer;--nie wszystko jest uzywane, niektore mienne tlkyo tymczasowo uzywane, nei mozna w adzie gdzie sie che deklarowac zmiennych jak w c
Movespeed : constant Duration:= 0.45;--czas czekania osoby po wukonaiu ruchu
Temp : Integer;
Celw: Integer;--numer windy do ktorej chemy wejsc
Celp: Integer;--numer pietra na tkore chem wejsc
-- Pokoj : Integer;
Pietro: Integer;--aktualne peitro na jakim jestesmy
Temp2 : Integer;
Reached: Boolean;--czy doszlismy do celu, jak w javie
procedure Hide is-- schowaj znak postaci, rysuje tam spacje, pamietaj ,ze uklad wpoldzenych na ekranie jest od 1 nie od 0 jak w javie oraz pierwszy parametr to os y,a potem x
begin
Ekran.Putat(Y,X," ");
end Hide;
procedure Show is--odwrotnosc hide
begin
Ekran.Putat(Y,X,"p");
end Show;
procedure Move( Yr, Xr: Integer) is--move jak w javie
begin
Oldx:= X;
Oldy:= Y;
X:= X + Xr;
Y:= Y + Yr;
Ekran.Drawat(Oldy,Oldx,Y,X,'p');--na starej pozycji czysci pole (stawia spacje) na nowej stawia p
delay Movespeed;
end Move;
procedure Movetox( Xto : Integer)is-- jak w javie
Di : Integer:=-1;
begin
if Xto > X then
Di:=1;
end if;
loop
if X = Xto then
exit;
end if;
Move(0,Di);
end loop;
end Movetox;
procedure Movetoy( Yto : Integer)is-- jak w javie
Di : Integer:=-1;
begin
if Yto > Y then
Di:=1;
end if;
loop
if Y = Yto then
exit;
end if;
Move(Di,0);
end loop;
end Movetoy;
begin--tu sie zaczyna kod watku osoby
Getrandom(Pietro,Floorcount);--wylosuj pietro na ktorym zaczynamy
X:=3;
Y:=Pietro*2+1;--ustaw pozycje poczatkowa
Show;
Reached:=True;--ustawiane na true, by od razu wylosowac nowe miejsce
loop
<<petla_begin>>-- to jest etykieta, goto pela_begin; to skok bezwarunkowy w to miejsce
if Reached then-- gdy doszlismy do celu
Reached :=False;
celp:=pietro;
while celp = pietro loop-- losuj pietro dopuki wypadnie jakies inne niz na ktorym jestesmy
Getrandom(Celp,Floorcount);
end loop;
end if;
Getrandom(Celw,Elevatorcount);--wylosuj docelowa winde
getrandom(temp,100);-- niestety nei wiem jak czas odmierzac w adzie, wiec ludziki losowa korzystaja ze schodow
if temp <15 then
Movetox(2);--idz w lewo na schody
if celp > pietro then--w zaleznosci czy pietro docelowe jest wyzej czy nizej
move(1,0);--idz w dol
move(1,0);
pietro := pietro+1;--jestesmy na nizszym pietrze
else
move(-1,0);--idz w gore
move(-1,0);
pietro:= pietro-1;
end if;
move(0,1);
move(0,1);--sun sie troche w prawo
if pietro=celp then--jak schodami doszlismy do celu to
reached:=true;
end if;
goto petla_begin;--skaczemy na poczatek petli, by znowu sobie cel obrac jezeli doszlismy
end if;
Movetox(Celw*2+2);--podejdz pod winde
<<nospace>>
--if Canenter(Celw,Pietro)= 0 then
if Celp > Pietro then--czekaj w odpowiedniej kolejce up lub down w zaleznosci od celu
Qenter(1,Celw,Pietro);
else
Qenter(0,Celw,Pietro);
end if;
--end if;
Move(0,1);
Hide;
Pb(Canenter_Sem);
Canenter(Celw,Pietro):= Canenter(Celw,Pietro) -1;--zmniejsz liczbe osob mogacych wejsc do windy
-- ekran.putati(1+ (pietro-1) *4+1,Elevatorcount*2+4+ celw*3+1,canenter(celw,pietro));
if Canenter(Celw,Pietro) < 0 then--jak zabraklo miejsca to sie wycofaj i powroc do kolejki
Vb(Canenter_Sem);
move(-1,0);
goto nospace;
end if;
if Canenter(Celw,Pietro) = 0 then-- jak juz ostatnia osoba weszla to
Pb(Elevator_Sem);
Canmove(Celw) := 1;--zasygnaluzuj windzie ze moze ruszac
Vb(Elevator_Sem);
end if;
Pb(Elevator_Sem);
W_Windzie(Celw) := W_Windzie(Celw) +1;--zwiekszamy informacje ile jest w windzie
Vb(Elevator_Sem);
Vb(Canenter_Sem);
Qenter(2,Celw,Celp);--czekamy w kolejce wyjscia na naszym pietrze docelowym
Pb(Elevator_Sem);
W_Windzie(Celw) := W_Windzie(Celw) -1;--zmniejszamy liczbe osob w windzie
Vb(Elevator_Sem);
Reached:=True;--jestesmy u celu
Pietro:=Celp;
Y:=Pietro*2+1;
Show;
Move(0,-1);--powrot na poczatek petli
end loop;
end Person;
------------------------------------------------------------------------
task body Elevator is--zadanie windy
Y : Integer := 2;--pozycje
X: Integer;
Czeka : Integer;--ile osob czeka w kolejce
Pietro : Integer:= 1;--pietro na ktorym jest winda
Dir : Integer :=1;--kierunek ruchu windy
Temp,Temp2,Temp3: Integer;
Elevatorspeed : constant Duration :=1.5;
begin
X:=Id*2+3;--ustaw pozycje poczatkowa
Ekran.Putat(Y,Id*2+3,"w");
loop
if Pietro= 1 then--jak doszlismy na krance to trzeba zmienic kierunek ruchu
Dir:= 1;
end if;
if Pietro= Floorcount then
Dir :=-1;
end if;
if Dir = -1 then--w zaleznosci od kierunku ruchu pobieramy liczbe osob czekajacyh w danej kolejce
Qget(0,Id,Pietro,Czeka);
else
Qget(1,Id,Pietro,Czeka);
end if;
Qreleaseall(2,Id,Pietro);--zwalniamy wszystkich czekajacych na wyjscie na tym pietrze
if Czeka >0 and w_windzie(id) < elevatorCapacity then--jezeli ktos czeka na wejsci i jest jeszcze iejsce
Pb(Elevator_Sem);
Canmove(Id) := 0;--ustaw ze winda stoi w miejscu
-- Ekran.Putati(id,42,canMove(id));
Vb(Elevator_Sem);
Pb(Elevator_Sem);
Temp2 := W_Windzie(Id);--pobierz i zapisz w tymczasowiej zmiennej ile jest w windzie osob
Vb(Elevator_Sem);
Pb(Canenter_Sem);
Canenter(Id,Pietro):= Elevatorcapacity - Temp2;
if Canenter(Id,Pietro) > Czeka then--wyznacz ile moze wejsc ,jak w javie
Canenter(Id,Pietro) := Czeka;
end if;
-- ekran.putati(1+ (pietro-1) *4+1,Elevatorcount*2+4+ id*3+1,canenter(id,pietro));
Temp2:= Canenter(Id,Pietro);
Vb(Canenter_Sem);
if Temp2 >0 then
for I in 1..Temp2 loop--zwolnij tyle osob ile moze wejsc
if Dir = -1 then
Qrelease(0,Id,Pietro);
else
Qrelease(1,Id,Pietro);
end if;
end loop;
end if;
loop--- czekaj az mozna ruszyc
Pb(Elevator_Sem);
if Canmove(Id) = 1 then
Vb(Elevator_Sem);
exit;
end if;
Vb(Elevator_Sem);
end loop;
end if;
Ekran.Putati(id,Elevatorcount*2+4+ elevatorCount*3+3,w_windzie(id));
-- Ekran.Putati(id,42,canMove(id));
Ekran.Putat(Y,X," ");
Y:= Y + Dir*2;--przswua i rysuje znaczek windy
Pietro:= Pietro+Dir;
Ekran.Putat(Y,X,"w");
delay Elevatorspeed;
getrandom(temp,100);--losowa wartosc czy wystawpi awaria
if temp < 5 then
Ekran.Putat(Y,X,"a");
delay elevatorSpeed*3;--wtedy czekamy dluzej
Ekran.Putat(Y,X,"w");
end if;
-- qReleaseall(kolejkaUp(id,pietro));
-- qReleaseall(kolejkaDown(id,pietro));
end loop;
end Elevator;
------------------------------------------------------------------------
Osoba : Personaptr;--tablica taskow person
Winda:Elevatoraptr;--tablica taskow wind
------------------------------------------------------------------------------- MAIN -------------------------------------------------
begin
loop--w petlach pobierz dane liczby, pobieraj poki <=0
Gnat.Io.Put("Podaj liczbe osob: ");
Get(Personcount);
if Personcount >0 then exit ; end if;
end loop;
loop
Gnat.Io.Put("Podaj liczbe pieter: ");
Get(floorcount);
if floorcount >0 then exit ; end if;
end loop;
loop
Gnat.Io.Put("Podaj liczbe wind: ");
Get(elevatorcount);
if elevatorcount >0 then exit ; end if;
end loop;
clearscreen;--czyscimy ekran
-- Personcount:=36;
-- Floorcount:=6;
-- Elevatorcount:=5;
for Y in 1..Floorcount loop--teraz rysowanie ramek jest
Ekran.Putat(Y*2,3,"#");
Ekran.Putat(Y*2,4,"#");
for X in 1..Elevatorcount loop
Ekran.Putat(Y*2,X*2+4,"#");
end loop;
end loop;
for Y in 1..Floorcount*2 loop
Ekran.Putat(Y+1,1,"#");
if Y mod 2 = 0 then
Ekran.Putat(Y+1,Elevatorcount*2+4,"#");
end if;
end loop;
for X in 1..Elevatorcount*2+4 loop
Ekran.Putat(Floorcount*2+2,X,"#");
Ekran.Putat(1,X,"#");
end loop;
Kolejkaup := new Queue2darray(1..Elevatorcount,1..Floorcount);--tworzenie naszych tablic, tablice sa indeksowane od 1 do rozmiar wlacznie
Kolejkadown := new Queue2darray(1..Elevatorcount,1..Floorcount);
Kolejkaout := new Queue2darray(1..Elevatorcount,1..Floorcount);
Canenter := new Integer2darray(1..Elevatorcount,1..Floorcount);
W_Windzie:= new Integerarray(1..Elevatorcount);
Canmove:= new Integerarray(1..Elevatorcount);
for X in 1..Elevatorcount loop --ustawianie wartosci poczatkowych
W_Windzie(X):=0;
Canmove(X):=0;
end loop;
for X in 1..Elevatorcount loop
for Y in 1..Floorcount loop--ustawlenie pozycji liczb wyswieltanych na ekranie
Kolejkaup(X,Y).Ypos := 1+ (Y-1) *4;
Kolejkaup(X,Y).Xpos :=Elevatorcount*2+4+ X*3;
Kolejkadown(X,Y).Ypos := 1+ (Y-1) *4+1;
Kolejkadown(X,Y).Xpos :=Elevatorcount*2+4+ X*3;
Kolejkaout(X,Y).Ypos := 1+ (Y-1) *4+2;
Kolejkaout(X,Y).Xpos :=Elevatorcount*2+4+ X*3;
Ekran.Putati(Kolejkaup(X,Y).Ypos,Kolejkaup(X,Y).Xpos,0);
Ekran.Putati(Kolejkadown(X,Y).Ypos,Kolejkadown(X,Y).Xpos,0);
Ekran.Putati(Kolejkaout(X,Y).Ypos,Kolejkaout(X,Y).Xpos,0);
-- Kolejkaup(X,Y):= 0;
-- Kolejkadown(X,Y):= 0;
-- Kolejkaout(X,Y):= 0;
Canenter(X,Y):= 0;
end loop;
end loop;
Winda := new Elevatorarray(1..Elevatorcount); --tworzenie wind
for I in 1..Elevatorcount loop
Winda(I) := new Elevator(I);
end loop;
Osoba := new Personarray(1..Personcount); --tworzenie osob
for I in 1..Personcount loop
Osoba(I) := new Person;
end loop;
------------------------------------------------------------------------
-- Ekran.Putat(10,10,"wejscie");
-- qenter(test);
-- Ekran.Putat(10,10,"wyjscie");
end Main;