Parse a tile map into efficient horizontal and vertical bounding boxes - c++

I'm working on a simple platformer game in C++, everything is working great except i want to group tiles into bounding boxes in order to have less passes of the physics function(i'm targeting both PC's and embedded devices so its all about speed).
What the following function does is load a simple map format:
"[char *header][char bytesize][bytesize w][bytesize h][char tw][char th][char *map]"
It then reads the array as a 2d map and groups vertical lines when possible.
The question is... could someone show me how to group these tiles into efficient bounding boxes on both vertical and horizontal axis?
Heres an image to help explain, i know my grammar and spelling is terrible: http://thetooth.name/dev/blocks_bic.png
void Environment::load_map(char* mapPath){
cl("Loading Map: %s ", mapPath);
FILE* mapFile = fopen(mapPath, "rb");
FILE* mapInfoFile = fopen(strcat(substr(mapPath, 0, strlen(mapPath)-3), "bmd"), "rb");
if (mapFile == NULL || mapInfoFile == NULL)
{
cl("[ERROR]\n");
throw KLGLException("Error loading map file!");
return;
}
size_t wordSize;
char tBuffer[8] = {};
int w = 0;
int h = 0;
int tileWidth = 0;
int tileHeight = 0;
fread(tBuffer, 1, 7, mapFile);
if (strcmp(tBuffer, "STME1.0"))
{
cl("[BADHEADER]");
}
fill_n(tBuffer, 8, NULL);
fread(tBuffer, 1, 1, mapFile);
if (!strcmp(tBuffer, "B"))
{
wordSize = sizeof(char);
}else{
wordSize = sizeof(int);
}
fseek(mapFile, 8, SEEK_SET);
fread(&w, wordSize, 1, mapFile);
fread(&h, wordSize, 1, mapFile);
fread(&tileWidth, 1, 1, mapFile);
fread(&tileHeight, 1, 1, mapFile);
#define lvLookup y*w+x
fill_n(mapData, (w*h)+1, '\0');
fill_n(mapMask, (w*h)+1, '\0');
// Read files into memory... back to front and inside out...
for(int y = 0; y < h; y++){
for(int x = 0; x < w; x++){
fread(&mapData[lvLookup], 1, 1, mapFile);
fread(&mapMask[lvLookup], 1, 1, mapInfoFile);
}
}
fclose(mapFile);
fclose(mapInfoFile);
// Parse map data into are geometry vectors
for(int x = 0; x < w; x++){
for(int y = 0; y < h; y++){
if(mapData[lvLookup] > 0){
int xl = x;
int yl = y;
while(mapData[yl*w+x] != 0/* && mapMask[yl*w+x] == 0*/){
yl++;
}
platforms->push_back(Platform(x*tileWidth, y*tileHeight, 1*tileWidth, (yl-y)*tileHeight, lvLookup, mapData, mapMask));
y = yl-1;
}
}
}
cl("[OK]\n");
}
Thanks in advanced!

This is a little ugly, but I think it should work as a starting point. It works by scanning left to right, top to bottom looking for to find whole columns that are alike. The challenging part is keeping track of consecutive complete vertical blocks and outputting "partial" runs correctly.
void find_bounds()
{
int startx = 0;
char last = mapData[0];
for (int x = 0; x < w; x++) {
int starty = 0;
for (int y = 0; y < h; y++) {
char c = mapData[x+y*w];
if (c != last) {
if (starty == 0) {
// finish last run of complete vertical blocks
if(startx != x) {
// it ran more than one column, output those first
span(last, startx, 0, x-1, h-1);
startx = x;
}
// and a run from the start of this column
span(last, x, 0, x, y);
} else {
// a run within a column
span(last, x, starty, x, y);
}
last = c;
starty = y;
}
}
// had a run withing this column or processing last column, finish it up
if (starty || x == w-1) {
span(last, x, starty, x, h-1);
startx= x + 1;
}
}
}
Test-suite (the first two should correspond to the second and third cases from your illustration):
#include <iostream>
#include <vector>
using namespace std;
const int w = 8, h = 8;
char mapData[w*h+1] =
#if 1
"xxxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
" xxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
#elif 0
"xxxxxxxx"
"xxxxxxxx"
"xxx xxxx"
"xxxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
#else
"xxxxxxxx"
"xx xxxxx"
"xxxxxxxx"
"xx xxxxx"
"xxxx xxx"
"xxxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
#endif
;
void span(char type, int x0, int y0, int x1, int y1)
{
if (!(x0 == x1 && y0 == y1))
cout << type << " " << x0 << ", " << y0 << " -> " << x1 << ", " << y1 << "\n";
}
int main()
{
find_bounds();
}

