![]() |
PortableGUI |
Hosted by SourceForge Project page |
/*** * Portable GUI * Code for Huarong Path * Copyright (C) 2001-2001 LittlePanda <littlepanda@mostlysunny.com> */ #include <portablegui.h> #include "huarong.h" class HRBoard; class HRPiece; class HRPossibleMove; #define mokka &g_hMokka #define choco &g_hChoco PGColor g_hMokka(187,170,142); PGColor g_hChoco(59,42,14); PGFont* g_hBoldfont; PGFrame* g_hMainFrame; PGPanel* g_hStatus; PGIcon* g_hIcon; PGImage* g_hLogo; HRBoard* g_hBoard; PGPanel* g_hControl; PGLabel* g_hSteps; PGButton* g_hButtonNew; PGButton* g_hButtonRandom; PGButton* g_hButtonUndo; PGButton* g_hButtonSolve; PGButton* g_hButtonHelp; PGButton* g_hButtonAbout; PGButton* g_hButtonQuit; void setSteps(int nb); void enableUndoButton(); void disableUndoButton(); class HRBoard : public PGCanvas { private: HRPiece* piece[10]; float xUnit, yUnit; HRPiece* pieceSelected; int oldX, oldY, steps; PGStack stack; int possibles[10][4][2]; boolean refresh; int margin; PGString message; PGDimension bufferdim; PGImage bufferimg; PGGraphics* buffergfx; private: HRPiece* selectPiece(int x, int y); int gridifyX(int x); int gridifyY(int y); public: HRBoard(); float getXUnit(); float getYUnit(); int getMargin(); void reposition(); void resetboard(); virtual void getPreferredSize(PGDimension* dim, BOOL recalc); virtual void paint(PGGraphics* g); virtual void update(PGGraphics* g); int isEmpty(int x, int y); void mousePressed(int x, int y); void mouseReleased(int x, int y); void randomize(); void autosolve(); void undo(); void possibleMoves(HRPossibleMove* marray); int nbMovables(HRPossibleMove* marray, int idx); int isDone(); }; class HRMouseListener : public PGMouseListener { public: virtual void mousePressed(PGMouseEvent* evt) { g_hBoard->mousePressed(evt->getX(), evt->getY()); } virtual void mouseReleased(PGMouseEvent* evt) { g_hBoard->mouseReleased(evt->getX(), evt->getY()); } }; class HRPiece { private: HRBoard *board; int pwidth, pheight, xpos, ypos; public: HRPiece::HRPiece(HRBoard* b, int w, int h) { board = b; pwidth = w; pheight = h; } void setPos(int x, int y) { xpos = x; ypos = y; } int getXPos() { return xpos; } int getYPos() { return ypos; } void show(PGGraphics* g) { g->setColor(mokka); int x1 = PGMathRound(xpos * board->getXUnit()) + board->getMargin(); int y1 = PGMathRound(ypos * board->getYUnit()) + board->getMargin(); int x2 = PGMathRound(pwidth * board->getXUnit()) - 2; int y2 = PGMathRound(pheight * board->getYUnit()) - 2; g->fillRect(x1,y1,x2,y2 ); g->draw3DRect(x1,y1,x2-1,y2-1,true); } void moveBy(PGGraphics* g, int x, int y) { x += xpos; y += ypos; int x1 = PGMathRound(xpos * board->getXUnit()) + board->getMargin(); int y1 = PGMathRound(ypos * board->getYUnit()) + board->getMargin(); int x2 = PGMathRound(pwidth * board->getXUnit()) - 2; int y2 = PGMathRound(pheight * board->getYUnit()) - 2; if (g != NULL) { g->setColor(PGCOLOR_BLACK); g->fillRect(x1,y1,x2,y2); } setPos(x,y); if (g != NULL) show(g); } void moveBy(int x, int y) { x += xpos; y += ypos; setPos(x,y); } boolean isSelected(int x, int y) { return (xpos <= x && ypos <= y && x < (xpos + pwidth) && y < (ypos + pheight)); } boolean isLegalMove(int* dir) { if (PGMathAbs(dir[0]) > 2) dir[0] = 2*dir[0]/PGMathAbs(dir[0]); if (PGMathAbs(dir[1]) > 2) dir[1] = 2*dir[1]/PGMathAbs(dir[1]); int dirX = dir[0]; int dirY = dir[1]; if (dirX == 0 && dirY == 0) return false; if (PGMathAbs(pwidth*dirY)+PGMathAbs(pheight*dirX) > 2) return false; if (PGMathAbs(dirX) == 2) { dir[0] /= 2; if (isLegalMove(dir)) { xpos += dir[0]; if (isLegalMove(dir)) dir[0] *= 2; xpos -= dirX/2; return true; } else return false; } if (PGMathAbs(dirY) == 2) { dir[1] /= 2; if (isLegalMove(dir)) { ypos += dir[1]; if (isLegalMove(dir)) dir[1] *= 2; ypos -= dirY/2; return true; } else return false; } if (PGMathAbs(dirX) == 1 && PGMathAbs(dirY) == 1) { dir[1] = 0; if (isLegalMove(dir)) { xpos += dirX; dir[0] = 0; dir[1] = dirY; if (!isLegalMove(dir)) dir[1] = 0; dir[0] = dirX; xpos -= dirX; return true; } else { dir[1] = dirY; dir[0] = 0; if (isLegalMove(dir)) { ypos += dirY; dir[0] = dirX; dir[1] = 0; if (!isLegalMove(dir)) dir[0] = 0; dir[1] = dirY; ypos -= dirY; return true; } else return false; } } int newX = xpos + dirX; int newY = ypos + dirY; if (newX < 0 || (newX + pwidth - 1) >= 4 || newY < 0 || (newY + pheight - 1) >= 5) return false; if (dirX == 1) return (g_hBoard->isEmpty(xpos + pwidth, ypos) && g_hBoard->isEmpty(xpos + pwidth, ypos+pheight-1)); if (dirX == -1) return (g_hBoard->isEmpty(xpos - 1, ypos)&& g_hBoard->isEmpty(xpos - 1, ypos + pheight - 1)); if (dirY == 1) return (g_hBoard->isEmpty(xpos, ypos + pheight) && g_hBoard->isEmpty(xpos + pwidth - 1, ypos + pheight)); if (dirY == -1) return (g_hBoard->isEmpty(xpos, ypos - 1) && g_hBoard->isEmpty(xpos+pwidth - 1, ypos - 1)); return false; } }; class HRMove : public PGObject { public: int px, py, dx, dy; public: HRMove(int* dir, HRPiece* piece) { px = dir[0]; py = dir[1]; dx = piece->getXPos(); dy = piece->getYPos(); } }; class HRPossibleMove : public PGObject { public: int dx, dy; boolean possible; public: HRPossibleMove() { dx = 0; dy = 0; possible = false; } void setPossible(boolean pos) { possible = pos; } void setDirection(int x, int y) { dx = x; dy = y; } boolean isPossible() { return possible; } }; HRPiece* HRBoard::selectPiece(int x, int y) { for (int i = 0; i < 10; i++) { if (piece[i]->isSelected(x, y)) { return piece[i]; } } return NULL; } int HRBoard::gridifyX(int x) { return (int)((x - margin)/xUnit); } int HRBoard::gridifyY(int y){ return (int)((y - margin)/yUnit); } HRBoard::HRBoard(){ piece[0] = new HRPiece(this, 2, 2); piece[1] = new HRPiece(this, 1, 2); piece[2] = new HRPiece(this, 1, 2); piece[3] = new HRPiece(this, 1, 2); piece[4] = new HRPiece(this, 1, 2); piece[5] = new HRPiece(this, 2, 1); piece[6] = new HRPiece(this, 1, 1); piece[7] = new HRPiece(this, 1, 1); piece[8] = new HRPiece(this, 1, 1); piece[9] = new HRPiece(this, 1, 1); int dirL[2]; dirL[0] = -1; dirL[1] = 0; int dirR[2]; dirR[0] = 1; dirR[1] = 0; int dirD[2]; dirD[0] = 0; dirD[1] = -1; int dirU[2]; dirU[0] = 0; dirU[1] = 1; for (int i = 0; i < 10; i++) { for (int j = 0; j < 2; j++) { possibles[i][0][j] = dirL[j]; possibles[i][1][j] = dirR[j]; possibles[i][2][j] = dirD[j]; possibles[i][3][j] = dirU[j]; } } margin = 8; message = ""; resetboard(); reposition(); addMouseListener(new HRMouseListener()); } float HRBoard::getXUnit(){ return xUnit; } float HRBoard::getYUnit(){ return yUnit; } int HRBoard::getMargin(){ return margin; } void HRBoard::reposition(){ piece[0]->setPos(1, 0); piece[1]->setPos(0, 0); piece[2]->setPos(0, 2); piece[3]->setPos(3, 0); piece[4]->setPos(3, 2); piece[5]->setPos(1, 2); piece[6]->setPos(0, 4); piece[7]->setPos(1, 3); piece[8]->setPos(2, 3); piece[9]->setPos(3, 4); repaint(); refresh = true; } void HRBoard::resetboard(){ message = ""; steps = 0; stack.removeAll(); } void HRBoard::getPreferredSize(PGDimension* dim, BOOL recalc) { dim->width = 200; dim->height = 200; } void HRBoard::paint(PGGraphics* g){ PGDimension d; getSize(&d); if ((buffergfx == NULL) || (d.width != bufferdim.width) || (d.height != bufferdim.height)) { bufferdim = d; xUnit = (d.width - 2*margin)/4.0f; yUnit = (d.height - 2*margin)/5.0f; createImage(d.width, d.height, &bufferimg); refresh = true; } if (refresh) { buffergfx = bufferimg.getGraphics(); buffergfx->setColor(PGCOLOR_BLACK); buffergfx->fillRect(0, 0, d.width, d.height); buffergfx->setColor(PGCOLOR_WHITE); buffergfx->draw3DRect(2, 2, d.width-5, d.height-5, false); buffergfx->draw3DRect(margin-2, margin-2, d.width-2*margin+3, d.height-2*margin+3, false); buffergfx->setColor(PGCOLOR_BLACK); buffergfx->fillRect(margin + PGMathRound(xUnit)-1, d.height-margin, PGMathRound(xUnit*2), margin); for (int i = 0; i < 10; i++) piece[i]->show(buffergfx); refresh = false; } if (strcmp(message,"") != 0) { buffergfx->setColor(choco); buffergfx->setFont(this, g_hBoldfont); buffergfx->drawString(message,12,d.height/2-12); } g->drawImage(&bufferimg, 0, 0); } void HRBoard::update(PGGraphics* g){ paint(g); } int HRBoard::isEmpty(int x, int y){ return (selectPiece(x, y) == NULL); } void HRBoard::mousePressed(int x, int y){ oldX = gridifyX(x); oldY = gridifyY(y); pieceSelected = selectPiece(oldX, oldY); } void HRBoard::mouseReleased(int x, int y){ if (pieceSelected != NULL) { x = gridifyX(x); y = gridifyY(y); int dir[2]; dir[0] = x - oldX; dir[1] = y - oldY; if (pieceSelected->isLegalMove(dir)) { oldX = pieceSelected->getXPos(); oldY = pieceSelected->getYPos(); if (steps == 0) enableUndoButton(); pieceSelected->moveBy(buffergfx, dir[0], dir[1]); HRMove* move = new HRMove(dir, pieceSelected); stack.push(move); PGINCREF(move); steps++; setSteps(steps); if (isDone()) { message = "Puzzle solved! :O)"; } else { if (strcmp(message,"") != 0){ message = ""; refresh = true; } } repaint(); } pieceSelected = NULL; } } void HRBoard::randomize(){ PGRandom* randomizer = new PGRandom(); PGINCREF(randomizer); HRPossibleMove movables[40]; for (int i = 0; i < 10000; i++) { possibleMoves(movables); int s = randomizer->nextInt(10); int nb = nbMovables(movables,s); while (nb == 0) { s = randomizer->nextInt(10); nb = nbMovables(movables,s); } int posidx = 0; int idx = randomizer->nextInt(nb); for (int ctr = 0; ctr < 4; ctr++) { if (movables[s*4+ctr].isPossible()) { if (posidx == idx) { piece[s]->moveBy(movables[s*4+ctr].dx, movables[s*4+ctr].dy); break; } posidx++; } } } PGDECREF(randomizer); refresh = true; repaint(); } int HRBoard::nbMovables(HRPossibleMove* marray, int idx) { int nb = 0; for(int i = 0; i < 4; i++) { if (marray[idx*4+i].isPossible()) nb++; } return nb; } void HRBoard::autosolve(){ piece[0]->setPos(2, 3); piece[1]->setPos(0, 0); piece[2]->setPos(1, 0); piece[3]->setPos(2, 0); piece[4]->setPos(3, 0); piece[5]->setPos(0, 2); piece[6]->setPos(2, 2); piece[7]->setPos(3, 2); piece[8]->setPos(0, 3); piece[9]->setPos(0, 4); refresh = true; repaint(); } void HRBoard::undo(){ if (! stack.empty()) { HRMove* move = (HRMove*)stack.pop(); int newX = move->dx; int newY = move->dy; int dirX = move->px; int dirY = move->py; PGDECREF(move); selectPiece(newX, newY)->moveBy(buffergfx, -dirX, -dirY); if (isDone()) { message = "Puzzle solved! :O)"; } else { if (strcmp(message, "") != 0){ message = ""; refresh = true; } } repaint(); steps --; if (steps == 0) disableUndoButton(); setSteps(steps); } else { steps = 0; disableUndoButton(); } } void HRBoard::possibleMoves(HRPossibleMove *movables){ for (int i = 0; i < 10; i++) { for (int j = 0; j < 4; j++) { int idir[2]; idir[0] = possibles[i][j][0]; idir[1] = possibles[i][j][1]; if (piece[i]->isLegalMove(idir)) { movables[i*4+j].setPossible(true); movables[i*4+j].setDirection(idir[0], idir[1]); } else movables[i*4+j].setPossible(false); } } } int HRBoard::isDone(){ return (piece[0]->getXPos() == 1 && piece[0]->getYPos() == 3); } class MyWindowListener : public PGWindowListener { virtual void windowClosing(PGWindow* wnd) { getPGApplication()->exit(0); } }; void setSteps(int nb) { if (nb == 1) g_hSteps->setText(STR(nb) + STR(" step")); else g_hSteps->setText(STR(nb) + STR(" steps")); } void enableAllButtons() { g_hButtonNew->setEnabled(true); g_hButtonRandom->setEnabled(true); g_hButtonSolve->setEnabled(true); g_hButtonHelp->setEnabled(true); g_hButtonAbout->setEnabled(true); g_hButtonQuit->setEnabled(true); } void disableAllButtons() { g_hButtonNew->setEnabled(false); g_hButtonRandom->setEnabled(false); g_hButtonSolve->setEnabled(false); g_hButtonHelp->setEnabled(false); g_hButtonAbout->setEnabled(false); g_hButtonQuit->setEnabled(false); } void enableUndoButton() { g_hButtonUndo->setEnabled(true); } void disableUndoButton() { g_hButtonUndo->setEnabled(false); } class HRButtonNewListener : public PGActionListener { public: virtual void actionPerformed(PGActionListenerParent* from) { g_hBoard->resetboard(); setSteps(0); disableUndoButton(); g_hBoard->reposition(); } }; class HRButtonRandomListener : public PGActionListener { public: virtual void actionPerformed(PGActionListenerParent* from) { g_hBoard->resetboard(); setSteps(0); disableUndoButton(); disableAllButtons(); g_hBoard->randomize(); enableAllButtons(); } }; class HRButtonUndoListener : public PGActionListener { public: virtual void actionPerformed(PGActionListenerParent* from) { g_hBoard->undo(); } }; class HRButtonSolveListener : public PGActionListener { public: virtual void actionPerformed(PGActionListenerParent* from) { g_hBoard->resetboard(); setSteps(0); disableUndoButton(); g_hBoard->autosolve(); } }; class HRButtonHelpListener : public PGActionListener { public: virtual void actionPerformed(PGActionListenerParent* from) { PGStyle* style = new PGStyle(); style->setFont(new PGFont("Dialog", PGFONT_BOLD | PGFONT_ITALIC, 16)); // Create help dialog PGDialog help(g_hMainFrame, "Help - Huarong Path Puzzle"); help.addWindowListener(new PGCloseWindowListener()); help.setLayout(new PGBorderLayout(1,1,5,5)); PGTextArea* ta = new PGTextArea("The goal of this puzzle is to move the big square to the exit at the bottom center of the game board.", 6, 30, 0); ta->append("\r\n"); ta->append("Use the mouse to drag the pieces."); ta->setEditable(false); help.add(ta, PGBORDERLAYOUT_CENTER); // Create and add close button PGButton* ok = new PGButton(" &Close ", true); ok->setToolTipText("Close this window"); ok->addActionListener(new PGDialogCancelListener(&help)); help.add(ok, PGBORDERLAYOUT_SOUTH); // Pack components in window and show modal help.pack(); help.doModal(); } }; class HRButtonAboutListener : public PGActionListener { public: virtual void actionPerformed(PGActionListenerParent* from) { PGStyle* style = new PGStyle(); style->setFont(new PGFont("Dialog", PGFONT_BOLD | PGFONT_ITALIC, 16)); // Create about dialog PGDialog about(g_hMainFrame, "About Huarong Path Puzzle"); about.addWindowListener(new PGCloseWindowListener()); about.setLayout(new PGBorderLayout(1,1,5,5)); PGTextArea* ta = new PGTextArea("Hua Rong Path Puzzle v1.0", 6, 30, 0); ta->append("\r\n"); ta->append("Author: LittlePanda <littlepanda@mostlysunny.com>"); ta->append("Version: v 1.0"); ta->append("Last Update: 18 June 2001"); ta->setEditable(false); about.add(ta, PGBORDERLAYOUT_CENTER); // Create and add close button PGButton* ok = new PGButton(" &Close ", true); ok->setToolTipText("Close this window"); ok->addActionListener(new PGDialogCancelListener(&about)); about.add(ok, PGBORDERLAYOUT_SOUTH); // Pack components in window and show modal about.pack(); about.doModal(); } }; class HRButtonQuitListener : public PGActionListener { public: virtual void actionPerformed(PGActionListenerParent* from) { getPGApplication()->exit(0); } }; PGPanel* makeControlPanel(PGFrame* frame) { PGPanel* panel = new PGPanel(); panel->setLayout(new PGPercentLayout("12% 12% 12% 12% 12% 12% 12% 4%d 12%", 4, 0, true)); g_hButtonNew = new PGButton("New"); g_hButtonNew->addActionListener(new HRButtonNewListener()); g_hButtonRandom = new PGButton("Random"); g_hButtonRandom->addActionListener(new HRButtonRandomListener()); g_hButtonUndo = new PGButton("Undo"); g_hButtonUndo->addActionListener(new HRButtonUndoListener()); g_hButtonUndo->setEnabled(false); g_hButtonSolve = new PGButton("Solve"); g_hButtonSolve->addActionListener(new HRButtonSolveListener()); //g_hButtonSolve->setEnabled(false); g_hButtonHelp = new PGButton("Help"); g_hButtonHelp->addActionListener(new HRButtonHelpListener()); g_hButtonAbout = new PGButton("About"); g_hButtonAbout->addActionListener(new HRButtonAboutListener()); g_hButtonQuit = new PGButton("Quit"); g_hButtonQuit->addActionListener(new HRButtonQuitListener()); g_hSteps = new PGLabel("0 steps"); panel->add(g_hButtonNew); panel->add(g_hButtonRandom); panel->add(g_hButtonUndo); panel->add(g_hButtonSolve); panel->add(g_hButtonHelp); panel->add(g_hButtonAbout); panel->add(g_hButtonQuit); panel->add(g_hSteps); return panel; } PGPanel* makeStatusPanel(PGFrame* frame) { // Create style for status line PGStyle* style = new PGStyle(); style->setFont(new PGFont("Dialog", PGFONT_PLAIN, 8)); // Create panel PGPanel* panel = new PGPanel(); panel->setLayout(new PGBorderLayout(3, 3)); // Create and add status line PGLabel* status = new PGLabel("Huarong Path v 1.0", PGLABEL_SUNKEN); status->setStyle(style); panel->add(status, PGBORDERLAYOUT_CENTER); // Add panel to main frame frame->setStatusDisplay(status); return panel; } PGImage* loadMemoryGIF(PGWindow* owner, const PGBYTE* data, long size) { PGImage* image = new PGImage(owner); PGMemoryInputStream file(data, size); PGImageReader reader(image); image->m_iError = PGLoadGIF(&file, &reader); return image; } PGMAINPROC { PGApplication app; // Initialize the app using Mainproc args PGINIT(app); // Create main frame window g_hMainFrame = new PGFrame("HuaRong Path"); PGINCREF(g_hMainFrame); g_hBoldfont = new PGFont("Dialog", PGFONT_BOLD, 16); PGINCREF(g_hBoldfont); // Load Huarong title image g_hLogo = loadMemoryGIF(g_hMainFrame, HUARONG_IMG, HUARONG_IMG_SIZE); PGINCREF(g_hLogo); // Add window listener to frame g_hMainFrame->addWindowListener(new MyWindowListener()); // Use simple layoutmanager g_hMainFrame->setLayout(new PGBorderLayout(5,5,8,8)); // Add the panels g_hMainFrame->add(new PGImageViewer(g_hLogo), PGBORDERLAYOUT_NORTH); g_hControl = makeControlPanel(g_hMainFrame); g_hMainFrame->add(g_hControl, PGBORDERLAYOUT_EAST); g_hStatus = makeStatusPanel(g_hMainFrame); g_hMainFrame->add(g_hStatus, PGBORDERLAYOUT_SOUTH); // Add the main Huarong Board g_hBoard = new HRBoard(); g_hMainFrame->add(g_hBoard, PGBORDERLAYOUT_CENTER); // Pack and show the frame g_hMainFrame->pack(); g_hMainFrame->setVisible(true); // Run the main event loop PGEXITCODE exitCode = app.run(); // Free global references PGDECREF(g_hBoldfont); PGDECREF(g_hMainFrame); PGDECREF(g_hLogo); return exitCode; }
Syntax highlighted by Code2HTML, v. 0.9 |
Back to PortableGUI