M-2048.cpp

#include <elgrint.cpp> // Color for tile that contains: 0 2 4 8 16 32 const int tileColorsSize = 12; const MColor tileColors[tileColorsSize] = {clWhite-30, clWhite, clCyan, clAzure+50, clGreen, clYellow, // 64 128 256 512 1024 2048 clViolet+100, clBlue+100, clOrange+50, clGray+30, clOrange+100, clBlack+50 }; class Board : public MWindow { public: Board(MWindow& parent, const MRect& rect) : MWindow(parent,rect), m_vals(16,0), m_score(0), m_hiscore(0) { // Init srand((unsigned)time(NULL)); setBackColor(clGray+clWhite); m_vals.set(rand()%16, 1); // Repeated use - load hi-score if (MSys::getFileInfo("M-2048.hi").name.cnt()) { MString s = MTextFile("M-2048.hi").readAll(); s >> m_hiscore; } // First use - show intro screen else { MDialogBox dlg(*this, AutoRect, "Intro", "Press arrow keys to merge equal numbers\n" "until you reach 2048", "Start game"); dlg.runMessageLoop(true); } } ~Board() // Save hi-score { MTextFile("M-2048.hi",fmOverwrite).append(m_hiscore); } // Auxiliary function - returns tile value in cell (i,j) int& val(int i, int j) { M_ASSERT(i >= 0 && i < 4 && j >= 0 && j < 4 && m_vals.cnt() == 16); return m_vals._getRef(i*4+j); } // Auxiliary function - paints a single tile (useful for animation) void drawTile(double i, double j, const MSize& s, double lum) { // Prepare int v = val(int(i),int(j)); M_ASSERT(v >= 0 && v < tileColorsSize); MColor c = tileColors[v]; c = ConvHSLToRGB(c.H(),c.S(),c.L()*lum); // Tile background setFillSettings(c); MRect r(s.w*0.255*j, s.h*0.2*i, s.w*0.23, s.h*0.18); fillPoly(MPoint(r.x+r.w*0.5,r.y+r.h*0.0), MPoint(r.x+r.w*0.8,r.y+r.h*0.0), MPoint(r.x+r.w*1.0,r.y+r.h*0.2), MPoint(r.x+r.w*1.0,r.y+r.h*0.8), MPoint(r.x+r.w*0.8,r.y+r.h*1.0), MPoint(r.x+r.w*0.2,r.y+r.h*1.0), MPoint(r.x+r.w*0.0,r.y+r.h*0.8), MPoint(r.x+r.w*0.0,r.y+r.h*0.2), MPoint(r.x+r.w*0.2,r.y+r.h*0.0), MPoint(r.x+r.w*0.5,r.y+r.h*0.0)); // Tile value setDrawTextSettings(MFont("Arial",Min(s.w,s.h)/(v>=10?15:10),taBold)); if (v) drawText(pow(2.0,v), r); } // Auxiliary for swipeXXXX - moves tile from (i2,j2) to (i1,j1) void moveTile(int i1, int j1, int i2, int j2) // 1: dst, 2: src { val(i1,j1) = val(i2,j2); val(i2,j2) = 0; } // Auxiliary for swipeXXXX - merges tile at (i2,j2) into tile at (i1,j1) void mergeTiles(int i1, int j1, int i2, int j2) { moveTile(i1,j1,i2,j2); m_score += (int)pow(2.0,++val(i1,j1)); m_hiscore = Max(m_hiscore,m_score); if (val(i1,j1) == 11) // 2048=2^11 { MDialogBox dlg(*this, AutoRect, "Game Over", "Congratulations, you win!", "Quit"); dlg.runMessageLoop(true); getParent().close(); // Mandatory exit to reduce addiction } } // Auxiliary for swipeXXXX (prevents code duplication) - direction-independent handling void finishSwipe() { repaint(); // Refresh board (scheduled) // Add new val (10% chance of 4=2^2, 90% chance of 2=2^1), if possible MVector<int> freeCells; for (MNum i = 0; i < m_vals.cnt(); ++i) if (!m_vals.get(i)) freeCells.append(i); if (freeCells.cnt()) // Select a free cell at random and put 2 or 4 into it { MNum cellIndex = rand()%freeCells.cnt(); int n = freeCells.get(cellIndex); m_vals.set(n, rand()%10 ? 1 : 2); MSize s = getSize(); for (int i = 0; i < 10; ++i) { MApp::sleep(10); drawTile(n/4,n%4,s,0.1*i); } repaint(); } else // No more free cells - fail { MDialogBox dlg(*this, AutoRect, "Game Over", "Sorry, no more moves.", "Quit"); dlg.runMessageLoop(true); getParent().close(); // Mandatory exit to reduce addiction } } // Swipe all tiles left or right (compress and merge adjacent equal tiles) void swipeHorz(bool L) // L: true iff left { for (int i = 0; i < 4; ++i) for (int j = (L?0:3), k = (L?1:2); L?k<4:k>=0; L?++k:--k) if (!val(i,k)) ; else if (!val(i,j) && val(i,k)) moveTile(i,j,i,k); else if (val(i,j) == val(i,k)) mergeTiles(i,L?j++:j--,i,k); else if (k == j+(L?+1:-1)) L?++j:--j; else { moveTile(i,L?++j:--j,i,k); k = j; } finishSwipe(); } // Swipe all tiles up or down (compress and merge adjacent equal tiles) void swipeVert(bool U) // U: true iff up { for (int j = 0; j < 4; ++j) for (int i = (U?0:3), k = (U?1:2); U?k<4:k>=0; U?++k:--k) if (!val(k,j)) ; else if (!val(i,j) && val(k,j)) moveTile(i,j,k,j); else if (val(i,j) == val(k,j)) mergeTiles(U?i++:i--,j,k,j); else if (k == i+(U?+1:-1)) U?++i:--i; else { moveTile(U?++i:--i,j,k,j); k = i; } finishSwipe(); } //// Handlers //// ON_KeysEntered { if (MSys::isPushed(kbEsc)) // Ignore key on Esc (abort move) MWindow::OnKeysEntered(); else switch (digKeys()) { case kbUnpush+kbLeft : case kbGestureLeft : swipeHorz(true); break; case kbUnpush+kbRight : case kbGestureRight : swipeHorz(false); break; case kbUnpush+kbUp : case kbGestureUp : swipeVert(true); break; case kbUnpush+kbDown : case kbGestureDown : swipeVert(false); break; default : MWindow::OnKeysEntered(); } } ON_Paint { // Prepare MSize s = getSize(); // Draw numeric tiles in each of the 16 cells (empty,2,4,8,...,2048) for (int i = 0; i < 4; ++i) for (int j = 0; j < 4; ++j) drawTile(i,j,s,1.0); // Draw total points setFillSettings(clGray); setDrawTextSettings(MFont("Arial",Min(s.w,s.h)/15,taBold)); drawText((MString)"Score: "+m_score, MRect(s.w*0.05,s.h*0.82,NoneSize), tjRight|tjBottom); drawText((MString)"Hi-score: "+m_hiscore, MRect(s.w*0.05,s.h*0.9,NoneSize), tjRight|tjBottom); } private: MVector<int> m_vals; // 16 ints, x=[0..9], 0 - empty, else 2^x int m_score, m_hiscore; }; void MAppMain() { // Init and configure maiframe MMainFrame wnd; wnd.setHighQuality(true); wnd.setSize(MSize(250,350)); wnd.setCaption("M-2048"); wnd.plugBar(MPtr<Board>(wnd,AutoRect)); // Custom icon MImage icon(MSize(32,32),clWhite); for (MImage::Iter it(icon); it(); ++it) *it = tileColors[(it.getY()/8*4+it.getX()/8)%tileColorsSize]; wnd.setIcon(icon); // Run wnd.runMessageLoop(); }

Miranor Home | About Miranor | About Elgrint | Create account | Login | Account settings | Contact Us | Privacy Policy | Site map

© Copyright 2014 by Miranor. All rights reserved. By using this site you agree to the Terms of Use.

Page last updated on August 10th, 2014.

Real Time Web Analytics