Writing a 2D vector to a file? c++ - c++

I'm wondering how I can output a 2D vector to a file with spaces in between the values. It's to write a map to a file at a specified size that the user chooses. I am already dynamically loading the map from there. I have a basis for the function but I'm kind of lost on the next bit.
void Map::SetMapSize(int sizeX, int sizeY, const char *filename)
{
std::ofstream out(filename);
out << "[Map]" << std::endl;
MapSizeVector[sizeX][sizeY];
for(int i = 0; i <= sizeX; i++)
{
for(int j = 0; j <= sizeY; j++)
{
std::ostream_iterator<std::string> output_iterator(out, " ");
}
}
}
The Map.txt looks like this:
[Map]
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 0 0 0 1 1 0 0 1 1 1 1 1 1 0 0
0 0 1 1 0 0 0 1 1 0 0 1 1 1 1 1 1 0 0
0 0 1 1 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0
0 0 1 1 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0
0 0 1 1 1 1 1 1 1 0 0 0 0 1 1 0 0 0 0
0 0 1 1 1 1 1 1 1 0 0 0 0 1 1 0 0 0 0
0 0 1 1 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0
0 0 1 1 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0
0 0 1 1 0 0 0 1 1 0 0 1 1 1 1 1 1 0 0
0 0 1 1 0 0 0 1 1 0 0 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 0 0 0 0 0 0 0 0 0
It also has a details bit underneath it. Basically, I want to rewrite that [Map] part to whatever size x and y the user requests above the [Details] and replacing the existing [Map] part. The numbers are fine with being 0. Thanks!
Declaration of vector in Map.h
std::vector <std::vector <int> > MapSizeVector;

Your function should look like this:
void Map::SetMapSize(int sizeX, int sizeY, const char *filename)
{
std::ofstream out(filename);
out << "[Map]" << std::endl;
MapSizeVector.resize(sizeX);
for(int i = 0; i < sizeX; i++)
{
MapSizeVector[i].resize(sizeY);
for(int j = 0; j < sizeY; j++)
{
char str[20];
sprintf(str, "%d ", MapSizeVector[i][j]);
out << str;
}
out << '\n';
}
}

Related

C++ reading from file is not giving expected, or any output

