Related
I'm creating a dungeon/rouge-like game in c++ and am trying to implement pathfinding.
The issue I am having is that when the player moves more than two times the adjacency matrix doesn't generate properly. What happens is that every place that the player has been turning to a zero which signifies that you cant go there. I am trying to regenerate the matrix every time the player moves but it doesn't seem to want to. here is the code.
#include <iostream>
#include <vector>
using namespace std;
int main ()
{
int World_Width = 10;
int World_Height = 10;
int Player_X = 1;
int Player_Y = 2;
int Enemy_X = 8;
int Enemy_Y = 1;
int X = Player_X;
int Y = Player_Y;
int Player_Health = 10;
int Enemy_Health = 5;
int Player_Damage = 1;
int Enemy_Damage = 1;
bool PlayerIsAlive = true;
bool EnemyIsAlive = true;
int World[World_Width][World_Height] =
{
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 1, 0, 4, 1},
{1, 2, 0, 0, 0, 0, 1, 0, 0, 1},
{1, 0, 0, 1, 1, 0, 1, 0, 0, 1},
{1, 0, 0, 1, 1, 0, 1, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 1, 1, 0, 1},
{1, 0, 0, 0, 0, 0, 1, 0, 0, 1},
{1, 1, 1, 1, 0, 0, 1, 0, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
};
int NodeMap[World_Width][World_Height] =
{
{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, 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,},
};
int NeighborMap[World_Width][World_Height] =
{
{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, 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,},
};
int NodeNumber = 1;
for (int h = 0; h < World_Height; h++)
{
for (int d = 0; d < World_Width; d++)
{
NodeMap[h][d] = NodeNumber;
NodeNumber ++;
}
}
vector<int> queue {};
vector<int> visited {};
string input;
bool AddNode = true;
int QueueNumber = 0;
int Max_iterations = 1000;
int TurnCount = 0;
bool run = true;
while (run)
{
TurnCount += 1;
//Prints out the map
for (int h = 0; h < World_Height; h++)
{
for (int d = 0; d < World_Width; d++)
{
cout << World[h][d] << " ";
}
cout << "\n";
}
cout << "\n";
cout << "Player health: " << Player_Health << "\n";
cout << "Enemy health: " << Enemy_Health << "\n" << "\n";
cout << "What do you want to do; move, attack, or open a chest: ";
//Player movement
cin >> input;
if (input == "w" && World[Player_Y - 1][Player_X] == 0)
{
World[Player_Y ][Player_X] = 0;
Player_Y--;
World[Player_Y][Player_X] = 2;
}
if (input == "a" && World[Player_Y][Player_X - 1] == 0)
{
World[Player_Y][Player_X] = 0;
Player_X--;
World[Player_Y][Player_X] = 2;
}
if (input == "s" && World[Player_Y + 1][Player_X] == 0)
{
World[Player_Y][Player_X] = 0;
Player_Y++;
World[Player_Y][Player_X] = 2;
}
if (input == "d" && World[Player_Y][Player_X + 1] == 0)
{
World[Player_Y][Player_X] = 0;
Player_X++;
World[Player_Y][Player_X] = 2;
}
if (input == "e")
{
if (Player_X == Enemy_X && Player_Y - 1 == Enemy_Y)
{
Enemy_Health -= Player_Damage;
}
if (Player_X == Enemy_X - 1 && Player_Y == Enemy_Y)
{
Enemy_Health -= Player_Damage;
}
if (Player_X == Enemy_X && Player_Y + 1 == Enemy_Y)
{
Enemy_Health -= Player_Damage;
}
if (Player_X == Enemy_X + 1 && Player_Y == Enemy_Y)
{
Enemy_Health -= Player_Damage;
}
}
if ( input == "stop")
{
Player_Health = 0;
}
queue.clear();
QueueNumber = 0;
X = Player_X;
Y = Player_Y;
NeighborMap[Y][X] = 0;
//BFS - Breadth First Search: Pathfinding Algorithim
for (int iterations = 0; iterations < Max_iterations; iterations++)
{
if (World[Y - 1][X] == 0 || World[Y - 1][X] == 4)
{
AddNode = true;
for (int i = 0; i < visited.size(); i++)
{
if (visited[i] == NodeMap[Y - 1][X])
{
AddNode = false;
}
}
if (AddNode)
{
queue.push_back(NodeMap[Y - 1][X]);
NeighborMap[Y - 1][X] = NodeMap[Y][X];
}
}
if (World[Y][X - 1] == 0 || World[Y][X - 1] == 4)
{
AddNode = true;
for (int i = 0; i < visited.size(); i++)
{
if (visited[i] == NodeMap[Y][X - 1])
{
AddNode = false;
}
}
if (AddNode)
{
queue.push_back(NodeMap[Y][X - 1]);
NeighborMap[Y][X - 1] = NodeMap[Y][X];
}
}
if (World[Y + 1][X] == 0 || World[Y + 1][X] == 4)
{
AddNode = true;
for (int i = 0; i < visited.size(); i++)
{
if (visited[i] == NodeMap[Y + 1][X])
{
AddNode = false;
}
}
if (AddNode)
{
queue.push_back(NodeMap[Y + 1][X]);
NeighborMap[Y + 1][X] = NodeMap[Y][X];
}
}
if (World[Y][X + 1] == 0 || World[Y][X + 1] == 4)
{
AddNode = true;
for (int i = 0; i < visited.size(); i++)
{
if (visited[i] == NodeMap[Y][X + 1])
{
AddNode = false;
}
}
if (AddNode)
{
queue.push_back(NodeMap[Y][X + 1]);
NeighborMap[Y][X + 1] = NodeMap[Y][X];
}
}
for (int h = 0; h < World_Height; h++)
{
for (int d = 0; d < World_Width; d++)
{
if(NodeMap[h][d] == queue[QueueNumber])
{
X = d;
Y = h;
}
}
}
visited.push_back(queue[QueueNumber]);
QueueNumber++;
}
//Enemy AI
if (Enemy_Health == 0)
{
if (EnemyIsAlive)
{
World[Enemy_Y][Enemy_X] = 0;
}
EnemyIsAlive = false;
}
if (Player_Health == 0)
{
run = false;
}
}
system("clear");
for (int h = 0; h < World_Height; h++)
{
for (int d = 0; d < World_Width; d++)
{
cout << NeighborMap[h][d] << " ";
}
cout << "\n";
}
cout << "\n";
for (int h = 0; h < World_Height; h++)
{
for (int d = 0; d < World_Width; d++)
{
cout << NodeMap[h][d] << " ";
}
cout << "\n";
}
cout << "GAME OVER" << "\n" << "Thanks for Playing!";
}
I have matrix inversion algorithm and a 19x19 matrix for testing. Running it in Windows Subsystem for Linux with g++ produces the correct inverted matrix.
In Visual Studio 2017 on Windows it used to work as well. However after I upgraded to Visual Studio 2019, I get a matrix containing all zeros as result. Is MSVC broken or what else is wrong here?
So far I have tested replacing ==0.0/!=0.0 (that in some cases can be unsafe due to round-off) with greater/smaller than a tolerance value, but this does not work either.
The expected result (that I get with g++) is {5.26315784E-2,-1.25313282E-2, ... -1.25000000E-1}.
I compile with Visual Studio 2019 v142, Windows SDK 10.0.19041.0, Release x64, and I get {0,0,...0}. With Debug x64 I get a different (also wrong) result: all matrix entries are -1.99839720E18.
I use C++17 language standard, /O2 /Oi /Ot /Qpar /arch:AVX2 /fp:fast /fp:except-.
I have an i7-8700K that supports AVX2.
I also marked the place where it wrongly returns in Windows in the code. Any help is greatly appreciated.
EDIT: I just found out that the cause of the wrong behavior is /arch:AVX2 in combination with /fp:fast. But I don't understand why. /arch:SSE, /arch:SSE2 and /arch:AVX with /fp:fast work correctly, but not /arch:AVX2. How can different round-off or operation order here trigger entirely different behavior?
#include <iostream>
#include <string>
#include <vector>
using namespace std;
typedef unsigned int uint;
void println(const string& s="") {
cout << s << endl;
}
struct floatNxN {
uint N{}; // matrix size is NxN
vector<float> M; // matrix data
floatNxN(const uint N, const float* M) : N {N}, M(N*N) {
for(uint i=0; i<N*N; i++) this->M[i] = M[i];
}
floatNxN(const uint N, const float x=0.0f) : N {N}, M(N*N, x) { // create matrix filled with zeros
}
floatNxN() = default;
~floatNxN() = default;
floatNxN invert() const { // returns inverse matrix
vector<double> A(2*N*N); // calculating intermediate values as double is strictly necessary
for(uint i=0; i<N; i++) {
for(uint j=0; j< N; j++) A[2*N*i+j] = (double)M[N*i+j];
for(uint j=N; j<2*N; j++) A[2*N*i+j] = (double)(i+N==j);
}
for(uint k=0; k<N-1; k++) { // at iteration k==2, the content of A is already different in MSVC and g++
if(A[2*N*k+k]==0.0) {
for(uint i=k+1; i<N; i++) {
if(A[2*N*i+k]!=0.0) {
for(uint j=0; j<2*N; j++) {
const double t = A[2*N*k+j];
A[2*N*k+j] = A[2*N*i+j];
A[2*N*i+j] = t;
}
break;
} else if(i+1==N) {
return floatNxN(N);
}
}
}
for(uint i=k+1; i<N; i++) {
const double t = A[2*N*i+k]/A[2*N*k+k];
for(uint j=k; j<2*N; j++) A[2*N*i+j] -= A[2*N*k+j]*t;
}
}
double det = 1.0;
for(uint k=0; k<N; k++) det *= A[2*N*k+k];
if(det==0.0) {
return floatNxN(N);
}
for(int k=N-1; k>0; k--) {
for(int i=k-1; i>=0; i--) {
const double t = A[2*N*i+k]/A[2*N*k+k];
for(uint j=k; j<2*N; j++) A[2*N*i+j] -= A[2*N*k+j]*t;
}
}
floatNxN r = floatNxN(N);
for(uint i=0; i<N; i++) {
const double t = A[2*N*i+i];
for(uint j=0; j<N; j++) r.M[N*i+j] = (float)(A[2*N*i+N+j]/t);
}
return r;
}
string stringify() const { // converts matrix into string without spaces or newlines
string s = "{"+to_string(M[0]);
for(uint i=1; i<N*N; i++) s += ","+to_string(M[i]);
return s+"}";
}
};
int main() {
const float Md[19*19] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-30,-11,-11,-11,-11,-11,-11, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
12, -4, -4, -4, -4, -4, -4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, -1, 0, 0, 0, 0, 1,-1, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0,
0, -4, 4, 0, 0, 0, 0, 1,-1, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0,
0, 0, 0, 1, -1, 0, 0, 1,-1, 0, 0, 1,-1,-1, 1, 0, 0, 1,-1,
0, 0, 0, -4, 4, 0, 0, 1,-1, 0, 0, 1,-1,-1, 1, 0, 0, 1,-1,
0, 0, 0, 0, 0, 1, -1, 0, 0, 1,-1, 1,-1, 0, 0,-1, 1,-1, 1,
0, 0, 0, 0, 0, -4, 4, 0, 0, 1,-1, 1,-1, 0, 0,-1, 1,-1, 1,
0, 2, 2, -1, -1, -1, -1, 1, 1, 1, 1,-2,-2, 1, 1, 1, 1,-2,-2,
0, -4, -4, 2, 2, 2, 2, 1, 1, 1, 1,-2,-2, 1, 1, 1, 1,-2,-2,
0, 0, 0, 1, 1, -1, -1, 1, 1,-1,-1, 0, 0, 1, 1,-1,-1, 0, 0,
0, 0, 0, -2, -2, 2, 2, 1, 1,-1,-1, 0, 0, 1, 1,-1,-1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,-1,-1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,-1,-1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,-1,-1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1,-1,-1, 1, 0, 0, 1,-1,-1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1,-1, 1,-1, 0, 0, 1,-1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1,-1,-1, 1, 0, 0,-1, 1, 1,-1
};
floatNxN M(19, Md);
floatNxN Mm1 = M.invert();
println(Mm1.stringify());
}
It seems that it is the comparison against literal 0 that breaks the algorithm with the optimizations on. Particularly the 1st one kills it, because the result would need to be exactly 0 for the correct action.
Generally instead of comparing a floating point value against literal zero, it is better to compare the absolute value against a very small constant.
This seems to work:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
typedef unsigned int uint;
void println(const string& s = "") {
cout << s << endl;
}
struct floatNxN {
const double epsilon = 1E-12;
uint N{}; // matrix size is NxN
vector<float> M; // matrix data
floatNxN(const uint N, const float* M) : N{ N }, M(N* N) {
for (uint i = 0; i < N * N; i++) this->M[i] = M[i];
}
floatNxN(const uint N, const float x = 0.0f) : N{ N }, M(N* N, x) { // create matrix filled with zeros
}
floatNxN() = default;
~floatNxN() = default;
floatNxN invert() const { // returns inverse matrix
vector<double> A(2 * N * N); // calculating intermediate values as double is strictly necessary
for (uint i = 0; i < N; i++) {
for (uint j = 0; j < N; j++) A[2 * N * i + j] = (double)M[N * i + j];
for (uint j = N; j < 2 * N; j++) A[2 * N * i + j] = (double)(i + N == j);
}
for (uint k = 0; k < N - 1; k++) { // at iteration k==2, the content of A is already different in MSVC and g++
if (fabs(A[2 * N * k + k]) < epsilon) { // comparing with 0 was the killer here
for (uint i = k + 1; i < N; i++) {
if (fabs(A[2 * N * i + k]) > epsilon) {
for (uint j = 0; j < 2 * N; j++) {
const double t = A[2 * N * k + j];
A[2 * N * k + j] = A[2 * N * i + j];
A[2 * N * i + j] = t;
}
break;
} else if (i + 1 == N) {
return floatNxN(N);
}
}
}
for (uint i = k + 1; i < N; i++) {
const double t = A[2 * N * i + k] / A[2 * N * k + k];
for (uint j = k; j < 2 * N; j++) A[2 * N * i + j] -= A[2 * N * k + j] * t;
}
}
double det = 1.0;
for (uint k = 0; k < N; k++) det *= A[2 * N * k + k];
if (fabs(det) < epsilon) {
return floatNxN(N);
}
for (int k = N - 1; k > 0; k--) {
for (int i = k - 1; i >= 0; i--) {
const double t = A[2 * N * i + k] / A[2 * N * k + k];
for (uint j = k; j < 2 * N; j++) A[2 * N * i + j] -= A[2 * N * k + j] * t;
}
}
floatNxN r = floatNxN(N);
for (uint i = 0; i < N; i++) {
const double t = A[2 * N * i + i];
for (uint j = 0; j < N; j++) r.M[N * i + j] = (float)(A[2 * N * i + N + j] / t);
}
return r;
}
string stringify() const { // converts matrix into string without spaces or newlines
string s = "{" + to_string(M[0]);
for (uint i = 1; i < N * N; i++) s += "," + to_string(M[i]);
return s + "}";
}
};
int main() {
const float Md[19 * 19] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-30,-11,-11,-11,-11,-11,-11, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
12, -4, -4, -4, -4, -4, -4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, -1, 0, 0, 0, 0, 1,-1, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0,
0, -4, 4, 0, 0, 0, 0, 1,-1, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0,
0, 0, 0, 1, -1, 0, 0, 1,-1, 0, 0, 1,-1,-1, 1, 0, 0, 1,-1,
0, 0, 0, -4, 4, 0, 0, 1,-1, 0, 0, 1,-1,-1, 1, 0, 0, 1,-1,
0, 0, 0, 0, 0, 1, -1, 0, 0, 1,-1, 1,-1, 0, 0,-1, 1,-1, 1,
0, 0, 0, 0, 0, -4, 4, 0, 0, 1,-1, 1,-1, 0, 0,-1, 1,-1, 1,
0, 2, 2, -1, -1, -1, -1, 1, 1, 1, 1,-2,-2, 1, 1, 1, 1,-2,-2,
0, -4, -4, 2, 2, 2, 2, 1, 1, 1, 1,-2,-2, 1, 1, 1, 1,-2,-2,
0, 0, 0, 1, 1, -1, -1, 1, 1,-1,-1, 0, 0, 1, 1,-1,-1, 0, 0,
0, 0, 0, -2, -2, 2, 2, 1, 1,-1,-1, 0, 0, 1, 1,-1,-1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,-1,-1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,-1,-1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,-1,-1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1,-1,-1, 1, 0, 0, 1,-1,-1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1,-1, 1,-1, 0, 0, 1,-1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1,-1,-1, 1, 0, 0,-1, 1, 1,-1
};
floatNxN M(19, Md);
floatNxN Mm1 = M.invert();
println(Mm1.stringify());
}
I've written a program which is computing the eigenvalues and eigenvectors of a hermitian matrix.
Does anyone know how this is done in GSL properly? Here is what I already have.
//hermitian matrix
0 1 0 -i
1 0 -i 0
0 i 0 1
i 0 1 0
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_complex.h>
#include <gsl/gsl_complex_math.h>
#include <gsl/gsl_eigen.h>
using namespace std;
const int N = 4;
int main(){
gsl_eigen_hermv_workspace *workN = gsl_eigen_hermv_alloc(N);
gsl_matrix_complex *A = gsl_matrix_complex_alloc(N, N);
gsl_complex i = gsl_complex_rect(0.0,1.0);
gsl_complex ii = gsl_complex_rect(0.0,-1.0);
gsl_vector *eval = gsl_vector_alloc(N);
gsl_matrix_complex *evec = gsl_matrix_complex_alloc(N, N);
double mTab[] = {
0, 1, 0, 5,
1, 0, 5, 0,
0, 5, 0, 1,
5, 0, 1, 0
};
gsl_matrix_complex_view tmpM = gsl_matrix_complex_view_array(mTab, N, N);
gsl_matrix_complex_memcpy(A, &tmpM.matrix);
gsl_matrix_complex_set(A, 0, 3, ii);
gsl_matrix_complex_set(A, 1, 2, ii);
gsl_matrix_complex_set(A, 2, 1, i);
gsl_matrix_complex_set(A, 3, 0, i);
gsl_eigen_hermv(A, eval, evec, workN);
for(int i=0; i < N; i++){
for(int j=0; j < N; j++){
gsl_complex z = gsl_matrix_complex_get(A, i, j);
cout << GSL_REAL(z) << "+ i" << GSL_IMAG(z) << " ";
}
cout << "\n";
}
cout << "\n";
for(int i=0; i < N; i++){
cout << gsl_vector_get(eval, i) << " ";
}
return 0;
}
This is how I output the eigenvectors
for(int i=0; i < N; i++){
for(int j=0; j < N; j++){
gsl_complex z = gsl_matrix_complex_get(A, i, j);
cout << GSL_REAL(z) << "+ i" << GSL_IMAG(z) << " ";
}
cout << "\n";
}
Finally, here's the way I declared the matrix in question.
double mTab[] = {
0, 1, 0, 5,
1, 0, 5, 0,
0, 5, 0, 1,
5, 0, 1, 0
};
Later, I added the complex numbers.
I managed to print the eigenvectors but I don't know how to do that for the eigenvalues. Any help with that is appreciated?.
You have an error in using the double mTab for gsl_matrix_complex_view_array. This assumes an array of complex numbers represented as real parts followed by imaginary parts in one large array of double values. You can change your definition to:
double mTab[] = {
0, 0, 1, 0, 0, 0, 5, 0,
1, 0, 0, 0, 5, 0, 0, 0,
0, 0, 5, 0, 0, 0, 1, 0,
5, 0, 0, 0, 1, 0, 0, 0,
};
(Which also means you don't need to use a "dummy" variable of 5 just to rewrite it by ±i later.) Then the code for printing eigenvalues works well.
Also you have a typo in the eigenvector printing loop: it should be
gsl_complex z = gsl_matrix_complex_get(evec, i, j);
not
gsl_complex z = gsl_matrix_complex_get(A, i, j);
I have a matrix called "temp_matrix" that looks kind of like this:
0.0,100.0,100.0,100.0,
0.0,45.1,60.6,66.2,0,
0.0,45.1,60.6,66.2,0,
0.0,100.0,100.0,100.0,0,
...except mine is a 20x20 matrix.
I've tried:
ofstream excel_plate("plate.csv");
excel_plate.write(temp_matrix[0],20);
excel_plate.close();
cout << endl;
but can't compile.
I've tried:
ofstream excel_plate("plate.csv");
excel_plate << temp_matrix[0], 20, 20;
excel_plate.close();
...but just get a csv file with a string of characters in the very first cell that looks like this: 0052EE98.
Here is my code:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <math.h>
#include <Windows.h>
#include <algorithm>
#include <string>
#include <array>
#undef max
using namespace std;
const double neighbors = 4;
// START FUNCTION: Update Elements
void average(double *temp_matrix, int ROWS, int COLUMNS)
{
int i = 0;
int j = 0;
double row_left = 0;
double row_right = 0;
double column_up = 100;
double column_down = 0;
double sum = 0;
double av = 0;
for (int i = 1; i < ROWS - 1; i++)
{
for (int j = 1; j < COLUMNS - 1; j++)
{
/*
cout << "row_left:" << *(temp_matrix + i*ROWS + (j - 1)) << " ";
cout << "row_right:" << *(temp_matrix + i*ROWS + (j + 1)) << " ";
cout << "column_up:" << *(temp_matrix + (i - 1)*ROWS + j) << " ";
cout << "column_down:" << *(temp_matrix + (i + 1)*ROWS + j) << " ";
*/
row_left = *(temp_matrix + i*ROWS + (j-1));
row_right = *(temp_matrix + i*ROWS + (j + 1));
column_up = *(temp_matrix + (i-1)*ROWS + j);
column_down = *(temp_matrix + (i+1)*ROWS + j);
sum = row_left + row_right + column_up + column_down;
av = sum / neighbors;
*(temp_matrix + i*ROWS + j) = av;
}
}
}
// END FUNCTION: Update Elements
// START FUNCTION: Updtate Until Stable
void update(double *temp_matrix, int ROWS, int COLUMNS)
{
int i = 0;
int j = 0;
double row_left = 0;
double row_right = 0;
double column_up = 100;
double column_down = 0;
double sum = 0;
double old_num = 0;
double new_num = 0;
double difference = 0;
double max_change = .11;
while (max_change > .1)
{
max_change = -1;
for (int i = 1; i < ROWS - 1; i++)
{
for (int j = 1; j < COLUMNS - 1; j++)
{
old_num = *(temp_matrix + i*ROWS + j);
/*
cout << "row_left:" << *(temp_matrix + i*ROWS + (j - 1)) << " ";
cout << "row_right:" << *(temp_matrix + i*ROWS + (j + 1)) << " ";
cout << "column_up:" << *(temp_matrix + (i - 1)*ROWS + j) << " ";
cout << "column_down:" << *(temp_matrix + (i + 1)*ROWS + j) << " ";
*/
row_left = *(temp_matrix + i*ROWS + (j - 1));
row_right = *(temp_matrix + i*ROWS + (j + 1));
column_up = *(temp_matrix + (i - 1)*ROWS + j);
column_down = *(temp_matrix + (i + 1)*ROWS + j);
sum = row_left + row_right + column_up + column_down;
new_num = sum / neighbors;
difference = new_num - old_num;
if (difference > max_change)
{
max_change = difference;
}
*(temp_matrix + i*ROWS + j) = new_num;
}
}
}
}
// END FUNCTION: Update Until Stable
// START FUNCTION: Print Array
void print_array(double *temp_matrix, int ROWS, int COLUMNS)
{
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLUMNS; j++)
{
if (j > 0)
{
cout << ",";
}
cout << fixed << setw(5) << setprecision(1) << *(temp_matrix + i*ROWS + j);
}
cout << endl;
}
}
// END FUNCTION: Print Array
// START FUNCTION: Print 4 Excel
void print_excel(double *temp_matrix, int ROWS, int COLUMNS)
{
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLUMNS; j++)
{
cout << fixed << setprecision(1) << *(temp_matrix + i*ROWS + j) << ",";
}
cout << endl;
}
}
// END FUNCTION: Print 4 Excel
int main()
{
const int ROWS = 20;
const int COLUMNS = 20;
double temp_matrix[ROWS][COLUMNS] =
{
{ 0, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 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, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 0 }
};
print_array(temp_matrix[0], 20, 20);
system("pause");
cout << endl << endl;
average(temp_matrix[0], 20, 20);
print_array(temp_matrix[0], 20, 20);
system("pause");
cout << endl << endl;
update(temp_matrix[0], 20, 20);
print_array(temp_matrix[0], 20, 20);
system("pause");
cout << endl << endl;
print_excel(temp_matrix[0], 20, 20);
ofstream excel_plate("plate.csv");
if (excel_plate.is_open())
{
excel_plate << temp_matrix[0], 20, 20;
excel_plate.close();
}
else
{
cout << "Unable to open file.";
}
/*
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLUMNS; j++)
{
if (j > 0)
{
cout << ",";
}
cout << temp_matrix[i][j];
}
cout << endl;
}
*/
system("pause");
return 0;
}
This should be very, very simple. Please kindly help a noob out. :)
P.S. Because this is an assignment, you'll notice that I print out several matrices. The last one I print out is the format in which the matrix needs to be transferred to a .csv file.
The simplest way would be something like the following (assuming you can use c++11)
std::ofstream out("test.csv");
for (auto& row : temp_matrix) {
for (auto col : row)
out << col <<',';
out << '\n';
}
So, this code conatains a functions that should be able to transfer any 2d string array into a csv file
#include <iostream>
#include <fstream>
#include<string>
/* This is for a string array, but if you want to use any other type, just replace
'std::string' with int,double....*/
template <size_t row, size_t col>
void twodarray2csv(std::string(&array)[row][col], std::string filename)
{
std::ofstream myfile;
myfile.open(filename);
for (size_t i = 0; i < row; ++i)
{
for (size_t j = 0; j < col; ++j)
if (j < (col - 1)) {
myfile << array[i][j] << ",";
}
else if (j == (col - 1)) {
myfile << array[i][j] << "\n";
}
}
}
Th template gets the row size and column size and also opens ofstream which is basically for just opening the csv file that will be the output file
int main() {
//example
std::string ArrayName[9][3];
/* this for loop is just there to populate the array, if you have an array
already skip this step */
#include <iostream>
#include <fstream>
#include<string>
/* This is for a string array, but if you want to use any other type, just replace
'std::string' with int,double....*/
template <size_t row, size_t col>
void twodarray2csv(std::string(&array)[row][col], std::string filename)
{
std::ofstream myfile;
myfile.open(filename);
for (size_t i = 0; i < row; ++i)
{
for (size_t j = 0; j < col; ++j)
if (j < (col - 1)) {
myfile << array[i][j] << ",";
}
else if (j == (col - 1)) {
myfile << array[i][j] << "\n";
}
}
}
So the function above uses a template to get the row size and column size of the array, after which it iterates through the array so that when it passes by elements of the same row it adds a comma to the file and at the end of each row it adds a new line (\n) which is a row separator
The part below is an example of how to use it and how it works
First i just created a an Array called ArrayName, and populated it with just some numbers (int number)
int number = 0;
for (int i = 0; i < 9; i++) {
for (int x = 0; x < 3; x++) {
ArrayName[i][x] = number;
number++;
}
}
//this part converts the array to a csv file of desried name
twodarray2csv(ArrayName, "outputfile.csv");
return 0;
}
The output will be a csv file with the name "outputfile.csv" stored in the same folder with the cpp file you have
Bassicly my code is supposed to be taking ints from int tt[] in main()
const int tt[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
The program then is exposed to give cordinates for a vector based on its sequential order and give cordinates for the texture if its gives #1. Based on my cout statement tiletype = tt[count]; I can tell the program crashes after reading the fith zero from int tt[] and gives the error Vector Subscript out of Range.
I assume the problem fall under this section of my code:
for(x = 1; x < c;++x)
{
for(y = 0; y < r;++y)
{
tiletype = tt[count];
cout <<tiletype<<", ";
vertices[a].position = sf::Vector2f((0+y)*ts,ts*(x+1)+80);
vertices[b].position = sf::Vector2f((0+y)*ts, (0+x)*ts+80);
vertices[d].position = sf::Vector2f(ts+(y*ts),(0+x)*ts+80);
vertices[e].position = sf::Vector2f(ts+(y*ts), ts*(x+1)+80);
vertices[a].texCoords = mapcords(tiletype,0);
vertices[b].texCoords = mapcords(tiletype,1);
vertices[d].texCoords = mapcords(tiletype,2);
vertices[e].texCoords = mapcords(tiletype,3);
a += 4; b += 4; d += 4; e += 4;count++;
}
row += 1;
cout <<endl<<"Row "<<row<<": "; y = 0;
}
This is the rest of the code.
#include <SFML/Graphics.hpp>
#include <iostream>
using namespace std;
using namespace sf;
Vector2f mapcords(int tt,int corner);
Vector2f mapcords(int tt,int corner)
{
if(tt ==0)
{
if (corner ==1)
{return Vector2f(48,8 );}
if(corner == 1)
{return Vector2f(48,0);}
if (corner ==2)
{return Vector2f(56, 0);}
if (corner == 3)
{return sf::Vector2f(56, 8);}
}
else{
if(corner ==0)
{return Vector2f(0,8 );}
if(corner == 1)
{return Vector2f(0,0);}
if (corner ==2)
{return Vector2f(8, 0);}
if (corner == 3)
{return sf::Vector2f(8, 8);}
}
return Vector2f(0,0 );
}
class drawmap : public sf::Drawable, public sf::Transformable
{
public:
bool load(const string& tileset,const int* tt, int ts, int r, int c, int num)
{
count =0; row =1; a = 0; b = 1; d = 2; e = 3;y=0;x=0;
tiletex.setRepeated(true);
if (!tiletex.loadFromFile(tileset))
return false;
tiletex.setRepeated(true);
vertices.setPrimitiveType(sf::Quads);
vertices.resize(2 * 2 * 4);
cout <<endl<<"Row "<<row<<": ";
for(x = 1; x < c;++x)
{
for(y = 0; y < r;++y)
{
tiletype = tt[count];
cout <<tiletype<<", ";
vertices[a].position = sf::Vector2f((0+y)*ts,ts*(x+1)+80);
vertices[b].position = sf::Vector2f((0+y)*ts, (0+x)*ts+80);
vertices[d].position = sf::Vector2f(ts+(y*ts),(0+x)*ts+80);
vertices[e].position = sf::Vector2f(ts+(y*ts), ts*(x+1)+80);
vertices[a].texCoords = mapcords(tiletype,0);
vertices[b].texCoords = mapcords(tiletype,1);
vertices[d].texCoords = mapcords(tiletype,2);
vertices[e].texCoords = mapcords(tiletype,3);
a += 4; b += 4; d += 4; e += 4;count++;
}
row += 1;
cout <<endl<<"Row "<<row<<": "; y = 0;
}
return true;
}
private:
int row;
int count;
int y,x;
int a,b,d,e;
int tiletype;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform();
states.texture = &tiletex;
target.draw(vertices, states);
}
sf::VertexArray vertices;
sf::Texture tiletex;
};
Even if r and c are properly initialized to (I assume) 4, once you've looped to the point where y = 4 (ie. x is incrementing) you don't reset a, b, d or e - meaning on the fifth loop through, you have a = 16, b = 17, d = 19 and e = 20, but then you still try to access vertices[a] (and b and d and e). Since vertices just before this was resized to (2 * 2 * 4), or 16, you then access the vector out of its bounds. Hence, the vector subscript out of range error.
In order to hold enough vertices for 4 * the number of tiles you want to put in the vector, you're going to need to do something like:
vertices.resize(4 * r * c);