/* ======================================================================== *\ ! ! * ! * This file is part of MARS, the MAGIC Analysis and Reconstruction ! * Software. It is distributed to you in the hope that it can be a useful ! * and timesaving tool in analysing Data of imaging Cerenkov telescopes. ! * It is distributed WITHOUT ANY WARRANTY. ! * ! * Permission to use, copy, modify and distribute this software and its ! * documentation for any purpose is hereby granted without fee, ! * provided that the above copyright notice appear in all copies and ! * that both that copyright notice and this permission notice appear ! * in supporting documentation. It is provided "as is" without express ! * or implied warranty. ! * ! ! ! Author(s): Thomas Bretz 07/2002 ! ! Copyright: MAGIC Software Development, 2000-2002 ! ! \* ======================================================================== */ ///////////////////////////////////////////////////////////////////////////// // // MagicDomino // ----------- // // Magic Camera games. // // Start the show by: // MagicDomino show; // // Use the following keys: // ----------------------- // // * Cursor up/down, left/right: // Move tile // // * Space: // Rotate tile // // * Enter: // Set tile // // * Esc: // Skip tile // // Rules: // ------ // // Each hexagon in the tile must at least have one neighbor // which has the same color. It is not allowed to put a tile onto // another one. The game is over if you have skipped three tiles // in a row. // //////////////////////////////////////////////////////////////////////////// #include "MagicDomino.h" #include #include #include #include #include #include "MHexagon.h" #include "MGeomPix.h" #include "MGeomCamCT1.h" #include "MGeomCamMagic.h" ClassImp(MagicDomino); using namespace std; // ------------------------------------------------------------------------ // // Free all onbects connected to a special camera geometry // void MagicDomino::Free() { if (!fGeomCam) return; fPixels->Delete(); delete fPixels; delete fGeomCam; } // ------------------------------------------------------------------------ // // Draw all pixels of the camera // (means apend all pixelobjects to the current pad) // void MagicDomino::DrawHexagons() { for (UInt_t i=0; iGetNumPixels(); fRange = fGeomCam->GetMaxRadius(); // // Construct all hexagons. Use new-operator with placement // fPixels = new TClonesArray("MHexagon", fNumPixels); for (UInt_t i=0; i ROOT_VERSION(3,01,06) h.SetBit(kNoContextMenu|kCannotPick); #endif } } // ------------------------------------------------------------------------ // // remove the pixel numbers in the tile from the pad // void MagicDomino::RemoveNumbers() { for (int i=0; i<6; i++) if (fText[i]) { delete fText[i]; fText[i] = NULL; } } // ------------------------------------------------------------------------ // // Reset/restart the game // void MagicDomino::Reset() { for (UInt_t i=0; i ROOT_VERSION(3,01,06) fDrawingPad->SetBit(kNoContextMenu); SetBit(kNoContextMenu); #endif if (fDone) { delete fDone; fDone = NULL; } fDrawingPad->SetFillColor(22); fNumPixel = -1; fNumTile = 0; fPoints = 0; NewTile(); } // ------------------------------------------------------------------------ // // default constructor // MagicDomino::MagicDomino() : fGeomCam(NULL), fDir(kBottom), fDone(NULL) { memset(fText, 0, sizeof(fText)); SetNewCamera(new MGeomCamMagic); // // Make sure, that the object is destroyed when the canvas/pad is // destroyed. Make also sure, that the interpreter doesn't try to // delete it a second time. // SetBit(kCanDelete); gInterpreter->DeleteGlobal(this); Draw(); } // ------------------------------------------------------------------------ // // Destructor. Deletes TClonesArrays for hexagons and legend elements. // MagicDomino::~MagicDomino() { Free(); RemoveNumbers(); if (fDrawingPad->GetListOfPrimitives()->FindObject(this)==this) { fDrawingPad->RecursiveRemove(this); delete fDrawingPad; } } // ------------------------------------------------------------------------ // // This is called at any time the canvas should get repainted. // Here we maintain an aspect ratio of 5/4=1.15. This makes sure, // that the camera image doesn't get distorted by resizing the canvas. // void MagicDomino::Paint(Option_t *opt) { const UInt_t w = (UInt_t)(gPad->GetWw()*gPad->GetAbsWNDC()); const UInt_t h = (UInt_t)(gPad->GetWh()*gPad->GetAbsHNDC()); // // Check for a change in width or height, and make sure, that the // first call also sets the range // if (w*fH == h*fW && fW && fH) return; // // Calculate aspect ratio (5/4=1.25 recommended) // const Double_t ratio = (Double_t)w/h; Float_t x; Float_t y; if (ratio>1.0) { x = fRange*(ratio*2-1); y = fRange; } else { x = fRange; y = fRange/ratio; } fH = h; fW = w; // // Set new range // fDrawingPad->Range(-fRange, -y, x, y); } // ------------------------------------------------------------------------ // // Call this function to draw the camera layout into your canvas. // Setup a drawing canvas. Add this object and all child objects // (hexagons, etc) to the current pad. If no pad exists a new one is // created. // void MagicDomino::Draw(Option_t *option) { // // if no canvas is yet existing to draw into, create a new one // /*TCanvas *c =*/ new TCanvas("MagicDomino", "Magic Domino Next Neighbours", 0, 0, 800, 800); //c->ToggleEventStatus(); fDrawingPad = gPad; fDrawingPad->SetBorderMode(0); // // Append this object, so that the aspect ratio is maintained // (Paint-function is called) // AppendPad(option); // // Reset the game pad // Reset(); DrawHexagons(); /* TPave *p = new TPave(-0.66*fRange, 0.895*fRange, 0.66*fRange, 0.995*fRange, 4, "br"); p->ConvertNDCtoPad(); p->SetFillColor(12); p->SetBit(kCanDelete); p->Draw(); */ fDomino.SetTextAlign(23); // centered/bottom #if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06) fDomino.SetBit(kNoContextMenu|kCannotPick); #endif fDomino.Draw(); } void MagicDomino::Update() { TString txt = "Points: "; txt += fPoints; txt += " Tile: "; txt += fNumTile; switch (fSkipped) { case 0: fDomino.SetTextColor(8/*kGreen*/); break; case 1: fDomino.SetTextColor(kYellow); break; case 2: fDomino.SetTextColor(kRed); break; default: fDomino.SetTextColor(kWhite); break; } fDomino.SetText(0, fRange, txt); } // ------------------------------------------------------------------------ // // Choose new colors for the tile // void MagicDomino::NewColors() { TRandom rnd(0); for (int i=0; i<3; i++) { Int_t color = (Int_t)rnd.Uniform(5)+2; fNewColors[i*2] = color; fNewColors[i*2+1] = color; } } // ------------------------------------------------------------------------ // // Create a new tile // void MagicDomino::NewTile() { if (fNumPixel>=0) { const MGeomPix &pix=(*fGeomCam)[fNumPixel]; (*this)[fNumPixel].ResetBit(kIsTile); for (int i=0; iUpdate(); } // ------------------------------------------------------------------------ // // Check for at least one correct color for each pixel in tile. // Ignore the tile itself and all background pixels. Check whether // background of tile is empty. // Bool_t MagicDomino::CheckTile() { if (fNumPixel<0) return kFALSE; for (int i=0; i<7; i++) if (fOldColors[i]!=kBackground) return kFALSE; Int_t cnt=0; const MGeomPix &pix1=(*fGeomCam)[fNumPixel]; for (int i=0; i0) cnt++; } return cnt==pix1.GetNumNeighbors(); } // ------------------------------------------------------------------------ // // Game over! // void MagicDomino::Done() { fDone = new TText(0, 0, "Game Over!"); fDone->SetTextColor(kWhite); // white fDone->SetTextAlign(22); // centered/centered fDone->SetTextSize(0.05); // white fDone->Draw(); fDomino.SetTextColor(kBlue); fDrawingPad->SetFillColor(kRed); #if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06) fDone->SetBit(kNoContextMenu|kCannotPick); fDrawingPad->ResetBit(kNoContextMenu); ResetBit(kNoContextMenu); #endif fDrawingPad->Modified(); fDrawingPad->Update(); } // ------------------------------------------------------------------------ // // Execute a mouse event on the camera // void MagicDomino::ExecuteEvent(Int_t event, Int_t keycode, Int_t keysym) { if (event!=kKeyPress || fDone) return; switch (keysym) { case kKey_Escape: fPoints -= 6; fSkipped++; if (fSkipped==3) { Done(); return; } NewColors(); RotateTile(0); return; case kKey_Space: RotateTile(-1); return; case kKey_Return: if (CheckTile()) NewTile(); return; case kKey_Right: fDir = kRight; Step(kRight); return; case kKey_Left: fDir = kLeft; Step(kLeft); return; case kKey_Up: Step(kTop|fDir); return; case kKey_Down: Step(kBottom|fDir); return; case kKey_Plus: RotateTile(+1); return; case kKey_Minus: RotateTile(-1); return; } } // ------------------------------------------------------------------------ // // Rotate the colors in the tile // void MagicDomino::RotateTile(Int_t add) { fPosition += add+6; // Make result positive fPosition %= 6; // Align result between 0 and 5 HideTile(); ShowTile(); Update(); fDrawingPad->Modified(); fDrawingPad->Update(); } // ------------------------------------------------------------------------ // // Hide the tile from the pad // void MagicDomino::HideTile() { if (fNumPixel<0) return; MagicDomino &This = *this; RemoveNumbers(); const MGeomPix &pix1=(*fGeomCam)[fNumPixel]; This[fNumPixel].SetFillColor(fOldColors[6]); This[fNumPixel].ResetBit(kIsTile); for (int i=0; iSetTextSize(0.3*This[idx].GetD()/fGeomCam->GetMaxRadius()); fText[i]->SetTextFont(122); fText[i]->SetTextAlign(22); // centered/centered fText[i]->Draw(); } } // ------------------------------------------------------------------------ // // Hide the tile, change its position, show it again, update status text // void MagicDomino::ChangePixel(Int_t add) { HideTile(); fNumPixel = add; ShowTile(); Update(); fDrawingPad->Update(); } // ------------------------------------------------------------------------ // // Analyse the directions of the next neighbors // Short_t MagicDomino::AnalysePixel(Int_t dir) { const MGeomPix &pix=(*fGeomCam)[fNumPixel<0?0:fNumPixel]; Double_t fAngle[6] = { -10, -10, -10, -10, -10, -10 }; for (int i=0; i-149 && angle<-90 && dir==kBottomLeft) return idx; //if (angle==-90 && dir==kBottom) // return idx; if (angle>-90 && angle<-31 && dir==kBottomRight) return idx; if (angle>-31 && angle<31 && dir==kRight) return idx; if (angle>31 && angle<90 && dir==kTopRight) return idx; //if (angle==90 && dir==kTop) // return idx; if (angle>90 && angle<149 && dir==kTopLeft) return idx; if (angle>149 && dir==kLeft) return idx; } return -1; } // ------------------------------------------------------------------------ // // Sort the next neighbort from the left, top, right, bottom // void MagicDomino::GetSortedNeighbors(Int_t indices[6]) { const MGeomPix &pix=(*fGeomCam)[fNumPixel<0?0:fNumPixel]; Double_t fAngle[6] = { -10, -10, -10, -10, -10, -10 }; for (int i=0; i