Extracting integers from file - c++

I have the following file stored in a string vector.
ratingsTiny.txt...
Jesse
-3 5 -3 0 -1 -1 0 0 5
Shakea
5 0 5 0 5 0 0 0 1
Batool
5 -5 0 0 0 0 0 -3 -5
Muhammad
0 0 0 -5 0 -3 0 0 0
Maria
5 0 5 0 0 0 0 1 0
Alex
5 0 0 5 0 5 5 1 0
Riley
-5 3 -5 0 -1 0 0 0 3
My goal is extract the numbers, preferably column wise, to add them together and get an average rating for each column among the 7 users.
My closest attempt is below, but I can only print the first column and I can't figure out how to iterate through the entirety of the rows to get the rest of the integers.
Any help is very much appreciated.
ourvector<string> ratings;
for (int i = 1; i < ratings.size(); i += 2){
int num = atoi(ratings[i].c_str());
intRatings.push_back(num);
cout << num << endl;
}

Related

Notepad++ regex - search only in certain column all numbers between two numbers?

i have now 250 million lines of text from a database.
I want to highlight only certain values, that are only in the third column.
I use this \b1011(3[1-9]\d[1-9]|[4]\d\d\d|5[0-8][0-3][0-6])\b for highlight all values between 10113101 to 10115836.
Can one exclude the numbers from column 4?
Edit: a column means for me the text between the spaces
1 2 3 4 5 ..... columns
307607 1317011864 10113101 -25 13135611 2700 0 0 0 12 0 0 0 walk029h.rwx
2264 910115836 10114632 -15 20111192 900 0 0 0 11 0 0 0 walk029.rwx
326169 1010523891 10115836 -1 20911192 0 0 0 0 11 0 0 0 walk12h.rwx
38718 826265392 10113628 0 10114603 2700 0 0 0 11 0 0 0 street2.rwx
241512 1317011864 636346 0 10113987 900 0 0 0 12 0 0 0 walk029h.rwx
38718 826266129 10113448 0 10114310 900 0 0 0 10 0 0 0 tree5m.rwx
38718 826266243 10113898 0 10114810 900 0 0 0 10 0 0 0 tree9m.rwx
This pattern will capture the numbers you want in the third column only. Refer to capture group 1 for their values.
^(?:\S+\s){2}\b(1011(?:3[1-9]\d{2}|4\d{3}|5[0-8][0-3][0-6]))\b.*
All I did was modify yours to add the prefix and removed some redundancy.

time series sliding window with occurrence counts

