source: trunk/MagicSoft/Mars/mtools/MagicSnake.cc@ 1460

Last change on this file since 1460 was 1439, checked in by tbretz, 23 years ago
*** empty log message ***
File size: 14.0 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz 07/2002 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2002
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MagicSnake
28// ----------
29//
30// Camera Display Games: Snake
31//
32// Start the game by:
33// MagicSnake snake;
34//
35// Controll the worm using right/left. Make sure, that the mouse pointer
36// is inside the canvas.
37//
38// Move the mouse pointer outside the canvas to pause the game.
39//
40// The pixel colors have the following meaning:
41// --------------------------------------------
42// Green: Food, collect all packages.
43// Red: Bombs, don't touch it!
44// Yellow: Transport, try it.
45// Magenta: Home, touch it to win the game.
46//
47// To restart the game use the context menu. It can only be accessed if
48// the game has been stopped (either because you win the game or because
49// you hit a bomb) With the context menu you can also toggle between
50// different camera layouts.
51//
52////////////////////////////////////////////////////////////////////////////
53#include "MagicSnake.h"
54
55#include <iostream.h>
56
57#include <KeySymbols.h>
58
59#include <TColor.h>
60#include <TCanvas.h>
61#include <TMarker.h>
62#include <TRandom.h>
63#include <TInterpreter.h>
64
65#include "MHexagon.h"
66
67#include "MGeomPix.h"
68#include "MGeomCamCT1.h"
69#include "MGeomCamMagic.h"
70
71ClassImp(MagicSnake);
72
73void MagicSnake::Free()
74{
75 if (!fGeomCam)
76 return;
77
78 fPixels->Delete();
79
80 delete fPixels;
81
82 delete fGeomCam;
83
84 delete fArray;
85}
86
87// ------------------------------------------------------------------------
88//
89// Draw all pixels of the camera
90// (means apend all pixelobjects to the current pad)
91//
92void MagicSnake::DrawHexagons()
93{
94 for (UInt_t i=0; i<fNumPixels; i++)
95 (*this)[i].Draw();
96}
97
98void MagicSnake::ChangeCamera()
99{
100 if (!fDone)
101 Done("Changing Camera...", 22);
102
103 static Bool_t ct1=kFALSE;
104
105 cout << "Change to " << (ct1?"Magic":"CT1") << endl;
106
107 if (ct1)
108 SetNewCamera(new MGeomCamMagic);
109 else
110 SetNewCamera(new MGeomCamCT1);
111
112 ct1 = !ct1;
113
114 Reset();
115 DrawHexagons();
116}
117
118void MagicSnake::SetNewCamera(MGeomCam *geom)
119{
120 Free();
121
122 //
123 // Reset the display geometry
124 //
125 fW=0;
126 fH=0;
127
128 //
129 // Set new camera
130 //
131 fGeomCam = geom;
132
133 //
134 // create the hexagons of the display
135 //
136 fNumPixels = fGeomCam->GetNumPixels();
137 fRange = fGeomCam->GetMaxRadius();
138
139 //
140 // Construct all hexagons. Use new-operator with placement
141 //
142 fPixels = new TClonesArray("MHexagon", fNumPixels);
143
144 for (UInt_t i=0; i<fNumPixels; i++)
145 {
146 MHexagon &h = *new ((*fPixels)[i]) MHexagon((*fGeomCam)[i]);
147#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
148 h.SetBit(kNoContextMenu|kCannotPick);
149#endif
150 }
151}
152
153// ------------------------------------------------------------------------
154//
155// default constructor
156//
157MagicSnake::MagicSnake()
158 : fTimer(this, 500, kTRUE), fGeomCam(NULL), fDone(NULL), fPaused(NULL), fW(0), fH(0)
159{
160 SetNewCamera(new MGeomCamMagic);
161
162 //
163 // Make sure, that the object is destroyed when the canvas/pad is
164 // destroyed. Make also sure, that the interpreter doesn't try to
165 // delete it a second time.
166 //
167 SetBit(kCanDelete);
168 gInterpreter->DeleteGlobal(this);
169
170 Draw();
171
172 Pause();
173
174 fTimer.TurnOn();
175}
176
177void MagicSnake::Pause(Bool_t yes)
178{
179 if (yes && !fPaused)
180 {
181 fPaused = new TText(0, 0, "Paused!");
182 fPaused->SetTextColor(kWhite);
183 fPaused->SetTextAlign(22);
184 fPaused->SetTextSize(0.05); // white
185 fPaused->Draw();
186#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
187 fPaused->SetBit(kNoContextMenu|kCannotPick);
188 fDrawingPad->ResetBit(kNoContextMenu);
189 ResetBit(kNoContextMenu);
190#endif
191 fDrawingPad->Update();
192 }
193
194 if (yes)
195 return;
196
197 if (!fDone)
198 {
199#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
200 fDrawingPad->SetBit(kNoContextMenu);
201 SetBit(kNoContextMenu);
202#endif
203 }
204 if (!fPaused)
205 return;
206
207 Remove(fPaused);
208
209 fDrawingPad->Update();
210
211 delete fPaused;
212 fPaused=NULL;
213}
214
215// ------------------------------------------------------------------------
216//
217// Destructor. Deletes TClonesArrays for hexagons and legend elements.
218//
219MagicSnake::~MagicSnake()
220{
221 Free();
222 Pause(kFALSE);
223
224 if (fDone)
225 delete fDone;
226
227 if (fDrawingPad->GetListOfPrimitives()->FindObject(this)==this)
228 {
229 fDrawingPad->RecursiveRemove(this);
230 delete fDrawingPad;
231 }
232}
233
234// ------------------------------------------------------------------------
235//
236// This is called at any time the canvas should get repainted.
237// Here we maintain an aspect ratio of 5/4=1.15. This makes sure,
238// that the camera image doesn't get distorted by resizing the canvas.
239//
240void MagicSnake::Paint(Option_t *opt)
241{
242 const UInt_t w = (UInt_t)(gPad->GetWw()*gPad->GetAbsWNDC());
243 const UInt_t h = (UInt_t)(gPad->GetWh()*gPad->GetAbsHNDC());
244
245 //
246 // Check for a change in width or height, and make sure, that the
247 // first call also sets the range
248 //
249 if (w*fH == h*fW && fW && fH)
250 return;
251
252 //
253 // Calculate aspect ratio (5/4=1.25 recommended)
254 //
255 const Double_t ratio = (Double_t)w/h;
256
257 Float_t x;
258 Float_t y;
259
260 if (ratio>1.0)
261 {
262 x = fRange*(ratio*2-1);
263 y = fRange;
264 }
265 else
266 {
267 x = fRange;
268 y = fRange/ratio;
269 }
270
271 fH = h;
272 fW = w;
273
274 //
275 // Set new range
276 //
277 fDrawingPad->Range(-fRange, -y, x, y);
278}
279
280// ------------------------------------------------------------------------
281//
282// Call this function to draw the camera layout into your canvas.
283// Setup a drawing canvas. Add this object and all child objects
284// (hexagons, etc) to the current pad. If no pad exists a new one is
285// created.
286//
287void MagicSnake::Draw(Option_t *option)
288{
289 //
290 // if no canvas is yet existing to draw into, create a new one
291 //
292 /*TCanvas *c =*/ new TCanvas("MagicSnake", "Magic Snake", 0, 0, 800, 800);
293 //c->ToggleEventStatus();
294
295 fDrawingPad = gPad;
296 fDrawingPad->SetBorderMode(0);
297
298 //
299 // Append this object, so that the aspect ratio is maintained
300 // (Paint-function is called)
301 //
302 AppendPad(option);
303
304 //
305 // Reset the game pad
306 //
307 Reset();
308 DrawHexagons();
309
310 fShow.SetTextAlign(23); // centered/bottom
311#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
312 fShow.SetBit(kNoContextMenu|kCannotPick);
313#endif
314 fShow.Draw();
315}
316
317void MagicSnake::Update()
318{
319 TString txt = "Pixels: ";
320 txt += fNumPixels;
321 txt += " Bombs: ";
322 txt += fNumBombs;
323 txt += " Food: ";
324 txt += fNumFood;
325
326 fShow.SetText(0, fRange, txt);
327}
328
329// ------------------------------------------------------------------------
330//
331// reset the all pixel colors to a default value
332//
333void MagicSnake::Reset()
334{
335 fDirection = fGeomCam->InheritsFrom("MGeomCamCT1") ? kLeft : kRight;
336 fLength = 2;
337
338 for (UInt_t i=0; i<fNumPixels; i++)
339 {
340 (*this)[i].SetFillColor(kBackground);
341 (*fGeomCam)[i].ResetBit(kUserBits);
342 }
343
344 fNumBombs = fNumPixels/30;
345
346 TRandom rnd(0);
347 for (int i=0; i<fNumBombs; i++)
348 {
349 Int_t idx;
350
351 do idx = (Int_t)rnd.Uniform(fNumPixels);
352 while ((*fGeomCam)[idx].TestBits(kHasBomb|kHasWorm));
353
354 (*fGeomCam)[idx].SetBit(kHasBomb);
355 (*this)[idx].SetFillColor(kRed);
356 }
357
358 fNumFood = fNumPixels/6;
359
360 fArray = new Int_t[fNumFood+3];
361
362 fArray[0] = 0;
363 fArray[1] = 1;
364
365 for (int i=0; i<fNumFood+3; i++)
366 {
367 Float_t f = (float)i/(fNumFood+3);
368 gROOT->GetColor(51+i)->SetRGB(f, f, f);
369 }
370 for (int i=0; i<fNumFood; i++)
371 {
372 Int_t idx;
373
374 do idx = (Int_t)rnd.Uniform(fNumPixels);
375 while ((*fGeomCam)[idx].TestBits(kHasBomb|kHasFood|kHasWorm));
376
377 (*fGeomCam)[idx].SetBit(kHasFood);
378 (*this)[idx].SetFillColor(kGreen);
379 }
380
381 SetWormColor();
382
383 for (int i=0; i<2; i++)
384 {
385 Int_t idx;
386
387 do idx = (Int_t)rnd.Uniform(fNumPixels);
388 while ((*fGeomCam)[idx].TestBits(kHasBomb|kHasFood|kHasWorm|kHasTransport));
389
390 fTransport[i] = idx;
391 (*fGeomCam)[idx].SetBit(kHasTransport);
392 (*this)[idx].SetFillColor(kYellow);
393 }
394
395 fDrawingPad->SetFillColor(22);
396
397#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
398 fDrawingPad->SetBit(kNoContextMenu);
399 SetBit(kNoContextMenu);
400#endif
401
402 if (!fDone)
403 return;
404
405 delete fDone;
406 fDone = NULL;
407}
408
409void MagicSnake::Done(TString txt, Int_t col)
410{
411 //(*this)[fArray[fLength-1]].SetFillColor(kBlue);
412
413 fDone = new TText(0, 0, txt);
414 fDone->SetTextColor(kWhite); // white
415 fDone->SetTextAlign(22); // centered/centered
416 fDone->SetTextSize(0.05); // white
417 fDone->Draw();
418 fDrawingPad->SetFillColor(col);
419#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
420 fDone->SetBit(kNoContextMenu|kCannotPick);
421 fDrawingPad->ResetBit(kNoContextMenu);
422 ResetBit(kNoContextMenu);
423#endif
424}
425
426void MagicSnake::Remove(TObject *obj)
427{
428 fDrawingPad->RecursiveRemove(obj);
429}
430
431// ------------------------------------------------------------------------
432//
433// Execute a mouse event on the camera
434//
435void MagicSnake::ExecuteEvent(Int_t event, Int_t keycode, Int_t keysym)
436{
437 if (event==kMouseEnter || event==kMouseMotion)
438 {
439 Pause(kFALSE);
440 return;
441 }
442
443 if (fDone)
444 return;
445
446 if (event==kMouseLeave)
447 {
448 Pause();
449 return;
450 }
451 if (event!=kKeyPress)
452 return;
453
454 switch (keysym)
455 {
456 case kKey_Left:
457 fDirection --;
458 break;
459
460 case kKey_Right:
461 fDirection ++;
462 break;
463
464 case kKey_Escape:
465 Done("Reset...", 22);
466 Reset();
467 return;
468
469 default:
470 cout << "Keysym=0x" << hex << keysym << endl;
471 }
472
473 if (fDirection < kRightTop)
474 fDirection = kLeftTop;
475 if (fDirection > kLeftTop)
476 fDirection = kRightTop;
477}
478
479void MagicSnake::Step(Int_t newpix)
480{
481 if ((*fGeomCam)[newpix].TestBit(kHasTransport))
482 {
483 (*this)[fArray[0]].SetFillColor(kBackground);
484 (*fGeomCam)[fArray[0]].ResetBit(kHasWorm);
485
486 for (int i=1; i<fLength; i++)
487 fArray[i-1] = fArray[i];
488
489 fArray[fLength-1] = newpix==fTransport[0]?fTransport[1]:fTransport[0];
490
491 return;
492 }
493
494 if (!(*fGeomCam)[newpix].TestBit(kHasFood))
495 {
496 MGeomPix &pix = (*fGeomCam)[fArray[0]];
497
498 if (!pix.TestBit(kHasTransport))
499 if (pix.TestBit(kHasDoor))
500 (*this)[fArray[0]].SetFillColor(kMagenta);
501 else
502 (*this)[fArray[0]].SetFillColor(kBackground);
503
504 pix.ResetBit(kHasWorm);
505
506 for (int i=1; i<fLength; i++)
507 fArray[i-1] = fArray[i];
508
509 fArray[fLength-1] = newpix;
510 }
511 else
512 {
513 fArray[fLength++] = newpix;
514 (*fGeomCam)[newpix].ResetBit(kHasFood);
515
516 fNumFood--;
517
518 if (fNumFood==0)
519 for (int i=1; i<7; i++)
520 {
521 (*this)[i].SetFillColor(kMagenta);
522 (*fGeomCam)[i].SetBit(kHasDoor);
523 }
524 }
525
526 SetWormColor();
527}
528
529void MagicSnake::SetWormColor()
530{
531 for (int i=0; i<fLength; i++)
532 {
533 const Int_t idx = fArray[i];
534
535 MGeomPix &pix = (*fGeomCam)[idx];
536
537 if (pix.TestBit(kHasTransport))
538 continue;
539
540 pix.SetBit(kHasWorm);
541
542 Int_t color = 51+fLength-i;
543 (*this)[idx].SetFillColor(color);
544 }
545}
546
547Int_t MagicSnake::ScanNeighbours()
548{
549 const Int_t first = fArray[fLength-1];
550
551 const MGeomPix &pix=(*fGeomCam)[first];
552
553 Double_t dx = pix.GetX();
554 Double_t dy = pix.GetY();
555
556 Int_t newpix = -1;
557 for (int i=0; i<pix.GetNumNeighbors(); i++)
558 {
559 const Int_t idx = pix.GetNeighbor(i);
560 const MGeomPix &next = (*fGeomCam)[idx];
561
562 const Double_t x = next.GetX();
563 const Double_t y = next.GetY();
564
565 switch (fDirection)
566 {
567 case kRightTop: if (x>=dx && y>dy) { newpix=idx; dy=y; } continue;
568 case kRight: if (x>dx) { newpix=idx; dx=x; } continue;
569 case kRightBottom: if (x>=dx && y<dy) { newpix=idx; dy=y; } continue;
570 case kLeftTop: if (x<=dx && y>dy) { newpix=idx; dy=y; } continue;
571 case kLeft: if (x<dx) { newpix=idx; dx=x; } continue;
572 case kLeftBottom: if (x<=dx && y<dy) { newpix=idx; dy=y; } continue;
573 }
574 }
575
576 if (newpix<0)
577 return -1;
578
579 const MGeomPix &np = (*fGeomCam)[newpix];
580
581 if (fNumFood==0 && np.TestBit(kHasDoor))
582 return -4;
583
584 if (np.TestBit(kHasBomb))
585 return -2;
586
587 if (np.TestBit(kHasWorm))
588 return -3;
589
590 return newpix;
591}
592
593Bool_t MagicSnake::HandleTimer(TTimer *timer)
594{
595 if (fDone || fPaused)
596 return kTRUE;
597
598 const Int_t newpix = ScanNeighbours();
599
600 switch (newpix)
601 {
602 case -1:
603 Done("You crashed! Don't drink and drive!", kRed);
604 break;
605 case -2:
606 Done("Ouch, you found the bomb!", kRed);
607 break;
608 case -3:
609 Done("Argh... don't eat yourself!", kRed);
610 break;
611 case -4:
612 Done("Congratulations! You won the game!", kGreen);
613 break;
614 default:
615 Step(newpix);
616 }
617
618 Update();
619
620 cout << "Update " << flush;
621
622 fDrawingPad->Modified();
623 fDrawingPad->Update();
624
625 cout << "Done." << endl;
626
627 return kTRUE;
628}
Note: See TracBrowser for help on using the repository browser.