Added Monza track. Solved bugs in Booking
[toni-reis.git] / src / simulator-track.adb
blob75a2d3b46735e6ad2158f0fc9418c53e49d420e5
1 with System;
2 with Ada.Text_IO; use Ada.Text_IO;
3 with Simulator.Controller;
4 with Simulator.Car;
5 with Simulator;
6 with Ada.Calendar;
7 use Ada.Calendar;
8 --with Ada.Real_Time;
9 --use Ada.Real_Time;
10 --with Ada.Numerics.Generic_Elementary_Functions;
12 use Simulator.Car;
13 with Input_Sources.File; use Input_Sources.File;
14 with Sax.Readers; use Sax.Readers;
15 with DOM.Readers; use DOM.Readers;
16 with DOM.Core; use DOM.Core;
17 with DOM.Core.Documents; use DOM.Core.Documents;
18 with DOM.Core.Nodes; use DOM.Core.Nodes;
19 with DOM.Core.Attrs; use DOM.Core.Attrs;
20 with Ada.Text_IO; use Ada.Text_IO;
21 with Ada.Numerics;
22 with Ada.Numerics.Generic_Elementary_Functions;
24 package body Simulator.Track is
25 package Float_Functions is new Ada.Numerics.Generic_Elementary_Functions (
26 Float);
28 --STRUTTURE DATI
29 MaxMultiplicity : Positive := 3;
30 n_registered : CarId_T :=1;
31 BoxSpeedLimit : Integer := 80;
32 PitStopSector : Positive;
34 type PitStopRequest_T is array (CarId_T) of Boolean ;
36 type PitStopRecord_T is record
37 CarFuel : CarFuel_T;
38 Tires : Tires_T;
39 end record;
40 type PitStopData_T is array (CarId_T) of PitStopRecord_T;
41 PitStopData : PitStopData_T;
42 PitStopRequest: PitStopRequest_T;
43 type RetireRequest_T is array (CarId_T) of Boolean ;
44 RetireRequest: PitStopRequest_T;
45 --TODO confornto tra indici di prestazioni
46 --Semantica: ritorna 1 se il primo argomento è maggiore del secondo, 0 altrimenti
47 function GreaterThan(id1: Natural; id2: Natural) return Boolean is
48 begin
49 if (id2 = 0) then
50 return True;
51 end if;
52 if (id1 = 0) then
53 return False;
54 end if;
55 if ( id1 > id2) then
56 return True;
57 else return False;
58 end if;
59 end GreaterThan;
62 procedure CalculateDriveTime(my_properties : CarProperties_T; my_length: Natural; my_level : Integer; isbox : Boolean; my_fuel: out Float; my_consumption : out Float; my_speed : in out Float; finish : out Time) is
63 start : Time;
64 Vmax : Float := 100.0;
65 difficulty : Integer := my_level;
66 -- dati per calcolo velocità e accelerazione
67 a : Float := 9.25;
68 Smax : Float:= Float(my_length);
69 S : Float;
70 V0 : Float := my_speed;
71 Vfinal : Float;
72 t : Float := 0.0;
73 begin
74 if (difficulty < 0) then
75 difficulty := - difficulty;
76 end if;
77 start := Clock;
78 finish := start;
79 a:= a - a*0.8* ( Float(my_properties.TiresConsumption ) * 0.35 + 0.5*( (Float(difficulty) / Float(MaxLevel))) + 0.15 * ( Float(my_properties.CarFuel)/ Float(MaxFuel)));
80 Vmax := Vmax * Float( Float(1 + MaxLevel - difficulty)/ Float(1 + MaxLevel));
81 Vmax := Vmax - ( Vmax * (10.0 * Float( my_properties.TiresConsumption) )) / 100.0;
82 Put_Line("Vmax ="& Float(Vmax* 3.6)'Img&"km/h");
83 Put_Line("Difficoltà della curva "& difficulty'Img);
84 Put_Line("a ="& a'Img&"m/s");
85 --TODO calcolare la durata di percorrenza in base ai parametri di auto e a quelli di sector e lane
86 if (isbox) then
87 Vmax := Float(BoxSpeedLimit);
88 end if;
89 if (V0 < Vmax) then
91 -- Parte in moto uniformemente accelerato
92 S := ((Vmax*Vmax) - (V0*V0))/(2.0*a);
93 -- Put_Line("Spazio di accelerazione necessario per raggiungere Vmax ="&S'Img);
95 if (S <= Smax) then
96 -- pezzo in moto uniformemente accelerato
97 -- Put_Line("La velocità che raggiungo è maggiore di quella consentita");
98 Vfinal := Vmax;
99 t := (Vmax - V0)/a;
100 -- pezzo in moto rettilineo uniforme
101 t := t + ((Smax - S) / Vmax);
103 else
104 -- percorro tutto il tratto accelerando
105 Vfinal := Float_Functions.Sqrt((V0*V0) + (2.0*a*Smax));
106 t := (Vfinal - V0) / a;
107 end if;
108 else
109 --arrivo a velocità troppo alta. Freno in maniera istantanea e percorro il tratto
110 --a velocità costante
111 t := Smax / Vmax;
112 Vfinal := Vmax;
113 end if;
114 -- Vfinal è la velocità di uscita dal tratto, t il tempo impiegato
115 if (isbox) then
116 if ( (Float( PitStopData(my_properties.CarId).CarFuel ) / 12.0) < 5.5) then
117 t := t + 5.5;
118 else
119 t := t + Float(Float(PitStopData(my_properties.CarId).CarFuel) / 12.0);
120 end if;
121 end if;
122 -- Put_Line("Vfinal ="& Float(Vfinal* 3.6)'Img&" km/h");
123 Put_Line("Durata tratto "&Duration(t)'Img);
124 my_speed := Vfinal;
125 my_consumption := 0.0;
126 my_fuel := 0.0;
127 finish := start + Duration(t);
128 -- Put_Line("Calcolo Tempo di risveglio previsto "& Seconds(finish)'Img);
129 end CalculateDriveTime;
131 --TODO driveLane aggiorna i carproperties in base al lane percorso
133 protected type Semaphore is
134 entry Wait; -- P
135 procedure Signal(start : Boolean); -- V
136 private
137 Started : Boolean := false;
138 end Semaphore;
140 protected body Semaphore is
141 entry Wait when Started = True is
142 begin
143 Put_Line("Auto partita");
144 end Wait;-- P
145 procedure Signal(start : Boolean) is
146 begin
147 Started := start;
148 end Signal;
150 end Semaphore;
153 protected type Lane_T(my_length: Natural; my_level : Integer; my_isbox : Boolean) is
154 entry Demand( my_properties : CarProperties_T; my_time : out Time; my_fuel: out Float; my_consumption : out Float; my_speed : in out Float);
155 private
156 IsBox : Boolean := my_isbox;
157 exit_time : Time := Clock;
158 Level : Integer := my_level;
159 Length : Natural := my_length;
160 max : Natural;
161 maxId : CarId_T;
162 tot : Integer :=0;
163 entered : Integer :=0;
164 open : Boolean := False;
165 end Lane_T;
167 type Corsie_Array_T is array (Positive range <>, Positive range<>) of access Lane_T;
168 Corsie : access Corsie_Array_T;
169 type PitLane_T is array(CarId_T) of Semaphore;
170 PitLane: access PitLane_T := new PitLane_T;
172 type LaneCounter_T is array (Positive range<>) of Natural;
173 type CarLane_T is array (CarId_T) of Positive;
175 type ExitRecord is record
176 CarId : CarId_T;
177 CarTime : Time := Clock;
178 Arrived : Boolean := False;
179 end record;
180 type ExitArray_T is array (Integer range <>) of ExitRecord;
182 protected type Sector(my_sector_id: Natural; my_multiplicity : Natural; my_length: Natural; my_level : Integer; my_isbox: Boolean ) is
183 --sceglie la corsia da percorrere in base alla strategia, calcola il tempo di percorrenza e effettua la requeue su di essa
184 entry Enter( my_properties : CarProperties_T; my_time : out Time; my_fuel: out Float; my_consumption : out Float; my_speed : in out Float);
185 entry Release(my_properties : CarProperties_T);
186 entry BookExit(my_properties: CarProperties_T; my_time : Time);
189 private
190 entry ExitLane(my_properties : CarProperties_T);
191 ExitArray : ExitArray_T(1 .. 5*MaxMultiplicity);
192 ExitCount : Natural := 0;
193 LaneCounter : LaneCounter_T(1 .. my_multiplicity) ;
194 CarLane : CarLane_T;
195 Free : Natural := 5 * my_multiplicity;
196 MaxCars : Natural := 5 * my_multiplicity;
198 Sector_Id: Natural :=my_sector_id;
199 Length : Natural := my_length;
200 Multiplicity: Natural := my_multiplicity;
201 Level : Integer := my_level;
202 IsBox : Boolean := my_isbox;
203 -- per la exit
204 Changed : Boolean := False;
205 max : Natural;
206 tot : Integer :=0;
207 entered : Integer :=0;
208 open : Boolean := False;
209 end Sector;
211 protected body Sector is
212 entry BookExit(my_properties: CarProperties_T; my_time : Time) when True is
213 --Temp : ExitRecord;
214 --temp : Integer;
215 begin
216 if (ExitCount <= 0) then
217 ExitArray(1) := (my_properties.CarId, my_time, False);
218 Put_Line("DEBUG : Book: accodo Auto "&my_properties.CarId'Img&" in posizione 1 perchè la lista uscite è vuota");
219 ExitCount := ExitCount + 1;
220 else
221 for Index in reverse 0 .. ExitCount loop
222 -- Put_Line("Debug: Book: loop esterno indice "& Index'Img);
223 if(Index = 0 ) then
224 Put_Line("DEBUG : Book: Inerisco l'auto in posizione 1");
225 for I in reverse (Index + 1) .. ExitCount loop
226 -- Put_Line("Debug: Book: loop interno");
227 ExitArray(I+1) := ExitArray(I);
228 end loop;
229 ExitArray(Index + 1) := (my_properties.CarId, my_time, False);
230 -- temp := Index + 1;
231 -- Put_Line("DEBUG : Book: accodo Auto "&my_properties.CarId'Img&" in posizione "&temp'Img);
232 ExitCount := ExitCount + 1;
233 exit;
234 else if(ExitArray(Index).CarTime < my_time) then
235 Put_Line("DEBUG : Book: Inerisco l'auto in posizione "&Integer(Index+1)'Img);
236 -- Put_Line("Debug: Book: dentro if");
237 for I in reverse (Index + 1) .. ExitCount loop
238 -- Put_Line("Debug: Book: loop interno");
239 ExitArray(I+1) := ExitArray(I);
240 end loop;
241 ExitArray(Index + 1) := (my_properties.CarId, my_time, False);
242 -- temp := Index + 1;
243 -- Put_Line("DEBUG : Book: accodo Auto "&my_properties.CarId'Img&" in posizione "&temp'Img);
244 ExitCount := ExitCount + 1;
245 exit;
246 end if;
247 end if;
248 end loop;
249 end if;
250 -- Put_Line("Non è stato preso ne l'if ne l'else");
251 end BookExit;
253 entry Enter( my_properties : CarProperties_T; my_time : out Time; my_fuel: out Float; my_consumption : out Float; my_speed : in out Float) when Free > 0 is
254 n_lane : Natural;
255 begin
256 -- Put_Line("DEBUG: entrato nella procedura Enter di Sector");
257 --Prima auto a entrare nel tracciato azzera i campi dato
258 if (MaxCars = Free) then
259 for Index in 1 .. Multiplicity loop
260 LaneCounter(Index) := 0;
261 end loop;
262 end if;
263 -- decido la corsia da percorrere. Trovo quella meno trafficata
265 n_lane := 1;
266 for Index in 1.. Multiplicity loop
267 if (LaneCounter(Index) < LaneCounter(n_lane)) then
268 n_lane := Index;
269 end if;
270 -- n_lane è l'id del lane meno trafficato
271 end loop;
272 LaneCounter(n_lane) := LaneCounter(n_lane) + 1;
273 Free := Free - 1;
274 CarLane(my_properties.CarId) := n_lane;
276 Put_Line("DEBUG: requeue su Corsie("&Sector_Id'Img&","&n_lane'Img&")");
277 requeue Corsie(Sector_Id,n_lane).Demand with abort;
278 --Corsie(sector_number,n_lane).Demand(my_id);
279 end Enter;
281 entry Release(my_properties : CarProperties_T) when Free < MaxCars is
282 a : Integer := 0;
283 begin
284 Put_Line("Debug: Relase invocata");
285 if (ExitCount = 0) then
286 Put_Line("Bug del software: invocata Relase senza aver invocato BookExit");
287 end if;
288 if (ExitArray(1).CarId = my_properties.CarId) then
289 Put_Line("DEBUG: relase : l'auto è in prima posizione : sposto le altre");
290 for Index in 2 .. ExitCount loop
291 Put_Line("DEBUG: relase : sposto l'auto che era in posizione "& Index'Img);
292 ExitArray(Index -1) := ExitArray(Index);
293 end loop;
294 LaneCounter(CarLane(my_properties.CarId)) := LaneCounter(CarLane(my_properties.CarId)) -1;
295 Free := Free + 1;
296 ExitCount := ExitCount -1;
297 if (ExitCount > 0) then
298 if(ExitArray(1).Arrived = True) then
299 Changed := True;
300 else
301 Changed := False;
302 end if;
303 end if;
304 Put_Line("Debug: Relase terminata");
305 else
306 for Index in 1 .. ExitCount loop
307 if (ExitArray(Index).CarId = my_properties.CarId) then
308 ExitArray(Index).Arrived := True;
309 Put_Line("DEBUG: Auto "&my_properties.CarId'Img&" ha superato dove non doveva..accodo in ExitLane");
310 Changed := False;
311 requeue ExitLane;
312 end if;
313 end loop;
315 end if;
316 end Release;
318 entry ExitLane(my_properties : CarProperties_T) when Changed = True is
319 begin
321 if (ExitArray(1).CarId = my_properties.CarId) then
322 -- Put_Line("DEBUG: Auto "&my_properties.CarId'Img&" in uscita da ExitLane");
323 for Index in 2 .. ExitCount loop
324 ExitArray(Index -1) := ExitArray(Index);
325 end loop;
326 LaneCounter(CarLane(my_properties.CarId)) := LaneCounter(CarLane(my_properties.CarId)) -1;
327 Free := Free + 1;
328 ExitCount := ExitCount -1;
329 if (ExitArray(1).Arrived = True) then
330 Changed := True;
331 else
332 Changed := False;
333 end if;
334 else
335 requeue ExitLane;
336 end if;
337 end ExitLane;
339 end Sector;
341 protected body Lane_T is
342 entry Demand(my_properties: CarProperties_T; my_time : out Time; my_fuel: out Float; my_consumption : out Float; my_speed : in out Float) when True is
344 begin
345 CalculateDriveTime(my_properties , my_length ,my_level ,IsBox ,my_fuel, my_consumption,my_speed, my_time );
346 if (my_time > exit_time) then
347 exit_time := my_time;
348 elsif (my_time < exit_time) then
349 my_time := exit_time + 0.001;
350 end if;
352 end Demand;
356 end Lane_T;
357 ----------------STRUTTURE DATI DI TRACK
358 --codice di test. Operazioni svolte dal lettore del file di configurazione xml
360 type Sector_Array_T is array (Positive range <>) of access Sector;
361 Sectors : access Sector_Array_T;
362 BoxSector : access Sector;
365 -- inserisce la macchina nel circuito, fornisce in ingresso le
366 -- caratteristiche iniziali dell'auto. Quando questo metodo termina vuol
367 -- dire che la macchina ha finito la gara (conclusa o per ritiro)
369 procedure PutOnPitLane(Self : Simulator.Partition_ID; my_CarProperties : CarProperties_T) is
370 Temp :CarWeight_T;
371 my_time : Time;
372 my_fuel : Float;
373 my_consumption : Float;
374 CarProperties : CarProperties_T := my_CarProperties;
375 Speed : Float := 0.0;
376 begin
378 Put_Line("Car " & CarId_T'Image(CarProperties.CarId) & " registered on track");
379 Temp := CarProperties.CarWeight +100;
381 --Auto si mette nelle linee di partenza. Quando tornerà da questa ciamata, la corsa per l'auto sarà iniziata
382 PitLane(CarProperties.CarId).Wait;
383 --inizio la corsa iterando tra i vari Sector
384 for i in 1 .. 4 loop
386 for Index in 1 .. Sectors'Length loop
388 if (RetireRequest(CarProperties.CarId) = True) then
389 exit;
390 end if;
391 if (Index = PitStopSector and PitStopRequest(CarProperties.CarId) = True) then
392 -- TODO effettua il pti stop
393 BoxSector.Enter(CarProperties, my_time,my_fuel, my_consumption, Speed);
394 Put_Line("Auto ferma ai box fino al tempo"&CarProperties.CarId'Img&" :"& Seconds(my_time)'Img);
395 BoxSector.BookExit(CarProperties, my_time);
396 CarProperties.CarFuel := CarProperties.CarFuel - 50;
397 Simulator.Controller.GetCar(Self).UpdateProperties(CarId => CarProperties.CarId,
398 Tires => CarProperties.Tires,
399 TiresConsumption => CarProperties.TiresConsumption,
400 CarWeight => CarProperties.CarWeight,
401 CarFuel => CarProperties.CarFuel,
402 CarPerformance => CarProperties.CarPerformance,
403 Speed => Speed);
404 -- Put_Line("!!! se stampa prima questo dei parametri auto aggiornati la chiamata è stata asincrona!!!");
405 delay until my_time;
406 Sectors(Index).Release(CarProperties);
407 Put_Line("Auto "&CarProperties.CarId'Img&" Entra nella corsia dei Box");
408 null;
409 else
410 Sectors(Index).Enter(CarProperties, my_time, my_fuel, my_consumption, Speed);
411 -- Put_Line("Velocità dell'auto "&CarProperties.CarId'Img&" è di "&Float(Speed * 3.6)'Img&" Km/h");
412 Put_Line("Tempo di risveglio previsto per l'auto"&CarProperties.CarId'Img&" :"& Seconds(my_time)'Img);
413 Sectors(Index).BookExit(CarProperties, my_time);
414 -- CarProperties.CarFuel := CarProperties.CarFuel - 50;
415 Simulator.Controller.GetCar(Self).UpdateProperties(CarId => CarProperties.CarId,
416 Tires => CarProperties.Tires,
417 TiresConsumption => CarProperties.TiresConsumption,
418 CarWeight => CarProperties.CarWeight,
419 CarFuel => CarProperties.CarFuel,
420 CarPerformance => CarProperties.CarPerformance,
421 Speed => Speed);
422 -- Put_Line("!!! se stampa prima questo dei parametri auto aggiornati la chiamata è stata asincrona!!!");
423 delay until my_time;
424 Sectors(Index).Release(CarProperties);
425 end if;
426 end loop;
428 end loop;
430 Put_Line("DEBUG: PutOnPitLane è ritornato dalla simulazione.. Auto "&CarProperties.CarId'Img&" ha terminato la corsa");
433 end PutOnPitLane;
436 procedure StartRace(n_cars : CarId_T) is
437 begin
438 -- inizializzo PitStopRequest.
439 for Index in 1 .. n_cars loop
440 PitStopRequest(Index) := False;
441 end loop;
443 -- sveglio le auto in attesa su PitLane
444 Put_Line("3...2...1... Go !!!");
445 for Index in 1 .. n_cars loop
446 PitLane(Index).Signal(True);
447 -- delay 0.001;
448 end loop;
450 Put_Line("DEBUG: Tutte le auto sono partite");
451 delay 10.0;
452 end StartRace;
454 -- Comunica di ritirare l'auto con id = CarId dal circuito
455 procedure Kill(CarId: in CarId_T) is
456 begin
457 Put_Line("Killing car "&CarId'Img&" ...");
458 RetireRequest(CarId) := True;
459 Simulator.Controller.GetRace.Kill(CarId);
460 end Kill;
462 -- metodo di richiesta fermata ai box
463 -- l'invocazione di questo metodo porta il circuito a far fare una sosta
464 -- all'auto "CarId" appena possibile.
465 procedure CallForPitStop(CarId: in CarId_T; CarFuel :CarFuel_T; Tires :Tires_T) is
466 begin
467 PitStopRequest(CarId) := True;
468 PitStopData(CarId) := (CarFuel, Tires);
469 Put_Line("Car "&CarId_T'Image(CarId)&" requires Pit Stop.");
470 end CallForPitStop;
473 procedure ReadTrackConf(confFile : String) is
474 Input : File_Input;
475 Reader : Tree_Reader;
476 Doc : Document;
477 List : Node_List;
478 TrackList : Node_List;
479 BoxList : Node_List;
480 Settore : Node;
481 A : Attr;
482 -- C : Node;
483 Livello : Integer;
484 Lunghezza : Natural;
485 Multiplicity : Positive;
486 begin
487 Put_Line("DEBUG: Leggo configurazione da file xml");
488 Set_Public_Id (Input, "input");
489 --da passare come parametro il percorso
490 Open (confFile, Input);
491 Set_Feature (Reader, Validation_Feature, False);
492 Set_Feature (Reader, Namespace_Feature, False);
493 Parse (Reader, Input);
494 Close (Input);
496 Doc := Get_Tree (Reader);
497 TrackList := Get_Elements_By_Tag_Name(Doc, "track");
498 if (Length(TrackList) /= 1) then
499 Put_Line("Errore nel file XML. Ogni file deve contenere esattamente 1 track");
501 end if;
502 List := Get_Elements_By_Tag_Name(Doc, "sector");
503 Put_Line("DEBUG TRACK:ci sono "&Length(List)'Img&" settori");
504 Sectors := new Sector_Array_T(1 .. Length(List));
505 Corsie:= new Corsie_Array_T (1 .. Length(List) + 1, 1 .. 4);
506 for Index in 1 .. Length (List) loop
507 Settore := Item (List, Index - 1);
509 A := Get_Named_Item (Attributes (Settore), "level");
510 Livello := Integer'Value (Node_Value(A)) ;
511 A := Get_Named_Item (Attributes (Settore), "length");
512 Lunghezza := Natural'Value (Node_Value(A));
513 A := Get_Named_Item (Attributes (Settore), "multiplicity");
514 Multiplicity := Positive'Value (Node_Value(A));
515 --Creo il settore e i lane
516 Sectors(Index) := new Sector(Index,Multiplicity,Lunghezza,Livello,False);
517 for i in 1 .. Multiplicity loop
518 Corsie(Index, i) := new Lane_T(Lunghezza,Livello,False);
519 end loop;
520 Put_Line ("creato settore "& Index'Img);
522 BoxList := Child_Nodes( Settore);
523 if (Length(BoxList) /= 0) then
524 Put_Line("Inizializzo box");
525 PitStopSector := Index;
526 A := Get_Named_Item (Attributes (Item(BoxList,1)), "length");
527 Lunghezza := Natural'Value (Node_Value(A));
528 BoxSector := new Sector(Length( List) + 1, 1, Lunghezza, Livello, True);
529 Corsie(Length( List ) + 1, 1) := new Lane_T(Lunghezza,Livello,True);
530 Put_Line("Trovati box nel sttore "& PitStopSector'Img&" di lunghezza "&Lunghezza'Img);
531 end if;
533 end loop;
535 Free (List);
537 Free (Reader);
538 end ReadTrackConf;
541 end Simulator.Track;