I am trying to get a count between two timestamped values:
for example:
time letter
1 A
4 B
5 C
9 C
18 B
30 A
30 B
I am dividing time to time windows: 1+ 30 / 30
then I want to know how many A B C in each time window of size 1
timeseries A B C
1 1 0 0
2 0 0 0
...
30 1 1 0
this shoud give me a table of 30 rows and 3 columns: A B C of ocurancess
The problem is the data is taking to long to be break down because it iterates through all master table every time to slice the data eventhough thd data is already sorted
master = mytable
minimum = master.timestamp.min()
maximum = master.timestamp.max()
window = (minimum + maximum) / maximum
wstart = minimum
wend = minimum + window
concurrent_tasks = []
while ( wstart <= maximum ):
As = 0
Bs = 0
Cs = 0
for d, row in master.iterrows():
ttime = row.timestamp
if ((ttime >= wstart) & (ttime < wend)):
#print (row.channel)
if (row.channel == 'A'):
As = As + 1
elif (row.channel == 'B'):
Bs = Bs + 1
elif (row.channel == 'C'):
Cs = Cs + 1
concurrent_tasks.append([m_id, As, Bs, Cs])
wstart = wstart + window
wend = wend + window
Could you help me in making this perform better ? i want to use map function and i want to prevent python from looping through all the loop every time.
This is part of big data and it taking days to finish ?
thank you
There is a faster approach - pd.get_dummies():
In [116]: pd.get_dummies(df.set_index('time')['letter'])
Out[116]:
A B C
time
1 1 0 0
4 0 1 0
5 0 0 1
9 0 0 1
18 0 1 0
30 1 0 0
30 0 1 0
If you want to "compress" (group) it by time:
In [146]: pd.get_dummies(df.set_index('time')['letter']).groupby(level=0).sum()
Out[146]:
A B C
time
1 1 0 0
4 0 1 0
5 0 0 1
9 0 0 1
18 0 1 0
30 1 1 0
or using sklearn.feature_extraction.text.CountVectorizer:
from sklearn.feature_extraction.text import CountVectorizer
cv = CountVectorizer(token_pattern=r"\b\w+\b", stop_words=None)
r = pd.SparseDataFrame(cv.fit_transform(df.groupby('time')['letter'].agg(' '.join)),
index=df['time'].unique(),
columns=df['letter'].unique(),
default_fill_value=0)
Result:
In [143]: r
Out[143]:
A B C
1 1 0 0
4 0 1 0
5 0 0 1
9 0 0 1
18 0 1 0
30 1 1 0
If we want to list all times from 1 to 30:
In [153]: r.reindex(np.arange(r.index.min(), r.index.max()+1)).fillna(0).astype(np.int8)
Out[153]:
A B C
1 1 0 0
2 0 0 0
3 0 0 0
4 0 1 0
5 0 0 1
6 0 0 0
7 0 0 0
8 0 0 0
9 0 0 1
10 0 0 0
11 0 0 0
12 0 0 0
13 0 0 0
14 0 0 0
15 0 0 0
16 0 0 0
17 0 0 0
18 0 1 0
19 0 0 0
20 0 0 0
21 0 0 0
22 0 0 0
23 0 0 0
24 0 0 0
25 0 0 0
26 0 0 0
27 0 0 0
28 0 0 0
29 0 0 0
30 1 1 0
or using Pandas approach:
In [159]: pd.get_dummies(df.set_index('time')['letter']) \
...: .groupby(level=0) \
...: .sum() \
...: .reindex(np.arange(r.index.min(), r.index.max()+1), fill_value=0)
...:
Out[159]:
A B C
time
1 1 0 0
2 0 0 0
3 0 0 0
4 0 1 0
5 0 0 1
6 0 0 0
7 0 0 0
8 0 0 0
9 0 0 1
10 0 0 0
... .. .. ..
21 0 0 0
22 0 0 0
23 0 0 0
24 0 0 0
25 0 0 0
26 0 0 0
27 0 0 0
28 0 0 0
29 0 0 0
30 1 1 0
[30 rows x 3 columns]
UPDATE:
Timing:
In [163]: df = pd.concat([df] * 10**4, ignore_index=True)
In [164]: %timeit pd.get_dummies(df.set_index('time')['letter'])
100 loops, best of 3: 10.9 ms per loop
In [165]: %timeit df.set_index('time').letter.str.get_dummies()
1 loop, best of 3: 914 ms per loop

Eigen: Zero matrix with smaller matrix as the "diagonals"

Is it possible to create a 9x9 matrix where the "diagonal" is another matrix and the rest are zeroes, like this:
5 5 5 0 0 0 0 0 0
5 5 5 0 0 0 0 0 0
5 5 5 0 0 0 0 0 0
0 0 0 5 5 5 0 0 0
0 0 0 5 5 5 0 0 0
0 0 0 5 5 5 0 0 0
0 0 0 0 0 0 5 5 5
0 0 0 0 0 0 5 5 5
0 0 0 0 0 0 5 5 5
from a smaller 3x3 matrix repeated:
5 5 5
5 5 5
5 5 5
I am aware of the Replicate function but that repeats it everywhere in the matrix and doesn't maintain the zeroes. Is there a builtin way of achieving what I'm after?
One way of doing this is by using blocks where .block<3,3>(0,0) is a 3x3 block starting at 0,0. (Note: Your IDE might flag this line as an error but it will compile and run)
for (int x=0, x<3, x++){
zero_matrix.block<3,3>(x*3,x*3) = five_matrix;
}
You can use the (unsupported) KroneckerProduct module for that:
#include <unsupported/Eigen/KroneckerProduct>
int main()
{
Eigen::MatrixXd A = Eigen::kroneckerProduct(Eigen::Matrix3d::Identity(), Eigen::Matrix3d::Constant(5));
std::cout << A << '\n';
}

