source: trunk/Mars/mtools/MagicJam.cc@ 19345

Last change on this file since 19345 was 19345, checked in by tbretz, 3 years ago
Improves the behaviour with RecursiveRemove. Strictly speaking this change might only be necessary if a class contains more than one member which is bound to recursive remove. Onth other hand setting all members to NULL which might be affected by RecursiveRemove is not wrong either.
File size: 22.9 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, 9/2005 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2005-2008
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MagicJam
28//
29// Jam is a multi player game. It is controlled by its context menu (click
30// with the right mouse button on one of the pixels in the game pad).
31//
32// Start the game with:
33// MagicJam jam;
34//
35// Rules:
36// MagicJam is a multiplayer game. The aim is to own the full game pad.
37// Ech pixel in the pad can contain as many entries as it has neighbors.
38// If it has more entries than neighbors it overflows into its neighbors.
39// All pixels into which such an overflow occures will be captured by
40// the current player. Player by player will be able to increase the
41// entry in one pixel by one. Increase the contents of an empty pixel to
42// one or by one in an owned pixel. The player who once will own the
43// all pixels will win.
44//
45// Editor:
46// To edit or create a new game start the editor from the context menu
47// of MagicJam. The editor is also controlled from its context menu.
48// Use the curso keys to shift your game.
49// Warning: You MUST create a single-island game. Games which have two
50// islands might result in edless loops. (Currently there is no check!)
51//
52/////////////////////////////////////////////////////////////////////////////
53#include "MagicJam.h"
54
55#include <climits> // INT_MAX (Ubuntu 8.10)
56
57#include <iostream>
58#include <fstream>
59
60#include <errno.h>
61
62#include <KeySymbols.h>
63
64#include <TMath.h>
65#include <TRandom.h>
66
67#include <TBox.h>
68#include <TLine.h>
69#include <TText.h>
70
71#include <TStyle.h>
72#include <TSystem.h>
73
74#include <TNtuple.h>
75#include <TASImage.h>
76#include <TInterpreter.h>
77#include <TGFileDialog.h>
78
79#include "MH.h"
80#include "MHexagon.h"
81#include "MGeomCam.h"
82#include "MGeomPix.h"
83
84#include "MDirIter.h"
85
86ClassImp(MagicJamAbc);
87ClassImp(MagicJamEditor);
88ClassImp(MagicJam);
89
90using namespace std;
91
92// -------------------------------------------------------------------------
93// The editor for MagicJam
94// -------------------------------------------------------------------------
95
96// --------------------------------------------------------------------------
97//
98// Move the contents of the pad
99//
100void MagicJamEditor::Move(int dx, int dy)
101{
102 const TArrayC cpy(fUsed);
103
104 Int_t h = cpy.GetSize()/fWidth;
105
106 for (int i=0; i<cpy.GetSize(); i++)
107 {
108 Int_t x = i%fWidth;
109 Int_t y = i/fWidth;
110
111 x += dx + fWidth;
112 y += dy*2 + h;
113
114 x %= fWidth;
115 y %= h;
116
117 fUsed[x+y*fWidth] = cpy[i];
118 }
119 gPad->GetPad(1)->Modified();
120 gPad->GetPad(1)->Update();
121 gPad->Modified();
122 gPad->Update();
123}
124
125// --------------------------------------------------------------------------
126//
127// Initialize the pad with size wx, hy
128//
129void MagicJamEditor::InitGeom(int wx, int hy)
130{
131 const Float_t dx = 0.5*(wx-1);
132 const Float_t dy = 0.5*(hy-1);
133
134 fWidth = wx;
135
136 MGeomCam cam(wx*hy, 1);
137
138 for (int x=0; x<wx; x++)
139 for (int y=0; y<hy; y++)
140 {
141 Float_t x0 = TMath::Odd(y) ? x-0.25 : x+0.25;
142
143 cam.SetAt(x + y*fWidth, MGeomPix(x0-dx, (y-dy)*0.866, 1));
144 }
145
146
147 cam.InitGeometry();
148
149 SetGeometry(cam);
150}
151
152// --------------------------------------------------------------------------
153//
154// Get index of pixel with position px, py
155//
156Int_t MagicJamEditor::GetPixelIndexFlt(Float_t px, Float_t py) const
157{
158 if (fNcells<=1)
159 return -1;
160
161 Int_t i;
162 for (i=0; i<fNcells-2; i++)
163 {
164 if ((*fGeomCam)[i].IsInside(px, py))
165 return i;
166 }
167 return -1;
168}
169
170// --------------------------------------------------------------------------
171//
172// Open the MagicJam editor. Load a game with name name.
173//
174MagicJamEditor::MagicJamEditor(const char *name) : fImage(NULL)
175{
176 InitGeom(20, 20);
177
178 SetBit(kNoLegend);
179 SetBit(kNoScale);
180
181 Draw();
182
183 gPad->SetEditable(kFALSE);
184
185 if (name)
186 LoadGame(name);
187}
188
189// --------------------------------------------------------------------------
190//
191// Delete fImage
192//
193MagicJamEditor::~MagicJamEditor()
194{
195 if (fImage)
196 {
197 delete fImage;
198 fImage = 0;
199 }
200}
201
202// --------------------------------------------------------------------------
203//
204// Change width and height of pad. Preserve contents.
205//
206void MagicJamEditor::SetWidthHeight(Int_t dx, Int_t dy)
207{
208 TNtuple tup("", "", "x:y");
209 tup.SetDirectory(0);
210
211 for (UInt_t i=0; i<GetNumPixels(); i++)
212 {
213 if (IsUsed(i))
214 tup.Fill((*fGeomCam)[i].GetX(), (*fGeomCam)[i].GetY());
215 }
216 InitGeom(dx, dy);
217
218 fEntries=0;
219 for (int i=0; i<tup.GetEntries(); i++)
220 {
221 tup.GetEntry(i);
222 const Int_t idx = GetPixelIndexFlt(tup.GetArgs()[0], tup.GetArgs()[1]);
223 if (idx>=0)
224 {
225 SetUsed(idx);
226 fEntries++;
227 }
228 }
229}
230
231// --------------------------------------------------------------------------
232//
233// Save the current game
234//
235void MagicJamEditor::SaveGame(const char *name)
236{
237 ofstream fout(name);
238 if (!fout)
239 {
240 cout << "Cannot open file " << name << ": " << strerror(errno) << endl;
241 return;
242 }
243
244 for (UInt_t i=0; i<GetNumPixels(); i++)
245 if (IsUsed(i))
246 fout << i%fWidth << " " << i/fWidth << endl;
247
248 SetName(name);
249
250}
251
252// --------------------------------------------------------------------------
253//
254// Load a game
255//
256void MagicJamEditor::LoadGame(const char *name)
257{
258 InitGeom(1,1);
259 Reset();
260
261 ifstream fin(name);
262 if (!fin)
263 {
264 cout << "Cannot open file " << name << ": " << strerror(errno) << endl;
265 return;
266 }
267
268 Int_t maxx=-INT_MAX;
269 Int_t maxy=-INT_MAX;
270 Int_t minx= INT_MAX;
271 Int_t miny= INT_MAX;
272
273 TNtuple tup("", "", "x:y");
274 tup.SetDirectory(0);
275
276 while (1)
277 {
278 Int_t x,y;
279 fin >> x >> y;
280 if (!fin)
281 break;
282
283 tup.Fill(x, y);
284
285 maxx = TMath::Max(maxx, x);
286 maxy = TMath::Max(maxy, y);
287 minx = TMath::Min(minx, x);
288 miny = TMath::Min(miny, y);
289 }
290
291 if (tup.GetEntries()==0)
292 {
293 cout << "File " << name << " contains no entries!" << endl;
294 return;
295 }
296
297 if (TMath::Odd(miny))
298 miny--;
299
300 InitGeom((maxx-minx)+1, (maxy-miny)+1);
301
302 for (int i=0; i<tup.GetEntries(); i++)
303 {
304 tup.GetEntry(i);
305
306 const Int_t x = TMath::Nint(tup.GetArgs()[0]) - minx;
307 const Int_t y = TMath::Nint(tup.GetArgs()[1]) - miny;
308 SetUsed(x + y*fWidth);
309 }
310
311 fEntries=tup.GetEntries();;
312
313 SetName(name);
314}
315
316void MagicJamEditor::ShowImageAsBackground(const char *name)
317{
318 if (fImage)
319 delete fImage;
320
321 fImage = new TASImage(name);
322 if (!fImage->IsValid())
323 {
324 delete fImage;
325 fImage = NULL;
326 return;
327 }
328
329 fImage->SetEditable(kFALSE);
330
331 SetFillStyle(4000);
332}
333
334void MagicJamEditor::RemoveBackgroundImage()
335{
336 if (fImage)
337 {
338 delete fImage;
339 fImage=NULL;
340 }
341
342 SetFillStyle(1001);
343}
344
345// --------------------------------------------------------------------------
346//
347// Paint the game pad
348//
349void MagicJamEditor::Paint(Option_t *o)
350{
351 TString str = Form("Jam Editor pad %dx%d", fWidth, GetNumPixels()/fWidth);
352 SetTitle(str);
353
354 Float_t maxx = 0;
355 Float_t minx = 0;
356 Float_t maxy = 0;
357 Float_t miny = 0;
358
359 for (UInt_t i=0; i<GetNumPixels(); i++)
360 {
361 const Float_t x = (*fGeomCam)[i].GetX();
362 const Float_t y = (*fGeomCam)[i].GetY();
363
364 maxx = TMath::Max(maxx, x);
365 minx = TMath::Min(minx, x);
366 maxy = TMath::Max(maxy, y);
367 miny = TMath::Min(miny, y);
368 }
369
370 if (fImage)
371 {
372 const Float_t r = fGeomCam->GetMaxRadius();
373
374 MH::SetPadRange(-r*1.02, -r*1.02, TestBit(kNoLegend) ? r : 1.15*r, r*1.2);
375
376 Double_t x1, y1, x2, y2;
377 gPad->GetRange(x1, y1, x2, y2);
378
379 gPad->SetLeftMargin ( (minx-x1)/(x2-x1));
380 gPad->SetBottomMargin( (miny-y1)/(y2-y1));
381 gPad->SetRightMargin (1 - (maxx-x1)/(x2-x1));
382 gPad->SetTopMargin (1 - (maxy-y1)/(y2-y1));
383
384 fImage->Paint();
385 }
386
387 gStyle->SetOptStat(11);
388 MHCamera::Paint(o);
389
390 TBox box;
391 box.SetLineColor(kBlack);
392 box.SetFillStyle(0);
393 box.PaintBox(minx-1, miny-1, maxx+1, maxy+1);
394
395 TLine l;
396 //l.SetLineStyle(kDashed);
397 l.SetLineColor(15);
398 l.PaintLine(0, miny, 0, maxy);
399 l.PaintLine(minx, 0, maxx, 0);
400}
401
402// --------------------------------------------------------------------------
403//
404// Call MHCamera Draw connect a signal to catch the keynoard events
405//
406void MagicJamEditor::Draw(Option_t *o)
407{
408 MHCamera::Draw();
409
410 // This seems to be necessary due to the pad-in-pad geometry
411 // otherwise I don't get the information about the keys pressed
412 gPad->GetCanvas()->Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)",
413 "MagicJamEditor", this,
414 "EventInfo(Int_t,Int_t,Int_t,TObject*)");
415}
416
417// --------------------------------------------------------------------------
418//
419// Process the keyboard events
420//
421void MagicJamEditor::EventInfo(Int_t event, Int_t px, Int_t py, TObject *o)
422{
423 if (event==kKeyPress)
424 {
425 switch (py)
426 {
427 case kKey_Left:
428 Move(-1, 0);
429 break;
430
431 case kKey_Right:
432 Move(1, 0);
433 break;
434
435 case kKey_Up:
436 Move(0, 1);
437 break;
438
439 case kKey_Down:
440 Move(0, -1);
441 break;
442
443 default:
444 return;
445 }
446
447 TVirtualPad *p = dynamic_cast<TVirtualPad*>(o);
448 if (p)
449 {
450 p->Modified();
451 p->Update();
452 }
453 }
454}
455
456// --------------------------------------------------------------------------
457//
458// Execute mouse events
459//
460void MagicJamEditor::ExecuteEvent(Int_t event, Int_t px, Int_t py)
461{
462 const Int_t idx = GetPixelIndex(px, py);
463 if (idx<0)
464 return;
465
466 switch (event)
467 {
468 case kButton1Down:
469 if (IsUsed(idx))
470 {
471 ResetUsed(idx);
472 fEntries--;
473 }
474 else
475 {
476 SetUsed(idx);
477 fEntries++;
478 }
479 break;
480
481 case kButton1Motion:
482 if (!IsUsed(idx))
483 {
484 SetUsed(idx);
485 fEntries++;
486 }
487 break;
488
489 default:
490 return;
491 }
492
493 gPad->Modified();
494 gPad->Update();
495}
496
497
498// -------------------------------------------------------------------------
499// MagicJam -- the Game
500// -------------------------------------------------------------------------
501
502// --------------------------------------------------------------------------
503//
504// Fill 1 in a single pixel. If the pixel has more content than neighbors
505// it overflows into its neighbors. Called recursivly.
506//
507void MagicJam::FillPix(Int_t idx)
508{
509 if (CountPlayers()==1)
510 return;
511
512 const Int_t newval = fBinEntries[idx+1]+1;
513
514 const MGeom &gpix = (*fGeomCam)[idx];
515 const Int_t n = gpix.GetNumNeighbors();
516
517 SetBinContent(idx+1, fNumPlayer);
518 SetUsed(idx);
519
520 if (newval <= n)
521 {
522 fBinEntries[idx+1] = newval;
523 return;
524 }
525
526 fEntries -= n;
527 fBinEntries[idx+1] = 1;
528
529 for (int i=0; i<n; i++)
530 FillPix(gpix.GetNeighbor(i));
531
532 gPad->Modified();
533 gPad->Update();
534}
535
536// --------------------------------------------------------------------------
537//
538// Count tiles of player
539//
540Int_t MagicJam::CountPlayer(Int_t player) const
541{
542 Int_t sum = 0;
543 for (int i=0; i<GetNbinsX(); i++)
544 if (IsUsed(i) && TMath::Nint(GetBinContent(i+1))==player)
545 sum += fBinEntries[i+1];
546 return sum;
547}
548
549// --------------------------------------------------------------------------
550//
551// Count number of players still able to move
552//
553Int_t MagicJam::CountPlayers() const
554{
555 if (GetEntries()<=fNumPlayers)
556 return 0;
557
558 Int_t cnt=0;
559 for (int i=0; i<fNumPlayers; i++)
560 if (CountPlayer(i)>0)
561 cnt++;
562
563 return cnt;
564}
565
566// --------------------------------------------------------------------------
567//
568// Start MagicJam. Loads the default game jam.txt and initializes a
569// two player game
570//
571MagicJam::MagicJam(const char *jam, MagicJam *game) : fNumPlayers(0), fGame(game)
572{
573 SetTitle("Magic Jam (game)");
574
575 SetBit(kNoLegend);
576 SetBit(kNoScale);
577 SetBit(kMustCleanup);
578
579 LoadGame(jam);
580
581 gInterpreter->DeleteGlobal(this);
582 gROOT->GetListOfCleanups()->Add(this);
583
584 if (fGame!=NULL)
585 {
586 SetBit(kNoContextMenu);
587 SetBit(kNoStats);
588 return;
589 }
590
591 if (!fGeomCam)
592 return;
593
594 SetNumPlayers(2);
595 SetMinMax(-0.5, 9.5);
596
597 Draw();
598 gPad->SetEditable(kFALSE);
599}
600
601// --------------------------------------------------------------------------
602//
603// Remove fGame if it was deleted
604//
605void MagicJam::RecursiveRemove(TObject *obj)
606{
607 if (fGame==obj)
608 fGame=0;
609}
610
611// --------------------------------------------------------------------------
612//
613// Set a new number of players. Restarts the game
614//
615void MagicJam::SetNumPlayers(Byte_t n)
616{
617 if (n<2 || n>9)
618 return;
619
620 fNumPlayers = n;
621 fNumPlayer = 0;
622
623 Reset();
624}
625
626// --------------------------------------------------------------------------
627//
628// Loads a new geometry (game). Restarts the game.
629//
630void MagicJam::LoadGame(const char *name)
631{
632 /*
633 if (gPad)
634 {
635 static const char *gOpenTypes[] =
636 {
637 "Template files", "*.txt",
638 "All files", "*",
639 NULL, NULL
640 };
641
642 static TString dir(".");
643
644 TGFileInfo fi; // fFileName and fIniDir deleted in ~TGFileInfo
645
646 fi.fFileTypes = (const char**)gOpenTypes;
647 fi.fIniDir = StrDup(dir);
648
649 dlg = new TGFileDialog(0, 0, kFDOpen, &fi);
650
651 // Checks is meanwhile the game has been closed!
652 if (!gPad)
653 return;
654
655 cout << "done" << endl;
656
657 cout << gPad << endl;
658
659 if (!fi.fFilename || gPad==NULL)
660 return;
661
662 cout << "test" << endl;
663
664 dir = fi.fIniDir;
665 name = fi.fFilename;
666 }
667 //if (!gROOT->GetListOfSpecials()->FindObject(this))
668 // return;
669
670 cout << "Done." << endl;
671 */
672 //***
673
674
675
676 ifstream fin(name);
677 if (!fin)
678 {
679 cout << "Cannot open file " << name << ": " << strerror(errno) << endl;
680 return;
681 }
682
683 Int_t maxx=-INT_MAX;
684 Int_t maxy=-INT_MAX;
685 Int_t minx= INT_MAX;
686 Int_t miny= INT_MAX;
687
688 TNtuple tup("", "", "x:y");
689 tup.SetDirectory(0);
690
691 while (1)
692 {
693 Int_t x,y;
694 fin >> x >> y;
695 if (!fin)
696 break;
697
698 tup.Fill(x, y);
699
700 maxx = TMath::Max(maxx, x);
701 maxy = TMath::Max(maxy, y);
702 minx = TMath::Min(minx, x);
703 miny = TMath::Min(miny, y);
704 }
705
706 if (tup.GetEntries()==0)
707 {
708 cout << "File " << name << " contains no entries!" << endl;
709 return;
710 }
711
712 MGeomCam cam(tup.GetEntries());
713
714 for (int i=0; i<tup.GetEntries(); i++)
715 {
716 tup.GetEntry(i);
717
718 const Int_t x = TMath::Nint(tup.GetArgs()[0]);
719 const Int_t y = TMath::Nint(tup.GetArgs()[1]);
720
721 Float_t dx = -minx-0.5*(maxx-minx+1);
722 Float_t dy = -miny-0.5*(maxy-miny+1);
723
724 dx += TMath::Odd(y) ? x-0.25 : x+0.25;
725 dy += y;
726
727 cam.SetAt(i, MGeomPix(dx, dy*0.866));
728 }
729
730 for (UInt_t i=0; i<cam.GetNumPixels(); i++)
731 {
732 Int_t nn[6] = { -1, -1, -1, -1, -1, -1 };
733 Int_t idx=0;
734
735 for (UInt_t j=0; j<cam.GetNumPixels(); j++)
736 if (i!=j && cam.GetDist(i,j)<1.5)
737 nn[idx++] = j;
738
739 cam[i].SetNeighbors(nn[0], nn[1], nn[2], nn[3], nn[4], nn[5]);
740 }
741
742 cam.InitGeometry();
743
744 SetGeometry(cam);
745
746 SetName(name);
747 Reset();
748}
749
750// --------------------------------------------------------------------------
751//
752// Restart the game.
753//
754void MagicJam::Reset(Option_t *o)
755{
756 MHCamera::Reset("");
757
758 if (fNumPlayers==0)
759 {
760 SetAllUsed();
761 return;
762 }
763
764 const Int_t max = TMath::Max((Int_t)GetNumPixels()/25, 1);
765 for (Int_t i=0; i<fNumPlayers; i++)
766 {
767 for (Int_t x=0; x<max; x++)
768 {
769 const Int_t idx = gRandom->Integer(GetNumPixels()-1);
770
771 if (IsUsed(idx))
772 {
773 x--;
774 continue;
775 }
776
777 SetUsed(idx);
778 SetBinContent(idx+1, i);
779 fBinEntries[idx+1] = 1;
780 }
781 }
782}
783
784// --------------------------------------------------------------------------
785//
786// Star an editor to make your own game.
787//
788void MagicJam::StartEditor() const
789{
790 TCanvas *c=new TCanvas;
791
792 c->SetName("Editor");
793 c->SetTitle("MagicJam Editor");
794
795 MagicJamEditor *build=new MagicJamEditor;
796
797 build->SetBit(kCanDelete);
798}
799
800// --------------------------------------------------------------------------
801//
802// Open the current game in the editor.
803//
804void MagicJam::OpenInEditor() const
805{
806 TCanvas *c=new TCanvas;
807
808 c->SetName("Editor");
809 c->SetTitle("MagicJam Editor");
810
811 MagicJamEditor *build=new MagicJamEditor(GetName());
812
813 build->SetBit(kCanDelete);
814}
815
816// --------------------------------------------------------------------------
817//
818// Show the Jam games of this directory
819//
820void MagicJam::ShowDirectory(const char *dir)
821{
822 MDirIter Next(dir, "*.jam");
823
824 TList list;
825
826 TString file;
827 while (1)
828 {
829 file=Next();
830 if (file.IsNull())
831 break;
832
833 MagicJam *jam = new MagicJam(file, this);
834 if (jam->GetNumPixels()==0)
835 {
836 delete jam;
837 continue;
838 }
839 list.Add(jam);
840 }
841
842 const Int_t n1 = TMath::Nint(TMath::Ceil(list.GetEntries()/3.));
843 const Int_t n2 = TMath::Nint(TMath::Ceil((float)list.GetEntries()/n1));
844
845 TCanvas *c = new TCanvas;
846 c->SetBorderMode(0);
847 c->SetFillColor(kWhite);
848 c->Divide(n1, n2, 0, 0);
849 c->SetBit(kNoContextMenu);
850 c->SetBit(kCannotPick);
851
852 Int_t i=0;
853
854 TObject *o=0;
855
856 TIter NextObj(&list);
857
858 while ((o=NextObj()))
859 {
860 list.Remove(o);
861
862 c->cd(++i);
863 gPad->SetFillColor(kWhite);
864 o->SetBit(kCanDelete);
865 o->Draw();
866 gPad->SetBit(kCannotPick);
867 }
868
869 // Delete empty pads
870 for (; i<=n1*n2; i++)
871 delete c->GetPad(i);
872}
873
874// --------------------------------------------------------------------------
875//
876// Process mouse events
877//
878void MagicJam::ExecuteEvent(Int_t event, Int_t px, Int_t py)
879{
880 if (fNumPlayers==0) // We are in ShowDirectory-Mode
881 {
882 if (event!=kButton1Down)
883 return;
884
885 if (fGame)
886 {
887 // Do a simple search for the pad containing fGame
888 TIter Next(gROOT->GetListOfCanvases());
889 TCanvas *c=0;
890 while((c=(TCanvas*)Next()))
891 {
892 TVirtualPad *pad1 = c->GetPad(1);
893 if (!pad1)
894 continue;
895
896 if (!pad1->GetListOfPrimitives()->FindObject(fGame))
897 continue;
898
899 fGame->LoadGame(GetName());
900
901 pad1->Modified();
902 pad1->Update();
903 return;
904 }
905 }
906
907 // No pad found. Open new canvas for it
908 new TCanvas;
909 new MagicJam(GetName());
910
911 return;
912 }
913
914 if (CountPlayers()==1) // We already have a winner
915 return;
916
917 if (event==kButton1Down)
918 {
919 const Int_t idx = GetPixelIndex(px, py);
920 if (idx<0)
921 return;
922
923 if (IsUsed(idx) && TMath::Nint(GetBinContent(idx+1))!=fNumPlayer)
924 {
925 const Int_t col = gPad->GetFillColor();
926
927 gPad->SetFillColor(kRed);
928 gPad->Modified();
929 gPad->Update();
930
931 gSystem->Sleep(250);
932
933 gPad->SetFillColor(col);
934 gPad->Modified();
935 gPad->Update();
936 return;
937 }
938
939 FillPix(idx);
940
941 do
942 {
943 fNumPlayer++;
944 fNumPlayer %= fNumPlayers;
945 }
946 while (CountPlayers()>1 && CountPlayer(fNumPlayer)==0);
947
948 gPad->Modified();
949 gPad->Update();
950 }
951}
952
953// --------------------------------------------------------------------------
954//
955// Paint game pad
956//
957void MagicJam::Paint(Option_t *o)
958{
959 if (GetNumPixels()==0)
960 return;
961
962 gStyle->SetOptStat(11);
963
964 Int_t palette[50] =
965 {
966 4, 4, 4, 4, 4, // light blue
967 3, 3, 3, 3, 3, // light green
968 6, 6, 6, 6, 6, // magenta
969 5, 5, 5, 5, 5, // yellow
970 7, 7, 7, 7, 7, // cyan
971 //8, 8, 8, 8, 8, // dark green
972 //11, 11, 11, 11,11, // light gray
973 12, 12, 12, 12,12, // dark gray
974 1, 1, 1, 1, 1, // black
975 46, 46, 46, 46, 46,
976 51, 51, 51, 51, 51, // brown
977 };
978
979 gStyle->SetPalette(50, palette);
980 MHCamera::Paint(o);
981
982 TText txt;
983 txt.SetTextAlign(13); // left/bottom
984 txt.SetTextSize(0.03);
985
986 const Double_t range = fGeomCam->GetMaxRadius();
987
988 Int_t max = 0;
989 Int_t num = 0;
990 Int_t pos = 0;
991 for (int i=0; i<fNumPlayers; i++)
992 {
993 const Int_t cnt = CountPlayer(i);
994
995 if (cnt>max)
996 {
997 max = cnt;
998 num = i;
999 }
1000 if (cnt==0)
1001 continue;
1002
1003 TString str = Form("Player #%d: %d %s", i+1, cnt, i==fNumPlayer?"<*>":"");
1004
1005 txt.SetTextColor(GetColor(i, fMinimum, fMaximum, kFALSE));
1006 txt.PaintText(-range*0.95, range-pos*range*0.06, str);
1007
1008 pos++;
1009 }
1010
1011 if (CountPlayers()==1)
1012 {
1013 TString str = "And the Winner... is... player #";
1014 str += Form("%d (Score=%d)", num+1, max);
1015 txt.SetTextColor(kRed); // white
1016 txt.SetTextAlign(22); // centered/centered
1017 txt.SetTextSize(0.05); // white
1018 txt.PaintText(0, 0, str);
1019 }
1020
1021 if (fNumPlayers==0)
1022 {
1023 txt.SetTextSize(0.075);
1024 txt.SetTextColor(kBlack);
1025
1026 txt.SetTextAlign(13); // left/top
1027 txt.PaintTextNDC(0.02, 0.99, GetName());
1028
1029 //txt.SetTextAlign(11); // left/bottom
1030 //txt.PaintTextNDC(0.01, 0.01, Form("%d", GetNumPixels()));
1031 txt.PaintTextNDC(0.02, 0.91, Form("%d", GetNumPixels()));
1032 }
1033}
1034
1035// --------------------------------------------------------------------------
1036//
1037// Calls draw of the base class MHCamera with the necessary options
1038//
1039void MagicJam::Draw(Option_t *o)
1040{
1041 MHCamera::Draw(fNumPlayers>0 ? "pixelentries nopal" : "nopal");
1042 gPad->SetBit(kCannotPick);
1043}
Note: See TracBrowser for help on using the repository browser.