I am using Lee's algorithm to find the shortest path inside a maze.
The maze consists of 0s and 1s. A cell with value 1 represents an empty space one can go to, a cell with value 0 is an obstacle one cannot pass.
However, by doing the q.pop() part inside the while(!q.isEmpty()) loop, I am loosing my "nodes"(I have implemented a strucutre pozitie_plan that stores the index of the row, the index of the column and the distance between an arbitrary-chosen point in a matrix and itself). These "nodes" could be part of the path that I want to output in the end. Yet, I think I should not be altering that part.
I am restricted to use the Queue on DLLA (Dynamic Linked List on Array). I have implemented my own. If needed, I will add its implementation, too.
The way I am finding the path is by determining the shortest length using Lee's algorithm and leaving a trace on an auxiliary matrix, the value in an (i, j) cell representing the distance from the source to that cell.
Finally, I am tracing back a path(there could be more than one, I believe) starting from the exit of the maze (provided the exit has been found) to the starting position, by searching for those cells that have the value equal to: the value in the current cell - 1.
I am keeping these pozitie_plan nodes in a queue, then reverting the queue in the end and outputing the final result.
I feel this could be done better. But how ?
Here is my code. If asked for, I could edit the post and change the code I posted to a version that has some couts and more commentaries and / or the implementation for the Queue.
main.cpp
#include <iostream>
#include <vector>
#include "Queue.h"
#include "ShortTest.h"
#include "ExtendedTest.h"
#define Nmax 25
using std::cin;
using std::cout;
using std::vector;
using std::swap;
#include <fstream>
using std::ifstream;
using std::ofstream;
template<typename T>
void citeste_mat(ifstream &input_stream, T mat[][Nmax], int &n, int &m)
{
input_stream >> n >> m;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
input_stream >> mat[i][j];
}
void citeste_poz_start(ifstream &input_stream, pozitie_plan &p)
{
input_stream >> p.i >> p.j;
p.dist = 0;
p.i--; p.j--; // utilizatorul vede in indexare de la 1, dar eu am implementat in indexare de la 0!
}
template<typename V>
void citeste_date(ifstream &input_file, V mat[][Nmax], int &n, int &m, pozitie_plan &p)
{
citeste_mat<V>(input_file, mat, n, m);
citeste_poz_start(input_file, p);
}
template<typename U> // ar fi fost problema daca puneam aici tot "T" in loc de "U" ?
void afis_mat(U mat[][Nmax], int n, int m)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
cout << mat[i][j] << " ";
cout << '\n';
}
cout << '\n';
}
bool valid_pozitie( int i, int j, int n, int m)
{
return 0 <= i && i < n && 0 <= j && j < m;
}
template<typename T>
bool obstacol(T mat[][Nmax], pozitie_plan p)
{
return mat[p.i][p.j] == 0;
}
template<typename T>
bool valid_nevizitat(T aux[][Nmax], pozitie_plan p)
{
return aux[p.i][p.j] == false;
}
template<typename T, typename U>
bool valid(T mat[][Nmax], U aux[][Nmax], pozitie_plan p, int n, int m)
{
return valid_pozitie(p.i, p.j, n, m) && !obstacol<T>(mat, p) && valid_nevizitat<U>(aux, p);
}
// e un pic "overhead" sa am toate functiile astea de valid, stiu; dar parca imi place sa am totul cat se poate de fragmentat
bool pe_contur(pozitie_plan p, int n, int m)
{
// return p.i == 0 || p.j == 0 || p.i == n - 1 || p.j == m - 1;
return p.i * p.j == 0 || p.i == n-1 || p.j == m-1;
}
template<typename T>
bool solution(T mat[][Nmax], pozitie_plan p , int n, int m)
{
return !obstacol(mat, p) && pe_contur(p, n, m);
}
template<typename T>
pozitie_plan gaseste_cale(T mat[][Nmax], int n, int m, pozitie_plan ps)
{
// voi pastra integritatea matricii ( mat nu va fi modificata )
const int dx[] = { -1, 0, 1, 0 };
const int dy[] = { 0, 1, 0, -1};
bool visited[Nmax][Nmax] = { false };
visited[ps.i][ps.j] = true; // marchez pozitia de start ca vizitata
Queue q;
q.push(ps); // bag in coada pozitia de start
pozitie_plan current_pos;
int row, column, distance;
while (!q.isEmpty())
// cat timp exista in coada pozitii pentru care trebuie verificati vecinii (daca vecinii sunt iesire sau nu)
{
current_pos = q.top();
if (solution<int>(mat, current_pos, n, m))
{
return current_pos; // voi returna prima solutie gasita, care garantat va fi cea mai scurta (BFS)
}
q.pop(); // stocand head ul in `current_pos` pot spune ca am tratat ce aveam in head, asa cu fac pop
for (int k = 0; k < 4; k++)
{
row = current_pos.i + dx[k];
column = current_pos.j + dy[k];
distance = current_pos.dist + 1;
pozitie_plan vecin{ row, column, distance };
if (valid<int,bool>(mat, visited, vecin, n, m))
{
mat[row][column] = distance;
visited[row][column] = true;
q.push(vecin);
}
}
}
return NULL_POZITIE_PLAN;
}
void reconstruct_path(int mat[][Nmax], int n, int m, pozitie_plan end, pozitie_plan begin, Queue& q)
{
const int dx[] = { -1, 0, 1, 0 };
const int dy[] = { 0, 1, 0, -1 };
q.push(end);
pozitie_plan current_pos = end;
int row, column, distance;
int len = current_pos.dist;
while(len != 1)
{
for (int k = 0; k < 4; k++)
{
row = current_pos.i + dx[k];
column = current_pos.j + dy[k];
distance = mat[row][column];
if (valid_pozitie(row, column, n, m)
&& distance == len - 1)
{
pozitie_plan new_pos = pozitie_plan{ row, column, distance };
q.push(new_pos);
current_pos = new_pos;
break;
}
}
len--;
}
q.push(begin);
}
void reverse_queue(Queue& q, const int len)
{
pozitie_plan *aux = new pozitie_plan[len];
for (int i = 0; i < len; i++)
aux[i] = q.pop();
for (int i = 0; i < len / 2; i++)
swap(aux[i], aux[len - 1 - i]);
for (int i = 0; i <len ; i++)
q.push(aux[i]);
}
int main()
{
int mat[Nmax][Nmax] = { 0 };
int n, m;
pozitie_plan pozitie_start;
ifstream input_file;
input_file.open("input.txt", ios::in);
citeste_date<int>(input_file, mat, n, m, pozitie_start);
input_file.close();
afis_mat<int>(mat, n, m);
// pana aici citesc datele de intrare
pozitie_plan end = gaseste_cale<int>(mat, n, m, pozitie_start); // presupun ca utilizatorul numara liniile & coloanele de la 1
if (end == NULL_POZITIE_PLAN)
{
cout << "NO SOLUTION FOUND!\n";
}
else
{
// Queue cale = reconstruct_path(mat, n, m, end);
Queue cale;
reconstruct_path(mat, n, m, end, pozitie_start, cale);
reverse_queue(cale, end.dist + 1);
cout << "The shortest path (length = " << end.dist << " not including the starting position) to be followed in the given matrix (above) is:\n";
cale.toString();
}
return 0;
}
Example
input.txt
18 20
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1
0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
17 3
console output
The shortest path...// everything is ok, the path is ok
I have this two-dimensial array array[y][x] (where x is horizontal and y vertical):
3 2 0 0 0 0 0 0 0 0
1 4 3 0 0 0 0 0 0 0
2 4 0 0 0 0 0 0 0 0
2 4 0 0 0 0 0 0 0 0
1 3 0 0 0 0 0 0 0 0
4 2 5 1 0 0 0 0 0 0
1 3 0 0 0 0 0 0 0 0
2 3 0 0 0 0 0 0 0 0
2 3 0 0 0 0 0 0 0 0
And I need to print it like this:
3 1 2 2 1 4 1 2 2
2 4 4 4 3 2 3 3 3
3 5
1
How would I do this using c++?
Note that there are no empty lines. If the whole column only has zero's in them, there shouldn't be an endl
You need to iterate over and print out each element. You can flip the elements around by swapping the indices used to get the value out of the array.
#include<iostream>
#include<iomanip>
int gridWidth = 10;
int gridHeight = 10;
int cellWidth = 2;
for (int i = 0; i < gridHeight; i++){
bool anyVals = false;
for (int j = 0; j < gridWidth; j++){
int val = array[i][j]; //Swap i and j to change the orientation of the output
if(val == 0){
std::cout << std::setw(cellWidth) << " ";
}
else{
anyVals = true;
std::cout << std::setw(cellWidth) << val;
}
}
if(anyVals)
std::cout << std::endl;
}
Remember that if you swap i and j then you will need to swap gridWidth and gridHeight.
Just to avoid confusion std::setw(cellWidth) thing is a convenient way to print fixed-width text (like text that must always be two characters long). It takes whatever you print out and adds spaces to it to make it the right length.
Take the transpose of your matrix , make 2 loops(outer and inner ) and print only if the no is greater than zero and print space for every zero. when you go back again to the outer loop ,print new line .
Something like this should help you.
for (int i = 0; i < y; i++)
for (int j = 0; j < x; j++)
if (array[i][j] != 0)
cout << array[i][j];
else
cout << " ";
cout << endl;
Does int myarray[7][7] not create a box with 8x8 locations of 0-7 rows and columns in C++?
When I run:
int board[7][7] = {0};
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
cout << board[i][j] << " ";
}
cout << endl;
}
I get output:
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 146858616 1 0 0 146858832 1 1978920048
So the 8 columns seem to work, but not the 8 rows.
If I change it to int board[8][7] = {0}; it works on mac CodeRunner IDE, but on linux Codeblocks I get:
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 1503452472
Not sure what's going on here.
Two dimensional arrays are not different to the one dimensional ones in this regard: Just as
int a[7];
can be indexed from 0 to 6,
int a2[7][7];
can be indexed from 0 to 6 in both dimensions, index 7 is out of bounds. In particular: a2 has 7 columns and rows, not 8.
int board[7][7]; will only allocate 7x7, not 8x8. When it's allocated, you specify how many, but indexes start at 0 and run to the size - 1.
So based on your source, I would say you really want int board[8][8].
int board[7][7] = {0}; creates a 7x7 array. You are going out of bounds in your loop. Change it to int board[8][8] = {0};
int board[8][7] = {0};
When you do as above, you created only 8 rows and 7 columns.
So your loop condition should be as follows:
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 7; j++)
{
If you try as follows system will print garbage values from 8th columns
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
Araay starts from zero means that it will have n-1 elements not n+1 elements
try
int a[8][8] = {}
i = 0
j = 0
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
{
a[i][j] = 0;
}
}
I should open with the fact that I am very new to c++.
I am attempting to display a constantly updating 20x20 matrix of chars. Currently, I am displaying the the matrix using for loops as cout's (code below) but that is incredibly flickery- I'm looking for something smoother.
Is there a way to convert this char matrix into an image and display that?
This is my first question here, so I apologize if I did something wrong!
Code so far:
#include <iostream>
#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
using namespace std;
int main()
{
int randInt;
//Initialize matrix and location
int matrix[20][20];
int location[2] = {0,0};
for (int i=0; i<20; i++)
{
for (int j=0; j<20; j++)
{
matrix[i][j] = 1;
}
}
//move the X around
for (int i=0; i<100; i++)
{
cout << string(50, '\n');
//Change the X's location
randInt = rand() % 4;
switch (randInt)
{
case 0:
if(location[1] > 0)
location[1] = location[1]-1;
break;
case 1:
if(location[0] < 20)
location[0] = location[0]+1;
break;
case 2:
if(location[1] < 20)
location[1] = location[1]+1;
break;
case 3:
if(location[0] > 0)
location[0] = location[0]-1;
break;
default:
cout << "Switch statement problem";
}
//Display the matrix
for (int x=0; x<20; x++)
{
for (int y=0; y<20; y++)
{
if(x==location[0] && y==location[1])
cout << "X";
else
cout << matrix[x][y];
}
cout << endl;
}
Sleep(100);
}
system ("pause");
return 0;
}
You should rename the location[2] to something like `struct { int x,y; } location for readability.
Then you can build an array of characters in RAM and put out it at once.
int _tmain(int argc, _TCHAR* argv[])
{
char matrix[20][20];
char image[21][21];
struct { int x, y; } location;
int x = 0;
int y = 0;
location.x = 7;
location.y = 3;
// fill the matrix
for (x = 0; x < 20; ++x)
{
for (y = 0; y < 20; ++y)
{
matrix[y][x] = 'a' + x + y;
}
}
// prepare the image
y = 0;
while (y < 20)
{
memcpy(image[y], matrix[y], 20);
image[y][20] = '\n';
++y;
}
// add the cross
image[location.y][location.x] = 'X';
image[20][0] = '\0';
// use the image
puts((char*)image);
}
Please add you random functionality as needed.
If you want to convert the char to a image and see the color means, write the char value as pixel in simple pgm format.
Write a file in this sample format
P2
# feep.pgm
24 7
15
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0
0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0
0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0
0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0
0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
check this link http://netpbm.sourceforge.net/doc/pgm.html for pgm format
I have a 2 dimensional array filled with 0s and 1s. I have to display that array in way that:
- 0s are always shown
- 1s are shown one at the time.
It suppose to look like a maze where 0 is a wall and 1 is a current position.
How can I do that in c++?
EDIT:
I came up with a solution but maybe there is simpler one. What if I'd create copy of my _array and copy 0s and blank spaces instead of 1s to it. Then in loop I'd assign one of _array "1" to second array then display whole array and then make swap 1 back with blank space?
EDIT2:
int _tmain(int argc, _TCHAR* argv[])
{
file();
int k=0,l=0;
for(int i=0;i<num_rows;i++)
{
for(int j=0;j<num_chars;j++)
{
if(_array[i][j] == 1)
{
k=i;
l=j;
break;
}
}
}
while(1)
{
for(int i=0;i<num_rows;i++)
{
for(int j=0;j<num_chars;j++)
{
if(_array[i][j] == 0) printf("%d",_array[i][j]);
else if(_array[i][j]==1)
{
if(k==i && l==j)
{
printf("1");
}
else printf(" ");
}
l++;
if(l>num_chars) break;
}
k++;
l=0;
printf("\n");
}
k=0;
system("cls");
}
return 0;
}
I wrote something like that but still i don't know how to clear screen in right moment. Function file() reads from file to 2D array.
Assuming you want something like that
000000
0 0
0000 0
0 1 0
0 0000
000000
You could print a 0 whenever it occurs and a blank space if not. To handle the current position you could use two additional variables like posX, posY. Now everytime you find a 1 in your array you check if (j == posX && i = posY) and print 1 if so...
As you just need to visualize the maze at different possible positions I'd propose a simple display function. DisplayMaze(int x, int y) is printing the maze in the required format to the screen. If _array[y][x] == 1 there is also printed a single 1...
void DisplayMaze(int x, int y)
{
for (int row = 0; row < num_rows; row++)
{
for (int col = 0; col < num_chars; col++)
{
if (_array[row][col] == 0)
std::cout << "0 ";
else if (row == y && col == x)
std::cout << "1 ";
else
std::cout << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
In order to display all possible positions you have to iterate over all of them and check if the current position is marked with 1 in the array (otherwise displaying would't make sense)
for (int y = 0; y < num_rows; y++)
{
for (int x = 0; x < num_chars; x++)
{
if (_array[y][x] == 1)
{
DisplayMaze(x, y);
}
}
}
The output should look like:
0 0 0 0 0 0
0 1 0
0 0 0 0 0
0 0
0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 1 0
0 0 0 0 0
0 0
0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 1 0
0 0 0 0 0
0 0
0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 1 0
0 0 0 0 0
0 0
0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0
0 0 0 0 1 0
0 0
0 0 0 0 0
0 0 0 0 0 0
...
However, i'd recommend a more C++ like approach as a maze could be implemented as a class. This class could bring it's own display-method and would encapsulate the internal data. It could basically look like:
class Maze
{
public:
// generate empty maze with given size
Maze(int width, int height);
// destructor
~Maze();
// print maze if the given position is marked with 1
void printPosition(int x, int y) const;
// takes a cstring as input to initialize the maze from
Maze& operator<<(const char* input);
// returns true if the given position is marked with 1
bool isValidPosition(int x, int y) const;
private:
// this is the actual representation of the maze
std::vector<std::vector<int> > grid_;
};
it would be used as followes:
Maze myMaze(num_chars, num_rows);
myMaze << "000000"
"011110"
"000010"
"011110"
"010000"
"000000";
for (int y = 0; y < num_rows; y++)
{
for (int x = 0; x < num_chars; x++)
{
if (myMaze.isValidPosition(x,y))
{
myMaze.printPosition(x,y);
}
}
}
hire you go*[solved]*
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
int x,y;
cin>>x>>y;
char map[x][y];
memset(map, 'a', sizeof(map));
int y_pos = 0;
for (int x_pos = 0; x_pos < x * y; x_pos++){
if (x_pos == x){
x_pos = 0;
y_pos = y_pos + 1;
cout<<endl;
}
if (y_pos == y){
system("pause");
return 0;
}
cout<<map[x_pos][y_pos];
}