Related

How can I get the common digits of two int in C++? Example: (1234, 41567) --> 1 4

Given two int I want to get all the common digits and print out them separated by spaces.
So for example, if int x=1234; int y=41567; then I want to print out: 1 4.
This is my code. It does not work properly. When I run it, it prints 0 1 2 3 4 5 then stops.
I don't want to use vector nor arrays.
void problema3() {
int x, y, kX=0, kY=0;
cout << "x="; cin >> x;
cout << "y="; cin >> y;
int cx = x;
int cy = y;
for (int i = 0; i < 10; i++) {
kX = 0;
kY = 0;
x = cx;
y = cx;
while (x != 0 || kX==0) {
if (x % 10 == i) kX=1;
x /= 10;
}
while (y != 0 || kY == 0) {
if (y % 10 == i) kY=1;
y /= 10;
}
if (kX == 1 && kY == 1) cout << i << ' ';
}
}
int main()
{
problema3();
return 0;
}
If you're allowed to use std::set then you can do what you want as follows:
#include <iostream>
#include <set>
void print(int x, int y)
{
int individual_number1 = 0, individual_number2 = 0;
std::set<int> myset;
int savey = y;//this will be used to reset y when the 2nd do while loop finishes
do
{
individual_number1 = x % 10;
do
{
individual_number2 = y % 10;
if(individual_number1 == individual_number2)
{
myset.insert(individual_number1);
break;
}
y = y / 10;
}while( y > 0);
y = savey;
x = x / 10;
} while (x > 0);
//print out the element of the set
for(int i: myset)
{
std::cout<<i<<" ";
}
}
int main()
{
int x = 1234, y = 41567;
print(x, y);
return 0;
}
The output of the above program is as follows:
1 4
which can be seen here.
Your main bug is when assigning copies of cy.
//...
for (int i = 0; i < 10; i++) {
//...
x = cx;
y = cx; // <-- BUG! should read y = cy;
But that's not the only bug in your program.
Your digit detection logic is wrong. In particular, zero is not handled correctly, and since you did not put that reusable code in a function, your program is way more complex than it needs.
Here's the corrected logic for digit detection.
// checks if base 10 representation of a positive integer contains a certain digit (0-9)
bool hasDigit(int x, int d)
{
do
{
if (x % 10 == d)
return true;
x /= 10;
} while (x != 0);
return false;
}
Your main loop then becomes:
// assuming int x, y as inputs.
// ...
for (int i = 0; i < 10; ++i)
{
if (hasDigit(x, i) && hasDigit(y, i))
std::cout << i << ' ';
}
Which leaves very little room for bugs.
You can play with the code here: https://godbolt.org/z/5c5brEcEq

Multithreaded Mandelbrot set code outputs incorrect image

#include <chrono>
#include <cstdint>
#include <cstdlib>
#include <complex>
#include <fstream>
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using std::chrono::duration_cast;
using std::chrono::milliseconds;
using std::chrono::seconds;
using std::complex;
using std::cout;
using std::endl;
using std::this_thread::sleep_for;
using std::ofstream;
using std::thread;
using std::mutex;
using std::condition_variable;
using std::unique_lock;
mutex mutex1;
mutex mutex2;
std::condition_variable done;
typedef std::chrono::steady_clock the_clock;
const int WIDTH1 = 960;
const int HEIGHT1 = 600;
const int WIDTH2 = 1920;
const int HEIGHT2 = 1200;
int finished_threads = 0;
const int MAX_ITERATIONS = 500;
uint32_t image[HEIGHT2][WIDTH2];
struct ThreadArgs { int id; int delay; };
void myThreadFunc(ThreadArgs args)
{
for (int i = 0; i < 1; i++) {
sleep_for(seconds(args.delay));
cout << args.id;
}
}
void write_tga(const char *filename)
{
unique_lock<mutex> lock(mutex2);
while (finished_threads < 2) {
done.wait(lock);
}
ofstream outfile(filename, ofstream::binary);
uint8_t header[18] = {
0, // no image ID
0, // no colour map
2, // uncompressed 24-bit image
0, 0, 0, 0, 0, // empty colour map specification
0, 0, // X origin
0, 0, // Y origin
WIDTH2 & 0xFF, (WIDTH2 >> 8) & 0xFF, // width
HEIGHT2 & 0xFF, (HEIGHT2 >> 8) & 0xFF, // height
24, // bits per pixel
0, // image descriptor
};
outfile.write((const char *)header, 18);
for (int y = 0; y < HEIGHT2; ++y)
{
for (int x = 0; x < WIDTH2; ++x)
{
uint8_t pixel[3] = {
image[y][x] & 0xFF, // blue channel
(image[y][x] >> 8) & 0xFF, // green channel
(image[y][x] >> 16) & 0xFF, // red channel
};
outfile.write((const char *)pixel, 3);
}
}
outfile.close();
if (!outfile)
{
cout << "Error writing to " << filename << endl;
exit(1);
}
}
// Render the Mandelbrot set into the image array.
// The parameters specify the region on the complex plane to plot.
void compute_mandelbrot(double left, double right, double top, double bottom)
{
unique_lock<mutex> lock(mutex2);
for (int y = 0; y < HEIGHT1; ++y)
{
for (int x = 0; x < WIDTH1; ++x)
{
complex<double> c(left + (x * (right - left) / WIDTH2),
top + (y * (bottom - top) / HEIGHT2));
// Start off z at (0, 0).
complex<double> z(0.0, 0.0);
// Iterate z = z^2 + c until z moves more than 2 units
// away from (0, 0), or we've iterated too many times.
int iterations = 0;
mutex1.lock();
while (abs(z) < 2.0 && iterations < MAX_ITERATIONS)
{
z = (z * z) + c;
++iterations;
}
mutex1.unlock();
if (iterations == MAX_ITERATIONS)
{
image[y][x] = 0x000000; // black
}
else
{
image[y][x] = 0xFFFFFF; // white
finished_threads = finished_threads + 1;
done.notify_all();
}
}
}
}
void compute_mandelbrot2(double left2, double right2, double top2, double bottom2)
{
unique_lock<mutex> lock(mutex2);
//map <int, int> val = map<int, int>(0, MAX_ITERATIONS);
//map <int, int> colourval = map<int, int>(0, MAX_ITERATIONS);
for (int y = HEIGHT1; y < HEIGHT2; ++y)
{
for (int x = HEIGHT1; x < WIDTH2; ++x)
{
complex<double> c(left2 + (x * (right2 - left2) / WIDTH2),
top2 + (y * (bottom2 - top2) / HEIGHT2));
// Start off z at (0, 0).
complex<double> z(0.0, 0.0);
// Iterate z = z^2 + c until z moves more than 2 units
int iterations = 0;
mutex1.lock();
while (abs(z) < 2.0 && iterations < MAX_ITERATIONS)
{
z = (z * z) + c;
++iterations;
}
mutex1.unlock();
if (iterations == MAX_ITERATIONS)
{
// z didn't escape from the circle.
// This point is in the Mandelbrot set.
image[y][x] = 0x000000; // black
}
else
{
// z escaped within less than MAX_ITERATIONS
// iterations. This point isn't in the set.
image[y][x] = 0xFFFFFF; // white
finished_threads = finished_threads + 1;
done.notify_one();
}
}
}
}
int main(int argc, char *argv[])
{
std::thread myThread;
std::thread myThread2;
std::thread myThread3;
ThreadArgs args;
myThread = std::thread(compute_mandelbrot, -2.0, 1.0, 1.125, -1.125);
myThread3 = std::thread(compute_mandelbrot2, -2.0, 1.0, 1.125, -1.125);
myThread2 = std::thread(write_tga, "output.tga");
cout << "Please wait..." << endl;
// Start timing
the_clock::time_point start = the_clock::now();
myThread.join();
myThread3.join();
// Stop timing
the_clock::time_point end = the_clock::now();
// Compute the difference between the two times in milliseconds
auto time_taken = duration_cast<milliseconds>(end - start).count();
cout << "Computing the Mandelbrot set took " << time_taken << " ms." << endl;
myThread2.join();
return 0;
}
Above is the multithreaded version of the code and it outputs an incorrect version of the set where most of it is black but some is correct, so I don't know what the issue is:Mandlebrot threaded but the non-threaded version outputs a correct Mandelbrot setMandelbrot not threaded the problem is likely something to do with how I used multithreading: I just don't know what I did wrong. Any help is appreciated.
OK, 'simple' things first! You have a 'typo' in your compute_mandelbrot2 function on the control statement for your inner (x) loop; This line:
for (int x = HEIGHT1; x < WIDTH2; ++x)
should (of course) be:
for (int x = WIDTH1; x < WIDTH2; ++x) // WIDTH1 not HEIGHT1
Now for the more 'subtle' stuff. You are trying to split the calculation into two halves, by splitting both the 'x' and 'y' ranges into halves. This will not work, as that would require four threads, each dealing with the relevant quarter of the plot. To keep to using just two halves, the 'y' ranges in the two thread functions must cover the whole plot (but the 'x' ranges can properly be split in two).
Thus, your outer ('y') loop control statements should cover the entire range in both thread functions, and they should both be this:
for (int y = 0; y < HEIGHT2; ++y) {
//...
I have tested your code with the aforementioned three changes and it produces the correct Mandelbrot set image. Feel free to ask for for further clarification and/or explanation.

How to read tiled images with OpenImageIO and read_tiles()

I have a problem reading a tiled image on Windows with VisualStudio and OIIO 2.0.8.
For testing I rendered an image with Arnold with tiled option checked and without the tile option. While reading the scanline image works fine, the tiled rendering does not read anything. I can see in debug mode that the tilePixels array does not change at all before and after reading a tile. The result of the read_tiles call is always true.
Maybe anyone can have a look and tell me if there is an obvious problem.
This is the still bit chaotic code I use.
std::string filename = "C:/daten/images/tiledRender.exr";
auto in = ImageInput::open(filename);
if (in)
{
int tw = spec.tile_width;
int th = spec.tile_height;
int w = spec.width;
int h = spec.height;
int numBytesPerPixel = 3;
size_t numBytesPerImage = w*h*numBytesPerPixel;
size_t numBytesPerLine = w*numBytesPerPixel;
std::vector<unsigned char> pixels(numBytesPerImage, 120);
unsigned char* line = &pixels[0];
unsigned char *bit = image->bits(); //this comes from QImage
if (tw == 0) // no tiles read scanlines
{
qDebug() << "Found scanline rendering.\n";
for (int i = 0; i < h; i++)
{
bool success = in->read_scanlines(0, 0, i, i+1, 0, 0, 3, TypeDesc::UCHAR, line);
if (!success)
qDebug() << "read scanline problem at scanline " << i << "\n";
line += numBytesPerLine;
}
memcpy(bit, &pixels[0], numBytesPerImage);
}
else {
qDebug() << "Found tiled rendering.\n";
int numTilePixels = tw * th;
int numBytesPerTile = numTilePixels * 3;
std::vector<unsigned char> tilePixels(numBytesPerTile, 80);
unsigned char* tilePtr = &tilePixels[0];
for (int x = 0; x < w; x += tw)
{
for (int y = 0; y < h; y += th)
{
int ttw = tw;
int tth = th;
if ((x + tw) >= w)
ttw = w - x;
if ((y + th) >= h)
tth = h - y;
bool success = in->read_tiles(0, 0, x, x+ttw, y, y+tth, 0, 0, 0, 3, TypeDesc::UCHAR, tilePtr);
if (!success)
qDebug() << "read tiles problem\n";
}
}
}
The solution lies in the way the tiles are read. Instead of reading zStart = 0 and zEnd = 0, I have to use zEnd = 1.
so instead of:
bool success = in->read_tiles(0, 0, x, x+ttw, y, y+tth, 0, 0, 0, 3, TypeDesc::UCHAR, tilePtr);
It has to be
bool success = in->read_tiles(0, 0, x, x+ttw, y, y+tth, 0, 1, 0, 3, TypeDesc::UCHAR, tilePtr);

Trouble with DFS in solving coastline length

I'm trying to solve one problem, which I found on website https://open.kattis.com/problems/coast. Tl;dr version of problem is, that for given map of landscape, I should print out length of coastline (without inner islands).
My idea was, to solve this by adding additional layer and then start DFS, so the algorithm will walk through every possible tile in map, and then watch on every tile, how many borders are around the tile.
However, for specific input, is my algorithm not working. When I've submitted the solution on this site (open.kattis), it says, that my program is giving wrong answer in 9th of 26 tests (previous 8 test were ok), but without any further explanation.
Can somebody look at my program, and say me, why is it bad? Where did I do mistake? Thanks
#include <iostream>
#include <stack>
#include <sstream>
using namespace std;
int main() {
string line;
getline(cin, line);
int rows = 0;
int columns = 0;
stringstream stream(line);
stream >> rows;
stream >> columns;
int map[rows][columns];
for (int i = 0; i < rows; i++) {
getline(cin, line);
for (int j = 0; j < columns; j++) {
map[i][j] = line[j] - 48;
}
}
//parsed landscape into 2d array
// int rows = 5;
// int columns = 6;
// int map[rows][columns] = {
// {0, 1, 1, 1, 1, 0,},
// {0, 1, 0, 1, 1, 0,},
// {1, 1, 1, 0, 0, 0,},
// {0, 0, 0, 0, 1, 0,},
// {0, 0, 0, 0, 0, 0,},
// };
int bigMap[rows+2][columns+2];
bool visited[rows+2][columns+2];
//create bigger map, so DFS can start from corner and assume
//that there is water around everywhere
//also initialize array visited for DFS
//add 2 new rows, before and after existing one
for (int i = 0; i < columns+2; i++) {
bigMap[0][i] = 0;
bigMap[rows + 1][i] = 0;
visited[0][i] = false;
visited[rows + 1][i] = false;
}
//add 2 new columns, before and after existing
//copy original map to new one
for (int i = 0; i < rows; i++) {
bigMap[i+1][0] = 0;
bigMap[i+1][columns + 1] = 0;
visited[i+1][0] = false;
visited[i+1][columns + 1] = false;
for (int j = 0; j < columns; j++) {
bigMap[i+1][j+1] = map[i][j];
visited[i+1][j+1] = false;
}
}
rows += 2;
columns += 2;
//starting DFS
int x = 0, y = 0;
//visited[x][y] = true; <-- edit
pair <int, int> coordinates;
coordinates.first = x;
coordinates.second = y;
stack<pair <int, int> > st;
//first vertex in stack
st.push(coordinates);
//total sum of borders
int borders = 0;
while(!st.empty()) {
//check coordinates in each round
x = st.top().first;
y = st.top().second;
//navigate to new vertex (only if new vertex wasn't visited (visited[x][y] == 0) and only
//if there is water (bigMap[x][y] == 0) and check if new vertex is still in the map
//if there is no possible vertex, then we reached the end so then pop the vertex and
//look in another way
if (visited[x][y+1] == 0 && bigMap[x][y+1] == 0 && y + 1 < columns) {
y++;
coordinates.second = y;
st.push(coordinates);
} else {
if (visited[x+1][y] == 0 && bigMap[x+1][y] == 0 && x + 1 < rows) {
x++;
coordinates.first = x;
st.push(coordinates);
} else {
if (visited[x][y-1] == 0 && bigMap[x][y-1] == 0 && y > 0) {
y--;
coordinates.second = y;
st.push(coordinates);
} else {
if (visited[x-1][y] == 0 && bigMap[x-1][y] == 0 && x > 0) {
x--;
coordinates.first = x;
st.push(coordinates);
} else {
st.pop();
continue;
}
}
}
}
//visited new vertex, so look around him and count borders
visited[x][y] = true;
if (bigMap[x][y+1] == 1 && y + 1 < columns) borders++;
if (bigMap[x+1][y] == 1 && x + 1< rows) borders++;
if (bigMap[x][y-1] == 1 && y > 0) borders++;
if (bigMap[x-1][y] == 1 && x > 0) borders++;
}
cout << borders << endl;
return 0;
The issue is that you are reusing the variable coordinates each time around the loop without setting it to the correct value. Your if test cascade is assuming that coordinates is set to the current location. This is only true while you are descending in your dfs. Once you start ascending again, the coordinate will be pointing to the wrong place.
Simple solution, add
coordinates = st.top();
at the top of your loop.
Here is a sample map that it will currently get wrong.
5 6
000000
011100
001010
000100
000000
Answer should be 14, but currently you get 18 as the program reaches the lake at row 3, column 4.
To check that it is doing this, add a debugging line at the end of your loop, where it is adding the borders.
cout << "adding " << x << " " << y << "\n";
You can then verify if the program is considering any locations it shouldn't.
I think it will fail for {1,0,0,0},{0,1,1,0},{0,1,1,0},{0,0,0,0}. This is because the walk through is prevented from completing due to setting visited=true for vertex 0,0. Set it false for 0,0 instead should improve things. Hope it helps.

I'm trying to change my Maze traversal recursive coding part into a while loop

Here's my code.
#include <iostream>
using namespace std;
enum Direction { EAST, NORTH, WEST, SOUTH };
const int size = 12;
int xStart = 2; int yStart = 0;
char *maze2[ ] = {
"############",
"#...#......#",
"..#.#.####.#",
"###.#....#.#",
"#....###.#..",
"####.#.#.#.#",
"#..#.#.#.#.#",
"##.#.#.#.#.#",
"#........#.#",
"######.###.#",
"#......#...#",
"############",
};
void printMaze ( char maze[][ size ] );
void mazeTraverse( char maze[][ size ], int x, int y, int direction );
int main()
{
char maze[ size ][ size ];
for (int x = 0; x < size; x++ )
for (int y = 0; y < size; y++)
maze[ x ][ y ] = maze2[ x ][ y ];
printMaze( maze );
mazeTraverse( maze, xStart, yStart, EAST);
}
void printMaze ( char maze[][ size ] )
{
for ( int x = 0; x < size; x++)
{
for ( int y = 0; y < size; y++)
cout << maze[ x ][ y ];
cout << endl;
}
cout << endl;
cout << "\nHit return to see next move\n";
cin.get();
}
bool validMove( char maze[][ size ], int x, int y )
{
return x >= 0 && x < size && y >= 0 && y < size && maze[x][y] != '#';
}
bool coordsAreEdge( int x, int y )
{
return x== 0 || x== size - 1 || y == 0 || y== size - 1;
}
void mazeTraverse( char maze[][ size ], int x, int y, int direction )
{
maze[ x ][ y ] = 'x';
printMaze( maze );
if (coordsAreEdge(x, y) && (x != xStart || y!= yStart ))
{
cout <<"\nMaze successfully exited!\n\n";
return;
}else{
for ( int move = direction, count = 0; count < 4;
count++, move++, move %=4 )
{
int nextX; int nextY;
switch ( move )
{
case SOUTH: nextX = x + 1; nextY = y; break;
case EAST: nextX = x; nextY = y + 1; break;
case NORTH: nextX = x - 1; nextY = y; break;
case WEST: nextX = x; nextY = y - 1; break;
default: ;
}
if (validMove( maze, nextX, nextY ))
{
//Recursion move part 1
//mazeTraverse ( maze, nextX , nextY, (move + 3)%4 );
return;
}
}
}
}
I'm trying to make my void mazeTraverse function a while loop, instead of the recursion and I'm stuck.
Create a struct to hold X, Y and direction (the three things that change between calls). We'll call that struct State;
Create a std::stack<State> object. Push the current values of X,Y, direction onto the stack before you change them, pop them after you do your work.
hence
while(.....)
{
push state
Do work of mazeTraverse
pop state
}
It would've been nice if you described how the traversal works. If I'm not reading the code wrong, you are basically moving south/east/north/west on any position that doesn't contain a # and is within the bounds of the matrix.
You can do this iteratively by using a BF search: http://en.wikipedia.org/wiki/Breadth-first_search or, applied to a matrix, the Lee algorithm: http://en.wikipedia.org/wiki/Lee_algorithm which can be efficiently implemented using a FIFO queue, which I describe how to do here: Change FloodFill-Algorithm to get Voronoi Territory for two data points?
Your validMove function will stay the same: you add a position to the queue only if that position is valid. Basically all checks stay the same, just that you use a FIFO queue to hold your states instead of an implicit stack.
You could use a breadth-first search instead using a standard queue and while loop.
typedef pair<int, int> Point;
queue<Point> path;
Point start(xStart, yStart);
path.push(start);
const int move_x[] = {-1, 0, 1, 0};
const int move_y[] = {0, -1, 0, 1};
while (!path.empty())
{
Point p = path.front();
int x = p.first, y = p.second;
maze[x][y] = 'x';
path.pop();
if (coordsAreEdge(x,y) && p != start)
{
// Finished
break;
}
for (int i = 0; i < 4; ++i)
{
int newx = x + move_x[i];
int newy = y + move_y[i];
if (validMove(maze, newx, newy))
path.push(Point(newx, newy));
}
}
That should do the trick. Note that it's untested though.
You can improve its performance by using A* instead, but that's a little more complex. Let me know if you need to find the shortest path from this code as well.
EDIT: Note that if you change the queue to a stack (and change path.front() to path.top()) then you'll get a depth-first search (DFS) instead, which is what your code does. The DFS, however, doesn't find the shortest path (if that is necessary).