I am trying to make a game which loads it's levels from a text file. I decided to do this with the help of a 2 dimensional vector of integers. Before implementing it in my main code, I first decided to check whether my logic was right so I made a Test.txt file containing the the level I wanted to draw.
Test.txt:-
1 1 0 0 1 0 0 0 0 0 1 1 1 1 1 1 1 0 1 0 1 0 0 1 0 0 1 0 0 1 1 0
1 0 1 0 1 1 1 0 1 1 0 1 1 0 1 1 1 0 1 0 0 1 1 1 1 1 1 0 0 1 0 0
0 0 0 0 0 0 0 1 0 1 0 0 0 1 1 0 1 1 0 0 0 0 0 0 1 0 0 1 0 1 1 0
0 0 1 1 1 1 1 0 0 0 1 0 1 0 1 1 0 0 0 1 1 1 1 0 0 0 1 0 1 1 1 0
1 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 1 0 0 0 0 0 1 0 0 1 0 1
0 1 0 1 0 1 1 1 0 0 1 0 0 0 0 1 0 1 0 0 1 0 1 1 0 0 0 0 1 1 0 1
0 1 1 1 0 1 1 0 1 0 1 1 0 1 1 0 0 1 0 0 0 1 1 0 1 1 1 1 1 1 0 1
0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 1 0 1 0 1 1 0 0 1 0 0 0 1 0 0
0 0 1 1 1 0 0 0 1 0 0 1 1 1 1 0 0 1 1 0 0 0 1 1 1 0 1 1 1 1 0 1
0 1 0 0 1 1 0 0 1 0 1 1 0 1 0 0 1 1 0 1 1 0 1 0 0 1 1 1 1 0 1 1
1 1 0 1 1 1 1 0 0 1 0 0 1 0 0 1 0 1 0 1 1 1 1 1 0 0 0 1 1 0 1 0
0 0 1 0 0 0 1 1 1 0 1 0 0 1 0 1 1 0 0 0 1 1 0 1 0 0 0 0 1 1 0 1
0 1 1 0 0 0 0 0 0 1 1 0 1 1 0 1 1 0 1 0 0 1 0 0 1 1 0 1 1 1 1 0
1 0 1 1 1 0 1 1 1 1 0 0 0 0 0 0 1 0 1 0 0 0 1 1 1 0 0 1 1 0 0 0
1 0 1 1 0 0 0 0 1 0 0 1 1 0 0 0 1 0 0 1 0 0 0 1 0 1 0 1 1 0 0 1
0 0 1 1 1 0 1 1 1 0 1 0 0 0 1 0 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 0
0 0 0 1 0 1 0 1 0 1 0 0 1 1 1 0 0 1 1 0 1 0 1 0 1 1 1 0 0 0 1 0
1 0 1 0 1 0 0 0 1 1 0 0 0 1 0 1 1 1 1 1 0 0 1 0 1 0 1 1 1 1 1 1
Each integer is seperated by a space and only one number is supposed to be read once at a time. The 1 and 0 tell the game which tile to draw. Now, with this wrote the following code in c++ to read the file and populate the vector with it's contents. After that it's supposed to output the contents of the vector.
Test.cpp:-
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int num;
vector<vector<int>> nums;
int main(void) {
ifstream FileIn;
FileIn.open("Test.txt");
for(int i = 0; i < 18; i++) {
vector<int> temp;
for(int j = 0; j < 32; j++) {
FileIn >> num;
temp.push_back(num);
}
nums.push_back(temp);
temp.clear();
}
cout << nums.size() << '\n'; // outputs 18
for (unsigned int i=0; i < nums.size(); i++) {
for (unsigned int j=0; j < nums[i].size(); j++) {
cout << nums[i][j];
if (j == nums[i].size() - 1) cout << '\n';
}
}
FileIn.close();
return 0;
}
but this is where the problem starts. The code doesn't output anything to the terminal it just starts and then goes back to the prompt.
The executable compiles with no errors and there are no crashes or runtime error either. There is just no output.
Things i have tried:
Putting in spaces between the numbers
Keeping all integers on the same line
both of the solutions above, but together this time
I am using atom with the platformio terminal plugin on windows 10 (64-bit) on a intel with amd-64 architecture. Any help would be very appreciated.
A few things: Start learning how to use a debugger. Your question to stackoverflow is something you probably could easily answer on your own, if you stepped through your code with a debugger. That'd save you time - and us.
Edited:
Also, you open 'test.txt' without verifying or setting the "current working directory". This will work only if you start the application from the same path, test.txt is in. But if you run the app from someplace else, the working directory may be different.
You did not check for eof or any other error condition. How do you know if opening the file did actually work? Or reading the number? Or that there are exactly the amount of numbers you are expecting.
Checking error conditions may seem like a nuisance, but it's definitely not. Hunting for errors, which you did not check in your code, is much more time consuming than forming a habit to check for errors.
Here is some code:
ifstream FileIn;
FileIn.open("test.txt");
if (!FileIn.good())
cerr << "Could not open file...";
else {
while (!FileIn.eof()) {
int num; ///!!! DONT make `num` a global variable
FileIn >> num;
if (FileIn.bad()) {
cerr << "Invalid number in file...";
return 1; // return prematurely from the application
}
// Do something with the number
}
}
Also, use cout << endl instead of cout << '\n';. endl is the official way of inserting a line break and it will work on any platform, whereas '\n' may or may not work. Some platforms require two characters.
So I finally found the problem, the code, logic, text file everything were working fine. After taking the advice about debuggers from the other answer, this time instead of using atom's terminal plugin, I used powershell and it worked. It gave the output i was expecting. Then i tried the same code with the atom's terminal and that gave no output. So the problem seemed to be not in the code but in the terminal I was using.

How to make a group of integers randomly "roll around" a 2d grid, decrementing every time, until each equals 0?

