source: trunk/MagicSoft/Mars/mtools/MagicReversi.cc@ 1880

Last change on this file since 1880 was 1880, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 14.3 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 03/2003 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2003
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MagicReversi
28// ------------
29//
30// Camera Display Games: Reversi
31//
32// Start the game by:
33// MagicReversi reversi;
34//
35////////////////////////////////////////////////////////////////////////////
36#include "MagicReversi.h"
37
38#include <iostream.h>
39
40#include <TText.h>
41#include <TMarker.h>
42#include <TRandom.h>
43#include <TCanvas.h>
44#include <TClonesArray.h>
45#include <TInterpreter.h>
46
47#include "MHexagon.h"
48
49#include "MGeomPix.h"
50#include "MGeomCamCT1.h"
51#include "MGeomCamMagic.h"
52
53ClassImp(MagicReversi);
54/*
55const Int_t MagicReversi::fColorBombs[7] = {
56 22,
57 kYellow,
58 kGreen,
59 kBlue,
60 kCyan,
61 kMagenta,
62 kRed
63};
64*/
65void MagicReversi::Free()
66{
67 if (!fGeomCam)
68 return;
69
70 fPixels->Delete();
71 fText->Delete();
72 fFlags->Delete();
73
74 delete fText;
75 delete fFlags;
76 delete fPixels;
77
78 delete fGeomCam;
79}
80
81void MagicReversi::ChangeCamera()
82{
83 static Bool_t ct1=kFALSE;
84
85 cout << "Change to " << (ct1?"Magic":"CT1") << endl;
86
87 if (ct1)
88 SetNewCamera(new MGeomCamMagic);
89 else
90 SetNewCamera(new MGeomCamCT1);
91
92 ct1 = !ct1;
93
94 Reset();
95 DrawHexagons();
96}
97
98void MagicReversi::SetNewCamera(MGeomCam *geom)
99{
100 Free();
101
102 //
103 // Reset the display geometry
104 //
105 fW=0;
106 fH=0;
107
108 //
109 // Set new camera
110 //
111 fGeomCam = geom;
112
113 //
114 // create the hexagons of the display
115 //
116 fNumPixels = fGeomCam->GetNumPixels();
117 fRange = fGeomCam->GetMaxRadius();
118
119 //
120 // Construct all hexagons. Use new-operator with placement
121 //
122// fNumBombs = fNumPixels/5;
123
124 fText = new TClonesArray("TText", fNumPixels);
125 fFlags = new TClonesArray("TMarker", fNumPixels);
126 fPixels = new TClonesArray("MHexagon", fNumPixels);
127
128 for (UInt_t i=0; i<fNumPixels; i++)
129 {
130 MHexagon &h = *new ((*fPixels)[i]) MHexagon((*fGeomCam)[i]);
131#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
132 h.SetBit(kNoContextMenu|kCannotPick);
133#endif
134
135 TText &t = *new ((*fText)[i]) TText;
136 t.SetTextFont(122);
137 t.SetTextAlign(22); // centered/centered
138 t.SetTextSize(0.3*h.GetD()/fRange);
139#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
140 t.SetBit(kNoContextMenu|kCannotPick);
141#endif
142
143 const MGeomPix &pix = (*fGeomCam)[i];
144
145 TMarker &m = *new ((*fFlags)[i]) TMarker(pix.GetX(), pix.GetY(), kOpenStar);
146#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
147 m.SetBit(kNoContextMenu|kCannotPick);
148#endif
149 }
150}
151
152// ------------------------------------------------------------------------
153//
154// Draw all pixels of the camera
155// (means apend all pixelobjects to the current pad)
156//
157void MagicReversi::DrawHexagons()
158{
159 for (UInt_t i=0; i<fNumPixels; i++)
160 (*this)[i].Draw();
161}
162
163// ------------------------------------------------------------------------
164//
165// default constructor
166//
167MagicReversi::MagicReversi()
168 : fGeomCam(NULL), fDone(NULL), fW(0), fH(0), fDrawingPad(NULL), fIsAllocated(kFALSE)
169{
170 SetNewCamera(new MGeomCamCT1);
171
172 //
173 // Make sure, that the object is destroyed when the canvas/pad is
174 // destroyed. Make also sure, that the interpreter doesn't try to
175 // delete it a second time.
176 //
177 SetBit(kCanDelete);
178 gInterpreter->DeleteGlobal(this);
179
180 Draw();
181}
182
183// ------------------------------------------------------------------------
184//
185// Destructor. Deletes TClonesArrays for hexagons and legend elements.
186//
187MagicReversi::~MagicReversi()
188{
189 Free();
190
191 for (int i=0; i<6; i++)
192 delete fUsrTxt[i];
193
194 if (fDone)
195 delete fDone;
196
197 if (fDrawingPad->GetListOfPrimitives()->FindObject(this)==this)
198 {
199 fDrawingPad->RecursiveRemove(this);
200 delete fDrawingPad;
201 }
202}
203
204// ------------------------------------------------------------------------
205//
206// This is called at any time the canvas should get repainted.
207// Here we maintain an aspect ratio of 5/4=1.15. This makes sure,
208// that the camera image doesn't get distorted by resizing the canvas.
209//
210void MagicReversi::Paint(Option_t *opt)
211{
212 const UInt_t w = (UInt_t)(gPad->GetWw()*gPad->GetAbsWNDC());
213 const UInt_t h = (UInt_t)(gPad->GetWh()*gPad->GetAbsHNDC());
214
215 //
216 // Check for a change in width or height, and make sure, that the
217 // first call also sets the range
218 //
219 if (w*fH == h*fW && fW && fH)
220 return;
221
222 //
223 // Calculate aspect ratio (5/4=1.25 recommended)
224 //
225 const Double_t ratio = (Double_t)w/h;
226
227 Float_t x;
228 Float_t y;
229
230 if (ratio>1.0)
231 {
232 x = fRange*(ratio*2-1);
233 y = fRange;
234 }
235 else
236 {
237 x = fRange;
238 y = fRange/ratio;
239 }
240
241 fH = h;
242 fW = w;
243
244 //
245 // Set new range
246 //
247 fDrawingPad->Range(-fRange, -y, x, y);
248
249 //
250 // Adopt absolute sized of markers to relative range
251 //
252 for (UInt_t i=0; i<fNumPixels; i++)
253 {
254 Float_t r = (*this)[i].GetD()*gPad->XtoAbsPixel(1)/325;
255 GetFlag(i)->SetMarkerSize(20.0*r/fRange);
256 }
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 MagicReversi::Draw(Option_t *option)
267{
268 // root 3.02:
269 // gPad->SetFixedAspectRatio()
270
271 if (fDrawingPad)
272 return;
273
274 //
275 // if no canvas is yet existing to draw into, create a new one
276 //
277 if (!gPad)
278 {
279 /*TCanvas *c =*/ new TCanvas("MagicReversi", "Magic Reversi", 0, 0, 800, 800);
280 //c->ToggleEventStatus();
281 fIsAllocated = kTRUE;
282 }
283 else
284 fIsAllocated = kFALSE;
285
286 fDrawingPad = gPad;
287 fDrawingPad->SetBorderMode(0);
288
289 //
290 // Append this object, so that the aspect ratio is maintained
291 // (Paint-function is called)
292 //
293 AppendPad(option);
294
295 //
296 // Draw the title text
297 //
298 for (int i=0; i<6; i++)
299 {
300 fUsrTxt[i] = new TText;
301 fUsrTxt[i]->SetTextAlign(13); // left/bottom
302 fUsrTxt[i]->SetTextSize(0.03);
303 fUsrTxt[i]->SetTextColor(kRed+i);
304#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
305 fUsrTxt[i]->SetBit(kNoContextMenu|kCannotPick);
306#endif
307 fUsrTxt[i]->Draw();
308 }
309
310 //
311 // Reset the game pad
312 //
313 Reset();
314 DrawHexagons();
315}
316
317void MagicReversi::Update()
318{
319 for (int i=0; i<fNumUsers; i++)
320 {
321 TString txt = "Pixels: ";
322 txt += fUsrPts[i];
323
324 if (fNumUser==i)
325 txt += " <*>";
326
327 fUsrTxt[i]->SetText(-fRange*0.95, fRange-(i+1)*fRange*0.06, txt);
328 }
329}
330
331// ------------------------------------------------------------------------
332//
333// reset the all pixel colors to a default value
334//
335void MagicReversi::Reset()
336{
337 if (fDone)
338 {
339 delete fDone;
340 fDone = NULL;
341 }
342
343 for (UInt_t i=0; i<fNumPixels; i++)
344 {
345 Remove(GetText(i));
346 Remove(GetFlag(i));
347
348 (*this)[i].SetFillColor(kEmpty);
349 (*fGeomCam)[i].ResetBit(kUserBits);
350
351 GetFlag(i)->SetMarkerColor(kBlack);
352 }
353
354 fNumUsers = 2; // not more than 6!
355 fNumUser = 0;
356
357 for (int i=0; i<6; i++)
358 fUsrPts[i]=0;
359
360 for (int i=1; i<5*fNumUsers; i++)
361 {
362 (*this)[i-1].SetFillColor(i%fNumUsers+kRed);
363 fUsrPts[i%fNumUsers]++;
364 }
365
366 Update();
367
368 fDrawingPad->SetFillColor(22);
369
370#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
371 fDrawingPad->SetBit(kNoContextMenu);
372 SetBit(kNoContextMenu);
373#endif
374}
375
376void MagicReversi::Done()
377{
378 Int_t max = 0;
379 Int_t winner = 0;
380
381 for (int i=0; i<6; i++)
382 if (fUsrPts[i]>max)
383 {
384 winner = i;
385 max = fUsrPts[i];
386 }
387
388 TString txt = "Player #";
389 txt += winner;
390 txt += " wins (";
391 txt += max;
392 txt += ")";
393
394 fDone = new TText(0, 0, txt);
395 fDone->SetTextColor(kWhite);
396 fDone->SetTextAlign(22);
397 fDone->SetTextSize(0.05);
398#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
399 fDone->SetBit(kNoContextMenu|kCannotPick);
400#endif
401 fDone->Draw();
402
403 fDrawingPad->SetFillColor(winner+kRed);
404
405#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
406 fDrawingPad->ResetBit(kNoContextMenu);
407 ResetBit(kNoContextMenu);
408#endif
409}
410
411void MagicReversi::Remove(TObject *obj)
412{
413 fDrawingPad->RecursiveRemove(obj);
414}
415
416Int_t MagicReversi::GetDirection(Int_t src, Int_t dst) const
417{
418 const MGeomPix &pix1=(*fGeomCam)[dst];
419 const MGeomPix &pix2=(*fGeomCam)[src];
420
421 const Double_t x1 = pix1.GetX();
422 const Double_t y1 = pix1.GetY();
423
424 const Double_t x2 = pix2.GetX();
425 const Double_t y2 = pix2.GetY();
426
427 if (x1>=x2 && y1>y2) return kRightTop;
428 if (x1>=x2 && y1<y2) return kRightBottom;
429 if (x1<=x2 && y1>y2) return kLeftTop;
430 if (x1<=x2 && y1<y2) return kLeftBottom;
431 if (x1>x2) return kRight;
432 if (x1<x2) return kLeft;
433
434 return -1;
435}
436
437Int_t MagicReversi::GetNeighbor(Int_t idx, Int_t dir) const
438{
439 MGeomPix &pix=(*fGeomCam)[idx];
440
441 //
442 // search for the neighbor in the given direction
443 //
444 int i;
445 for (i=0; i<pix.GetNumNeighbors(); i++)
446 if (GetDirection(idx, pix.GetNeighbor(i))==dir)
447 return pix.GetNeighbor(i);
448
449 return -1;
450}
451
452Bool_t MagicReversi::Flip(Int_t origidx, Bool_t flip)
453{
454 const Int_t col = kRed+fNumUser;
455
456 int test[6] = {0,0,0,0,0,0};
457
458 for (int dir=kRightTop; dir<=kLeftTop; dir++)
459 {
460 Int_t idx = origidx;
461 Int_t length = 0;
462
463 while (1)
464 {
465 idx = GetNeighbor(idx, dir);
466 if (idx<0 || (*this)[idx].GetFillColor()==kEmpty)
467 break;
468
469 if ((*this)[idx].GetFillColor()==col)
470 {
471 if (length!=0)
472 test[dir] = length;
473 break;
474 }
475
476 length++;
477 }
478 }
479
480 int cnt = 0;
481
482 for (int dir=kRightTop; dir<=kLeftTop; dir++)
483 {
484 Int_t idx = origidx;
485
486 if (test[dir])
487 cnt++;
488
489 if (flip)
490 for (int i=0; i<test[dir]; i++)
491 {
492 idx = GetNeighbor(idx, dir);
493
494 fUsrPts[(*this)[idx].GetFillColor()-kRed]--;
495 fUsrPts[fNumUser]++;
496
497 (*this)[idx].SetFillColor(col);
498 }
499 }
500
501 return cnt ? kTRUE : kFALSE;
502}
503
504Bool_t MagicReversi::CheckMoves()
505{
506 for (unsigned int i=0; i<fNumPixels; i++)
507 if ((*this)[i].GetFillColor()==kEmpty && Flip(i, kFALSE))
508 return kTRUE;
509 return kFALSE;
510}
511
512// ------------------------------------------------------------------------
513//
514// Execute a mouse event on the camera
515//
516void MagicReversi::ExecuteEvent(Int_t event, Int_t px, Int_t py)
517{
518 if (event==kMouseMotion || event==kMouseEnter || event==kMouseLeave ||
519 event==kButton1Up || event==kButton2Up || event==kButton3Up ||
520 event==kButton1Motion || event==kButton2Motion || event==kButton3Motion ||
521 event==kButton2Double || event==kButton3Double ||
522 fDone)
523 return;
524
525 UInt_t idx;
526 for (idx=0; idx<fNumPixels; idx++)
527 if ((*fPixels)[idx]->DistancetoPrimitive(px, py)==0)
528 break;
529
530 if (idx==fNumPixels)
531 return;
532
533 if (event==kButton1Down && (*this)[idx].GetFillColor()==kEmpty)
534 {
535 if (!Flip(idx, kTRUE))
536 return;
537
538 fUsrPts[fNumUser]++;
539
540 (*this)[idx].SetFillColor(kRed+fNumUser);
541
542 Int_t start = fNumUser;
543
544 fNumUser++;
545 fNumUser%=fNumUsers;
546
547 while (!CheckMoves())
548 {
549 cout << "Sorry, no moves possible!" << endl;
550 fNumUser++;
551 fNumUser%=fNumUsers;
552
553 if (fNumUser==start)
554 Done();
555 }
556
557 Update();
558 }
559
560 fDrawingPad->Modified();
561
562 /*
563 if (event==kKeyPress && py==0x1000)
564 {
565 Reset();
566 return;
567 }
568 */
569 /*
570 UInt_t idx;
571 for (idx=0; idx<fNumPixels; idx++)
572 if ((*fPixels)[idx]->DistancetoPrimitive(px, py)==0)
573 break;
574
575 if (idx==fNumPixels)
576 return;
577
578 MGeomPix &pix=(*fGeomCam)[idx];
579
580 if (event==kButton1Double)
581 {
582 OpenHexagon(idx);
583
584 if (pix.TestBit(kHasBomb))
585 Done("Argh... you hit the Bomb!!!", kRed);
586 }
587
588 if (event==kButton1Down && !pix.TestBit(kIsVisible))
589 {
590 if (pix.TestBit(kHasFlag))
591 Remove(GetFlag(idx));
592 else
593 GetFlag(idx)->Draw();
594
595 pix.InvertBit(kHasFlag);
596 }
597
598 UInt_t vis=fNumBombs;
599 UInt_t flg=fNumBombs;
600 for (UInt_t i=0; i<fNumPixels; i++)
601 {
602 if ((*fGeomCam)[i].TestBit(kIsVisible))
603 vis++;
604 if ((*fGeomCam)[i].TestBit(kHasFlag))
605 flg--;
606 }
607
608 Update(flg);
609
610 if (vis==fNumPixels && !fDone)
611 Done("Great! Congratulations, you did it!", kGreen);
612
613 fDrawingPad->Modified();
614 */
615 /*
616 switch (event)
617 {
618 case kNoEvent: cout << "No Event" << endl; break;
619 case kButton1Down: cout << "Button 1 down" << endl; break;
620 case kButton2Down: cout << "Button 2 down" << endl; break;
621 case kButton3Down: cout << "Button 3 down" << endl; break;
622 case kKeyDown: cout << "Key down" << endl; break;
623 case kKeyUp: cout << "Key up" << endl; break;
624 case kKeyPress: cout << "Key press" << endl; break;
625 case kButton1Locate: cout << "Button 1 locate" << endl; break;
626 case kButton2Locate: cout << "Button 2 locate" << endl; break;
627 case kButton3Locate: cout << "Button 3 locate" << endl; break;
628 }
629 */
630}
Note: See TracBrowser for help on using the repository browser.