source: trunk/Mars/mtools/MagicDomino.cc@ 9844

Last change on this file since 9844 was 9369, checked in by tbretz, 16 years ago
*** empty log message ***
File size: 14.8 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// MagicDomino
28// -----------
29//
30// Magic Camera games.
31//
32// Start the show by:
33// MagicDomino show;
34//
35// Use the following keys:
36// -----------------------
37//
38// * Cursor up/down, left/right:
39// Move tile
40//
41// * Space:
42// Rotate tile
43//
44// * Enter:
45// Set tile
46//
47// * Esc:
48// Skip tile
49//
50// Rules:
51// ------
52//
53// Each hexagon in the tile must at least have one neighbor
54// which has the same color. It is not allowed to put a tile onto
55// another one. The game is over if you have skipped three tiles
56// in a row.
57//
58////////////////////////////////////////////////////////////////////////////
59#include "MagicDomino.h"
60
61#include <iostream>
62
63#include <KeySymbols.h>
64
65#include <TMath.h>
66#include <TCanvas.h>
67#include <TRandom.h>
68#include <TInterpreter.h>
69
70#include "MH.h"
71
72#include "MGeomPix.h"
73#include "MGeomCamCT1.h"
74#include "MGeomCamMagic.h"
75
76ClassImp(MagicDomino);
77
78using namespace std;
79
80// ------------------------------------------------------------------------
81//
82// Free all onbects connected to a special camera geometry
83//
84void MagicDomino::Free()
85{
86 if (!fGeomCam)
87 return;
88
89 delete fGeomCam;
90}
91
92// ------------------------------------------------------------------------
93//
94// Change camera from Magic to CT1 and back
95//
96void MagicDomino::ChangeCamera()
97{
98 static Bool_t ct1=kFALSE;
99
100 cout << "Change to " << (ct1?"Magic":"CT1") << endl;
101
102 if (ct1)
103 SetNewCamera(new MGeomCamMagic);
104 else
105 SetNewCamera(new MGeomCamCT1);
106
107 ct1 = !ct1;
108
109 Reset();
110 AppendPad();
111}
112
113// ------------------------------------------------------------------------
114//
115// Reset/set all veriables needed for a new camera geometry
116//
117void MagicDomino::SetNewCamera(MGeomCam *geom)
118{
119 Free();
120
121 //
122 // Set new camera
123 //
124 fGeomCam = geom;
125
126 //
127 // create the hexagons of the display
128 //
129 fNumPixels = fGeomCam->GetNumPixels();
130 fRange = fGeomCam->GetMaxRadius();
131
132 fColors.Set(fNumPixels);
133}
134
135// ------------------------------------------------------------------------
136//
137// remove the pixel numbers in the tile from the pad
138//
139void MagicDomino::RemoveNumbers()
140{
141 for (int i=0; i<6; i++)
142 fText[i]->SetText(0, 0, "");
143}
144
145// ------------------------------------------------------------------------
146//
147// Reset/restart the game
148//
149void MagicDomino::Reset()
150{
151 for (UInt_t i=0; i<fNumPixels; i++)
152 {
153 fColors[i] = kBackground;
154 (*fGeomCam)[i].ResetBit(kUserBits);
155 }
156
157
158#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
159 SetBit(kNoContextMenu);
160#endif
161
162 if (fDone)
163 {
164 delete fDone;
165 fDone = NULL;
166 }
167
168
169 gPad->SetFillColor(22);
170
171 fNumPixel = -1;
172 fNumTile = 0;
173 fPoints = 0;
174
175 NewTile();
176}
177
178// ------------------------------------------------------------------------
179//
180void MagicDomino::Init()
181{
182 for (int i=0; i<6; i++)
183 {
184 fText[i] = new TText(0, 0, "");
185 fText[i]->SetTextFont(122);
186 fText[i]->SetTextAlign(22); // centered/centered
187 }
188
189 //
190 // Make sure, that the object is destroyed when the canvas/pad is
191 // destroyed. Make also sure, that the interpreter doesn't try to
192 // delete it a second time.
193 //
194 SetBit(kCanDelete);
195 gInterpreter->DeleteGlobal(this);
196
197 Draw();
198}
199
200// ------------------------------------------------------------------------
201//
202// default constructor
203//
204MagicDomino::MagicDomino()
205 : fGeomCam(NULL), fDir(kBottom), fDone(NULL)
206{
207 SetNewCamera(new MGeomCamMagic);
208 Init();
209}
210// ------------------------------------------------------------------------
211//
212//
213MagicDomino::MagicDomino(const MGeomCam &geom)
214 : fGeomCam(NULL), fDir(kBottom), fDone(NULL)
215{
216 SetNewCamera(static_cast<MGeomCam*>(geom.Clone()));
217 Init();
218}
219
220// ------------------------------------------------------------------------
221//
222// Destructor. Deletes TClonesArrays for hexagons and legend elements.
223//
224MagicDomino::~MagicDomino()
225{
226 Free();
227
228 RemoveNumbers();
229}
230
231// ------------------------------------------------------------------------
232//
233// This is called at any time the canvas should get repainted.
234// Here we maintain an aspect ratio of 5/4=1.15. This makes sure,
235// that the camera image doesn't get distorted by resizing the canvas.
236//
237void MagicDomino::Paint(Option_t *opt)
238{
239 const Float_t r = fGeomCam->GetMaxRadius();
240
241 MH::SetPadRange(-r, -r, r, r*1.1);
242
243 TAttLine line;
244 TAttFill fill;
245
246 // FIXME:
247 for (UInt_t i=0; i<fNumPixels; i++)
248 {
249 const MGeom &pix = (*fGeomCam)[i];
250
251 fill.SetFillColor(fColors[i]);
252 pix.PaintPrimitive(line, fill);
253 }
254
255 for (int i=0; i<6; i++)
256 fText[i]->Paint();
257}
258
259// ------------------------------------------------------------------------
260//
261// Call this function to draw the camera layout into your canvas.
262// Setup a drawing canvas. Add this object and all child objects
263// (hexagons, etc) to the current pad. If no pad exists a new one is
264// created.
265//
266void MagicDomino::Draw(Option_t *option)
267{
268 //
269 // if no canvas is yet existing to draw into, create a new one
270 //
271 new TCanvas("MagicDomino", "Magic Domino Next Neighbours", 0, 0, 800, 800);
272
273 gPad->SetBorderMode(0);
274
275 //
276 // Append this object, so that the aspect ratio is maintained
277 // (Paint-function is called)
278 //
279 AppendPad(option);
280
281 //
282 // Reset the game pad
283 //
284 Reset();
285
286 fDomino.SetTextAlign(23); // centered/bottom
287#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
288 fDomino.SetBit(kNoContextMenu|kCannotPick);
289#endif
290 fDomino.Draw();
291}
292
293void MagicDomino::Update()
294{
295 TString txt = "Points: ";
296 txt += fPoints;
297 txt += " Tile: ";
298 txt += fNumTile;
299
300 switch (fSkipped)
301 {
302 case 0:
303 fDomino.SetTextColor(8/*kGreen*/);
304 break;
305 case 1:
306 fDomino.SetTextColor(kYellow);
307 break;
308 case 2:
309 fDomino.SetTextColor(kRed);
310 break;
311 default:
312 fDomino.SetTextColor(kWhite);
313 break;
314 }
315 fDomino.SetText(0, fRange, txt);
316}
317
318// ------------------------------------------------------------------------
319//
320// Choose new colors for the tile
321//
322void MagicDomino::NewColors()
323{
324 TRandom rnd(0);
325 for (int i=0; i<3; i++)
326 {
327 Int_t color = (Int_t)rnd.Uniform(5)+2;
328 fNewColors[i*2] = color;
329 fNewColors[i*2+1] = color;
330 }
331}
332
333// ------------------------------------------------------------------------
334//
335// Create a new tile
336//
337void MagicDomino::NewTile()
338{
339 if (fNumPixel>=0)
340 {
341 MGeom &pix=(*fGeomCam)[fNumPixel];
342 pix.ResetBit(kIsTile);
343 for (int i=0; i<pix.GetNumNeighbors(); i++)
344 (*fGeomCam)[pix.GetNeighbor(i)].ResetBit(kIsTile);
345
346 fPoints += pix.GetNumNeighbors();
347 }
348
349 RemoveNumbers();
350
351 fNumPixel = -1;
352 fSkipped = 0;
353 fNumTile++;
354
355 NewColors();
356 Update();
357
358 gPad->Update();
359}
360
361// ------------------------------------------------------------------------
362//
363// Check for at least one correct color for each pixel in tile.
364// Ignore the tile itself and all background pixels. Check whether
365// background of tile is empty.
366//
367Bool_t MagicDomino::CheckTile()
368{
369 if (fNumPixel<0)
370 return kFALSE;
371
372 for (int i=0; i<7; i++)
373 if (fOldColors[i]!=kBackground)
374 return kFALSE;
375
376 Int_t cnt=0;
377 const MGeom &pix1=(*fGeomCam)[fNumPixel];
378 for (int i=0; i<pix1.GetNumNeighbors(); i++)
379 {
380 const Int_t idx1 = pix1.GetNeighbor(i);
381 const MGeom &pix2 = (*fGeomCam)[idx1];
382
383 Byte_t ignored = 0;
384 Byte_t found = 0;
385 for (int j=0; j<pix2.GetNumNeighbors(); j++)
386 {
387 const Int_t idx2 = pix2.GetNeighbor(j);
388 const MGeom &hex = (*fGeomCam)[idx2];
389
390 if (hex.TestBit(kIsTile) || fColors[idx2]==kBackground)
391 {
392 ignored++;
393 continue;
394 }
395
396 if (fColors[idx2]==fColors[idx1])
397 found++;
398 }
399 if (ignored==pix2.GetNumNeighbors() || found>0)
400 cnt++;
401 }
402
403 return cnt==pix1.GetNumNeighbors();
404}
405
406// ------------------------------------------------------------------------
407//
408// Game over!
409//
410void MagicDomino::Done()
411{
412 fDone = new TText(0, 0, "Game Over!");
413 fDone->SetTextColor(kWhite); // white
414 fDone->SetTextAlign(22); // centered/centered
415 fDone->SetTextSize(0.05); // white
416 fDone->Draw();
417
418 fDomino.SetTextColor(kBlue);
419
420 gPad->SetFillColor(kRed);
421#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
422 fDone->SetBit(kNoContextMenu|kCannotPick);
423 ResetBit(kNoContextMenu);
424#endif
425
426 gPad->Modified();
427 gPad->Update();
428}
429
430// ------------------------------------------------------------------------
431//
432// Execute a mouse event on the camera
433//
434void MagicDomino::ExecuteEvent(Int_t event, Int_t keycode, Int_t keysym)
435{
436 if (event!=kKeyPress || fDone)
437 return;
438
439 switch (keysym)
440 {
441 case kKey_Escape:
442 fPoints -= 6;
443 fSkipped++;
444 if (fSkipped==3)
445 {
446 Done();
447 return;
448 }
449 NewColors();
450 RotateTile(0);
451 return;
452
453 case kKey_Space:
454 RotateTile(-1);
455 return;
456
457 case kKey_Return:
458 if (CheckTile())
459 NewTile();
460 return;
461
462 case kKey_Right:
463 fDir = kRight;
464 Step(kRight);
465 return;
466
467 case kKey_Left:
468 fDir = kLeft;
469 Step(kLeft);
470 return;
471
472 case kKey_Up:
473 Step(kTop|fDir);
474 return;
475
476 case kKey_Down:
477 Step(kBottom|fDir);
478 return;
479
480 case kKey_Plus:
481 RotateTile(+1);
482 return;
483
484 case kKey_Minus:
485 RotateTile(-1);
486 return;
487 }
488}
489
490// ------------------------------------------------------------------------
491//
492// Rotate the colors in the tile
493//
494void MagicDomino::RotateTile(Int_t add)
495{
496 fPosition += add+6; // Make result positive
497 fPosition %= 6; // Align result between 0 and 5
498
499 HideTile();
500 ShowTile();
501
502 Update();
503
504 gPad->Modified();
505 gPad->Update();
506}
507
508// ------------------------------------------------------------------------
509//
510// Hide the tile from the pad
511//
512void MagicDomino::HideTile()
513{
514 if (fNumPixel<0)
515 return;
516
517 RemoveNumbers();
518
519 MGeom &pix1=(*fGeomCam)[fNumPixel];
520 fColors[fNumPixel] = fOldColors[6];
521 pix1.ResetBit(kIsTile);
522 for (int i=0; i<pix1.GetNumNeighbors(); i++)
523 {
524 Int_t idx = pix1.GetNeighbor(i);
525
526 fColors[idx] = fOldColors[i];
527 (*fGeomCam)[idx].ResetBit(kIsTile);
528 }
529}
530
531// ------------------------------------------------------------------------
532//
533// Show the tile on the pad
534//
535void MagicDomino::ShowTile()
536{
537 if (fNumPixel<0)
538 return;
539
540 Int_t indices[6];
541 GetSortedNeighbors(indices);
542
543 RemoveNumbers();
544
545 MGeom &pix2=(*fGeomCam)[fNumPixel];
546 fOldColors[6] = fColors[fNumPixel];
547 fColors[fNumPixel] = kBlack;
548 pix2.SetBit(kIsTile);
549 for (int i=0; i<pix2.GetNumNeighbors(); i++)
550 {
551 Int_t idx = pix2.GetNeighbor(i);
552
553 fOldColors[i] = fColors[idx];
554
555 int j=0;
556 while (indices[j]!=i)
557 j++;
558
559 MGeom &pix = (*fGeomCam)[idx];
560
561 fColors[idx] = fNewColors[(j+fPosition)%6];
562 pix.SetBit(kIsTile);
563
564 TString num;
565 num += idx;
566
567 fText[i]->SetText(pix.GetX(), pix.GetY(), num);
568 fText[i]->SetTextSize(0.3*pix.GetT()/fGeomCam->GetMaxRadius());
569 }
570}
571
572// ------------------------------------------------------------------------
573//
574// Hide the tile, change its position, show it again, update status text
575//
576void MagicDomino::ChangePixel(Int_t add)
577{
578 HideTile();
579
580 fNumPixel = add;
581
582 ShowTile();
583
584 Update();
585
586 gPad->Update();
587}
588
589// ------------------------------------------------------------------------
590//
591// Analyse the directions of the next neighbors
592//
593Short_t MagicDomino::AnalysePixel(Int_t dir)
594{
595 const MGeom &pix=(*fGeomCam)[fNumPixel<0?0:fNumPixel];
596
597 Double_t fAngle[6] = { -10, -10, -10, -10, -10, -10 };
598
599 for (int i=0; i<pix.GetNumNeighbors(); i++)
600 {
601 MGeom &next = (*fGeomCam)[pix.GetNeighbor(i)];
602 fAngle[i] = atan2(next.GetY()-pix.GetY(), next.GetX()-pix.GetX());
603 }
604
605 Int_t indices[6];
606 TMath::Sort(6, fAngle, indices); // left, top, right, bottom
607
608 for (int i=0; i<pix.GetNumNeighbors(); i++)
609 {
610 const Int_t idx = pix.GetNeighbor(indices[i]);
611 const Double_t angle = fAngle[indices[i]]*180/TMath::Pi();
612
613 if (angle<-149 && dir==kLeft)
614 return idx;
615 if (angle>-149 && angle<-90 && dir==kBottomLeft)
616 return idx;
617 //if (angle==-90 && dir==kBottom)
618 // return idx;
619 if (angle>-90 && angle<-31 && dir==kBottomRight)
620 return idx;
621 if (angle>-31 && angle<31 && dir==kRight)
622 return idx;
623 if (angle>31 && angle<90 && dir==kTopRight)
624 return idx;
625 //if (angle==90 && dir==kTop)
626 // return idx;
627 if (angle>90 && angle<149 && dir==kTopLeft)
628 return idx;
629 if (angle>149 && dir==kLeft)
630 return idx;
631 }
632 return -1;
633}
634
635// ------------------------------------------------------------------------
636//
637// Sort the next neighbort from the left, top, right, bottom
638//
639void MagicDomino::GetSortedNeighbors(Int_t indices[6])
640{
641 const MGeom &pix=(*fGeomCam)[fNumPixel<0?0:fNumPixel];
642
643 Double_t fAngle[6] = { -10, -10, -10, -10, -10, -10 };
644
645 for (int i=0; i<pix.GetNumNeighbors(); i++)
646 {
647 MGeom &next = (*fGeomCam)[pix.GetNeighbor(i)];
648 fAngle[i] = atan2(next.GetY()-pix.GetY(), next.GetX()-pix.GetX());
649 }
650
651 TMath::Sort(6, fAngle, indices); // left, top, right, bottom
652}
653
654// ------------------------------------------------------------------------
655//
656// Move tile one step in the given direction
657//
658void MagicDomino::Step(Int_t dir)
659{
660 Short_t newidx = AnalysePixel(dir);
661 if (newidx<0)
662 return;
663 ChangePixel(newidx);
664}
665
Note: See TracBrowser for help on using the repository browser.