sorry for the weird question, but I can explain.
Imagine you have 50 marbles that are wet with paint, and you are standing over a large canvas. You will drop each marble in the middle of the canvas, wait until it stops rolling around (assume when the marble stops, it disppears), and then drop your next one until you run out of marbles.
You will notice that when you are finished dropping all the marbles, the canvas is painted all over, with some streaks being darker than others.
That is what I am trying to represent with a 2d grid. So if I were to have 5 marbles, each with a "life" of 2, it would look something like this (given a 10x10 2d array)
/*
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 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 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 0
0 0 0 0 0 0 0 0 0 0
*/
Note, we dropped in the middle, then the marble went up and right
We moved twice, so our initial maxLife == 2 is now maxLife == 0, so we move onto the next marble
/*
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 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 2 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
0 0 0 0 0 0 0 0 0 0
*/
Note, we dropped in the middle again, then the marble went right
We moved twice, so our initial maxLife == 2 is now maxLife == 0, so we move onto the next marble
/*
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 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 3 1 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 0
*/
so on, and so on until we have dropped 5 marbles.
This seems basic enough with a simple nested for loop and recursive method to travel across and increment the array until the base case (when maxLife == 0), is hit. However, I am not getting expected results.
Here is my code :
#include <iostream>
#include <ctime>
using namespace std;
int width, height, xMax, xMin, yMax, yMin, numParticles, maxLife, waterLine;
int main()
{
/* Take in width, height, numParticles, maxLife, removed for code clarity */
int **land = makeParticleMap(width, height, numParticles, maxLife);
printIsland(land, width, height);
return 0;
}
void printIsland(int **land, int width, int height) { ... }
int **makeParticleMap(int width, int height, int numParticles, int maxLife)
{
int **land;
land = new int *[height];
for (int i = 0; i < height; ++i)
{
land[i] = new int[width]; //we have the 2d array
}
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
land[i][j] = 0;
}
}
int x, y = (width + height) / 2;
while (numParticles != 0) //while we have particles to drop
{
particleRoll(land, width, height, x, y, maxLife);
numParticles--;
}
return land;
}
void particleRoll(int **map, int width, int height, int x, int y, int maxLife)
{
if (maxLife <= 0)
{
return;
}
map[x][y]++;
maxLife--;
int xDir = (randomBool()) ? 1 : -1;
int yDir = (randomBool()) ? 1 : -1;
//i + xDir means: i-- or i++, either roll up or down rows, and j--, j++ same thing across columns
particleRoll(map, width, height, x + xDir, y + yDir, maxLife);
}
bool randomBool() { //returns -1 or 1 }
height and width never change, they are just the sizes of the array, since I am working with an int** instead of a vector.
I am just getting a width x height array of all 0's. I assume that the whole logic problem is within the recursion of particleRoll. I tried approaching it in a DFS style search, like the famous Number of Islands algorithm problem. However, I cannot figure out why my code is working like this.

storing integers in an array stores a random value

I'm coding my own minesweeper game for fun in C++ (The language I'm most familiar with) and when I'm storing a constant in a 2d array, it sometimes ends up storing a random value.
Here's my code:
using namespace std;
Table::Table() {
tiles[16][16] = {0};
covers[16][16] ={1};
}//stores position of mines, covers, and values
//places mines on the board
void Table::placemines() {
int minecount=0;
int i = rand()%15;
int j = rand()%15;
while(minecount<40){
if (tiles[i][j] == 0) {
tiles[i][j] = -10;
minecount++;
} else {}
i = rand()%15;
j = rand()%15;
}
}
and my main.cpp to display the values
using namespace std;
int main() {
Table newtable = Table();
newtable.placemines(6, 7);
for (int j = 0; j < 16; j++) {
for (int i = 0; i < 16; i++) {
cout << newtable.tiles[i][j] << ' ';
}
cout << '\n';
}
}
and the output
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 -10 -10 -10 0 0 1 -10 0 0
0 0 0 0 0 0 0 -10 0 -10 -10 0 -10 0 0 0
0 0 0 0 0 -10 0 0 0 -10 -10 0 -10 0 0 0
-10 0 0 -10 -10 0 0 -10 -10 0 0 0 0 -10 0 0
-10 0 -10 0 0 -10 0 0 0 0 0 0 0 -10 0 0
0 0 0 0 0 0 0 0 -10 -10 0 1920169263 0 -10 0 0
0 0 -10 0 0 0 0 0 0 -10 -10 1651076143 0 0 0 0
0 0 0 0 0 0 0 0 -10 -10 0 1819894831 -10 0 0 0
0 0 0 0 0 0 0 0 0 0 0 100 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 -10 0 0 0 0
0 0 0 0 0 0 0 -10 0 -10 0 32 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-10 0 0 -10 0 0 0 0 0 0 -10 2 0 0 0 0
-10 0 0 0 0 -10 0 0 0 -10 0 4 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 0
Can anyone tell what's going on? Thank you!
Too much code missing, no declaration, no placemines() code
You have bug here:
tiles[16][16] = {0};
This statement sets some element of array, with indices 16 and 16, to 0. If your array defined as type tiles[16][16] that means you write into the Abyss and cause UB (because last element of array is tiles[15][15]).
If you have to initialize an array, use std::fill http://en.cppreference.com/w/cpp/algorithm/fill . For zero-intialization this works:
Table::Table() : tiles{0} {
Another bug possible:
int i = rand()%15;
You have to use array's size to cover the range properly.
PS. Avoid using namespace std; in global scope, pleeeese.

3d maze recursion method - c++

I am making a 3D maze in c++. I am having trouble with a recursive method to find a valid path between the two endpoints (starting point is m[0][0][0]; endpoint is m[7][7][7];). It checks positions in the array. If its contents are a 1, then it is a valid part of the path; if 0, it is not a valid part of the path. Here is my method:
bool Maze::findPath(int row, int column, int level,string path){
cout << "findPath " << row << ", " << column << ", " << level << " value " << m[row][column][level] << endl;
if(row < 0 || row > 7 || column < 0 || column > 7 || level < 0 || level > 7 ){
cout << "Out of bounds" << endl;
//system("PAUSE");
return false;
}
else if(m[row][column][level] == 0){
cout << "spot is zero" << endl;
//system("PAUSE");
return false;
}
else if(visited[row][column][level] == 1){
cout << "visited" << endl;
return false;
}
else if(row == 7 && column == 7 && level == 7 && m[row][column][level] == 1){
cout << "Found!" << endl;
//system("PAUSE");
return true;
}
else{
visited[row][column][level] = 1;
//cout << "searching..." << endl;
if(row < 7 && findPath(row + 1,column,level,path))
return true;
if(column < 7 && findPath(row,column + 1,level,path))
return true;
if(level < 7 && findPath(row,column,level + 1,path))
return true;
if(row > 7 && findPath(row - 1,column,level,path))
return true;
if(column > 7 && findPath(row,column - 1,level,path))
return true;
if(level > 7 && findPath(row,column,level - 1,path))
return true;
}
return false;
}
So the method checks for "Out of bounds", an invalid spot on the path (zero), a visited location. I'm not sure what exactly I'm missing, but the method returns true to mazes that are unsolvable. Can anybody see some blatant mistake that I may be missing with my recursive call? Thanks
EDIT: Fixed a few code mistakes, but it still seems to be "solving" unsolvable mazes.
Here's an example of a solvable maze that it is saying is not possible to solve:
1 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 0 0 0 1
0 0 0 1 0 0 0 0
1 0 0 1 0 1 0 0
0 0 0 1 0 0 0 0
1 0 0 1 0 0 0 1
1 0 0 0 0 0 0 0
1 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 0 0 0 0
1 0 0 0 0 0 0 0
0 1 1 0 0 0 0 0
0 0 0 1 0 1 1 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 1
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 1
0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
0 0 0 1 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 1 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
1 1 1 1 0 0 0 0
0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 1
0 0 0 0 0 0 1 0
0 0 0 0 0 0 1 0
1 0 0 0 0 1 0 0
0 1 0 0 0 0 0 0
1 0 0 0 0 0 0 1
1 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 1 0
1 1 1 1 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
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 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 1 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 1
0 0 1 0 0 0 0 1
0 0 1 0 0 0 0 1
0 0 1 0 0 0 0 1
0 0 1 1 0 0 0 1
0 0 0 1 0 0 0 1
0 0 0 1 0 0 0 1
0 0 0 1 1 1 0 1
There's a problem in the findPath(++row,column,level,path) (and similar recursive calls): you don't want the variable increments to carry over to the other recursive calls. (For example, the variable row in findPath(row,++column,level,path) would be affected by the first recursive call.)
Use findPath(row + 1,column,level,path) (and similar) instead.
Also, in the last three recursive calls, you're not making the right tests:
//instead of level < 7
if(level < 7 && findPath(--row,column,level,path)) //should be row > 0
return true;
if(level < 7 && findPath(row,--column,level,path)) //should be column > 0
return true;
if(level < 7 && findPath(row,column,--level,path)) //should be level > 0
return true;
EDIT
However, you don't actually need these tests since you filter out out of bounds errors at the top of your recursive function. Therefore, these calls can be simplified to:
return findPath(row + 1,column,level,path) || findPath(row,column + 1,level,path)
|| findPath(row,column,level + 1,path) || findPath(row - 1,column,level,path)
|| findPath(row,column - 1,level,path) || findPath(row,column,level - 1,path);
Additionally, the test && m[row][column][level] == 1 is redundant since the else if(m[row][column][level] == 0) takes care of that. (I'd check m[7][7][7] before even calling this function the first time, by the way.)
I just Finished this algorithm as an assignment for a class, ours only used a 5x5 block as the maze, but I found that it will go very slowly testing all possibilities each time it reaches the block from any angle, I found that the program can be sped up significantly by setting values in your array to 0 as you determine that they're not useful. I did it at the return false at the end of the function.

How do I add a number to an array if it is less than a corresponding number in a "Max" array?

So here is my issue. In the program I have below, towards the bottom of the function "SetBoardStartingConfig" I attempt to fill in the first 4 rows of an array by randomly generating numbers, checking if the square I'm attempting to place them onto is empty (0), and if the addition of the piece would make it go over the specified max values in array "MaxPieces". If it wouldn't, it should theoretically be added - but its not working as I intended, and throwing me interesting values. In main, I go on to repeat this function 10 times, but it always seems to produce a different error - below I've also pasted some of my results.
Note: I've commented out both algorithms to try this, they're separated by a bit of white space.
Sidenote: I seem to always get FlagSide = 1 (right side) the first time I run the program - any ideas on how to fix this?
Thank you all very much for your help :).
#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;
int board[10][10];
int AIPieces[11];
int PlayerPieces[11];
int MaxPieces[11];
string PieceNames[11];
//insert stuff for maximum number of things
#define NullSpace -1 // Spaces that pieces can not move to
#define Flag -5
#define Bomb 1
#define EmptySpace 0 //Empty board spaces
void SetMaxPieces()
{
MaxPieces[0] = 1;
MaxPieces[Bomb] = 6;
MaxPieces[2] = 8;
MaxPieces[3] = 5;
MaxPieces[4] = 4;
MaxPieces[5] = 4;
MaxPieces[6] = 4;
MaxPieces[7] = 3;
MaxPieces[8] = 2;
MaxPieces[9] = 1;
MaxPieces[10] = 1;
MaxPieces[11] = 1; //Spy
}
void ResetAIPieces()
{
for (int i = 0; i < 11; i++)
AIPieces[i] = 0;
}
void SetPieceNames()
{
PieceNames[0] = "Flags:";
PieceNames[1] = "Bombs:";
PieceNames[2] = "Twos:";
PieceNames[3] = "Threes:";
PieceNames[4] = "Fours:";
PieceNames[5] = "Fives:";
PieceNames[6] = "Sixes:";
PieceNames[7] = "Sevens:";
PieceNames[8] = "Eights:";
PieceNames[9] = "Nines:";
PieceNames[10] = "Tens:";
PieceNames[11] = "Spies:";
}
void PrintBoard()
{
for (int i=0; i<10; i++)
{
for (int j=0; j<10; j++)
{
cout << board[i][j] << " ";
if (board[i][j] >= 0)
{
cout << " ";
}
}
cout << endl;
}
}
void SetBoardStartingConfig()
{
for (int i=0; i<10; i++)
{
for (int j=0; j<10; j++)
{
board[i][j] = EmptySpace;
}
}
//arrays work in [row] and [column].
//below defines areas that the pieces can not move to.
board[4][2] = NullSpace;
board[4][3] = NullSpace;
board[5][2] = NullSpace;
board[5][3] = NullSpace;
board[4][6] = NullSpace;
board[4][7] = NullSpace;
board[5][6] = NullSpace;
board[5][7] = NullSpace;
int FlagSide = rand() % 2;
if (FlagSide == 0)
{
board[0][0] = Flag;
AIPieces[0]++;
AIPieces[board[2][0] = Bomb]++;
AIPieces[board[1][1] = Bomb]++;
AIPieces[board[0][2] = Bomb]++;
AIPieces[board[1][0] = rand() % 3 + 4]++;
AIPieces[board[0][1] = rand() % 3 + 4]++;
}
else if (FlagSide == 1)
{
board[0][9-0] = Flag;
AIPieces[0]++;
AIPieces[board[2][9-0] = Bomb]++;
AIPieces[board[1][9-1] = Bomb]++;
AIPieces[board[0][9-2] = Bomb]++;
AIPieces[board[1][9-0] = rand() % 3 + 4]++;
AIPieces[board[0][9-1] = rand() % 3 + 4]++;
}
//for (int i =0; i < 4; i++)
// for (int j = 0; j < 10; j++)
// {
// if (board[i][j] == 0)
// {
// int Chosen = rand() % 10+1;
// if (AIPieces[Chosen] < MaxPieces[Chosen])
// {
// board[i][j] = Chosen;
// AIPieces[Chosen]++;
// }
// else
// break;
// }
// else
// break;
// // if (AIPieces[0] < MaxPieces[0] || AIPieces[1] < MaxPieces[1] || AIPieces[2] < MaxPieces[2] || AIPieces[3] < MaxPieces[3] || AIPieces[4] < MaxPieces[4] || AIPieces[5] < MaxPieces[5] || AIPieces[5] < MaxPieces[5] || AIPieces[6] < MaxPieces[6] || AIPieces[7] < MaxPieces[7] || AIPieces[8] < MaxPieces[8] || AIPieces[9] < MaxPieces[9] || AIPieces[10] < MaxPieces[10] || AIPieces[11] < MaxPieces[11])
// //{
// // AIPieces[board[i][j] = rand() % 10+1]++;
// //}
// }
}
int main()
{
SetMaxPieces();
SetPieceNames();
int loop = 0;
do
{
SetBoardStartingConfig();
PrintBoard();
cout << endl;
for (int i = 0; i < 11; i++)
{
cout << PieceNames[i] << AIPieces[i] << endl;
}
cout << endl;
ResetAIPieces();
loop++;
} while (loop <= 10);
system("PAUSE");
}
My Results (They seem to be the same every time I run it using the first algorithm)
1 10 5 9 0 0 0 1 5 -5
3 5 6 6 2 8 2 2 1 6
6 3 8 7 2 5 3 4 3 1
3 2 7 0 0 0 0 0 0 0
0 0 -1 -1 0 0 -1 -1 0 0
0 0 -1 -1 0 0 -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 0
0 0 0 0 0 0 0 0 0 0
Flags:1
Bombs:4
Twos:5
Threes:5
Fours:1
Fives:4
Sixes:4
Sevens:2
Eights:2
Nines:1
Tens:1
2 9 10 3 8 0 0 1 4 -5
6 5 4 2 3 4 4 5 1 6
2 2 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0
0 0 -1 -1 0 0 -1 -1 0 0
0 0 -1 -1 0 0 -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 0
0 0 0 0 0 0 0 0 0 0
Flags:1
Bombs:3
Twos:4
Threes:2
Fours:4
Fives:2
Sixes:2
Sevens:0
Eights:1
Nines:1
Tens:1
8 8 10 4 2 0 0 1 5 -5
9 7 6 1 3 0 0 0 1 6
7 1 3 5 0 0 0 0 0 1
7 6 1 0 0 0 0 0 0 0
0 0 -1 -1 0 0 -1 -1 0 0
0 0 -1 -1 0 0 -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 0
0 0 0 0 0 0 0 0 0 0
Flags:1
Bombs:6
Twos:1
Threes:2
Fours:1
Fives:2
Sixes:3
Sevens:3
Eights:2
Nines:1
Tens:1
-5 4 1 0 0 0 0 0 0 0
6 1 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
2 4 9 10 4 5 5 7 1 7
0 0 -1 -1 0 0 -1 -1 0 0
0 0 -1 -1 0 0 -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 0
0 0 0 0 0 0 0 0 0 0
Flags:1
Bombs:4
Twos:1
Threes:0
Fours:3
Fives:2
Sixes:1
Sevens:2
Eights:0
Nines:1
Tens:1
-5 5 1 0 0 0 0 0 0 0
6 1 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
5 10 7 4 8 9 0 0 0 0
0 0 -1 -1 0 0 -1 -1 0 0
0 0 -1 -1 0 0 -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 0
0 0 0 0 0 0 0 0 0 0
Flags:1
Bombs:3
Twos:0
Threes:0
Fours:1
Fives:2
Sixes:1
Sevens:1
Eights:1
Nines:1
Tens:1
-5 6 1 0 0 0 0 0 0 0
4 1 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
4 6 10 9 5 1 8 7 4 7
0 0 -1 -1 0 0 -1 -1 0 0
0 0 -1 -1 0 0 -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 0
0 0 0 0 0 0 0 0 0 0
Flags:1
Bombs:4
Twos:0
Threes:0
Fours:3
Fives:1
Sixes:2
Sevens:2
Eights:1
Nines:1
Tens:1
3 1 10 8 4 8 3 1 6 -5
7 1 2 7 6 0 0 0 1 6
6 5 2 3 1 0 0 0 0 1
2 5 7 0 0 0 0 0 0 0
0 0 -1 -1 0 0 -1 -1 0 0
0 0 -1 -1 0 0 -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 0
0 0 0 0 0 0 0 0 0 0
Flags:1
Bombs:6
Twos:3
Threes:3
Fours:1
Fives:2
Sixes:4
Sevens:3
Eights:2
Nines:0
Tens:1
8 8 0 0 0 0 0 1 5 -5
4 4 6 10 0 0 0 0 1 6
9 2 0 0 0 0 0 0 0 1
3 7 7 1 4 0 0 0 0 0
0 0 -1 -1 0 0 -1 -1 0 0
0 0 -1 -1 0 0 -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 0
0 0 0 0 0 0 0 0 0 0
Flags:1
Bombs:4
Twos:1
Threes:1
Fours:3
Fives:1
Sixes:2
Sevens:2
Eights:2
Nines:1
Tens:1
-5 4 1 0 0 0 0 0 0 0
6 1 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
6 1 10 5 8 9 4 6 2 3
0 0 -1 -1 0 0 -1 -1 0 0
0 0 -1 -1 0 0 -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 0
0 0 0 0 0 0 0 0 0 0
Flags:1
Bombs:4
Twos:1
Threes:1
Fours:2
Fives:1
Sixes:3
Sevens:0
Eights:1
Nines:1
Tens:1
-5 6 1 0 0 0 0 0 0 0
5 1 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
5 1 7 2 9 10 0 0 0 0
0 0 -1 -1 0 0 -1 -1 0 0
0 0 -1 -1 0 0 -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 0
0 0 0 0 0 0 0 0 0 0
Flags:1
Bombs:4
Twos:1
Threes:0
Fours:0
Fives:2
Sixes:1
Sevens:1
Eights:0
Nines:1
Tens:1
-5 4 1 0 0 0 0 0 0 0
5 1 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
4 10 9 0 0 0 0 0 0 0
0 0 -1 -1 0 0 -1 -1 0 0
0 0 -1 -1 0 0 -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 0
0 0 0 0 0 0 0 0 0 0
Flags:1
Bombs:3
Twos:0
Threes:0
Fours:2
Fives:1
Sixes:0
Sevens:0
Eights:0
Nines:1
Tens:1
Press any key to continue . . .
I'm not really clear what you expect to happen or what is happening, you should try explaining why what you get is wrong, so people don't have to spend ages analysing the code and results. Is the first algorithm working and the second not? Or are both wrong? The changes below will make the program easier to reason about anyway.
Your variable and function naming is a bit unconventional. It's more usual to see variables and functions start with a lowercase letter, and classes start with an uppercase letter. Your program looks as though Everything Is Very Important.
Why are you using macros here?
#define NullSpace -1 // Spaces that pieces can not move to
#define Flag -5
#define Bomb 1
#define EmptySpace 0 //Empty board spaces
In general, macros suck, especially if you don't name them to avoid clashing with other names. The inventor of C++ recommends using ALL_CAPS for macros. Better still, don't use them:
const int NullSpace = -1; // Spaces that pieces can not move to
const int Flag -5;
const int Bomb 1;
const int EmptySpace 0; //Empty board spaces
This is a very tedious way to set arrays:
void SetMaxPieces()
{
MaxPieces[0] = 1;
MaxPieces[Bomb] = 6;
MaxPieces[2] = 8;
...
MaxPieces[10] = 1;
MaxPieces[11] = 1; //Spy
}
Just initialize the array when you define it:
int MaxPieces[11] = {
1, 6, 8, 5, 4, 4, 4, 3, 2, 1, 1, 1
};
string PieceNames[11] = {
"Flags:", "Bombs:", "Twos:", "Threes:", "Fours:", "Fives:", "Sixes:",
"Sevens:", "Eights:", "Nines:", "Tens:", "Spies:"
};
But wait! Now the compiler refuses to compile the program:
game.cc:13:1: error: too many initializers for ‘int [11]’
game.cc:17:1: error: too many initializers for ‘std::string [11] {aka std::basic_string [11]}’
You are setting twelve values in an array of eleven! The compiler didn't complain when you did MaxPieces[11] (but maybe should have done) but it definitely won't let you initialize an array with too many values. Are your arrays supposed have twelve elements? Or are you just filling them wrong?
As a commenter pointed out, you must seed rand() or the pseudo-random number generator always starts in the same initial state and produces the exact same sequence of "random" numbers.
Why are you using do-while in main? do-while is only useful in a few situations, when the condition can't be tested initially (or for some clever hacks to make its block scope act as a single statement in evil macros). In your case the condition is initially true (loop is less than 10) so just use a for or while loop. I would prefer a for because your loop variable doesn't need to exist after the for so you can initialize it there:
for (int loop = 0; loop <= 10; ++loop)
{
SetBoardStartingConfig();
PrintBoard();
cout << '\n';
for (int i = 0; i < 11; i++)
{
cout << PieceNames[i] << AIPieces[i] << '\n';
}
cout << '\n';
ResetAIPieces();
}
cout << flush;
Using endl every time you want a newline is unnecessary, endl adds a newline and flushes the stream, which doesn't need to be done on every line. The code above does it just once after the loop.
Now for the first algorithm:
for (int i =0; i < 4; i++)
for (int j = 0; j < 10; j++)
{
if (board[i][j] == 0)
{
int Chosen = rand() % 10+1;
if (AIPieces[Chosen] < MaxPieces[Chosen])
{
board[i][j] = Chosen;
AIPieces[Chosen]++;
}
else
break;
}
else
break;
Surrounding the first for in braces could help readability too. It would also help to write rand()%10 + 1 rather than the spacing you have above, so that the operator precedence is more obvious, currently it looks like you mean it to be rand() % 11 because you've grouped the addition operands.
Shouldn't the check board[i][j] == 0 be board[i][j] == EmptySpace ? Otherwise what's the point of having that constant?
Do you really want to break there? Doesn't that mean you stop filling a row as soon as you find a non-empty square or run out of a particular kind of piece? If the break should be there, where do they go for the second algo? Your code is impossible to reason about, partly because all the important logic is commented out (that's not a helpful way to read code!) and because of the inconsistent indentation.
Your second algorithm is completely unreadable, do you have a screen wide enough to see that line without wrapping? Even if you do it would be easier to read broken up.
Does the second algo check board[i][j] == EmptySpace? It doesn't seem to, but maybe that's just your formatting.
Also, all those comments make it awkward to switch between implementations to compare the results. If you do this:
for (int i =0; i < 4; i++)
{
for (int j = 0; j < 10; j++)
{
if (board[i][j] == EmptySpace)
{
#if 0
int Chosen = rand()%10 +1;
if (AIPieces[Chosen] < MaxPieces[Chosen])
{
board[i][j] = Chosen;
AIPieces[Chosen]++;
}
else
break;
#else
if (AIPieces[0] < MaxPieces[0]
|| AIPieces[1] < MaxPieces[1]
|| AIPieces[2] < MaxPieces[2]
|| AIPieces[3] < MaxPieces[3]
|| AIPieces[4] < MaxPieces[4]
|| AIPieces[5] < MaxPieces[5]
|| AIPieces[5] < MaxPieces[5]
|| AIPieces[6] < MaxPieces[6]
|| AIPieces[7] < MaxPieces[7]
|| AIPieces[8] < MaxPieces[8]
|| AIPieces[9] < MaxPieces[9]
|| AIPieces[10] < MaxPieces[10]
|| AIPieces[11] < MaxPieces[11])
{
AIPieces[board[i][j] = rand() % 10+1]++;
}
#endif
}
else
break;
}
}
Then you only need to change one character (change #if 0 to #if 1) to switch between them.
Now I can see the second algorithm properly it's obvious that if any pieces remain you will place a piece, but that could place a piece which you've run out of. e.g. if AIPieces[1] < MaxPieces[1] but AIPieces[2] == MaxPieces[2] the condition is true, but then if rand()%10 + 1 returns 2 you put a piece you aren't allowed to place. That means you place too many of some types of piece.
I think Scott has a much better idea, separate the placing of pieces into a function, which will make that loop much easier to read:
for (int i =0; i < 4; i++)
for (int j = 0; j < 10; j++)
AddPiece(rand() % 3 + 4, 1, 0);
Now you could write AddPiece2 and change the call to that to experiment with different implementations. Comparing the two algorithms could help find where it goes wrong.
I'm not sure I'm understanding the question well. But, trying to answer it. Something like this seems to be what you're asking for:
Instead of incrementing AIPieces, you need to first check that the board doesn't already have something on it and that MaxPieces haven't already been used.
AIPieces[board[1][0] = rand() % 3 + 4]++;
So try a function to do this:
void AddPiece(int pieceType, int locationX, int locationY)
{
if( board[locationX][locationY] != 0 )
return; // board already has something here, so don't add.
if( AIPieces[pieceType] >= MaxPieces[pieceType] )
return; // Can't add as all of these pieces have already been used.
board[locationX][locationY] = pieceType;
AIPieces[pieceType]++;
}
And in place of the original line, call the function like this:
AddPiece(rand() % 3 + 4, 1, 0);
Your second algorithm won't work because when you try and add a piece, the if statement checks if any type of piece has been used, instead of just checking the type of piece you're trying to add.