Solving a 2D Maze. const int WIDTH = 10; const int HEIGHT = 10;

Similar documents
Programming Language. Functions. Eng. Anis Nazer First Semester

int n = 10; int sum = 10; while (n > 1) { sum = sum + n; n--; } cout << "The sum of the integers 1 to 10 is " << sum << endl;

Agenda. The main body and cout. Fundamental data types. Declarations and definitions. Control structures

Building on the foundation. Now that we know a little about cout cin math operators boolean operators making decisions using if statements

Review: Expressions, Variables, Loops, and more.

Chapter Four: Loops. Slides by Evan Gallagher. C++ for Everyone by Cay Horstmann Copyright 2012 by John Wiley & Sons. All rights reserved

As an example using arrays, let s write some code to get started with the Upthrust game. We can use a 2D array to represent the game board.

do { statements } while (condition);

#include <iostream> #include <algorithm> #include <cmath> using namespace std; int f1(int x, int y) { return (double)(x/y); }

1. a) What #include statement do you put at the top of a program that does uses cin, cout or endl?

Multiple Choice (Questions 1 13) 26 Points Select all correct answers (multiple correct answers are possible)

Multiple Choice (Questions 1 13) 26 Points Select all correct answers (multiple correct answers are possible)

Tutorial 12 Craps Game Application: Introducing Random Number Generation and Enumerations

1- Write a single C++ statement that: A. Calculates the sum of the two integrates 11 and 12 and outputs the sum to the consol.

Week 3. Function Definitions. Example: Function. Function Call, Return Statement. Functions & Arrays. Gaddis: Chapters 6 and 7.

Chapter Four: Loops II

Why Is Repetition Needed?

Problem Solving: Storyboards for User Interaction

CSCS 261 Programming Concepts Exam 1 Fall EXAM 1 VERSION 1 Fall Points. Absolutely no electronic devices may be used during this exam.

Computer Programming. Basic Control Flow - Loops. Adapted from C++ for Everyone and Big C++ by Cay Horstmann, John Wiley & Sons

Lab Instructor : Jean Lai

THE INTEGER DATA TYPES. Laura Marik Spring 2012 C++ Course Notes (Provided by Jason Minski)

CSCE Practice Midterm. Data Types

Chapter 3 - Functions

Chapter 13. Recursion. Copyright 2016 Pearson, Inc. All rights reserved.

Othello Game. First, to learn the rules of Othello and play online, you can go here:

Islamic University of Gaza Computer Engineering Dept. C++ Programming. For Industrial And Electrical Engineering By Instructor: Ruba A.

Looping and Counting. Lecture 3 Hartmut Kaiser hkaiser/fall_2012/csc1254.html

Looping and Counting. Lecture 3. Hartmut Kaiser hkaiser/fall_2011/csc1254.html

causing a set of statements (the body) to be executed repeatedly. C++ provides three control structures to support iteration (or looping).

Multiple Choice (Questions 1 14) 28 Points Select all correct answers (multiple correct answers are possible)

Week 3. Function Definitions. Example: Function. Function Call, Return Statement. Functions & Arrays. Gaddis: Chapters 6 and 7. CS 5301 Spring 2018

Sol. Sol. a. void remove_items_less_than(int arr[], int size, int value) #include <iostream> #include <ctime> using namespace std;

Introduction to Programming

Linked List using a Sentinel

1) What of the following sets of values for A, B, C, and D would cause the string "one" to be printed?

Functions and Recursion

Notes on the 2008 Exam

Introduction to Programming using C++

CSCE Practice Midterm. Data Types

Chapter 10 - Notes Applications of Arrays

More Flow Control Functions in C++ CS 16: Solving Problems with Computers I Lecture #4

Welcome Back. CSCI 262 Data Structures. Hello, Let s Review. Hello, Let s Review. How to Review 1/9/ Review. Here s a simple C++ program:

Functions. CS111 Lab Queens College, CUNY Instructor: Kent Chin

C++ For Science and Engineering Lecture 12

Summary of basic C++-commands

Increment and the While. Class 15

Basic program The following is a basic program in C++; Basic C++ Source Code Compiler Object Code Linker (with libraries) Executable

causing a set of statements (the body) to be executed repeatedly. C++ provides three control structures to support iteration (or looping).

Using the Xcode Debugger

C++ for Everyone, 2e, Cay Horstmann, Copyright 2012 John Wiley and Sons, Inc. All rights reserved. Using a Debugger WE5.

