source: trunk/Mars/mtools/MagicSnake.cc@ 10048

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