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

Last change on this file since 8983 was 8756, checked in by tbretz, 17 years ago
*** empty log message ***
File size: 13.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// 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
183void MagicReversi::Init()
184{
185 //
186 // Make sure, that the object is destroyed when the canvas/pad is
187 // destroyed. Make also sure, that the interpreter doesn't try to
188 // delete it a second time.
189 //
190 SetBit(kCanDelete);
191 gInterpreter->DeleteGlobal(this);
192
193 fNumUsers = 2;
194
195 Draw();
196}
197
198// ------------------------------------------------------------------------
199//
200// default constructor
201//
202MagicReversi::MagicReversi()
203 : fGeomCam(NULL), fDone(NULL), fW(0), fH(0), fDrawingPad(NULL), fIsAllocated(kFALSE)
204{
205 SetNewCamera(new MGeomCamMagic);
206
207 Init();
208}
209
210MagicReversi::MagicReversi(const MGeomCam &geom)
211 : fGeomCam(NULL), fDone(NULL), fW(0), fH(0), fDrawingPad(NULL), fIsAllocated(kFALSE)
212{
213 SetNewCamera(static_cast<MGeomCam*>(geom.Clone()));
214
215 Init();
216}
217
218// ------------------------------------------------------------------------
219//
220// Destructor. Deletes TClonesArrays for hexagons and legend elements.
221//
222MagicReversi::~MagicReversi()
223{
224 Free();
225
226 for (int i=0; i<6; i++)
227 delete fUsrTxt[i];
228
229 if (fDone)
230 delete fDone;
231
232 if (fDrawingPad->GetListOfPrimitives()->FindObject(this)==this)
233 {
234 fDrawingPad->RecursiveRemove(this);
235 delete fDrawingPad;
236 }
237}
238
239// ------------------------------------------------------------------------
240//
241// This is called at any time the canvas should get repainted.
242// Here we maintain an aspect ratio of 5/4=1.15. This makes sure,
243// that the camera image doesn't get distorted by resizing the canvas.
244//
245void MagicReversi::Paint(Option_t *opt)
246{
247 const UInt_t w = (UInt_t)(gPad->GetWw()*gPad->GetAbsWNDC());
248 const UInt_t h = (UInt_t)(gPad->GetWh()*gPad->GetAbsHNDC());
249
250 //
251 // Check for a change in width or height, and make sure, that the
252 // first call also sets the range
253 //
254 if (w*fH == h*fW && fW && fH)
255 return;
256
257 //
258 // Calculate aspect ratio (5/4=1.25 recommended)
259 //
260 const Double_t ratio = (Double_t)w/h;
261
262 Float_t x;
263 Float_t y;
264
265 if (ratio>1.0)
266 {
267 x = fRange*(ratio*2-1);
268 y = fRange;
269 }
270 else
271 {
272 x = fRange;
273 y = fRange/ratio;
274 }
275
276 fH = h;
277 fW = w;
278
279 //
280 // Set new range
281 //
282 fDrawingPad->Range(-fRange, -y, x, y);
283
284 //
285 // Adopt absolute sized of markers to relative range
286 //
287 for (UInt_t i=0; i<fNumPixels; i++)
288 {
289 Float_t r = (*this)[i].GetD()*gPad->XtoAbsPixel(1)/325;
290 GetFlag(i)->SetMarkerSize(20.0*r/fRange);
291 }
292}
293
294// ------------------------------------------------------------------------
295//
296// Call this function to draw the camera layout into your canvas.
297// Setup a drawing canvas. Add this object and all child objects
298// (hexagons, etc) to the current pad. If no pad exists a new one is
299// created.
300//
301void MagicReversi::Draw(Option_t *option)
302{
303 // root 3.02:
304 // gPad->SetFixedAspectRatio()
305
306 if (fDrawingPad)
307 return;
308
309 //
310 // if no canvas is yet existing to draw into, create a new one
311 //
312 if (!gPad)
313 {
314 /*TCanvas *c =*/ new TCanvas("MagicReversi", "Magic Reversi", 0, 0, 800, 800);
315 //c->ToggleEventStatus();
316 fIsAllocated = kTRUE;
317 }
318 else
319 fIsAllocated = kFALSE;
320
321 fDrawingPad = gPad;
322 fDrawingPad->SetBorderMode(0);
323
324 //
325 // Append this object, so that the aspect ratio is maintained
326 // (Paint-function is called)
327 //
328 AppendPad(option);
329
330 //
331 // Draw the title text
332 //
333 for (int i=0; i<6; i++)
334 {
335 fUsrTxt[i] = new TText;
336 fUsrTxt[i]->SetTextAlign(13); // left/bottom
337 fUsrTxt[i]->SetTextSize(0.03);
338 fUsrTxt[i]->SetTextColor(kRed+i);
339#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
340 fUsrTxt[i]->SetBit(kNoContextMenu|kCannotPick);
341#endif
342 fUsrTxt[i]->Draw();
343 }
344
345 //
346 // Reset the game pad
347 //
348 Reset();
349 DrawHexagons();
350}
351
352void MagicReversi::Update()
353{
354 int i;
355 for (i=0; i<fNumUsers; i++)
356 {
357 TString txt = "Pixels: ";
358 txt += fUsrPts[i];
359
360 if (fNumUser==i)
361 txt += " <*>";
362
363 fUsrTxt[i]->SetText(-fRange*0.95, fRange-(i+1)*fRange*0.06, txt);
364 }
365 for (; i<6; i++)
366 fUsrTxt[i]->SetText(0, 0, "");
367}
368
369void MagicReversi::TwoPlayer()
370{
371 fNumUsers = 2;
372 Reset();
373}
374
375void MagicReversi::ThreePlayer()
376{
377 fNumUsers = 3;
378 Reset();
379}
380
381void MagicReversi::FourPlayer()
382{
383 fNumUsers = 4;
384 Reset();
385}
386
387void MagicReversi::FivePlayer()
388{
389 fNumUsers = 5;
390 Reset();
391}
392
393void MagicReversi::SixPlayer()
394{
395 fNumUsers = 6;
396 Reset();
397}
398
399// ------------------------------------------------------------------------
400//
401// reset the all pixel colors to a default value
402//
403void MagicReversi::Reset()
404{
405 if (fDone)
406 {
407 delete fDone;
408 fDone = NULL;
409 }
410
411 for (UInt_t i=0; i<fNumPixels; i++)
412 {
413 Remove(GetText(i));
414 Remove(GetFlag(i));
415
416 (*this)[i].SetFillColor(kEmpty);
417 (*fGeomCam)[i].ResetBit(kUserBits);
418
419 GetFlag(i)->SetMarkerColor(kBlack);
420 }
421
422 fNumUser = 0;
423
424 for (int i=0; i<6; i++)
425 fUsrPts[i]=0;
426
427 for (int i=1; i<5*fNumUsers; i++)
428 {
429 (*this)[i-1].SetFillColor(i%fNumUsers+kRed);
430 fUsrPts[i%fNumUsers]++;
431 }
432
433 Update();
434
435 fDrawingPad->SetFillColor(22);
436
437#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
438 fDrawingPad->SetBit(kNoContextMenu);
439 SetBit(kNoContextMenu);
440#endif
441}
442
443void MagicReversi::Done()
444{
445 Int_t max = 0;
446 Int_t winner = 0;
447
448 for (int i=0; i<6; i++)
449 if (fUsrPts[i]>max)
450 {
451 winner = i;
452 max = fUsrPts[i];
453 }
454
455 TString txt = "Player #";
456 txt += winner+1;
457 txt += " wins (";
458 txt += max;
459 txt += ")";
460
461 fDone = new TText(0, 0, txt);
462 fDone->SetTextColor(kWhite);
463 fDone->SetTextAlign(22);
464 fDone->SetTextSize(0.05);
465#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
466 fDone->SetBit(kNoContextMenu|kCannotPick);
467#endif
468 fDone->Draw();
469
470 fDrawingPad->SetFillColor(winner+kRed);
471
472#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
473 fDrawingPad->ResetBit(kNoContextMenu);
474 ResetBit(kNoContextMenu);
475#endif
476}
477
478void MagicReversi::Remove(TObject *obj)
479{
480 fDrawingPad->RecursiveRemove(obj);
481}
482
483Bool_t MagicReversi::Flip(Int_t origidx, Bool_t flip)
484{
485 const Int_t col = kRed+fNumUser;
486
487 int test[6] = {0,0,0,0,0,0};
488
489 for (int dir=MGeomPix::kRightTop; dir<=MGeomPix::kLeftTop; dir++)
490 {
491 Int_t idx = origidx;
492 Int_t length = 0;
493
494 while (1)
495 {
496 idx = fGeomCam->GetNeighbor(idx, dir);
497 if (idx<0 || (*this)[idx].GetFillColor()==kEmpty)
498 break;
499
500 if ((*this)[idx].GetFillColor()==col)
501 {
502 if (length!=0)
503 test[dir] = length;
504 break;
505 }
506
507 length++;
508 }
509 }
510
511 int cnt = 0;
512
513 for (int dir=MGeomPix::kRightTop; dir<=MGeomPix::kLeftTop; dir++)
514 {
515 Int_t idx = origidx;
516
517 if (test[dir])
518 cnt++;
519
520 if (flip)
521 for (int i=0; i<test[dir]; i++)
522 {
523 idx = fGeomCam->GetNeighbor(idx, dir);
524
525 fUsrPts[(*this)[idx].GetFillColor()-kRed]--;
526 fUsrPts[fNumUser]++;
527
528 (*this)[idx].SetFillColor(col);
529 }
530 }
531
532 return cnt ? kTRUE : kFALSE;
533}
534
535Bool_t MagicReversi::CheckMoves()
536{
537 for (unsigned int i=0; i<fNumPixels; i++)
538 if ((*this)[i].GetFillColor()==kEmpty && Flip(i, kFALSE))
539 return kTRUE;
540 return kFALSE;
541}
542
543// ------------------------------------------------------------------------
544//
545// Execute a mouse event on the camera
546//
547void MagicReversi::ExecuteEvent(Int_t event, Int_t px, Int_t py)
548{
549 if (event==kMouseMotion || event==kMouseEnter || event==kMouseLeave ||
550 event==kButton1Up || event==kButton2Up || event==kButton3Up ||
551 event==kButton1Motion || event==kButton2Motion || event==kButton3Motion ||
552 event==kButton2Double || event==kButton3Double ||
553 fDone)
554 return;
555
556 if (event==kKeyPress && py==kKey_Escape)
557 {
558 Done();
559 fDrawingPad->Modified();
560 fDrawingPad->Update();
561 return;
562 }
563
564 UInt_t idx;
565 for (idx=0; idx<fNumPixels; idx++)
566 if ((*fPixels)[idx]->DistancetoPrimitive(px, py)==0)
567 break;
568
569 if (idx==fNumPixels)
570 return;
571
572 if (event==kButton1Down && (*this)[idx].GetFillColor()==kEmpty)
573 {
574 if (!Flip(idx, kTRUE))
575 return;
576
577 fUsrPts[fNumUser]++;
578
579 (*this)[idx].SetFillColor(kRed+fNumUser);
580
581 Int_t start = fNumUser;
582
583 fNumUser++;
584 fNumUser%=fNumUsers;
585
586 while (!CheckMoves())
587 {
588 cout << "Sorry, no moves possible for player #" << fNumUser << endl;
589 fNumUser++;
590 fNumUser%=fNumUsers;
591
592 if (fNumUser==start)
593 {
594 Done();
595 break;
596 }
597 }
598
599 Update();
600 }
601
602 fDrawingPad->Modified();
603}
Note: See TracBrowser for help on using the repository browser.