Advertisement
SuperLemrick

Maze

Jun 3rd, 2015
308
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 22.87 KB | None | 0 0
  1. ////////////////////////////////////////////////////////////////
  2. // Copyright 2013, CompuScholar, Inc.
  3. //
  4. // This source code is for use by the students and teachers who
  5. // have purchased the corresponding TeenCoder or KidCoder product.
  6. // It may not be transmitted to other parties for any reason
  7. // without the written consent of CompuScholar, Inc.
  8. // This source is provided as-is for educational purposes only.
  9. // CompuScholar, Inc. makes no warranty and assumes
  10. // no liability regarding the functionality of this program.
  11. //
  12. ////////////////////////////////////////////////////////////////
  13.  
  14. using System;
  15. using System.Collections.Generic;
  16. using System.Linq;
  17. using Microsoft.Xna.Framework;
  18. using Microsoft.Xna.Framework.Audio;
  19. using Microsoft.Xna.Framework.Content;
  20. using Microsoft.Xna.Framework.GamerServices;
  21. using Microsoft.Xna.Framework.Graphics;
  22. using Microsoft.Xna.Framework.Input;
  23. using Microsoft.Xna.Framework.Media;
  24. using Microsoft.Xna.Framework.Net;
  25. using Microsoft.Xna.Framework.Storage;
  26.  
  27. namespace Maze
  28. {
  29.  
  30.     // this class tells us which walls in a square are
  31.     // still up (true) or knocked down (false)
  32.     class WallDirections
  33.     {
  34.         public bool North = false;
  35.         public bool East = false;
  36.         public bool South = false;
  37.         public bool West = false;
  38.     }
  39.  
  40.     // a Cell represents one square on the maze grid
  41.     class Cell
  42.     {
  43.         // this object tracks which walls are up or down
  44.         public WallDirections Walls = new WallDirections();
  45.  
  46.         // this property determins the display location of the cell
  47.         public Vector2 UpperLeft;
  48.  
  49.         // this property should be set to true if a backtracking
  50.         // algorithm visits the cell at any point
  51.         public bool Visited = false;
  52.  
  53.         // this property should be set to true if a backtracking
  54.         // algorithm determins the cell is part of the solution
  55.         public bool Solution = false;
  56.  
  57.     }
  58.  
  59.     /// <summary>
  60.     /// This is the main type for your game
  61.     /// </summary>
  62.     ///
  63.    
  64.     public class Maze : Microsoft.Xna.Framework.Game
  65.     {
  66.         GraphicsDeviceManager graphics;
  67.         SpriteBatch spriteBatch;
  68.  
  69.         // the entire maze is drawn with a single pixel that is
  70.         // stretched and tinted as needed!
  71.         Texture2D pixelTexture;
  72.  
  73.         // mazeGrid represent the entire maze as a 2D array of Cells
  74.         private Cell[,] mazeGrid;
  75.  
  76.         // these constants control how large the cells appear on screen
  77.         private const int CELL_HEIGHT = 50;
  78.         private const int CELL_WIDTH = 50;
  79.  
  80.         // the number of columns and rows is calculated based on
  81.         // the screen size and the CELL_HEIGHT and CELL_WIDTH
  82.         private int numCols;
  83.         private int numRows;
  84.  
  85.         // these values are set by the main program to indicate
  86.         // which is the starting cell (0, 0) and ending cell (numCols-1, numRows-1)
  87.         private int startingCol;
  88.         private int startingRow;
  89.         private int endingCol;
  90.         private int endingRow;
  91.  
  92.         // this enumeration describes a direction that the next step will take
  93.         enum Direction { North, East, South, West }
  94.  
  95.         // random number generator used to select next step
  96.         Random randomNumGen = new Random(DateTime.Now.Millisecond);
  97.  
  98.         // when set to true, indicates walkMaze() has found the solution
  99.         bool isDone = false;
  100.  
  101.         // used to detect user input
  102.         KeyboardState oldKeyboardState;
  103.  
  104.         // This method is provided complete as part of the activity starter.
  105.         public Maze()
  106.         {
  107.             graphics = new GraphicsDeviceManager(this);
  108.             Content.RootDirectory = "Content";
  109.         }
  110.  
  111.  
  112.         /// <summary>
  113.         /// LoadContent will be called once per game and is the place to load
  114.         /// all of your content.
  115.         /// </summary>
  116.         // This method is provided complete as part of the activity starter.
  117.         protected override void LoadContent()
  118.         {
  119.             // Create a new SpriteBatch, which can be used to draw textures.
  120.             spriteBatch = new SpriteBatch(GraphicsDevice);
  121.  
  122.             // load the pixel image that will be used to draw the maze
  123.             pixelTexture = Content.Load<Texture2D>("pixel");
  124.  
  125.         }
  126.  
  127.         /// <summary>
  128.         /// UnloadContent will be called once per game and is the place to unload
  129.         /// all content.
  130.         /// </summary>
  131.         // This method is provided complete as part of the activity starter.
  132.         protected override void UnloadContent()
  133.         {
  134.            
  135.         }
  136.  
  137.         /// <summary>
  138.         /// Allows the game to perform any initialization it needs to before starting to run.
  139.         /// This is where it can query for any required services and load any non-graphic
  140.         /// related content.  Calling base.Initialize will enumerate through any components
  141.         /// and initialize them as well.
  142.         /// </summary>
  143.         // This method is provided complete as part of the activity starter.
  144.         protected override void Initialize()
  145.         {
  146.  
  147.             // get the textures loaded first by calling LoadContent
  148.             base.Initialize();
  149.  
  150.             // figure out how many columns and rows we can fit with the current screen size
  151.             numCols = (graphics.GraphicsDevice.Viewport.Width / CELL_WIDTH) -1;
  152.             numRows = (graphics.GraphicsDevice.Viewport.Height / CELL_HEIGHT) -1;
  153.  
  154.             // initialize the starting position as (0,0) and the ending position
  155.             // as the bottom-right square
  156.             startingCol = 0;
  157.             startingRow = 0;
  158.             endingCol = numCols - 1;
  159.             endingRow = numRows - 1;
  160.  
  161.             // go ahead and automatically generate and solve the first maze
  162.             generateAndWalkMaze();
  163.  
  164.         }
  165.  
  166.         // This method is provided complete as part of the activity starter.
  167.         private void generateAndWalkMaze()
  168.         {
  169.             // start by resetting the done flag -- this is a new maze!
  170.             isDone = false;
  171.  
  172.             // clear the entire maze grid and reset all walls to "up"
  173.             initializeMazeGrid();
  174.  
  175.             // call student-implemented method to generate a maze
  176.             generateMaze(startingCol, startingRow);
  177.  
  178.             // reset all of the "visited" flags but leave the maze intact
  179.             resetMazeGrid();
  180.  
  181.             // call student-implemented method to solve a maze
  182.             walkMaze(startingCol, startingRow);
  183.         }
  184.  
  185.  
  186.         // This method is provided complete as part of the activity starter.
  187.         private void initializeMazeGrid()
  188.         {
  189.             // allocate new maze grid
  190.             mazeGrid = new Cell[numCols, numRows];
  191.  
  192.             // for each cell in the grid
  193.             for (int col = 0; col < numCols; col++)
  194.             {
  195.                 for (int row = 0; row < numRows ; row++)
  196.                 {
  197.                     // create new cell and initialize the upper left corner
  198.                     mazeGrid[col, row] = new Cell();
  199.                     mazeGrid[col, row].UpperLeft = new Vector2(CELL_WIDTH / 2 + col * CELL_WIDTH,
  200.                                                                CELL_HEIGHT/ 2 + row * CELL_HEIGHT);
  201.  
  202.                     //initially all cells have all four walls
  203.                     mazeGrid[col, row].Walls.North = true;
  204.                     mazeGrid[col, row].Walls.East = true;
  205.                     mazeGrid[col, row].Walls.South = true;
  206.                     mazeGrid[col, row].Walls.West = true;
  207.                  }
  208.             }
  209.         }
  210.  
  211.         // This method is provided complete as part of the activity starter.
  212.         private void resetMazeGrid()
  213.         {
  214.             // reset the visited flag on all cells to false
  215.             for (int col = 0; col < numCols; col++)
  216.             {
  217.                 for (int row = 0; row < numRows; row++)
  218.                 {
  219.                     mazeGrid[col, row].Visited = false;
  220.                 }
  221.             }
  222.         }
  223.  
  224.  
  225.         // the student will complete this method as part of the chapter activity
  226.         private void generateMaze(int currentCol, int currentRow)
  227.         {
  228.             mazeGrid[currentCol, currentRow].Visited = true;
  229.  
  230.             LinkedList<Direction> avaliableDirections = getAvailableDirections(currentCol, currentRow);
  231.  
  232.             while (avaliableDirections.Count > 0)
  233.             {
  234.                 Direction currentDirection = avaliableDirections.ElementAt(randomNumGen.Next(0, avaliableDirections.Count));
  235.  
  236.                 int newCol = currentCol;
  237.                 int newRow = currentRow;
  238.  
  239.                 if (currentDirection == Direction.East)
  240.                 {
  241.                     mazeGrid[currentCol, currentRow].Walls.East = false;
  242.  
  243.                     newCol += 1;
  244.  
  245.                     mazeGrid[newCol, newRow].Walls.West = false;
  246.                 }
  247.  
  248.                 if (currentDirection == Direction.West)
  249.                 {
  250.                     mazeGrid[currentCol, currentRow].Walls.West = false;
  251.  
  252.                     newCol += 1;
  253.  
  254.                     mazeGrid[newCol, newRow].Walls.East = false;
  255.                 }
  256.  
  257.                 if (currentDirection == Direction.North)
  258.                 {
  259.                     mazeGrid[currentCol, currentRow].Walls.North = false;
  260.  
  261.                     newRow += 1;
  262.  
  263.                     mazeGrid[newCol, newRow].Walls.South = false;
  264.                 }
  265.  
  266.                 if (currentDirection == Direction.South)
  267.                 {
  268.                     mazeGrid[currentCol, currentRow].Walls.North = false;
  269.  
  270.                     newRow += 1;
  271.  
  272.                     mazeGrid[newCol, newRow].Walls.North = false;
  273.                 }
  274.                 generateMaze(newCol, newRow);
  275.  
  276.                 avaliableDirections = getAvailableDirections(currentCol, currentRow);
  277.             }
  278.         }
  279.  
  280.    
  281.         // the student will complete this method as part of the chapter activity
  282.         private void walkMaze(int currentCol, int currentRow)
  283.         {
  284.             if ((currentCol == endingCol) && (currentRow == endingRow))
  285.             {
  286.                 isDone = true;
  287.                 return;
  288.             }
  289.             mazeGrid[currentCol, currentRow].Visited = true;
  290.             mazeGrid[currentCol, currentRow].Solution = true;
  291.  
  292.             LinkedList<Direction> availableDirections = getAvailableDirections(currentCol, currentRow);
  293.  
  294.             while (availableDirections.Count > 0)
  295.             {
  296.                 Direction currentDirection = availableDirections.ElementAt(randomNumGen.Next(0, availableDirections.Count));
  297.  
  298.                 int newCol = currentCol;
  299.                 int newRow = currentRow;
  300.  
  301.                 if (currentDirection == Direction.East)
  302.                 {
  303.                     newCol += 1;
  304.                 }
  305.  
  306.                 if (currentDirection == Direction.West)
  307.                 {
  308.                     newCol -= 1;
  309.                 }
  310.  
  311.                 if (currentDirection == Direction.South)
  312.                 {
  313.                     newRow += 1;
  314.                 }
  315.  
  316.                 if (currentDirection == Direction.North)
  317.                 {
  318.                     newRow -= 1;
  319.                 }
  320.  
  321.                 walkMaze(newCol, newRow);
  322.  
  323.                 if (isDone)
  324.                     return;
  325.  
  326.                 availableDirections = getAvailableDirections(currentCol, currentRow);
  327.             }
  328.             mazeGrid[currentCol, currentRow].Solution = false;
  329.         }
  330.  
  331.         // This method is provided complete as part of the activity starter.
  332.         private LinkedList<Direction> getAvailableSolutions(int currentCol, int currentRow)
  333.         {
  334.             LinkedList<Direction> result = new LinkedList<Direction>();
  335.  
  336.             // Can we step to the east without hitting a wall
  337.             // or previously visited square?
  338.             if ((currentCol + 1 < numCols ) && (mazeGrid[currentCol + 1, currentRow].Visited == false) && (mazeGrid[currentCol, currentRow].Walls.East == false))
  339.             {
  340.                 // add this direction to the list of available directions
  341.                 result.AddLast(Direction.East);
  342.             }
  343.  
  344.             // Can we step to the west without hitting a wall
  345.             // or previously visited square?
  346.             if ((currentCol - 1 >= 0) && (mazeGrid[currentCol - 1, currentRow].Visited == false) && (mazeGrid[currentCol, currentRow].Walls.West == false))
  347.             {
  348.                 // add this direction to the list of available directions
  349.                 result.AddLast(Direction.West);
  350.             }
  351.  
  352.             // Can we step to the south without hitting a wall
  353.             // or previously visited square?
  354.             if ((currentRow + 1 < numRows) && (mazeGrid[currentCol, currentRow + 1].Visited == false) && (mazeGrid[currentCol, currentRow].Walls.South == false))
  355.             {
  356.                 // add this direction to the list of available directions
  357.                 result.AddLast(Direction.South);
  358.             }
  359.  
  360.             // Can we step to the north without hitting a wall
  361.             // or previously visited square?
  362.             if ((currentRow - 1 >= 0) && (mazeGrid[currentCol, currentRow - 1].Visited == false) && (mazeGrid[currentCol, currentRow].Walls.North == false))
  363.             {
  364.                 // add this direction to the list of available directions
  365.                 result.AddLast(Direction.North);
  366.             }
  367.  
  368.             // return whatever list we have made, containing
  369.             // 0, 1, 2, 3, or 4 directions
  370.             return result;
  371.         }
  372.  
  373.         // This method is provided complete as part of the activity starter.
  374.         private LinkedList<Direction> getAvailableDirections(int currentCol, int currentRow)
  375.         {
  376.             LinkedList<Direction> result = new LinkedList<Direction>();
  377.  
  378.             // Can we step to the east without hitting a previously visited square?
  379.             if ((currentCol + 1 < numCols) && (mazeGrid[currentCol + 1, currentRow].Visited == false))
  380.             {
  381.                 // add this direction to the list of available directions
  382.                 result.AddLast(Direction.East);
  383.             }
  384.  
  385.             // Can we step to the west without hitting a previously visited square?
  386.             if ((currentCol - 1 >= 0) && (mazeGrid[currentCol - 1, currentRow].Visited == false))
  387.             {
  388.                 // add this direction to the list of available directions
  389.                 result.AddLast(Direction.West);
  390.             }
  391.  
  392.             // Can we step to the south without hitting a previously visited square?
  393.             if ((currentRow + 1 < numRows) && (mazeGrid[currentCol, currentRow + 1].Visited == false))
  394.             {
  395.                 // add this direction to the list of available directions
  396.                 result.AddLast(Direction.South);
  397.             }
  398.  
  399.             // Can we step to the north without hitting a previously visited square?
  400.             if ((currentRow - 1 >= 0) && (mazeGrid[currentCol, currentRow - 1].Visited == false))
  401.             {
  402.                 // add this direction to the list of available directions
  403.                 result.AddLast(Direction.North);
  404.             }
  405.  
  406.             // return whatever list we have made, containing
  407.             // 0, 1, 2, 3, or 4 directions
  408.             return result;
  409.         }
  410.  
  411.         /// <summary>
  412.         /// Allows the game to run logic such as updating the world,
  413.         /// checking for collisions, gathering input, and playing audio.
  414.         /// </summary>
  415.         /// <param name="gameTime">Provides a snapshot of timing values.</param>
  416.         // This method is provided complete as part of the activity starter.
  417.         protected override void Update(GameTime gameTime)
  418.         {
  419.             // Allows the game to exit
  420.             if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
  421.                 this.Exit();
  422.  
  423.             // initialize keyboard states
  424.             KeyboardState currentKeyboard = Keyboard.GetState();
  425.             if (oldKeyboardState == null)
  426.                 oldKeyboardState = currentKeyboard;
  427.  
  428.             // if space bar was just released
  429.             if (oldKeyboardState.IsKeyDown(Keys.Space) && currentKeyboard.IsKeyUp(Keys.Space))
  430.             {
  431.                 // generate and solve a new maze!
  432.                 generateAndWalkMaze();
  433.             }
  434.  
  435.             // if escape key was just released
  436.             if (oldKeyboardState.IsKeyDown(Keys.Escape) && currentKeyboard.IsKeyUp(Keys.Escape))
  437.             {
  438.                 // exit program!
  439.                 this.Exit();
  440.             }
  441.  
  442.             // update old keyboard state for next time
  443.             oldKeyboardState = currentKeyboard;
  444.  
  445.             base.Update(gameTime);
  446.         }
  447.  
  448.         /// <summary>
  449.         /// This is called when the game should draw itself.
  450.         /// </summary>
  451.         /// <param name="gameTime">Provides a snapshot of timing values.</param>
  452.         // This method is provided complete as part of the activity starter.
  453.         protected override void Draw(GameTime gameTime)
  454.         {
  455.             // create white background
  456.             GraphicsDevice.Clear(Color.White);
  457.  
  458.             // determine how thick the maze walls will be
  459.             int lineWidth = 4;
  460.  
  461.             // calculate the size and location offset of the large solution square
  462.             int solutionBlockWidth = CELL_WIDTH / 2;
  463.             int solutionBlockHeight = CELL_HEIGHT / 2;
  464.             int solutionBlockXOffset = (CELL_WIDTH - solutionBlockWidth) / 2 + lineWidth / 2;
  465.             int solutionBlockYOffset = (CELL_HEIGHT - solutionBlockHeight) / 2 + lineWidth / 2;
  466.  
  467.             // calculate the size and location offset of the smaller visited square
  468.             int visitedBlockWidth = CELL_WIDTH / 4;
  469.             int visitedBlockHeight = CELL_HEIGHT / 4;
  470.             int visitedBlockXOffset = (CELL_WIDTH - visitedBlockWidth) / 2 + lineWidth / 2;
  471.             int visitedBlockYOffset = (CELL_HEIGHT - visitedBlockHeight) / 2 + lineWidth / 2;
  472.  
  473.             // for a grayscale image suitable for black and white printing, uncomment the lines below
  474.             // and comment the second set of colors
  475.             //Color startColor = Color.Black;
  476.             //Color endColor = Color.Black;
  477.             //Color solutionColor = Color.DarkGray;
  478.             //Color visitedColor = Color.LightGray;
  479.  
  480.             // for a color image suitable for viewing onscreen, uncomment the lines below
  481.             // and comment the first set of colors
  482.             Color startColor = Color.Red;
  483.             Color endColor = Color.Green;
  484.             Color solutionColor = Color.Blue;
  485.             Color visitedColor = Color.DarkGray;
  486.  
  487.             spriteBatch.Begin();
  488.  
  489.             // for each cell in the maze
  490.             for (int col = 0; col < numCols; col++)
  491.             {
  492.                 for (int row = 0; row < numRows; row++)
  493.                 {
  494.                     // if this is the starting square, draw it in the starting color
  495.                     if ((col == startingCol) && (row == startingRow))
  496.                         spriteBatch.Draw(pixelTexture, new Rectangle((int)mazeGrid[col, row].UpperLeft.X + lineWidth + 1,
  497.                                                                      (int)mazeGrid[col, row].UpperLeft.Y + lineWidth + 1,
  498.                                                                      CELL_WIDTH - lineWidth - 2, CELL_HEIGHT - lineWidth - 2), null, startColor);
  499.  
  500.                     // if this is the ending square, draw it in the ending color
  501.                     else if ((col == endingCol) && (row == endingRow))
  502.                         spriteBatch.Draw(pixelTexture, new Rectangle((int)mazeGrid[col, row].UpperLeft.X + lineWidth + 1,
  503.                                                                      (int)mazeGrid[col, row].UpperLeft.Y + lineWidth + 1,
  504.                                                                      CELL_WIDTH - lineWidth - 2, CELL_HEIGHT - lineWidth - 2), null, endColor);
  505.  
  506.                     // if this square is part of the solution, draw the large interior square
  507.                     else if (mazeGrid[col, row].Solution)
  508.                         spriteBatch.Draw(pixelTexture, new Rectangle((int)mazeGrid[col, row].UpperLeft.X + solutionBlockXOffset,
  509.                                                                      (int)mazeGrid[col, row].UpperLeft.Y + solutionBlockYOffset,
  510.                                                                      solutionBlockWidth, solutionBlockHeight), null, solutionColor);
  511.  
  512.                     // if this square was visited, draw the small interior square
  513.                     else if (mazeGrid[col, row].Visited)
  514.                         spriteBatch.Draw(pixelTexture, new Rectangle((int)mazeGrid[col, row].UpperLeft.X + visitedBlockXOffset,
  515.                                                                      (int)mazeGrid[col, row].UpperLeft.Y + visitedBlockYOffset,
  516.                                                                      visitedBlockWidth, visitedBlockHeight), null, visitedColor);
  517.  
  518.                     // if the west wall is up, draw the wall
  519.                     if (mazeGrid[col, row].Walls.West)
  520.                         spriteBatch.Draw(pixelTexture, new Rectangle((int)mazeGrid[col, row].UpperLeft.X,
  521.                                                                      (int)mazeGrid[col, row].UpperLeft.Y,
  522.                                                                      lineWidth,CELL_HEIGHT), null,Color.Black);
  523.  
  524.                     // if the east wall is up, draw the wall
  525.                     if (mazeGrid[col, row].Walls.East)
  526.                         spriteBatch.Draw(pixelTexture, new Rectangle((int)mazeGrid[col, row].UpperLeft.X + CELL_WIDTH,
  527.                                                                      (int)mazeGrid[col, row].UpperLeft.Y,
  528.                                                                      lineWidth, CELL_HEIGHT+ lineWidth), null, Color.Black);
  529.  
  530.                     // if the north wall is up, draw the wall
  531.                     if (mazeGrid[col, row].Walls.North)
  532.                         spriteBatch.Draw(pixelTexture, new Rectangle((int)mazeGrid[col, row].UpperLeft.X,
  533.                                                                      (int)mazeGrid[col, row].UpperLeft.Y,
  534.                                                                      CELL_WIDTH, lineWidth), null, Color.Black);
  535.  
  536.                     // if the south wall is up, draw the wall
  537.                     if (mazeGrid[col, row].Walls.South)
  538.                         spriteBatch.Draw(pixelTexture, new Rectangle((int)mazeGrid[col, row].UpperLeft.X,
  539.                                                                      (int)mazeGrid[col, row].UpperLeft.Y + CELL_HEIGHT,
  540.                                                                      CELL_WIDTH + lineWidth, lineWidth), null, Color.Black);
  541.                 }
  542.             }
  543.            
  544.             spriteBatch.End();
  545.  
  546.             base.Draw(gameTime);
  547.         }
  548.     }
  549. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement