source: trunk/Mars/mtools/MineSweeper.cc@ 13768

Last change on this file since 13768 was 9369, checked in by tbretz, 16 years ago
*** empty log message ***
File size: 11.1 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of CheObs, the Modular 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 appears 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, 7/2002 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: CheObs Software Development, 2000-2009
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 "MH.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 fText->Delete();
85 fFlags->Delete();
86
87 delete fText;
88 delete fFlags;
89
90 delete fGeomCam;
91}
92
93void MineSweeper::ChangeCamera()
94{
95 static Bool_t ct1=kFALSE;
96
97 cout << "Change to " << (ct1?"Magic":"CT1") << endl;
98
99 if (ct1)
100 SetNewCamera(new MGeomCamMagic);
101 else
102 SetNewCamera(new MGeomCamCT1);
103
104 ct1 = !ct1;
105
106 Reset();
107 AppendPad();
108}
109
110void MineSweeper::SetNewCamera(MGeomCam *geom)
111{
112 Free();
113
114 //
115 // Set new camera
116 //
117 fGeomCam = geom;
118
119 //
120 // create the hexagons of the display
121 //
122 fNumPixels = fGeomCam->GetNumPixels();
123 fRange = fGeomCam->GetMaxRadius();
124
125 //
126 // Construct all hexagons. Use new-operator with placement
127 //
128 fNumBombs = fNumPixels/5;
129
130 fText = new TClonesArray("TText", fNumPixels);
131 fFlags = new TClonesArray("TMarker", fNumPixels);
132 fColors.Set(fNumPixels);
133 //fPixels = new TClonesArray("MHexagon", fNumPixels);
134
135 for (UInt_t i=0; i<fNumPixels; i++)
136 {
137 const MGeom &pix = (*fGeomCam)[i];
138
139 TText &t = *new ((*fText)[i]) TText;
140 t.SetTextFont(122);
141 t.SetTextAlign(22); // centered/centered
142 t.SetTextSize(0.3*pix.GetT()/fRange);
143#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
144 t.SetBit(kNoContextMenu|kCannotPick);
145#endif
146
147 TMarker &m = *new ((*fFlags)[i]) TMarker(pix.GetX(), pix.GetY(), kOpenStar);
148#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
149 m.SetBit(kNoContextMenu|kCannotPick);
150#endif
151 }
152}
153
154void MineSweeper::Init()
155{
156 //
157 // Make sure, that the object is destroyed when the canvas/pad is
158 // destroyed. Make also sure, that the interpreter doesn't try to
159 // delete it a second time.
160 //
161 SetBit(kCanDelete);
162 gInterpreter->DeleteGlobal(this);
163
164 Draw();
165}
166
167// ------------------------------------------------------------------------
168//
169// default constructor
170//
171MineSweeper::MineSweeper()
172 : fGeomCam(NULL), fDone(NULL), fShow(NULL)
173{
174 SetNewCamera(new MGeomCamMagic);
175 Init();
176}
177
178MineSweeper::MineSweeper(const MGeomCam &geom)
179 : fGeomCam(NULL), fDone(NULL), fShow(NULL)
180{
181 SetNewCamera(static_cast<MGeomCam*>(geom.Clone()));
182 Init();
183}
184
185// ------------------------------------------------------------------------
186//
187// Destructor. Deletes TClonesArrays for hexagons and legend elements.
188//
189MineSweeper::~MineSweeper()
190{
191 Free();
192
193 delete fShow;
194
195 if (fDone)
196 delete fDone;
197}
198
199// ------------------------------------------------------------------------
200//
201// This is called at any time the canvas should get repainted.
202// Here we maintain an aspect ratio of 5/4=1.15. This makes sure,
203// that the camera image doesn't get distorted by resizing the canvas.
204//
205void MineSweeper::Paint(Option_t *opt)
206{
207 const Float_t r = fGeomCam->GetMaxRadius();
208
209 MH::SetPadRange(-r, -r, r, r*1.1);
210
211 TAttLine line;
212 TAttFill fill;
213
214 // FIXME:
215 for (UInt_t i=0; i<fNumPixels; i++)
216 {
217 const MGeom &pix = (*fGeomCam)[i];
218
219 fill.SetFillColor(fColors[i]);
220 pix.PaintPrimitive(line, fill);
221
222 //
223 // Adopt absolute sized of markers to relative range
224 //
225 Float_t r = (*fGeomCam)[i].GetT()*gPad->XtoAbsPixel(1)/325;
226 GetFlag(i)->SetMarkerSize(20.0*r/fRange);
227
228 if (pix.TestBit(kHasFlag))
229 GetFlag(i)->Paint();
230
231 GetText(i)->Paint();
232 }
233}
234
235// ------------------------------------------------------------------------
236//
237// Call this function to draw the camera layout into your canvas.
238// Setup a drawing canvas. Add this object and all child objects
239// (hexagons, etc) to the current pad. If no pad exists a new one is
240// created.
241//
242void MineSweeper::Draw(Option_t *option)
243{
244 // root 3.02:
245 // gPad->SetFixedAspectRatio()
246
247 //
248 // if no canvas is yet existing to draw into, create a new one
249 //
250 if (!gPad)
251 new TCanvas("MineSweeper", "Magic Mine Sweeper", 0, 0, 800, 800);
252
253 gPad->SetBorderMode(0);
254
255 //
256 // Append this object, so that the aspect ratio is maintained
257 // (Paint-function is called)
258 //
259 AppendPad(option);
260
261 //
262 // Draw the title text
263 //
264 fShow = new TText;
265 fShow->SetTextAlign(23); // centered/bottom
266#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
267 fShow->SetBit(kNoContextMenu|kCannotPick);
268#endif
269 fShow->Draw();
270 //
271 // Reset the game pad
272 //
273 Reset();
274}
275
276void MineSweeper::Update(Int_t num)
277{
278 TString txt = "Pixels: ";
279 txt += fNumPixels;
280 txt += " Bombs: ";
281 txt += num;
282
283 fShow->SetText(0, fRange, txt);
284}
285
286// ------------------------------------------------------------------------
287//
288// reset the all pixel colors to a default value
289//
290void MineSweeper::Reset()
291{
292 if (fDone)
293 {
294 delete fDone;
295 fDone = NULL;
296 }
297
298 for (UInt_t i=0; i<fNumPixels; i++)
299 {
300 fColors[i] = kHidden;
301 (*fGeomCam)[i].ResetBit(kUserBits);
302
303 GetFlag(i)->SetMarkerColor(kBlack);
304 GetText(i)->SetText(0, 0, "");
305 }
306 Update(fNumBombs);
307
308 TRandom rnd(0);
309 for (int i=0; i<fNumBombs; i++)
310 {
311 Int_t idx;
312
313 do idx = (Int_t)rnd.Uniform(fNumPixels);
314 while ((*fGeomCam)[idx].TestBit(kHasBomb));
315
316 (*fGeomCam)[idx].SetBit(kHasBomb);
317 }
318
319 gPad->SetFillColor(22);
320
321#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
322 gPad->SetBit(kNoContextMenu);
323 SetBit(kNoContextMenu);
324#endif
325}
326
327void MineSweeper::Done(TString txt, Int_t col)
328{
329 for (unsigned int j=0; j<fNumPixels; j++)
330 if ((*fGeomCam)[j].TestBit(kHasBomb))
331 {
332 fColors[j] = kBlack;
333 GetFlag(j)->SetMarkerColor(kWhite);
334 }
335
336 fDone = new TText(0, 0, txt);
337 fDone->SetTextColor(kWhite); // white
338 fDone->SetTextAlign(22); // centered/centered
339 fDone->SetTextSize(0.05); // white
340#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
341 fDone->SetBit(kNoContextMenu|kCannotPick);
342#endif
343 fDone->Draw();
344
345 gPad->SetFillColor(col);
346
347#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
348 gPad->ResetBit(kNoContextMenu);
349 ResetBit(kNoContextMenu);
350#endif
351}
352
353// ------------------------------------------------------------------------
354//
355// Check whether a hexagon should be opened and which color/number should
356// be visible
357//
358void MineSweeper::OpenHexagon(Int_t idx)
359{
360 MGeom &pix=(*fGeomCam)[idx];
361
362 if (pix.TestBit(kIsVisible))
363 return;
364
365 pix.SetBit(kIsVisible);
366 pix.ResetBit(kHasFlag);
367
368 Int_t cnt=0;
369 for (int j=0; j<pix.GetNumNeighbors(); j++)
370 if ((*fGeomCam)[pix.GetNeighbor(j)].TestBit(kHasBomb))
371 cnt++;
372
373 fColors[idx] = fColorBombs[cnt];
374
375 TString str;
376 if (cnt)
377 str += cnt;
378
379 TText *txt = GetText(idx);
380 txt->SetText(pix.GetX(), pix.GetY(), str);
381
382 if (cnt)
383 return;
384
385 for (int j=0; j<pix.GetNumNeighbors(); j++)
386 OpenHexagon(pix.GetNeighbor(j));
387}
388
389// ------------------------------------------------------------------------
390//
391// Execute a mouse event on the camera
392//
393void MineSweeper::ExecuteEvent(Int_t event, Int_t px, Int_t py)
394{
395 if (event==kMouseMotion || event==kMouseEnter || event==kMouseLeave ||
396 event==kButton1Up || event==kButton2Up || event==kButton3Up ||
397 event==kButton1Motion || event==kButton2Motion || event==kButton3Motion ||
398 event==kButton2Double || event==kButton3Double ||
399 fDone)
400 return;
401
402 /*
403 if (event==kKeyPress && py==0x1000)
404 {
405 Reset();
406 return;
407 }
408 */
409
410 UInt_t idx;
411 for (idx=0; idx<fNumPixels; idx++)
412 if ((*fGeomCam)[idx].DistancetoPrimitive(px, py)<=0)
413 break;
414
415 if (idx==fNumPixels)
416 return;
417
418 MGeom &pix=(*fGeomCam)[idx];
419
420 if (event==kButton1Double)
421 {
422 OpenHexagon(idx);
423
424 if (pix.TestBit(kHasBomb))
425 Done("Argh... you hit the Bomb!!!", kRed);
426 }
427
428 if (event==kButton1Down && !pix.TestBit(kIsVisible))
429 pix.InvertBit(kHasFlag);
430
431 UInt_t vis=fNumBombs;
432 UInt_t flg=fNumBombs;
433 for (UInt_t i=0; i<fNumPixels; i++)
434 {
435 if ((*fGeomCam)[i].TestBit(kIsVisible))
436 vis++;
437 if ((*fGeomCam)[i].TestBit(kHasFlag))
438 flg--;
439 }
440
441 Update(flg);
442
443 if (vis==fNumPixels && !fDone)
444 Done("Great! Congratulations, you did it!", kGreen);
445
446 gPad->Modified();
447
448 /*
449 switch (event)
450 {
451 case kNoEvent: cout << "No Event" << endl; break;
452 case kButton1Down: cout << "Button 1 down" << endl; break;
453 case kButton2Down: cout << "Button 2 down" << endl; break;
454 case kButton3Down: cout << "Button 3 down" << endl; break;
455 case kKeyDown: cout << "Key down" << endl; break;
456 case kKeyUp: cout << "Key up" << endl; break;
457 case kKeyPress: cout << "Key press" << endl; break;
458 case kButton1Locate: cout << "Button 1 locate" << endl; break;
459 case kButton2Locate: cout << "Button 2 locate" << endl; break;
460 case kButton3Locate: cout << "Button 3 locate" << endl; break;
461 }
462 */
463}
Note: See TracBrowser for help on using the repository browser.