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

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