source: trunk/MagicSoft/Mars/mtools/MineSweeper.cc@ 4308

Last change on this file since 4308 was 2173, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 12.5 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 07/2002 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2002
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MineSweeper
28// -----------
29//
30// Camera Display Games: Mine Sweeper
31//
32// Start the game by:
33// MineSweeper mine;
34//
35// It is the well known Mine Sweeper.
36// Set a mark using a single mouse click.
37// Open a pixel using a double click.
38//
39// Try to open all pixels without bombs. If you open a pixel with no
40// bomb around all pixels around are opened.
41//
42// To restart the game use the context menu. It can only be accessed if
43// the game has been stopped (either because you win the game or because
44// you hit a bomb) With the context menu you can also toggle between
45// different camera layouts.
46//
47////////////////////////////////////////////////////////////////////////////
48#include "MineSweeper.h"
49
50#include <iostream>
51
52#include <TText.h>
53#include <TMarker.h>
54#include <TRandom.h>
55#include <TCanvas.h>
56#include <TClonesArray.h>
57#include <TInterpreter.h>
58
59#include "MHexagon.h"
60
61#include "MGeomPix.h"
62#include "MGeomCamCT1.h"
63#include "MGeomCamMagic.h"
64
65ClassImp(MineSweeper);
66
67using namespace std;
68
69const Int_t MineSweeper::fColorBombs[7] = {
70 22,
71 kYellow,
72 kGreen,
73 kBlue,
74 kCyan,
75 kMagenta,
76 kRed
77};
78
79void MineSweeper::Free()
80{
81 if (!fGeomCam)
82 return;
83
84 fPixels->Delete();
85 fText->Delete();
86 fFlags->Delete();
87
88 delete fText;
89 delete fFlags;
90 delete fPixels;
91
92 delete fGeomCam;
93}
94
95void MineSweeper::ChangeCamera()
96{
97 static Bool_t ct1=kFALSE;
98
99 cout << "Change to " << (ct1?"Magic":"CT1") << endl;
100
101 if (ct1)
102 SetNewCamera(new MGeomCamMagic);
103 else
104 SetNewCamera(new MGeomCamCT1);
105
106 ct1 = !ct1;
107
108 Reset();
109 DrawHexagons();
110}
111
112void MineSweeper::SetNewCamera(MGeomCam *geom)
113{
114 Free();
115
116 //
117 // Reset the display geometry
118 //
119 fW=0;
120 fH=0;
121
122 //
123 // Set new camera
124 //
125 fGeomCam = geom;
126
127 //
128 // create the hexagons of the display
129 //
130 fNumPixels = fGeomCam->GetNumPixels();
131 fRange = fGeomCam->GetMaxRadius();
132
133 //
134 // Construct all hexagons. Use new-operator with placement
135 //
136 fNumBombs = fNumPixels/5;
137
138 fText = new TClonesArray("TText", fNumPixels);
139 fFlags = new TClonesArray("TMarker", fNumPixels);
140 fPixels = new TClonesArray("MHexagon", fNumPixels);
141
142 for (UInt_t i=0; i<fNumPixels; i++)
143 {
144 MHexagon &h = *new ((*fPixels)[i]) MHexagon((*fGeomCam)[i]);
145#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
146 h.SetBit(kNoContextMenu|kCannotPick);
147#endif
148
149 TText &t = *new ((*fText)[i]) TText;
150 t.SetTextFont(122);
151 t.SetTextAlign(22); // centered/centered
152 t.SetTextSize(0.3*h.GetD()/fRange);
153#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
154 t.SetBit(kNoContextMenu|kCannotPick);
155#endif
156
157 const MGeomPix &pix = (*fGeomCam)[i];
158
159 TMarker &m = *new ((*fFlags)[i]) TMarker(pix.GetX(), pix.GetY(), kOpenStar);
160#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
161 m.SetBit(kNoContextMenu|kCannotPick);
162#endif
163 }
164}
165
166// ------------------------------------------------------------------------
167//
168// Draw all pixels of the camera
169// (means apend all pixelobjects to the current pad)
170//
171void MineSweeper::DrawHexagons()
172{
173 for (UInt_t i=0; i<fNumPixels; i++)
174 (*this)[i].Draw();
175}
176
177// ------------------------------------------------------------------------
178//
179// default constructor
180//
181MineSweeper::MineSweeper()
182 : fGeomCam(NULL), fDone(NULL), fShow(NULL), fW(0), fH(0), fDrawingPad(NULL), fIsAllocated(kFALSE)
183{
184 SetNewCamera(new MGeomCamMagic);
185
186 //
187 // Make sure, that the object is destroyed when the canvas/pad is
188 // destroyed. Make also sure, that the interpreter doesn't try to
189 // delete it a second time.
190 //
191 SetBit(kCanDelete);
192 gInterpreter->DeleteGlobal(this);
193
194 Draw();
195}
196
197// ------------------------------------------------------------------------
198//
199// Destructor. Deletes TClonesArrays for hexagons and legend elements.
200//
201MineSweeper::~MineSweeper()
202{
203 Free();
204
205 delete fShow;
206
207 if (fDone)
208 delete fDone;
209
210 if (fDrawingPad->GetListOfPrimitives()->FindObject(this)==this)
211 {
212 fDrawingPad->RecursiveRemove(this);
213 delete fDrawingPad;
214 }
215}
216
217// ------------------------------------------------------------------------
218//
219// This is called at any time the canvas should get repainted.
220// Here we maintain an aspect ratio of 5/4=1.15. This makes sure,
221// that the camera image doesn't get distorted by resizing the canvas.
222//
223void MineSweeper::Paint(Option_t *opt)
224{
225 const UInt_t w = (UInt_t)(gPad->GetWw()*gPad->GetAbsWNDC());
226 const UInt_t h = (UInt_t)(gPad->GetWh()*gPad->GetAbsHNDC());
227
228 //
229 // Check for a change in width or height, and make sure, that the
230 // first call also sets the range
231 //
232 if (w*fH == h*fW && fW && fH)
233 return;
234
235 //
236 // Calculate aspect ratio (5/4=1.25 recommended)
237 //
238 const Double_t ratio = (Double_t)w/h;
239
240 Float_t x;
241 Float_t y;
242
243 if (ratio>1.0)
244 {
245 x = fRange*(ratio*2-1);
246 y = fRange;
247 }
248 else
249 {
250 x = fRange;
251 y = fRange/ratio;
252 }
253
254 fH = h;
255 fW = w;
256
257 //
258 // Set new range
259 //
260 fDrawingPad->Range(-fRange, -y, x, y);
261
262 //
263 // Adopt absolute sized of markers to relative range
264 //
265 for (UInt_t i=0; i<fNumPixels; i++)
266 {
267 Float_t r = (*this)[i].GetD()*gPad->XtoAbsPixel(1)/325;
268 GetFlag(i)->SetMarkerSize(20.0*r/fRange);
269 }
270}
271
272// ------------------------------------------------------------------------
273//
274// Call this function to draw the camera layout into your canvas.
275// Setup a drawing canvas. Add this object and all child objects
276// (hexagons, etc) to the current pad. If no pad exists a new one is
277// created.
278//
279void MineSweeper::Draw(Option_t *option)
280{
281 // root 3.02:
282 // gPad->SetFixedAspectRatio()
283
284 if (fDrawingPad)
285 return;
286
287 //
288 // if no canvas is yet existing to draw into, create a new one
289 //
290 if (!gPad)
291 {
292 /*TCanvas *c =*/ new TCanvas("MineSweeper", "Magic Mine Sweeper", 0, 0, 800, 800);
293 //c->ToggleEventStatus();
294 fIsAllocated = kTRUE;
295 }
296 else
297 fIsAllocated = kFALSE;
298
299 fDrawingPad = gPad;
300 fDrawingPad->SetBorderMode(0);
301
302 //
303 // Append this object, so that the aspect ratio is maintained
304 // (Paint-function is called)
305 //
306 AppendPad(option);
307
308 //
309 // Draw the title text
310 //
311 fShow = new TText;
312 fShow->SetTextAlign(23); // centered/bottom
313#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
314 fShow->SetBit(kNoContextMenu|kCannotPick);
315#endif
316 fShow->Draw();
317 //
318 // Reset the game pad
319 //
320 Reset();
321 DrawHexagons();
322}
323
324void MineSweeper::Update(Int_t num)
325{
326 TString txt = "Pixels: ";
327 txt += fNumPixels;
328 txt += " Bombs: ";
329 txt += num;
330
331 fShow->SetText(0, fRange, txt);
332}
333
334// ------------------------------------------------------------------------
335//
336// reset the all pixel colors to a default value
337//
338void MineSweeper::Reset()
339{
340 if (fDone)
341 {
342 delete fDone;
343 fDone = NULL;
344 }
345
346 for (UInt_t i=0; i<fNumPixels; i++)
347 {
348 Remove(GetText(i));
349 Remove(GetFlag(i));
350
351 (*this)[i].SetFillColor(kHidden);
352 (*fGeomCam)[i].ResetBit(kUserBits);
353
354 GetFlag(i)->SetMarkerColor(kBlack);
355 }
356 Update(fNumBombs);
357
358 TRandom rnd(0);
359 for (int i=0; i<fNumBombs; i++)
360 {
361 Int_t idx;
362
363 do idx = (Int_t)rnd.Uniform(fNumPixels);
364 while ((*fGeomCam)[idx].TestBit(kHasBomb));
365
366 (*fGeomCam)[idx].SetBit(kHasBomb);
367 }
368
369 fDrawingPad->SetFillColor(22);
370
371#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
372 fDrawingPad->SetBit(kNoContextMenu);
373 SetBit(kNoContextMenu);
374#endif
375}
376
377void MineSweeper::Done(TString txt, Int_t col)
378{
379 for (unsigned int j=0; j<fNumPixels; j++)
380 if ((*fGeomCam)[j].TestBit(kHasBomb))
381 {
382 (*this)[j].SetFillColor(kBlack);
383 GetFlag(j)->SetMarkerColor(kWhite);
384 }
385
386 fDone = new TText(0, 0, txt);
387 fDone->SetTextColor(kWhite); // white
388 fDone->SetTextAlign(22); // centered/centered
389 fDone->SetTextSize(0.05); // white
390#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
391 fDone->SetBit(kNoContextMenu|kCannotPick);
392#endif
393 fDone->Draw();
394
395 fDrawingPad->SetFillColor(col);
396
397#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
398 fDrawingPad->ResetBit(kNoContextMenu);
399 ResetBit(kNoContextMenu);
400#endif
401}
402
403// ------------------------------------------------------------------------
404//
405// Check whether a hexagon should be opened and which color/number should
406// be visible
407//
408void MineSweeper::OpenHexagon(Int_t idx)
409{
410 MGeomPix &pix=(*fGeomCam)[idx];
411
412 if (pix.TestBit(kIsVisible))
413 return;
414
415 if (pix.TestBit(kHasFlag))
416 Remove(GetFlag(idx));
417
418 pix.SetBit(kIsVisible);
419 pix.ResetBit(kHasFlag);
420
421 Int_t cnt=0;
422 for (int j=0; j<pix.GetNumNeighbors(); j++)
423 if ((*fGeomCam)[pix.GetNeighbor(j)].TestBit(kHasBomb))
424 cnt++;
425
426 (*this)[idx].SetFillColor(fColorBombs[cnt]);
427
428 if (cnt)
429 {
430 TText *txt = GetText(idx);
431 TString str;
432 str += cnt;
433 txt->SetText(pix.GetX(), pix.GetY(), str);
434 txt->Draw();
435 return;
436 }
437
438 for (int j=0; j<pix.GetNumNeighbors(); j++)
439 OpenHexagon(pix.GetNeighbor(j));
440}
441
442void MineSweeper::Remove(TObject *obj)
443{
444 fDrawingPad->RecursiveRemove(obj);
445}
446
447// ------------------------------------------------------------------------
448//
449// Execute a mouse event on the camera
450//
451void MineSweeper::ExecuteEvent(Int_t event, Int_t px, Int_t py)
452{
453 if (event==kMouseMotion || event==kMouseEnter || event==kMouseLeave ||
454 event==kButton1Up || event==kButton2Up || event==kButton3Up ||
455 event==kButton1Motion || event==kButton2Motion || event==kButton3Motion ||
456 event==kButton2Double || event==kButton3Double ||
457 fDone)
458 return;
459
460 /*
461 if (event==kKeyPress && py==0x1000)
462 {
463 Reset();
464 return;
465 }
466 */
467
468 UInt_t idx;
469 for (idx=0; idx<fNumPixels; idx++)
470 if ((*fPixels)[idx]->DistancetoPrimitive(px, py)==0)
471 break;
472
473 if (idx==fNumPixels)
474 return;
475
476 MGeomPix &pix=(*fGeomCam)[idx];
477
478 if (event==kButton1Double)
479 {
480 OpenHexagon(idx);
481
482 if (pix.TestBit(kHasBomb))
483 Done("Argh... you hit the Bomb!!!", kRed);
484 }
485
486 if (event==kButton1Down && !pix.TestBit(kIsVisible))
487 {
488 if (pix.TestBit(kHasFlag))
489 Remove(GetFlag(idx));
490 else
491 GetFlag(idx)->Draw();
492
493 pix.InvertBit(kHasFlag);
494 }
495
496 UInt_t vis=fNumBombs;
497 UInt_t flg=fNumBombs;
498 for (UInt_t i=0; i<fNumPixels; i++)
499 {
500 if ((*fGeomCam)[i].TestBit(kIsVisible))
501 vis++;
502 if ((*fGeomCam)[i].TestBit(kHasFlag))
503 flg--;
504 }
505
506 Update(flg);
507
508 if (vis==fNumPixels && !fDone)
509 Done("Great! Congratulations, you did it!", kGreen);
510
511 fDrawingPad->Modified();
512
513 /*
514 switch (event)
515 {
516 case kNoEvent: cout << "No Event" << endl; break;
517 case kButton1Down: cout << "Button 1 down" << endl; break;
518 case kButton2Down: cout << "Button 2 down" << endl; break;
519 case kButton3Down: cout << "Button 3 down" << endl; break;
520 case kKeyDown: cout << "Key down" << endl; break;
521 case kKeyUp: cout << "Key up" << endl; break;
522 case kKeyPress: cout << "Key press" << endl; break;
523 case kButton1Locate: cout << "Button 1 locate" << endl; break;
524 case kButton2Locate: cout << "Button 2 locate" << endl; break;
525 case kButton3Locate: cout << "Button 3 locate" << endl; break;
526 }
527 */
528}
Note: See TracBrowser for help on using the repository browser.