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

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