Sample Final Exam. 1) (24 points) Show what is printed by the following segments of code (assume all appropriate header files, etc.

Learning Recursion. Recursion [ Why is it important?] ~7 easy marks in Exam Paper. Step 1. Understand Code. Step 2. Understand Execution

Name SECTION: 12:45 2:20. True or False (12 Points)

Chapter 17 - Notes Recursion

CS101 PLEDGED SPRING 2001

Introduction to Programming EC-105. Lecture 2

Review: Exam 1. Your First C++ Program. Declaration Statements. Tells the compiler. Examples of declaration statements

CS 117 Programming II, Spring 2018 Dr. Ghriga. Midterm Exam Estimated Time: 2 hours. March 21, DUE DATE: March 28, 2018 at 12:00 PM

Introduction to C++ Systems Programming

1. (18 pts) Short Answer. Provide brief (1-3 sentence) answers to the following:

Chapter 3. More Flow of Control. Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Non-numeric types, boolean types, arithmetic. operators. Comp Sci 1570 Introduction to C++ Non-numeric types. const. Reserved words.

Fundamentals of Programming CS-110. Lecture 2

Multiple Choice (Questions 1 14) 28 Points Select all correct answers (multiple correct answers are possible)

Memory and Pointers written by Cathy Saxton

CSCE 206: Structured Programming in C++

Welcome Back. CSCI 262 Data Structures. Hello, Let s Review. Hello, Let s Review. How to Review 8/19/ Review. Here s a simple C++ program:

Name Section: M/W or T/TH. True or False (14 Points)

Chapter 15 - C++ As A "Better C"

C++ basics Getting started with, and Data Types.

Lab 10: Alternate Controls

Laboratory 0 Week 0 Advanced Structured Programming An Introduction to Visual Studio and C++

Lab 2: Pointers. //declare a pointer variable ptr1 pointing to x. //change the value of x to 10 through ptr1

CPE 112 Spring 2015 Exam III (100 pts) April 8, True or False (12 Points)

Due Date: See Blackboard

Programming. C++ Basics

Chapter 4: Subprograms Functions for Problem Solving. Mr. Dave Clausen La Cañada High School

CMSC 202 Midterm Exam 1 Fall 2015

Introduction to Algorithms and Data Structures. Lecture 6 - Stringing Along - Character and String Manipulation

! A program is a set of instructions that the. ! It must be translated. ! Variable: portion of memory that stores a value. char

Ch 6. Functions. Example: function calls function

CS2255 HOMEWORK #1 Fall 2012

CHAPTER 4 FUNCTIONS. Dr. Shady Yehia Elmashad

CSC 126 FINAL EXAMINATION Spring Total Possible TOTAL 100

CPE 112 Spring 2015 Exam II (100 pts) March 4, Definition Matching (8 Points)

C++ Final Exam 2017/2018

Objectives. Chapter 2: Basic Elements of C++ Introduction. Objectives (cont d.) A C++ Program (cont d.) A C++ Program

Chapter 2: Basic Elements of C++

1. Which of the following best describes the situation after Line 1 has been executed?

Chapter 4. Procedural Abstraction and Functions That Return a Value. Copyright 2015 Pearson Education, Ltd.. All rights reserved.

Chapter 2: Basic Elements of C++ Objectives. Objectives (cont d.) A C++ Program. Introduction

In either case, remember to delete each array that you allocate.

University of Michigan EECS 183: Elem. Programming Concepts Fall 2011 Exam 1: Part 1: Form 1. Professors: ML Dorf, Elliot Soloway

Computer Programming

DHA Suffa University CS 103 Object Oriented Programming Fall 2015 Lab #01: Introduction to C++

2. Functions I: Passing by Value

C++ Basics. Data Processing Course, I. Hrivnacova, IPN Orsay

Local and Global Variables

FORM 1 (Please put your name and form # on the scantron!!!!) CS 161 Exam I: True (A)/False(B) (2 pts each):

Transcription:

Solving a 2D Maze Let s use a 2D array to represent a maze. Let s start with a 10x10 array of char. The array of char can hold either X for a wall, for a blank, and E for the exit. Initially we can hard-code what our maze looks like, as such: #include <iostream> using namespace std; const int WIDTH = 10; const int HEIGHT = 10; int main() char maze[height][width] = 'X','X','X','X','X','X','X','X','X','X', 'X',' ',' ',' ',' ',' ','X',' ',' ','X', 'X',' ','X',' ',' ',' ','X',' ',' ','X', 'X',' ','X','X','X',' ','X',' ',' ','X', 'X',' ',' ',' ','X',' ','X',' ',' ','X', 'X',' ',' ',' ','X',' ',' ',' ','X','X', 'X',' ','X','X','X',' ',' ',' ',' ','X', 'X',' ','X',' ',' ',' ','X',' ',' ','X', 'X',' ',' ',' ',' ',' ','X',' ','E','X', 'X','X','X','X','X','X','X','X','X','X' ; int x=1,y=1; Here we are using the format that initializes a 2D array when the array is defined. In this case let s make it so maze[0][0] is the upper left corner and maze[9][9] is the lower right corner. Because of the way 2D array contents are specified in C++, the first index refers to the row (y coordinate) and the second index corresponds to the column (x coordinate). This is a little different than normal! Usually we would use the first index for x and the second index for y. If we weren t hard-coding the array as shown above, we could use the more conventional format. In addition, let s use integers x and y to store the location of the player. For example, if we start in the upper left corner then we would begin at x=1, y=1. We could have stored the player location as part of the maze, but keeping this separate will make things a little easier later on as we move around. For debugging purposes a function we will want off the bat is a way to print the maze out:

void printmaze(char maze[][width], int curx, int cury) for (int y=0; y < HEIGHT;y++) for (int x=0; x < WIDTH; x++) if ((x==curx) && (y==cury)) cout << "@"; else cout << maze[y][x]; cout << endl; Calling this function will print out our maze. It might look a little funny if you have a proportional size font so the maze will not look square but rectangular. Next, let s make it so we can use WASD to move up, down, left, or right. If we hit a wall then make it invalid to move there. It is machine-specific to get a keypress without pressing the enter key, so for now we ll just require the user press a key and then enter to move. If we hit the exit then stop. Here is complete code: #include <iostream> using namespace std; const int WIDTH = 10; const int HEIGHT = 10; // Function prototypes void printmaze(char maze[][width], int curx, int cury); bool validmove(char maze[][width], int newx, int newy); bool move(char maze[][width], int &curx, int &cury, int newx, int newy); // Return true or false if moving to the specified coordinate is valid bool validmove(char maze[][width], int newx, int newy) // Check for going off the maze edges if (newx < 0 newx >= WIDTH) if (newy < 0 newy >= HEIGHT) // Check if target is a wall if (maze[newy][newx]=='x') return true;

// Make the move on the maze to move to a new coordinate // I passed curx and cury by reference so they are changed to // the new coordinates. I assume the move coordinates are valid. // This returns true if we move onto the exit, false otherwise. bool move(char maze[][width], int &curx, int &cury, int newx, int newy) bool foundexit = false; if (maze[newy][newx]=='e') // Check for exit foundexit = true; curx = newx; // Update location cury = newy; return foundexit; // Display the maze in ASCII void printmaze(char maze[][width], int curx, int cury) for (int y=0; y < HEIGHT;y++) for (int x=0; x < WIDTH; x++) if ((x==curx) && (y==cury)) cout << "@"; else cout << maze[y][x]; cout << endl; int main() char maze[height][width] = 'X','X','X','X','X','X','X','X','X','X', 'X',' ',' ',' ',' ',' ','X',' ',' ','X', 'X',' ','X',' ',' ',' ','X',' ',' ','X', 'X',' ','X','X','X',' ','X',' ',' ','X', 'X',' ',' ',' ','X',' ','X',' ',' ','X', 'X',' ',' ',' ','X',' ',' ',' ','X','X', 'X',' ','X','X','X',' ',' ',' ',' ','X', 'X',' ','X',' ',' ',' ','X',' ',' ','X', 'X',' ',' ',' ',' ',' ','X',' ','E','X', 'X','X','X','X','X','X','X','X','X','X' ; int x = 1, y = 1; bool foundexit = false; while (!foundexit)

printmaze(maze,x,y); cout << "Enter WASD to move." << endl; char c; cin >> c; c = tolower(c); switch (c) case 'w': if (validmove(maze,x,y-1)) foundexit = move(maze,x,y,x,y-1); break; case 'a': if (validmove(maze,x-1,y)) foundexit = move(maze,x,y,x-1,y); break; case 's': if (validmove(maze,x,y+1)) foundexit = move(maze,x,y,x,y+1); break; case 'd': if (validmove(maze,x+1,y)) foundexit = move(maze,x,y,x+1,y); To have the computer solve the maze perhaps the easiest approach is to randomly pick a direction and try it. In theory, eventually we would find out way to the exit. Here are some modification we would make: #include <cstdlib> #include <ctime> in main srand(time(null)); printmaze(maze,x,y); char c; int rnd = rand() % 4; if (rnd == 0) c = 'w'; else if (rnd == 1) c = 'a'; else if (rnd == 2) c = 's'; else c = 'd'; switch (c)

If we try this then on our simple maze eventually we reach the end, sometimes it takes a while though! A better solution is to actually search for the exit. We can do this in a fairly small amount of code using. The stack used by the computer will help us remember which moves we have made. To remember the cells we have already been to we can make a new 2D array of booleans. Initially they are set to false to indicate we haven t visited them yet. When we visit that location we set it to true. In checking for a valid move, we make sure we haven t already visited that cell yet. If we have, we can consider it invalid. To declare and initialize this array in main: bool visited[height][width]; // Initialize visited locations for (int x = 0; x < WIDTH; x++) for (int y = 0; y < HEIGHT; y++) visited[y][x] = false; visited[y][x] = true; Here are updated versions of our functions: bool validmove(char maze[][width], bool visited[][width], int newx, int newy) if (newx < 0 newx >= WIDTH) if (newy < 0 newy >= HEIGHT) if (maze[newy][newx]=='x') if (visited[newy][newx]) return true;

bool move(char maze[][width], bool visited[][width], int &curx, int &cury, int newx, int newy) bool foundexit = false; if (maze[newy][newx]=='e') // Check for exit foundexit = true; curx = newx; // Update location cury = newy; visited[cury][curx] = true; return foundexit; We have to change our function calls in main for validmove and move to also pass in the visited array. We could run this with our random move algorithm but it may get stuck! Do you know why? Now that we have a way to remember where we ve been, here is pseudocode for the recursive algorithm to search for the exit. We start with x,y set to our start coordinates: search(maze, visited, x, y) If current cell is the exit then return true Mark the current cell as being visited If up is valid and not visited search(maze,visited,curx, cury-1) if left is valid and not visited and we haven t found an exit yet search(maze,visited,curx-1, cury) if right is valid and not visited and we haven t found an exit yet search(maze, visited, curx+1,cury) if down is valid and not visited and we haven t found an exit yet search(maze, visited, curx, cury+1) if exit found, return true // couldn t find a solution from this cell in any direction We can trace the algorithm logic from our start position. Let s say we start at 2,2 using the small maze shown below. This is what things look like when we are in main.

When we call search for the first time we check that we are not at the exit and set visited to true: Inside search, we see that it is valid to move up to (2,1). It is not visited and is not a wall. So we make a recursive call to search with y-1. In this recursive call, moving up is not valid because there is a wall at (2,0). Next we would try moving left, which is allowed because there is no wall at (1,1) and it is not visited.

In this recursive call, we check up and that is not valid because of the wall at (1,0). We check left, and that is not valid because of the wall at (0,1). Next we check right and that is not allowed because we already visited (2,1). So finally we check down and that is allowed because (1,2) is a blank and not visited. At this point our recursive calls have reached a dead end! Checking up is a cell we have visited already. Checking left is a wall. Checking right is a cell we have visited already. Checking down is a wall. This recursive call must exit and return false. We return to execution of search in the previous stack frame.

In this recursive call, we resume execution from searching down. It turns out there is nothing left to search, so this recursive call also returns false and we return to execution of search in the previous stack frame. This recursive call would resume execution from looking left, so it will try looking right but we can t move there because of the wall at (3,1). We try looking down but can t move there because we already visited (2,2). So this recursive call also returns false and we resume execution in the previous stack frame. This recursive call would resume execution from looking up, so next it will look left but we can t move there because we already visited (1,2). Next we look right and can t move there because of the wall at (3,2). Next we look down and we can move there! (2,3) is not visited and is empty.

From this recursive call we mark the cell as visited and check up at (2,2), left at (1,3), right at (3,3) and none of those are not allowed. But we can move down to (2,4). It is empty and not a wall. At this point the first line of the recursive call kicks in! We are at the exit, so this returns true. All of the other recursive calls return true until execution resumes in main. Here is complete code: include <iostream> #include <ctime> #include <cstdlib> using namespace std; const int WIDTH = 10; const int HEIGHT = 10; // Function prototypes void printmaze(char maze[][width], int curx, int cury); bool validmove(char maze[][width], bool visited[][width], int newx, int newy); bool move(char maze[][width], bool visited[][width], int &curx, int &cury, int newx, int newy);

// Return true or false if moving to the specified coordinate is valid // Return false if we have been to this cell already bool validmove(char maze[][width], bool visited[][width], int newx, int newy) // Check for going off the maze edges if (newx < 0 newx >= WIDTH) if (newy < 0 newy >= HEIGHT) // Check if target is a wall if (maze[newy][newx]=='x') // Check if visited if (visited[newy][newx]) return true; // Make the move on the maze to move to a new coordinate // I passed curx and cury by reference so they are changed to // the new coordinates. Here we assume the move coordinates are valid. // This returns true if we move onto the exit, false otherwise. // Also update the visited array. bool move(char maze[][width], bool visited[][width], int &curx, int &cury, int newx, int newy) bool foundexit = false; if (maze[newy][newx]=='e') // Check for exit foundexit = true; curx = newx; // Update location cury = newy; visited[cury][curx] = true; return foundexit; // Display the maze in ASCII void printmaze(char maze[][width], int curx, int cury) for (int y=0; y < HEIGHT;y++) for (int x=0; x < WIDTH; x++) if ((x==curx) && (y==cury)) cout << "@"; else cout << maze[y][x];

cout << endl; // Recursively search from x,y until we find the exit bool search(char maze[][width], bool visited[][width], int x, int y) bool foundexit; if (maze[y][x]=='e') return true; visited[y][x]=true; if (validmove(maze,visited,x,y-1)) foundexit = search(maze,visited,x,y-1); if (!foundexit && (validmove(maze,visited,x,y+1))) foundexit = search(maze,visited,x,y+1); if (!foundexit && (validmove(maze,visited,x-1,y))) foundexit = search(maze,visited,x-1,y); if (!foundexit && (validmove(maze,visited,x+1,y))) foundexit = search(maze,visited,x+1,y); return foundexit; int main() char maze[height][width] = 'X','X','X','X','X','X','X','X','X','X', 'X',' ',' ',' ',' ',' ','X',' ',' ','X', 'X',' ','X',' ',' ',' ','X',' ',' ','X', 'X',' ','X','X','X',' ','X',' ',' ','X', 'X',' ',' ',' ','X',' ','X',' ',' ','X', 'X',' ',' ',' ','X',' ',' ',' ','X','X', 'X',' ','X','X','X',' ',' ',' ',' ','X', 'X',' ','X',' ',' ',' ','X',' ',' ','X', 'X',' ',' ',' ',' ',' ','X',' ','E','X', 'X','X','X','X','X','X','X','X','X','X' ; bool visited[height][width]; int x = 1, y = 1; bool foundexit = false; // Initialize visited locations to false for (int x = 0; x < WIDTH; x++) for (int y = 0; y < HEIGHT; y++) visited[y][x] = false; visited[y][x] = true; cout << search(maze,visited,x,y) << endl;

This program runs, but it doesn t produce very exciting output. It just prints out 1 showing that a path was found to the exit! To print the actual path to the exit, look at the call stack at the point where we found the exit: The (x,y) coordinates stored on the call stack contain the locations we need to move to in order to reach the goal. If we simply output these coordinates (or the board with the @ at these coordinates) as the recursive search function exits a found exit, then it will output the sequence of mazes to reach the exit. Here is the modified search function: bool search(char maze[][width], bool visited[][width], int x, int y) bool foundexit; if (maze[y][x]=='e') return true; visited[y][x]=true; if (validmove(maze,visited,x,y-1)) foundexit = search(maze,visited,x,y-1); if (!foundexit && (validmove(maze,visited,x,y+1))) foundexit = search(maze,visited,x,y+1); if (!foundexit && (validmove(maze,visited,x-1,y))) foundexit = search(maze,visited,x-1,y); if (!foundexit && (validmove(maze,visited,x+1,y))) foundexit = search(maze,visited,x+1,y); if (foundexit) printmaze(maze,x,y); cout << endl; return true; Here is sample output for our full maze. Note the path is output in reverse order from the goal first, to the start last, because of the way the values are on the stack.

XX XXXXXX X @X EX XX XXXXXX X @ X EX XX XXXXXX @EX XX XXXXXX @ EX

XX XXXXXX X @ X EX XX XXXXXX X @ X EX XX XXXXX@ XXX EX XX X @ X XXXXXX EX

XX X @ X XXXXXX EX XX X @ X XXXXXX EX XX X @ X XXXXXX EX XX X@ X XXXXXX EX

X@ XXX XXXXXX EX X@ X XX XXXXXX EX X@X XX XXXXXX EX X@ X XX XXXXXX EX 1