Variable vector size in all class instantiations in c++ - c++

I'm trying to code a chess game for usage in terminal. A game consists of a Board class, consisting of Piece classes. For each piece I want to determine the allowed moves if no other pieces where on the board and put this in a vector<pair<int,int>> (a1 = 1,1).
You can image that for a Queen you have more allowed moves than for a pawn. Ideally I would like my Piece to have a variable size vector so it is just filled with moves for that specific Piece.
This is my Piece instantiation:
class Piece{
private:
int row;
int col;
// number of moves made by the piece
int moveCnt;
// white = 1, black = -1
int color;
// 'p', 'n', 'b', 'r', 'q', 'k'
char type;
// permissable moves for the piece
vector<pair<int,int>> permMoves;
// allowable moves for the piece, taking the entire board into account (1. Ke2 is not allowed but permissable)
vector<pair<int,int>> allowedMoves;
and then for the allowed permissable moves I do this:
void Piece::computePermMoveS(){
vector<pair<int,int>> emptyPermMoves {{0,0}};
permMoves.swap(emptyPermMoves);
// PAWN
if (getType() == 'p'){
// add move to one row ahead
pair<int,int> add_pair (getCol(),getRow()+1*getColor());
permMoves.push_back(add_pair);
if (getMoveCnt() == 0){
// add move to two rows ahead
pair<int,int> add_pair (getCol(),getRow()+2*getColor());
permMoves.push_back(add_pair);
}
cout << "new pawn at " << getCol() << ", " << getRow() << endl;
for (int i=0; i<sizeof(permMoves)/sizeof(permMoves[0]); i++){
cout << permMoves[i].first << ", " << permMoves[i].second << endl;
}
}
The last printing statement is for debugging purposes. If I compile and run this, I get that each piece (pawn, rook) has three permissible moves (as a pawn, which is first in the loop has -> 0 0, a3, a4).
Could anyone tell me how to fix this? I tried reserving 21 moves (the most possible) with
Piece(){
permMoves.reserve(21);
allowedMoves.reserve(21);
}
but this is not the solution I want and I don't get this working either. So I would really like to use the original approach of each piece having their unique allowed moves.

for (int i=0; i<sizeof(permMoves)/sizeof(permMoves[0]); i++)
This line is incorrect. The number of entries in a std::vector is given by the size() member function:
for (size_t i=0; i<permMoves.size(); i++){
cout << permMoves[i].first << ", " << permMoves[i].second << endl;
}
What you are doing is assuming that std::vector works the same as an array, but that is not true.
A much easier way to perform the loop is to use a ranged-based for loop instead:
for (auto& p : permMoves)
cout << p.first << ", " << p.second << endl;

Related

Vector going out of bounds

I'm attempting to iterate through a list of 6 'Chess' pieces. Each round they move a random amount and if they land on another then they 'kill' it.
The problem is that when the last piece in my vector kills another piece I'm getting a vector 'out of range' error. I'm guessing it's because I'm iterating through a vector whilst also removing items from it, but I'm not increasing the count when I erase a piece so I'm not entirely sure. Any help would be greatly appreciated.
Here is my vector:
vector<Piece*> pieces;
pieces.push_back(&b);
pieces.push_back(&r);
pieces.push_back(&q);
pieces.push_back(&b2);
pieces.push_back(&r2);
pieces.push_back(&q2);
and this is the loop I iterate using:
while (pieces.size() > 1) {
cout << "-------------- Round " << round << " --------------" << endl;
round++;
cout << pieces.size() << " pieces left" << endl;
i = 0;
while (i < pieces.size()) {
pieces.at(i)->move(board.getMaxLength());
j = 0;
while (j < pieces.size()) {
if (pieces.at(i) != pieces.at(j) && col.detectCollision(pieces.at(i), pieces.at(j))) {
cout << pieces.at(i)->getName() << " has slain " << pieces.at(j)->getName() << endl << endl;
pieces.at(i)->setKills(pieces.at(i)->getKills() + 1);
pieces.erase(pieces.begin() + j);
}
else {
j++;
}
}
i++;
}
}
Solution
pieces.erase(pieces.begin() + j);
break;
Your logic needs a little refinement.
The way you coded it, it seems the "turn based" nature of chess has been replaced by a kind of "priority list" -- the pieces closer to the start of the vector are allowed to move first and, thus, get the priority into smashing other pieces.
I don't know if you want this logic to be right or wrong. Anyway, the trouble seems to be due to unconditionally executing the line
i++;
It should not be executed if you remove a piece for the same reason 'j++' isn't executed: you will jump over a piece.
I have a very strong feeling that this line of code:
i++;
is your culprit which is missing either a needed break condition or another conditional check that is missing from your loops. As it pertains to your nested while loops' conditions since they are based on the current size of your vector and are not being updated accordingly.
while (pieces.size() > 1) {
// ...
while (i < pieces.size()) {
// ...
while (j < pieces.size()) {
// ...
}
}
}
This is due to the fact that you are calling this within the inner most nested loop:
pieces.erase(pieces.begin() + j);
You are inside of a nested while loop and if a certain condition is met you are then erasing the object at this index location within your vector while you are still inside of the inner while loop that you never break from or check to see if the index is still valid.
Initially you are entering this while loop with a vector that has 6 entries, and you call erase on it within the nested loop and now your vector has 5 entries.
This can reek havoc on your loops because your index counters i & j were set according to the original length of your vector with a size of 6, but now the vector has been reduced to a size of 5 while you are still within the inner most nested loop that you never break from nor check to see if the indices are valid. On the next iteration these values are now invalidated as you never break out of the loops to reset the indices according to the new size of your vector, nor check to see if they are valid.
Try running this simple program that will demonstrate what I mean by the indices being invalidated within your nested loops.
int main() {
std::vector<std::string> words{ "please", "erase", "me" };
std::cout << "Original Size: " << words.size() << '\n';
for (auto& s : words)
std::cout << s << " ";
std::cout << '\n';
words.erase(words.begin() + 2);
std::cout << "New Size: " << words.size() << '\n';
for (auto& s : words)
std::cout << s << " ";
std::cout << '\n';
return 0;
}
-Output-
Original Size: 3
please erase me
New Size: 2
please erase
You should save locally pieces.at(i) and use this local variable everywhere you use pieces.at(i).
To avoid both elements out of bound and logical problems you can use std::list.
As aside, you should use std::vector<Piece*> only if these are non-owning pointers, otherwise you should use smart-pointers, probably unique_ptr.

Working with vectors and loops

sorry to post a student question here. I'm not looking for a quick solution, I'm looking to understand. Comments in my code will explain the same, but here's a plain text version:
This is the beginning of a "LoShu Magic Square", I'm not to the addition of all parts of the matrix I'm making, I'm stuck at trying to verify that the same number has not been put into the rows before. My idea was to use one vector to "test" numbers that had been entered so far, so it does not need to be multi-dimensional (none of them are, but I don't care about the limit on the tester).
As-is the code will take the first number into the test vector, go to the check function, realize that number is there (which it should, haven't hashed out where to add the initial value), and after that initial check it will take ANY other value between 1-9, including repeats, which is bad. Help please? Why does it stop recognizing values inside the test vector after the initial round?
Separate link to code if it's maybe easier to read there: http://ideone.com/Dzh4mJ
#include<iostream> // This is the beginning of a "LoShu magic square" program for class, currently my
#include <vector> // goal is simply getting vectors to check whether or not a number has already been
using namespace std; // entered, and if so to go back and ask for another one. As-is it does not work
// through the first iteration. It recognizes the first number, says it's already in
bool theCheckening(vector<int>, int ); // and proceeds to take ANY numbers afterwards, repeats and all.
int main () {
int tester;
vector<int> loShu1; // Rows 1-3 of a "square"
vector<int> loShu2;
vector<int> loShu3;
vector<int> testCaseOut(1,0); // Test vector to iterate inside check function
do {
do{
cout << "Enter 1-9: "; // Working as intended, makes sure no number besides 1-9 is entered
cin >> tester;
} while (tester < 1 || tester > 9);
// Put initial value into test Vector
if (theCheckening(testCaseOut, tester)){ // If check function returns true, add value to row 1
loShu1.push_back(tester);
testCaseOut.push_back(tester);
cout << "It worked?!";
}
} while (loShu1.size() <= 2); // shooting for size of 3, working as intended
for (int var : loShu1) // Debug to see rows before maths and adding them (to come)
cout << var << " ";
cout << "\n";
for (int var : loShu2)
cout << var << " ";
cout << "\n";
for (int var : loShu3)
cout << var << " ";
return 0;
}
bool theCheckening(vector<int> testCaseInc, int testInt) {
int count;
vector<int> testCase(testCaseInc); // Initialize vector inside check function to current test numbers
for (int var : testCase)
cout << var << " ";
for (count = 0;count<=testCase.size();count++) { // for all the numbers inside the testing vector
if (testCase[count]!=testInt){ // if current position of test vector is ! in vector already,
cout << "ADDED!"; // add it to row back in main()
return true;
for (int var : testCase)
cout << var << " ";
}
cout << "ALREADY ENTERED!"; // Debug
cout << testCase.size();
return false; // otherwise, ignore and ask for another number
}
}
i think you have a logical error in your theCheckening function.
As far as i understand you want your function to return TRUE if the value is NOT in in the vector and FALSE if it IS in your vector.
Now to the problem:
Imagine someone has tipped in the following values to your code:
1 2 5 8
This values will be added to your vector and the vector will also contain:
1 2 5 8
Now let's say you tipp one more time the 2. Your Function will now start with value 1 of the vector and compare it to the 2. This is of course FALSE.
Look at your code:
if (testCase[count]!=testInt)
return true;
Your code says you can now return true. Which will cause your function to end and return true to the caller.
You didn't check the following values of the vector.
Your function theCheckening should look like this:
// user const vector<int> &, which will not cause to copy the
// vector
bool theCheckening(const vector<int> & testCase, int testInt) {
// use size_t which represents a integer datatype which
// is as big as arrays can be in the current bit setting
// 32 bit => size_t = unsigned int
// 64 bit => size_t = unsigned long long
for(size_t count = 0; count <= testCase.size(); count++) {
if(testCase[i] == testInt)
return false;
}
return true;
}
I hope this works and i understood this qestion correctly.

How to pushback a vector of 3 elements into a vector in C++?

I have a long vector of values, a specified user input of row/column size. I need to assign a set of 3 numbers into a vector, from the long list of vectors. The vector with 3 number set will be pushed back into another vector, with user input row/column size. 1 column = the 3 number vector set and so on, until every column is filled out. I have trouble making this code (it needs to be in a loop). Any help please?
The picture is an example of a 4x4 vector, with each column a vector of 3 numbers
It sounds as if you want nested vectors, where each smaller vector inside your "long vector" represents a column of 3 values. If so you could do so like:
std::vector<int> columnVec = { 1, 2, 3 };
std::vector<std::vector<int>> longVector;
longVector.push_back(columnVec);
In the first line we declare a vector representing our column and place three integers inside it. On line two we declare another vector, but this time containing vectors which themselves contain ints, i.e. a vector full of column vectors. We then used push_back() to push the column vector into our vector of vectors. If you needed to print the values you could do so like:
for(auto& vec : longVector) { //Walk through our vector of vectors.
for(int value : vec) { //Walk through our column vectors of values.
std::cout << value; //Print out each value of the column.
}
std::cout << std::endl; //Add a newline.
}
Note that if you print them, the columns will appear as rows in the console. If you care about the formatting in the console it will take a bit more effort and might be worth asking as a separate question.
One possible approach might look something like this:
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
int main()
{
typedef std::vector<int> VecInt;
typedef VecInt::iterator VecIntIter;
typedef std::vector<VecInt> VecVecInt;
typedef VecVecInt::iterator VecVecIntIter;
VecVecInt rows;
const int maxRows = 10, maxCols = 10;
cout << "Values during creation" << endl;
cout << "----------------------" << endl;
for (int rowNum=0; rowNum<maxRows; rowNum++)
{
VecInt curRow;
for (int colNum=0; colNum<maxCols; colNum++)
{
if (colNum != 0)
cout << " ";
int cellValue = rand() % 32;
cout << cellValue;
curRow.push_back( cellValue );
}
cout << endl;
rows.push_back(curRow);
}
cout << endl;
cout << "Values during retrieval" << endl;
cout << "----------------------" << endl;
for (VecVecIntIter rowIter=rows.begin(); rowIter!=rows.end(); rowIter++)
{
VecInt curRow = (*rowIter);
for (VecIntIter colIter=curRow.begin(); colIter!=curRow.end(); colIter++)
{
if (colIter != curRow.begin())
cout << " ";
cout << (*colIter);
}
cout << endl;
}
}
Though, this will store a collection of rows, rather than a collection of columns. Easy enough to change the for loops.

(C++)1 dimensional battleship game help? advice for improvement

Unfortunately I do not have the Instructor to aid me with this assignment over the weekend and I am stuck. I'm just learning C++ and I've taken a Logic and Design class for Programming but like I said I'm very new to C++. I'm having a hard time catching up to the rest of the students.
I'd like if someone could list improvements and maybe clarify if I've done anything wrong in comparison to the assignment statement. I do really appreciate the help!
My code is repetitive and I'm sure I could go another way into displaying the array values without all that code. An error also pops up after use of the application that says:
"Run-Time Check Failure #2 - Stack around the variable 'enemy' was corrupted.
If there is a handler for this exception, the program may be safely continued."
The assignment is:
"Create a Battleship struct containing 5 one-dimensional integer coordinates representing its location within a region (of any size). Instantiate 2 copies of the struct and have the user enter a single coordinate for each Battleship. Design your code to take this single coordinate and use it to populate the remaining 4 coordinates for each ship. Do this for both ship structs. Then, have your code calculate the numeric distance between the 2 ships based on their respective coordinates. Finally, display the resulting distance to the user with an English language sentence."
My code as for right now is :
#include <iostream>
#include <string>
using namespace std;
struct Ship
{
int x[5];
int y[5];
};
int main()
{
Ship good;
Ship enemy;
good.x[0] = 0;
enemy.y[0] = 0;
cout << "Enter a coordinate (out of 100) for good ship: "<< endl;
cin >> good.x[0];
good.x[1] = good.x[0] + 1;
good.x[2] = good.x[1] + 1;
good.x[3] = good.x[2] + 1;
good.x[4] = good.x[3] + 1;
cout << "Good ship coordinates:" << endl;
cout << good.x[0]<< "*" << endl;
cout << good.x[1]<< endl;
cout << good.x[2]<< endl;
cout << good.x[3]<< endl;
cout << good.x[4]<< endl;
cout << "Enter a coordinate (out of 100) for enemy ship: "<< endl;
cin >> enemy.y[0];
enemy.y[1] = enemy.y[0] + 1;
enemy.y[2] = enemy.y[1] + 1;
enemy.y[3] = enemy.y[2] + 1;
enemy.y[4] = enemy.y[3] + 1;
cout << "enemy ship coordinates:" << endl;
cout << enemy.y[0]<< "*" << endl;
cout << enemy.y[1]<< endl;
cout << enemy.y[2]<< endl;
cout << enemy.y[3]<< endl;
cout << enemy.y[4]<< endl;
int distance=0;
distance = good.x[1] - enemy.y[1];
cout << "The distance between good ship and enemy ship is: " << distance << endl;
system("pause");
return 0;
}
The error probably comes from having only 4 coordinates in each struct, not 5. When you declare an array with int x[4];, it will only have 4 elements, namely x[0] to x[3].
There are a number of other problems:
You do not need two structs for two ships. Use just one. That's the whole point of structs/classes: to represents classes of objects. Use only one struct (named e.g. Ship) and declare both your ships good and enemy to have that type.
Don't be afraid of both the enemy ship and the good ship having x coordinates. The compiler and the computer won't get confused at that, and neither should you.
Learn to use loops. Even if you get confused at first, remember that loops are one of the most (if not the most) important tools at a programmers disposal. Think what would happen if you had 100 ships, each with 100 coordinates...
Remember, again, that the first element of an array is at index 0, not index 1. (And the last element is at index N-1.)
Calculating the distance is a little more complex than you've written. Can the distance between two objects ever be negative? What happens if the enemy ship's coordinate is greater than the friendly ship? What's the actual formula for one-dimensional distances?
Remove unused code. What's the use of that region variable? Have you used it anywhere?
UPDATE: (For anyone reading in the future, remember that OP has updated and modified their question and code, to the point that some of my point would not apply or would apply differently.)
Do you REALLY need both xs and ys in Ship?
Not sure if the use of system("PAUSE") is something your instructor taught, but that's definitely something you could improve on, too. Explained here
So starting with
Create a Battleship struct containing 5 one-dimensional integer coordinates representing its location within a region (of any size). Instantiate 2 copies of the struct and have the user enter a single coordinate for each Battleship
You need a single struct:
struct Ship
{
int x[5];
};
Now make 2 copies
int main()
{
Ship good;
Ship bad;
...
Then the rest looks good, it compiles and runs without any issues on my computer. You can add a function to populate the ship to reduce the number of code
Ship createShip(int startPos) {
Ship newShip;
newShip[0] = startPos;
// ... <- rest of your code that you have to populate
return newShip;
}
int main()
{
int pos;
cout << "Enter a coordinate (out of 100) for good ship: "<< endl;
cin >> pos;
Ship good = createShip(pos);
//...
//... <- Get pos of bad ship
Ship bad = createShip(pos);
}
Then you can also create a simular function that prints the location of the ship

My array takes random values despite user input

Excuse me again, I'm not any genius in Programming.
First of all, a summary: array input. Two 3D vectors...ha ha, let's use vectors to calculate MORE vectors. Anyway: dot product is just and plain ridiculous (nine numerals before decimals; I mean, seriously, I didn't ever thought that 1x8+7x5+4x2 could have NINE numerals). Cross product is...even worse.
I made the...uhm...how could I call it? Well, we call it "traza". I'll translate a definition ir order to get understood: a code's "traza" tell us the sequence of instructions of its execution, and how do the variables change after every line of code. You know, the table with variables and number marks referred to code lines where we look if the code is doing something unexpected. Getting to the point: it's everything fine as far as I could see.
Then, I made an unexpectedly "pseudotraza" with a print command and every value from the vectors. Just after input and just before te dot product (in a function). Guess what:
1) it's not my input, in either of them
2) they are not even the same values
3) first values are far away from my input, but the following ones at least were more logic (less difference to the input).
I learned this morning, 12 hours ago, to use arrays/vectors/whatever. I didn't ever have any need to set as 0 as default any value before its input. But it's the only thing I have known to do when things like this happened to me before.
(Someday any of you will be my Programming teacher, you are learning me more than himself...and excuse my awful grammar, English teaching in Spain is just "take some grammar rules and no more than 50 exercises in last High School year...it's all you need to pass the University Entrance Exam!")
#include <iostream>
using namespace std;
#include <stdlib.h>
const int N = 3;
typedef int Vector[N];
void introduirVector (Vector);
float producteEscalar (const Vector, const Vector); /*Input vector and dot product*/
int main (void)
{
Vector v1, v2;
float p_esc;
cout << "Introduim les dades del vector A: "; /* Input */
introduirVector (v1);
cout << "Introduim les dades del vector B: "; /* 2x Input combo */
introduirVector (v2);
cout << v1[0] << "\n" << v1[1] << "\n" << v1[2] << "\n" << v2[0] << "\n" << v2[1] << "\n" << v2[2] << endl; /* "Puseudotraza*/
p_esc= producteEscalar (v1, v2); /*Dot product*/
cout << "El producte escalar: " << p_esc; /*Dot product is...*/
system ("PAUSE");
return 0;
}
/*3x Input combo*/
void introduirVector (Vector)
{
int i;
Vector v;
for (i = 0; i < N; i++)
{
cin >> v[i];
}
return;
}
/* Dot product (why all the Vectors are set as constants but another after this is not set? It's the hint given by the teacher, my (not) beloved teacher...they gave us the main function and the other function's prototypes, but that's all) */
float producteEscalar (const Vector, const Vector)
{
float escalar;
Vector v1, v2;
/* Pseudotrazas for all*/
cout << v1[0] << "\n" << v1[1] << "\n" << v1[2] << "\n" << v2[0] << "\n" << v2[1] << "\n" << v2[2] << endl;
/* Dot product and all that */
escalar = (v1[0]*v2[0])+(v1[1]*v2[1])+(v1[2]*v2[2]);
return escalar;
}
The problem is this:
/*3x Input combo*/
void introduirVector (Vector)
{
int i;
Vector v;
This function takes a Vector as a parameter, but the Vector has no name so it cannot be used inside the function.
Then you declare a new, local Vector v. You read your user's input into this vector.
The function then ends, at which point the vector into which you read user input goes away.
Firstly, you should be using the parameter you were called with, not a local variable. But your second problem is that you are using pass by value. When you call this function, introduirVector (v1); it is not the "v1" you know and love from main that you are working with inside introduirVector, but a local copy of it that ceases to exist when your function returns.
What you need to do is make your function accept a pointer or a reference to the Vector it is being called with:
void introduirVector(Vector& v)
{
for (size_t i = 0; i < 3; ++i) {
cin >> v[i];
}
}
This does not fully solve all of the problems with your code, but it should get you moving forward.
I'm not seeing any input, which would be why you are not receiving any input.
Try using:
string inpt;
int a, b, c;
cin >> inpt;
a = atoi( inpt.c_str());
inpt = "";
cin >> inpt;
b = atoi( inpt.c_str());
// etc...
// Make your vector in this fashion, grabbing each integer separately then loading them
// into a vector