DEMO.LST 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. Listing:
  2. 1 (*# check(stack=>off,
  3. 2 index=>off,
  4. 3 range=>off,
  5. 4 overflow=>off,
  6. 5 nil_ptr=>off) *)
  7. 6
  8. 7
  9. 8 (*%F _mthread*) This program is only valid in multithread model (*%E*)
  10. 9 MODULE Demo;
  11. 10 IMPORT SYSTEM,IO,Window,Lib,Process ;
  12. 11 FROM Lib IMPORT RANDOM ;
  13. ***** ^ duplicate identifier
  14. 12
  15. 13
  16. 14 CONST
  17. 15 xNum = Window.ScreenWidth;
  18. ***** ^ not supported yet
  19. ***** ^ not supported yet
  20. 16 yNum = Window.ScreenDepth;
  21. ***** ^ not supported yet
  22. ***** ^ not supported yet
  23. 17 CarNum = 100 ;
  24. 18
  25. 19 TYPE
  26. 20 xCoord = [0..xNum-1] ;
  27. 21 yCoord = [0..yNum-1] ;
  28. 22
  29. 23 Coord = RECORD
  30. 24 x : xCoord ;
  31. 25 y : yCoord ;
  32. 26 END ;
  33. ***** ^ not supported yet
  34. 27
  35. 28 Direction = (East,South,North,West) ;
  36. 29
  37. 30 DirSet = SET OF Direction ;
  38. ***** ^ not supported yet
  39. 31
  40. 32 Location = RECORD
  41. 33 Entry,Exit : DirSet ;
  42. 34 Occupied : BOOLEAN ;
  43. 35 Scenery : SHORTCARD ;
  44. 36 END ;
  45. ***** ^ not supported yet
  46. 37
  47. 38 DA = ARRAY Direction OF Direction ;
  48. ***** ^ not supported yet
  49. ***** ^ not supported yet
  50. 39
  51. 40 CarRange = [0..CarNum-1] ;
  52. ***** ^ not supported yet
  53. 41
  54. 42 CONST
  55. 43
  56. 44 Reverse = DA(West,North,South,East) ; (* reverse of Direction *)
  57. ***** ^ not supported yet
  58. ***** ^ not supported yet
  59. ***** ^ not supported yet
  60. ***** ^ not supported yet
  61. 45
  62. 46
  63. 47 VAR
  64. 48
  65. 49 World : ARRAY xCoord,yCoord OF Location;
  66. ***** ^ not supported yet
  67. 50
  68. 51 Car : ARRAY CarRange OF
  69. 52 RECORD
  70. 53 Pos : Coord;
  71. 54 Color : Window.Color;
  72. 55 Speed : CARDINAL ; (* MPH*10 *)
  73. 56 LastD : Direction ;
  74. 57 END;
  75. 58
  76. 59 ToNorth : ARRAY yCoord OF CARDINAL ;
  77. 60 ToSouth : ARRAY yCoord OF CARDINAL ;
  78. 61 ToEast : ARRAY xCoord OF CARDINAL ;
  79. 62 ToWest : ARRAY xCoord OF CARDINAL ;
  80. 63
  81. 64 IsBW : BOOLEAN ;
  82. 65
  83. 66 VAR (*W+*) (* Volatile *)
  84. 67
  85. 68 AvSpeed : CARDINAL;
  86. 69 MaxCar : CarRange ;
  87. 70
  88. 71 (*$W=*)
  89. 72
  90. 73
  91. 74 PROCEDURE Plot(x : xCoord; y : yCoord );
  92. 75
  93. 76 TYPE
  94. 77 Chars = ARRAY SHORTCARD [0..15] OF SHORTCARD ;
  95. 78 CONST
  96. 79 Road = Chars(176,32,32,201,32,200,186,204,32,205,187,203,188,202,185,206);
  97. 80 VAR
  98. 81 loc : Location;
  99. 82 sc : SHORTCARD ;
  100. 83 color : Window.Color ;
  101. 84 BEGIN
  102. 85 loc := World[x,y] ;
  103. 86 sc := Road[SHORTCARD(loc.Entry+loc.Exit)];
  104. 87 IF sc=176 THEN
  105. 88 IF IsBW THEN color := Window.LightGray
  106. 89 ELSE color := Window.Brown
  107. 90 END ;
  108. 91 ELSIF sc=32 THEN RETURN
  109. 92 ELSE color := Window.LightGray ;
  110. 93 END ;
  111. 94 Window.TextColor(color);
  112. 95 Window.DirectWrite(x+1,y+1,ADR(sc),1) ;
  113. 96 END Plot;
  114. 97
  115. 98 PROCEDURE PlotCar( v : CarRange ; dir : Direction );
  116. 99
  117. 100 TYPE
  118. 101 Chars = ARRAY Direction OF SHORTCARD ;
  119. 102 CONST
  120. 103 CarSym = Chars(16,31,30,17) ;
  121. 104 BEGIN
  122. 105 Window.TextColor(Car[v].Color);
  123. 106 Window.DirectWrite(Car[v].Pos.x+1,Car[v].Pos.y+1,ADR(CarSym[dir]),1) ;
  124. 107 END PlotCar;
  125. 108
  126. 109
  127. 110
  128. 111 PROCEDURE NewCar ;
  129. 112 VAR
  130. 113 x : xCoord ;
  131. 114 y : yCoord ;
  132. 115 v : CarRange ;
  133. 116 d : Direction ;
  134. 117 BEGIN
  135. 118 INC(MaxCar) ;
  136. 119 v := MaxCar ;
  137. 120 d := MAX(Direction);
  138. 121 LOOP
  139. 122 IF d=MAX(Direction) THEN
  140. 123 REPEAT
  141. 124 x := RANDOM(xNum); y := RANDOM(yNum) ;
  142. 125 UNTIL NOT World[x,y].Occupied ;
  143. 126 d := MIN(Direction) ;
  144. 127 ELSE
  145. 128 INC(d) ;
  146. 129 END ;
  147. 130 IF d IN World[x,y].Exit THEN EXIT END ;
  148. 131 END ;
  149. 132 World[x,y].Occupied := TRUE ;
  150. 133 WITH Car[v] DO
  151. 134 Pos.x := x ; Pos.y := y ;
  152. 135 Speed := RANDOM(100) ;
  153. 136 LastD := Direction(RANDOM(4));
  154. 137 END ;
  155. 138 IF IsBW THEN Car[v].Color := Window.White ;
  156. 139 ELSE Car[v].Color := Window.Color( 9+RANDOM(7) ) ;
  157. 140 END ;
  158. 141 PlotCar(v,d) ;
  159. 142 END NewCar ;
  160. 143
  161. 144 PROCEDURE ParkCar ( v : CarRange ) ;
  162. 145 VAR
  163. 146 x : xCoord ;
  164. 147 y : yCoord ;
  165. 148 BEGIN
  166. 149 x := Car[v].Pos.x ; y := Car[v].Pos.y ;
  167. 150 IF MaxCar = 0 THEN HALT END ;
  168. 151 World[x,y].Occupied := FALSE ;
  169. 152 Plot(x,y);
  170. 153 WHILE v<MaxCar DO
  171. 154 Car[v] := Car[v+1] ; INC(v) ;
  172. 155 END ;
  173. 156 DEC(MaxCar) ;
  174. 157 END ParkCar ;
  175. 158
  176. 159
  177. 160
  178. 161 PROCEDURE MoveCar ( v:CarRange ) ;
  179. 162 VAR
  180. 163 exit : Direction;
  181. 164 x,newx : xCoord ;
  182. 165 y,newy : yCoord ;
  183. 166 tried : DirSet ;
  184. 167 CONST
  185. 168 SpeedLimit = 450 ; (* 30 MPH ?! *)
  186. 169 BEGIN
  187. 170 WITH Car[v] DO
  188. 171 IF Speed < SpeedLimit THEN
  189. 172 INC(Speed,RANDOM(80)) ;
  190. 173 IF Speed>SpeedLimit THEN Speed := SpeedLimit END ;
  191. 174 IF Speed<RANDOM(SpeedLimit) THEN RETURN END ;
  192. 175 END ;
  193. 176 x := Pos.x; y := Pos.y;
  194. 177 END ;
  195. 178 tried := DirSet{};
  196. 179 LOOP
  197. 180 exit := Direction(RANDOM(4));
  198. 181 IF exit IN World[x,y].Exit THEN
  199. 182 newx := x; newy := y;
  200. 183 CASE exit OF
  201. 184 | East : newx := ToEast[x];
  202. 185 | South : newy := ToSouth[y];
  203. 186 | North : newy := ToNorth[y];
  204. 187 | West : newx := ToWest[x];
  205. 188 END;
  206. 189 IF World[newx,newy].Occupied THEN
  207. 190 Car[v].Speed := Car[v].Speed DIV 4 (* Brake *) ; RETURN ;
  208. 191 ELSE
  209. 192 World[x,y].Occupied := FALSE ;
  210. 193 Plot(x,y);
  211. 194 World[newx,newy].Occupied := TRUE ;
  212. 195 WITH Car[v] DO
  213. 196 Pos.x := newx; Pos.y := newy;
  214. 197 IF LastD<>exit THEN
  215. 198 (* Cornering *)
  216. 199 Speed := Speed DIV 2 ;
  217. 200 LastD := exit ;
  218. 201 END ;
  219. 202 END ;
  220. 203 PlotCar(v,exit);
  221. 204 RETURN ;
  222. 205 END;
  223. 206 END;
  224. 207 INCL(tried,exit);
  225. 208 IF tried = DirSet{East..West} THEN
  226. 209 Car[v].Speed := 0 (* Stop *) ; RETURN ;
  227. 210 RETURN ;
  228. 211 END;
  229. 212 END;
  230. 213 END MoveCar;
  231. 214
  232. 215
  233. 216
  234. 217
  235. 218
  236. 219 PROCEDURE InitWorld;
  237. 220
  238. 221 PROCEDURE ok( x:xCoord ; y:yCoord ) : BOOLEAN;
  239. 222
  240. 223 (* Returns whether we have planning permission to build road at x,y *)
  241. 224 (* Tries to avoid making very small plots of land *)
  242. 225
  243. 226 BEGIN
  244. 227 RETURN ( World[ x,y ].Exit = DirSet{} ) OR
  245. 228 ( World[ ToEast[x],y ].Exit = DirSet{} ) OR
  246. 229 ( World[ ToEast[x],ToSouth[y] ].Exit = DirSet{} ) OR
  247. 230 ( World[ x,ToSouth[y] ].Exit = DirSet{} ) ;
  248. 231 END ok;
  249. 232
  250. 233
  251. 234 VAR
  252. 235 x,newx : xCoord ;
  253. 236 y,newy : yCoord ;
  254. 237 n : CARDINAL;
  255. 238 newdir,
  256. 239 newentry: Direction;
  257. 240 v : CarRange ;
  258. 241 BEGIN
  259. 242 FOR x := MIN(xCoord) TO MAX(xCoord) DO
  260. 243 ToEast[x] := (x+1)MOD xNum ;
  261. 244 ToWest[x] := (x+xNum-1)MOD xNum ;
  262. 245 END ;
  263. 246 FOR y := MIN(yCoord) TO MAX(yCoord) DO
  264. 247 ToSouth[y] := (y+1)MOD yNum ;
  265. 248 ToNorth[y] := (y+yNum-1)MOD yNum ;
  266. 249 END ;
  267. 250 Lib.Fill(ADR(World),SIZE(World),0) ;
  268. 251 x := xNum DIV 2; y := yNum DIV 2;
  269. 252 newx := x; newy := y;
  270. 253 newdir := Direction(RANDOM(4));
  271. 254 n := 1000 + RANDOM(1000);
  272. 255 (* initialise map using randomish walk of n steps *)
  273. 256 WHILE n <> 0 DO
  274. 257 DEC(n);
  275. 258 IF RANDOM(4)=0 THEN
  276. 259 newdir := Direction(RANDOM(4));
  277. 260 END;
  278. 261 WHILE newdir IN World[x,y].Entry DO (* enforce one-way streets *)
  279. 262 newdir := Direction(RANDOM(4)) ;
  280. 263 END;
  281. 264 newx := x; newy := y;
  282. 265 CASE newdir OF
  283. 266 | East : newx := ToEast[x] ;
  284. 267 | South : newy := ToSouth[y] ;
  285. 268 | North : newy := ToNorth[y] ;
  286. 269 | West : newx := ToWest[x] ;
  287. 270 END;
  288. 271 newentry := Reverse[newdir] ;
  289. 272 IF NOT ( newentry IN World[newx,newy].Entry ) THEN
  290. 273 INCL( World[newx,newy].Entry, newentry );
  291. 274 IF (RANDOM(50)=0) OR
  292. 275 ( ok( newx, newy ) AND
  293. 276 ok( ToWest[newx], newy ) AND
  294. 277 ok( ToWest[newx], ToNorth[newy] ) AND
  295. 278 ok( newx, ToNorth[newy] )
  296. 279 )
  297. 280 THEN
  298. 281 INCL( World[x,y].Exit, newdir );
  299. 282 Plot( x, y );
  300. 283 Plot( newx,newy );
  301. 284 Plot( ToEast[x],y );
  302. 285 Plot( ToWest[x],y );
  303. 286 Plot( x, ToNorth[y] );
  304. 287 Plot( x, ToSouth[y] );
  305. 288 x := newx; y := newy;
  306. 289 ELSE
  307. 290 EXCL( World[newx,newy].Entry, newentry );
  308. 291 END;
  309. 292 ELSE
  310. 293 x := newx; y := newy;
  311. 294 END;
  312. 295 END;
  313. 296 (* make some cars *)
  314. 297 MaxCar := MAX(CARDINAL) ;
  315. 298 FOR v := 1 TO CarNum-RANDOM(50) DO
  316. 299 NewCar ;
  317. 300 END;
  318. 301 END InitWorld;
  319. 302
  320. 303
  321. 304
  322. 305 PROCEDURE Statistics ;
  323. 306 CONST
  324. 307 MsgWindowDef = Window.WinDef ( 5,5, 37,10,
  325. 308 Window.Blue,Window.LightGray,
  326. 309 FALSE,TRUE,FALSE,TRUE,
  327. 310 Window.SingleFrame,
  328. 311 Window.Red, Window.LightGray );
  329. 312 VAR
  330. 313 MsgW : Window.WinType;
  331. 314 MsgX,MsgY : CARDINAL;
  332. 315 WD : Window.WinDef ;
  333. 316 count : CARDINAL ;
  334. 317 change : BOOLEAN ;
  335. 318 BEGIN
  336. 319 WD := MsgWindowDef ;
  337. 320 IF IsBW THEN
  338. 321 WD.Foreground := Window.Black ;
  339. 322 WD.FrameBack := Window.LightGray ;
  340. 323 WD.FrameFore := Window.Black ;
  341. 324 END ;
  342. 325
  343. 326 MsgW := Window.Open( WD );
  344. 327 Window.SetTitle(MsgW,' TopSpeed Modula-2 Demo ',Window.CenterUpperTitle) ;
  345. 328 MsgX := 5 ; MsgY := 5 ;
  346. 329 Window.Use(MsgW);
  347. 330 count := 200 ;
  348. 331 LOOP
  349. 332 Process.Delay(1) ;
  350. 333 IO.WrLn;
  351. 334 IO.WrStr('Cars: ');IO.WrCard(MaxCar+1,1) ;
  352. 335 IO.WrStr(' Average Speed: ');IO.WrCard(AvSpeed DIV 10, 1 );
  353. 336 IO.WrChar('.');IO.WrCard(AvSpeed MOD 10, 1 );
  354. 337 IF count=0 THEN
  355. 338 MsgX := RANDOM(50);
  356. 339 MsgY := RANDOM(20);
  357. 340 count := 200 ;
  358. 341 ELSE
  359. 342 DEC(count) ;
  360. 343 END ;
  361. 344 change := TRUE ;
  362. 345 IF WD.X1+2<MsgX THEN INC(WD.X1,3);INC(WD.X2,3);
  363. 346 ELSIF WD.X1>MsgX+2 THEN DEC(WD.X1,3);DEC(WD.X2,3);
  364. 347 ELSIF WD.Y1=MsgY THEN change := FALSE ;
  365. 348 END ;
  366. 349 IF WD.Y1<MsgY THEN INC(WD.Y1);INC(WD.Y2);
  367. 350 ELSIF WD.Y1>MsgY THEN DEC(WD.Y1);DEC(WD.Y2);
  368. 351 END ;
  369. 352 IF change THEN
  370. 353 Window.Change(MsgW,WD.X1,WD.Y1,WD.X2,WD.Y2) ;
  371. 354 END ;
  372. 355 END ;
  373. 356 END Statistics;
  374. 357
  375. 358
  376. 359 PROCEDURE RunSimulation ;
  377. 360 VAR
  378. 361 v : CARDINAL;
  379. 362 i : CARDINAL;
  380. 363 SumSpeed : CARDINAL ;
  381. 364 up : BOOLEAN ;
  382. 365 c : CHAR ;
  383. 366 BEGIN
  384. 367 up := TRUE ;
  385. 368 LOOP
  386. 369 SumSpeed := 0;
  387. 370 v := MaxCar+1 ;
  388. 371 REPEAT
  389. 372 DEC(v) ;
  390. 373 MoveCar(v) ;
  391. 374 SumSpeed := SumSpeed + Car[v].Speed ;
  392. 375 UNTIL v=0;
  393. 376 IF IO.KeyPressed() THEN
  394. 377 c := IO.RdKey() ;
  395. 378 EXIT
  396. 379 END ;
  397. 380 AvSpeed := SumSpeed DIV (MaxCar+1);
  398. 381 (* Add or subtract card *)
  399. 382 IF RANDOM(5)=0 THEN
  400. 383 IF MaxCar=1 THEN up := TRUE
  401. 384 ELSIF MaxCar=CarNum-1 THEN up := FALSE ;
  402. 385 END ;
  403. 386 IF up THEN NewCar ELSE ParkCar(RANDOM(MaxCar+1)) END ;
  404. 387 Window.TextColor(Window.Black) ;
  405. 388 END ;
  406. 389 END ;
  407. 390 END RunSimulation ;
  408. 391
  409. 392 PROCEDURE Intro ;
  410. 393 VAR
  411. 394 DescWin : Window.WinType ;
  412. 395 r : CARDINAL ;
  413. 396 BEGIN
  414. 397 Window.CursorOff ;
  415. 398 Window.SetProcessLocks(Process.Lock,Process.Unlock) ;
  416. 399 DescWin := Window.Open(Window.WinDef(0,11,79,25,Window.LightGray,Window.Black,
  417. 400 FALSE,TRUE,FALSE,TRUE,
  418. 401 Window.DoubleFrame,Window.Black,Window.LightGray)) ;
  419. 402
  420. 403 Window.SetTitle(DescWin,' TopSpeed Modula-2 : Traffic Simulation ',Window.CenterUpperTitle);
  421. 404 IO.WrLn;
  422. 405 IO.WrStr(' This program is a simple simulation of traffic flow in a closed road system.');
  423. 406 IO.WrLn;
  424. 407 IO.WrStr(' Up to 200 cars move randomly within a one-way network of roads.');IO.WrLn;
  425. 408 IO.WrLn;
  426. 409 IO.WrStr(' The average speed is monitored by a separate process and displayed in');IO.WrLn;
  427. 410 IO.WrStr(' the Statistics window. 30.0 MPH indicates no congestion.');IO.WrLn;
  428. 411 IO.WrLn;
  429. 412 IO.WrStr(' Any resemblance to rush-hour traffic in New York is purely coincidental.');IO.WrLn;
  430. 413 IO.WrLn; IO.WrLn; Window.TextColor(Window.White) ;
  431. 414 IO.WrStr(' Press any key to start the simulation and then any key to terminate.');IO.WrLn;
  432. 415 Window.Use(Window.FullScreen);
  433. 416 Window.SetWrap(FALSE) ;
  434. 417 Window.TextBackground(Window.Black) ;
  435. 418 IF IsBW THEN
  436. 419 Window.TextColor(Window.LightGray) ;
  437. 420 ELSE
  438. 421 Window.TextColor(Window.Green) ;
  439. 422 END ;
  440. 423 FOR r := 1 TO Window.ScreenDepth DO
  441. 424 Window.GotoXY(1,r) ;
  442. 425 IO.WrCharRep(CHAR(178),Window.ScreenWidth) ;
  443. 426 END ;
  444. 427 Window.TextBackground(Window.Black) ;
  445. 428 Lib.RANDOMIZE;
  446. 429 InitWorld;
  447. 430 WHILE NOT IO.KeyPressed() DO END ;
  448. 431 IF IO.RdKey()=' ' THEN END ;
  449. 432 Window.Close(DescWin) ;
  450. 433 END Intro;
  451. 434
  452. 435 (*%F _OS2*)
  453. 436 PROCEDURE CheckBW ;
  454. 437 VAR
  455. 438 R : SYSTEM.Registers ;
  456. 439 BEGIN
  457. 440 R.AH := 15 ;
  458. 441 Lib.Intr(R,10H) ;
  459. 442 IsBW := (R.AL = 0)OR(R.AL = 2)OR(R.AL = 5)OR(R.AL = 6)OR(R.AL = 7) ;
  460. 443 END CheckBW ;
  461. 444 (*%E*)
  462. 445
  463. 446 BEGIN
  464. 447 (*%F _OS2*)
  465. 448 CheckBW ;
  466. 449 (*%E*)
  467. 450 Intro ;
  468. 451 AvSpeed := 300 ;
  469. 452 Process.StartScheduler ;
  470. 453 Process.StartProcess(Statistics,2000H,1) ;
  471. 454 RunSimulation ;
  472. 455 (*%F _OS2*)
  473. 456 Lib.NoSound ;
  474. 457 (*%E*)
  475. 458 Window.GotoXY(1,Window.ScreenDepth);
  476. 459 Window.CursorOn ;
  477. 460 END Demo.
  478. 16 errors