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

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