zero298

Grid Game

Oct 24th, 2013
19
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Grid Game
  3. ///////////////////////////////////////////////////////////////////////////////
  4. // Grid game board program that lets users move a cursor around on a board
  5. ///////////////////////////////////////////////////////////////////////////////
  6.  
  7. #include <stdio.h>      // For I/O
  8. #include <stdlib.h>     // For rand
  9. #include <time.h>       // For seeding Rand
  10. #include <string>     // For memset
  11.  
  12. // Need to include windows so that we can capture key presses properly
  13. #if defined _WIN32 || defined __CYGWIN__
  14. #include <windows.h>
  15. #endif
  16.  
  17. #define USE_SEPARATE_FILES
  18. #ifdef USE_SEPARATE_FILES
  19. #include "RenderContext.h"
  20. #include "I_Drawable.h"
  21. #include "GameBoard.h"
  22. #ifdef WIN32
  23. #include "CmdPromptHelper.h"
  24. #endif
  25. #else
  26.  
  27. // RenderContext
  28. #ifndef USE_SEPARATE_FILES
  29. // Class that acts a canvas for things to draw to
  30. class RenderContext {
  31. private:
  32.    int m_width, m_height; // Width and Height of this canvas
  33.    char* m_renderBuffer; // Array to hold "pixels" of canvas
  34.    char m_clearChar; // What to clear the array to
  35.  
  36. public:
  37.    // Empty Constructor
  38.    RenderContext() : m_width(50), m_height(20), m_clearChar(' ') {
  39.       m_renderBuffer = new char[m_width * m_height];
  40.    }
  41.  
  42.    // Construct to specify width and height of canvas
  43.    RenderContext(int width, int height) : m_width(width), m_height(height), m_clearChar(' ') {
  44.       m_renderBuffer = new char[m_width * m_height];
  45.    }
  46.  
  47.    // Destructor
  48.    ~RenderContext() {
  49.       if (m_renderBuffer) {
  50.          delete m_renderBuffer;
  51.       }
  52.    }
  53.  
  54.    // Get a specific "pixel" on a canvas
  55.    char getContentAt(int x, int y) {
  56.       if (((0 <= x) && (x < m_width)) && ((0 <= y) && (y < m_height))) {
  57.          return m_renderBuffer[(x + (y * m_width))];
  58.       }
  59.    }
  60.  
  61.    // Fill a specific "pixel" on the canvas
  62.    void setContentAt(int x, int y, char val) {
  63.       if (((0 <= x) && (x < m_width)) && ((0 <= y) && (y < m_height))) {
  64.          m_renderBuffer[(x + (y * m_width))] = val;
  65.       }
  66.    }
  67.  
  68.    // Change what this canvas is flooded with when cleared
  69.    void setClearChar(char clearChar) {
  70.       m_clearChar = clearChar;
  71.    }
  72.  
  73.    // Paint the canvas to the shell
  74.    void render() {
  75.       int row, column;
  76.       for (row = 0; row < m_height; row++) {
  77.          for (column = 0; column < m_width; column++) {
  78.             printf("%c", getContentAt(column, row));
  79.          }
  80.          printf("\n");
  81.       }
  82.    }
  83.  
  84.    // Clear the canvas
  85.    void clear() {
  86.       memset(m_renderBuffer, m_clearChar, m_width * m_height);
  87.    }
  88. };
  89. #endif
  90.  
  91. // I_Drawable
  92. #ifndef USE_SEPARATE_FILES
  93. // Interface that allows objects to draw to the canvas
  94. class I_Drawable {
  95. public:
  96.    // Virtual function that draws to the canvas
  97.    virtual void draw(RenderContext&) = 0;
  98. };
  99. #endif
  100.  
  101. // Marker
  102. #ifndef USE_SEPARATE_FILES
  103. // Class representing the cursor that selects objects on a game board
  104. class Marker : public I_Drawable {
  105. private:
  106.    int m_xPos, m_yPos; // Position of cursor
  107. public:
  108.    // Empty constructor
  109.    Marker() : m_xPos(0), m_yPos(0) {
  110.    }
  111.    // Parameterized constructor allowing for setting of initial position
  112.    Marker(int xPos, int yPos) : m_xPos(xPos), m_yPos(yPos) {
  113.    }
  114.    // Draw the cursor to the canvas
  115.    void draw(RenderContext& renderTarget) {
  116.  
  117.       // Adjust marker by board spacing
  118.       // (This is kind of a hack and should be changed)
  119.       int tmpX, tmpY;
  120.       tmpX = ((m_xPos * 5) + 1);
  121.       tmpY = ((m_yPos * 3) + 1);
  122.  
  123.       // Set surrounding elements
  124.       renderTarget.setContentAt(tmpX - 0, tmpY - 1, '-');
  125.       renderTarget.setContentAt(tmpX - 1, tmpY - 0, '|');
  126.       renderTarget.setContentAt(tmpX - 0, tmpY + 1, '-');
  127.       renderTarget.setContentAt(tmpX + 1, tmpY - 0, '|');
  128.    }
  129.    // Get x position
  130.    int getXPos() {
  131.       return m_xPos;
  132.    }
  133.    // Get y position
  134.    int getYPos() {
  135.       return m_yPos;
  136.    }
  137.    // Set x position
  138.    void setXPos(int xPos) {
  139.       m_xPos = xPos;
  140.    }
  141.    // Set y position
  142.    void setYPos(int yPos) {
  143.       m_yPos = yPos;
  144.    }
  145. };
  146. #endif
  147.  
  148. // MoveDirection
  149. #ifndef USE_SEPARATE_FILES
  150. // Enumeration to hold directions a cursor can move
  151. typedef enum {
  152.    MD_UP,
  153.    MD_DOWN,
  154.    MD_LEFT,
  155.    MD_RIGHT
  156. } MoveDirection;
  157. #endif
  158.  
  159. // GameBoard
  160. #ifndef USE_SEPARATE_FILES
  161. // Class to represent the board of a game being played
  162. class GameBoard : public I_Drawable {
  163. private:
  164.    int m_width, m_height; // Width and height of the board
  165.    int m_verticalSpacing, m_horizontalSpacing; // Spaces between each element on the board
  166.    Marker m_marker; // The cursor that will draw on this board
  167.    int* m_board; // Array of elements on this board
  168.  
  169.    // Set a value at a spot on this board
  170.    // (There is no actual padding on the board, so do not include vertical/horizontal spacing)
  171.    void setAtPos(int x, int y, int val) {
  172.       if (((0 <= x) && (x < m_width)) && ((0 <= y) && (x < m_height))) {
  173.          m_board[(x + (y * m_width))] = val;
  174.       }
  175.    }
  176.  
  177.    // Actually create the board
  178.    void generateBoard() {
  179.       int row, column, randomNumber, valToLeft, valToTop;
  180.  
  181.       // Iterate over all rows and columns
  182.       for (row = 0; row < m_height; row++) {
  183.          for (column = 0; column < m_width; column++) {
  184.             // Get the previous elements
  185.             valToLeft = getAtPos(column - 1, row);
  186.             valToTop = getAtPos(column, row - 1);
  187.  
  188.             // Generate random numbers until we have one
  189.             // that is not the same as an adjacent element
  190.             do {
  191.                randomNumber = (2 + (rand() % 7));
  192.             } while ((valToLeft == randomNumber) || (valToTop == randomNumber));
  193.             setAtPos(column, row, randomNumber);
  194.          }
  195.       }
  196.    }
  197.  
  198. public:
  199.    // Empty Constructor
  200.    GameBoard() : m_width(10), m_height(10), m_verticalSpacing(5), m_horizontalSpacing(3), m_marker(Marker()) {
  201.       m_board = new int[m_width * m_height];
  202.       generateBoard();
  203.    }
  204.  
  205.    // Constructor that takes a width and height of a board
  206.    GameBoard(int width, int height) : m_width(width), m_height(height), m_verticalSpacing(5), m_horizontalSpacing(3), m_marker(Marker()) {
  207.       m_board = new int[m_width * m_height];
  208.       generateBoard();
  209.    }
  210.  
  211.    // Destructor
  212.    ~GameBoard() {
  213.       if (m_board) {
  214.          delete m_board;
  215.       }
  216.    }
  217.  
  218.    // Function to get an element on the board
  219.    // I would say overload operator() but it's often overkill
  220.    // and can lead to hard to find bugs
  221.    int getAtPos(int x, int y) {
  222.       if (((0 <= x) && (x < m_width)) && ((0 <= y) && (x < m_height))) {
  223.          return m_board[(x + (y * m_width))];
  224.       }
  225.    }
  226.  
  227.    // Function to draw to the canvas
  228.    void draw(RenderContext& renderTarget) {
  229.       int row, column;
  230.       char buffer[8];
  231.  
  232.       // Iterate over every element
  233.       for (row = 0; row < m_height; row++) {
  234.          for (column = 0; column < m_width; column++) {
  235.  
  236.             // Convert the integer to a char
  237.             sprintf(buffer, "%d", getAtPos(column, row));
  238.  
  239.             // Set the canvas "pixel" to the char at the
  240.             // desired position including the padding
  241.             renderTarget.setContentAt(
  242.                     ((column * m_verticalSpacing) + 1),
  243.                     ((row * m_horizontalSpacing) + 1),
  244.                     buffer[0]);
  245.          }
  246.       }
  247.  
  248.       // Draw the marker
  249.       m_marker.draw(renderTarget);
  250.    }
  251.  
  252.    // Function to move the cursor around depending on input
  253.    // (Does not allow the cursor to move off of the board)
  254.    void handleInput(MoveDirection moveDirection) {
  255.       switch (moveDirection) {
  256.          case MD_UP:
  257.             if (m_marker.getYPos() > 0) {
  258.                m_marker.setYPos(m_marker.getYPos() - 1);
  259.             }
  260.             break;
  261.          case MD_DOWN:
  262.             if (m_marker.getYPos() < m_height - 1) {
  263.                m_marker.setYPos(m_marker.getYPos() + 1);
  264.             }
  265.             break;
  266.          case MD_LEFT:
  267.             if (m_marker.getXPos() > 0) {
  268.                m_marker.setXPos(m_marker.getXPos() - 1);
  269.             }
  270.             break;
  271.          case MD_RIGHT:
  272.             if (m_marker.getXPos() < m_width - 1) {
  273.                m_marker.setXPos(m_marker.getXPos() + 1);
  274.             }
  275.             break;
  276.       }
  277.    }
  278.  
  279.    // Get the width of the board
  280.    int getWidth() {
  281.       return m_width;
  282.    }
  283.  
  284.    // Get the height of the board
  285.    int getHeight() {
  286.       return m_height;
  287.    }
  288. };
  289. #endif
  290.  
  291. // CmdPromptHelper
  292. #ifndef USE_SEPARATE_FILES
  293. // This class is only useful if we are building on windows
  294. #ifdef WIN32
  295.  
  296. // Class to help with drawing on the windows command prompt
  297. class CmdPromptHelper {
  298. private:
  299.    DWORD inMode; // Attributes of std::in before we change them
  300.    DWORD outMode; // Attributes of std::out before we change them
  301.    HANDLE hstdin; // Handle to std::in
  302.    HANDLE hstdout; // Handle to std::out
  303. public:
  304.    // Empty constructor
  305.    CmdPromptHelper() {
  306.       // Get a handle to input of prompt
  307.       hstdin = GetStdHandle(STD_INPUT_HANDLE);
  308.       if ((hstdin == INVALID_HANDLE_VALUE)
  309.               || !GetConsoleMode(hstdin, &inMode)
  310.               || !SetConsoleMode(hstdin, 0)) {
  311.          return;
  312.       }
  313.  
  314.       // Get handle for output of prompt
  315.       hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
  316.       if ((hstdout == INVALID_HANDLE_VALUE)
  317.               || !GetConsoleMode(hstdout, &outMode)) {
  318.          return;
  319.       }
  320.    }
  321.  
  322.    // Revert the console
  323.    void reset() {
  324.       SetConsoleMode(hstdin, inMode);
  325.    }
  326.  
  327.    // See what key is pressed by the user and return it
  328.    WORD getKeyPress() {
  329.       if (hstdin != INVALID_HANDLE_VALUE) {
  330.          DWORD count;
  331.          INPUT_RECORD inrec;
  332.  
  333.          // Get Key Press
  334.          ReadConsoleInput(hstdin, &inrec, 1, &count);
  335.  
  336.          // Return key
  337.          if (inrec.Event.KeyEvent.bKeyDown) {
  338.             return inrec.Event.KeyEvent.wVirtualKeyCode;
  339.          }
  340.  
  341.          // Flush input
  342.          FlushConsoleInputBuffer(hstdin);
  343.       } else {
  344.          return 0;
  345.       }
  346.    }
  347.  
  348.    // Flood the console with empty space so that we can
  349.    // simulate single buffering (I have no idea how to double buffer this)
  350.    void clearScreen() {
  351.       if (hstdout != INVALID_HANDLE_VALUE) {
  352.          CONSOLE_SCREEN_BUFFER_INFO csbi;
  353.          DWORD cellCount; // How many cells to paint
  354.          DWORD count; // How many we painted
  355.          COORD homeCoord = {0, 0}; // Where to put the cursor when we're done
  356.  
  357.          // Get console info
  358.          if (!GetConsoleScreenBufferInfo(hstdout, &csbi)) {
  359.             return;
  360.          }
  361.  
  362.          // Get cell count
  363.          cellCount = csbi.dwSize.X * csbi.dwSize.Y;
  364.  
  365.          // Fill the screen with spaces
  366.          FillConsoleOutputCharacter(
  367.                  hstdout,
  368.                  (TCHAR) ' ',
  369.                  cellCount,
  370.                  homeCoord,
  371.                  &count
  372.                  );
  373.  
  374.          // Set cursor position
  375.          SetConsoleCursorPosition(hstdout, homeCoord);
  376.       }
  377.    }
  378. };
  379. #endif
  380.  
  381. #endif
  382.  
  383. #endif
  384. // Entry point of program
  385. int main() {
  386.    // Create a game board
  387.    GameBoard gb(5, 5);
  388.  
  389.    // Create something to render to
  390.    RenderContext rc(25, 15);
  391.    rc.setClearChar('.');
  392.    rc.clear();
  393.  
  394.    // If on windows, we can animate
  395. #ifdef WIN32
  396.    // Make a helper
  397.    CmdPromptHelper cph;
  398.  
  399.    // Variable to hold key presses
  400.    WORD key;
  401.  
  402.    // Play Game
  403.    do {
  404.       // Draw the board to the render object
  405.       gb.draw(rc);
  406.  
  407.       // Draw the render object
  408.       rc.render();
  409.  
  410.       // Get Key Press
  411.       key = cph.getKeyPress();
  412.  
  413.       // Handle the key press
  414.       switch (key) {
  415.          case VK_UP:
  416.             gb.handleInput(MD_UP);
  417.             break;
  418.          case VK_DOWN:
  419.             gb.handleInput(MD_DOWN);
  420.             break;
  421.          case VK_LEFT:
  422.             gb.handleInput(MD_LEFT);
  423.             break;
  424.          case VK_RIGHT:
  425.             gb.handleInput(MD_RIGHT);
  426.             break;
  427.       }
  428.  
  429.       // Clear Screen
  430.       rc.clear();
  431.       cph.clearScreen();
  432.  
  433.    } while (key != VK_ESCAPE);
  434.  
  435.    // Reset console
  436.    cph.reset();
  437.  
  438.    // If we aren't on windows, we can't animate and have
  439.    // to write OS specific code to handle key presses
  440. #else
  441.  
  442.    // Variable to hold key presses
  443.    char key;
  444.  
  445.    // Play Game
  446.    do {
  447.       // Draw the board to the render object
  448.       gb.draw(rc);
  449.  
  450.       // Draw the render object
  451.       rc.render();
  452.  
  453.       // Get Key Press
  454.       key = getchar();
  455.  
  456.    } while (key != 0);
  457.  
  458. #endif
  459. }
  460.  
  461. // EoF
Advertisement
Add Comment
Please, Sign In to add comment