parse collection of single integers into floats

So i slurped in a file with numbers in it like: 39.00 into a vector<std::string> and now I need to convert groups of numbers that look like 3 9 0 0 back into the form 39.00
heres a small sample.
3 4 5 0 1 2 5 0 3 4 0 0 3 4 9 0 7 0 0 0 8 0 0 0 9 0 0 0 6 5 0 0 3 9 3 2 1 1 2 0 0 0 2 5 0 0 3 0 9 0 4 0 0 0 5 5 5 0 2 0 0 0 2 5 0 0 3 0 9 0 4 0 0 0 5 5 5 0 2 2 3 0 0 0 2 4 0 0 4 5 0 0 6 7 0 0 6 5 5 0 5 6 9 0 8 7 0 0 4 3 5 0 5 6 9 8 5 5 4 0 3 3 6 2 0 0 3 4 5 0 1 2 5 0 3 4 0 0 3 4 9 0 7 0 0 0 8 0 0 0 9 0 0 0 6 5 0 0 3 9 0 3 2 1 1 2 0 0 0 2 5 0 0 3 0 9 0 4 0 0 0 5 5 5 0 2 0 0 0 2 5 0 0 3 0 9 0 4 0 0 0 5 5 5 0 2 2 3 0 0 0 2 4 0 0 4 5 0 0 6 7 0 0 6 5 5 0 5 6 9 0 8 7 0 0 4 3 5 0 5 6 9 8 5 5 4 0 3 3 6 2 0 0 3 4 5 0 1 2 5 0 3 4 0 0 3 4 9 0 7 0 0 0 8 0 0 0 9 0 0 0 6 5 0 0 3 9 0 0
transformed into 34.50 12.50 34.00....
My goal is to eventually find the average of all the floats.
Of course if there is a way to slurp a file while keeping formatting only using the standard library that would be cool too.
#include <iostream>
#include <string>
#include <fstream>
#include <streambuf>
#include <regex>
#include <vector>
#include <math.h>
void tableWriter(std::string);
float employeeAverage(std::string);
float employeeTotal(std::string);
float totalAverage(std::string);
void totalPayroll(std::string, std::vector<std::string>);
std::string getEmployeeName(std::string, std::string[]);
int main(int argc, const char * argv[]) {
try {
std::vector<std::string> regexContainer;
std::ifstream t("TheSales.txt");
std::string theSales;
t.seekg(0, std::ios::end);
theSales.reserve(t.tellg());
t.seekg(0, std::ios::beg);
theSales.assign((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
//std::cout << theSales << std::endl;
totalPayroll(theSales, regexContainer);
std::cout << std::endl << regexContainer.empty() << std::endl;
return 0;
} catch (int w) {
std::cout << "Could not open file. Exiting Now." << std::endl; return 0;
}
}
void tableWriter(std::string){}
float employeeAverage(std::string){return 0.0;}
float employeeTotal(std::string){return 0.0;}
float totalAverage(std::string){return 0.0;}
void totalPayroll(std::string theSales, std::vector<std::string> regexContainer) {
std::string matches;
std::regex pattern ("\\d");
const std::sregex_token_iterator end;
for (std::sregex_token_iterator i(theSales.cbegin(), theSales.cend(), pattern);
i != end;
++i)
{
regexContainer.push_back(*i);
for (std::vector<std::string>::const_iterator i = regexContainer.begin(); i != regexContainer.end(); ++i)
std::cout << *i << ' ';
}
}
this is the data:
2.40 5.30 6.30 65.34 65.34
3.40 7.80 3.20 65.34 65.34
3.40 5.20 8.20 23.54 12.34
2.42 5.30 6.30 5.00 65.34
3.44 7.80 3.20 34.55 65.34
3.45 5.20 8.20 65.34 65.34
Functions such as fscanf are able to read from your file and return a correctly formed float number. This should be more efficient than trying to reconstruct them from a stream of char...

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.