The int winner should be set to 2 under certain conditions but it's somehow being set to a variety of higher values, most commonly 6. I have no idea how this is happening, as there is no other function in my class that affects winner, and the variable isn't even mentioned anywhere else in the program. What is most confusing to me is that I have an almost identical function (P2Move()) that is literally identical in how it sets the winner variable to P1Move(), and that function runs perfectly.
Some info: The class this is part of is called Board, which acts as a checkerboard array made up of Square class objects.
Below is the function causing the problem. Near the bottom, the statement else if((canTake.size()==0)&&(canMove.size()==0)) {Board::winner = 2;} causes the problem. Everything else seems to work when I remove the problematic part from the function, but I need that part to work in order to submit the final project.
void Board::P1Move()
{
P1pieces = 0;
std::vector <Move> canMove;
std::vector <Move> canTake;
for(int j = 0; j < bSize; j++)
{ //Start of j loop.
for(int i = 0; i < bSize; i++)
{ //Start of i loop.
Square sq = board[i][j];
bool cTakeL = canTakeL(i,j);
bool cTakeR = canTakeR(i,j);
bool cMoveL = canMoveL(i,j);
bool cMoveR = canMoveR(i,j);
if(board[i][j].getPl() == P1)
{
P1pieces++;
if(cTakeL)
{
Move a = Move(sq.getIndex(),board[i-2][j+2].getIndex(),board[i-1][j+1].getIndex(),0);
canTake.push_back(a);
}
if(cTakeR)
{
Move b = Move(sq.getIndex(),board[i+2][j+2].getIndex(),board[i+1][j+1].getIndex(),0);
canTake.push_back(b);
}
if(cMoveL)
{
Move c = Move(sq.getIndex(),board[i-1][j+1].getIndex(),0,0);
canMove.push_back(c);
}
if(cMoveR)
{
Move d = Move(sq.getIndex(),board[i+1][j+1].getIndex(),0,0);
setWinner(d.getSpos());
canMove.push_back(d);
}
}
} //End of i loop.
} //End of j loop.
if(canTake.size()!=0)
{
time_t t;
time(&t);
srand(t);
int moveNum = rand()%canTake.size();
std::string output = "p1 ";
Move out = canTake.at(moveNum);
int i = 0;
int j = 0;
for(int y = 0; y < bSize; y++)
{
for(int x = 0; x < bSize; x++)
{
if(board[x][y].getIndex()==out.getSpos())
{
i = x;
j = y;
}
}
}
if(board[i-2][j+2].getIndex()==out.getEndPos())
{
board[i-2][j+2].setOcc(true);
board[i-2][j+2].setPl(P1);
board[i-1][j+1].setOcc(false);
board[i-1][j+1].setPl(NA);
}
else if(board[i+2][j+2].getIndex()==out.getEndPos())
{
board[i+2][j+2].setOcc(true);
board[i+2][j+2].setPl(P1);
board[i+1][j+1].setOcc(false);
board[i+1][j+1].setPl(NA);
}
output = output + out.toString();
setCmove(output);
board[i][j].setOcc(false);
board[i][j].setPl(NA);
}
else if(canMove.size()!=0)
{
time_t t;
time(&t);
srand(t);
int moveNum = rand()%canMove.size();
std::string output = "p1 ";
Move out = canMove.at(moveNum);
int i = 0;
int j = 0;
for(int y = 0; y < bSize; y++)
{
for(int x = 0; x < bSize; x++)
{
if(board[x][y].getIndex()==out.getSpos())
{
i = x;
j = y;
}
}
}
if(board[i-1][j+1].getIndex()==out.getEndPos())
{
board[i-1][j+1].setOcc(true);
board[i-1][j+1].setPl(P1);
}
else if(board[i+1][j+1].getIndex()==out.getEndPos())
{
board[i+1][j+1].setOcc(true);
board[i+1][j+1].setPl(P1);
}
output = output + out.toString();
setCmove(output);
board[i][j].setOcc(false);
board[i][j].setPl(NA);
}
else if((canTake.size()==0)&&(canMove.size()==0))
{
Board::winner = 2;
}
P1pieces = canTake.size() + canMove.size();
}
You are working with std::vector, which is a good thing. (Too much beginner "C++" code uses C arrays.) The vector class template allows for a pretty easy way to find out if and where you might have an out-of-bounds access (as suggested in the comments):
Instead of accessing vector elements using operator[], change your code to use the .at() member function. .at() is bounds-checking, and will throw an exception if you access out-of-bounds (instead of silently breaking your program).
In production code, operator[] is usually preferred as omitting the bounds check is more efficient. But while learning, .at() can help you quite a bit.
Also, getting in the habit of using code checkers like valgrind or the assert macro to check your assumptions is a good thing, even when you got past the point where you wouldn't use .at() anymore.
Related
I was trying this problem on leetcode,
https://leetcode.com/problems/naming-a-company/description/ .
I've observed the following
My Code :
long long distinctNames(vector<string>& ideas) {
unordered_map<string,bool> isPresent;
vector<vector<long long>> dp(26,vector<long long>(26,0));
int n = ideas.size();
long long ans = 0;
for(int i = 0; i < n; i++)
isPresent[ideas[i]] = true;
for(int i = 0; i < n; i++)
{
char x = ideas[i][0];
string ts = ideas[i];
for(int j = 0; j < 26; j++)
{
char y = 'a' + j;
ts[0] = y;
if(!isPresent[ts])
dp[x-'a'][j]++;
}
}
for(int i = 0; i < 26; i++)
{
for(int j = 0; j < 26; j++)
{
if(i==j) continue;
ans += (dp[i][j] * dp[j][i]);
}
}
return ans;
}
This code was getting TLE (85/89).
But, in the same code, if I replace
!isPresent[ts]
with
!isPresent.count(ts)
Same code runs much faster and passes.
Anyone can explain why ?
isPresent[ts] returns a reference to a map value object (so you can write isPresent[ts] = something. So if ts is not present in the map, then isPresent[ts] must default construct a map entry so that it has something to return a reference to. This is the reason that map::operator[] is not const.
isPresent.count(ts) has no such problems. If the ts key is not present then the map is unchanged.
operator[] on std::unordered_map inserts a default constructed element if none is yet present (which is also why the operator doesn't work on a const object.) Insertion potentially requires allocating memory or other somewhat slow things. Calling count does not, nor would e.g. find.
I wrote this knapsack problem solution in c++ however when I run it, it gives me segmentation fault
I have tried everything and my compiler will always give me the segmentation fault error.
#include<iostream>
#include<algorithm>
int knapsack(int v[],int w[],int n,int W)
{
int V[n][W];
for(int i = 0; i<=W;i++)
{
V[0][i] = 0;
}
for(int i = 0; i <= n; i++){
for(int j = 1; j<=W; j++)
{
if(w[i]<=W)
{
V[i][j] = std::max(V[i-1][j], v[i]+V[i-1][j-w[i]]);
}
else
{
V[i][j] = V[i-1][j];
}
}
}
return V[n][W];
}
int main()
{
int v[4] = {10,40,30,50};
int w[4] = {5,4,6,3};
int n = 3;
int W = 10;
std::cout<<"item value:"<<knapsack(v,w,n,W);
}
Don't use VLAs. The size of an array must be known at compile time, else it's not standard C++. Those are compiler extensions that are not portable and introduce some hidden costs.
Array indices go from 0 to length-1. in you loop
for(int i = 0; i<=W;i++)
i can reach W, then V[0][W] is out of bounds which causes the seg fault. You have to use < instead of <=:
for(int i = 0; i < W; i++)
n should probably be 4, if it's meant to represent the size of the array, a std::vector would make your life easier here, because a vector knows it's size
In general don't use C-style arrays or raw pointers at all in this day and age, use std::vector instead.
int V[n][W];
for(int i = 0; i<=W;i++)
{
V[0][i] = 0;
}
Note that V's indexes go from V[0][0] to V[0][W-1]. Your for loop will try to read V[0][W].
The same error is repeated in other places. Your end condition in your for loops should be < (strictly less) instead of <= (less or equal than).
I'm trying to "erase" an element from a vector that is itself contained in another vector. However, either I forgot how to do this, I missed the point, or there's a huge oversight. It always erases the very first element in the vector, whatever I try.
void release_docking() {
int loop_R = (int)parent_cell->cells.size();
for (int i = 0; i < loop_R; i++) {
int loop_C = (int)parent_cell->cells[i].size();
for (int j = 0; j < loop_C; j++) {
if (parent_cell->cells[i][j] = this) {
parent_cell->cells[i].erase(parent_cell->cells[i].begin() + j);
if (parent_cell->cells[i].empty()) {
parent_cell->cells.erase(parent_cell->cells.begin() + i);
}
parent_cell = nullptr;
is.docked = false;
resize_cells(root_cell);
break;
}
}
}
}
This line
if (parent_cell->cells[i][j] = this) {
will assign this to parent_cell->cells[i][j] and evaluate to true.
After that it will be erased.
That should be == not =.
Recent compilers should warn you about this. Make sure that warnings are turned on.
C++ rookie here.
I have the following code:
std::vector<float> MyBuffer::readAverage(int numberOfBuffers) {
std::vector<float> result = std::vector<float>(streams.size());
for (int i = 0; i < streams.size(); ++i) {
result[i] = getAverage(streams[i], numberOfBuffers);
}
return result;
}
float MyBuffer::getAverage(std::deque<float> input, int numberOfBuffers) {
float sum = 0;
for (int i = 0; i < numberOfBuffers; ++i) {
sum += input[i];
}
return sum / numberOfBuffers;
}
This code randomly crashes at getAverage(), I am not sure why.
Strange thing (for me as a C++ rookie at least) is that when I inline the function, it does not crash:
std::vector<float> MyBuffer::readAverage(int numberOfBuffers) {
std::vector<float> result = std::vector<float>(streams.size());
for (int i = 0; i < streams.size(); ++i) {
float sum = 0;
for (int i1 = 0; i1 < numberOfBuffers; ++i1) {
sum += streams[i][i1];
}
result[i] = sum / numberOfBuffers;
}
return result;
}
I can understand that there may be many reasons why this specific code is crashing - so my question relates more to what changes when I inline it, rather than calling a function? In my mind it should be exactly the same thing, but I guess there is something about the way C++ works that I am not grasping?
The program has many potential reasons why it can cause a crash.
bufferDurationMs is not initialized in the provided code, I hope its initialized to value other than 0.
for (int i = 0; i < streams.size(); ++i) {
result[i] = getAverage(streams[i], numberOfBuffers); } use result.size() instead of streams.size() as result is lvalue. It
is better to check both of these conditions in for.
It is quite possible that numberOfBuffers can be 0 in which case code would crash(divide by zero)
Some optimizations that can be done in the code:
std::vector<float> result = std::vector<float>(streams.size()); use reserve rather than using a costly operation of creating a
vector and assigning it to lvalue.
std::vector result; result.reserve(streams.size());
float MyBuffer::getAverage(std::deque<float> input, int numberOfBuffers) prefer const reference rather than creating a copy
of an object
const std::deque& input
I have a probably very simple question but I can't see the solution.
First, I have a struct named Seed with the following code:
struct Seed
{
int x, y;
int i, j;
int Type;
};
I then create a 2D array and a queue, respectively, like so:
Seed Grid[ROW][COL];
std::queue<Seed> SeedsToUpdate;
I populate the grid with a loop:
void CApp::LoopSeeds(int function, int Type)
{
for(int i = 0;i < ROW;i++)
{
for(int j = 0;j < COL;j++)
{
switch (function)
{
case SET:
SetSeed(i, j, Type);
break;
case DRAW:
DrawSeed(i,j);
break;
case GROW:
GrowSeed(i,j,Type);
}
}
}
}
Then, I set individual seeds in the array to other types, such as GREEN. I then fill the queue by going through the array and filling it with all array elements that have the GREEN type:
void CApp::BuildQueue()
{
for(int i = 0;i < ROW;i++)
{
for(int j = 0;j < COL;j++)
{
if (Grid[i][j].Type != SEED_EMPTY)
{
SeedsToUpdate.push(Grid[i][j]);
}
}
}
}
At this point, everything is good (I think). However, what I want to do is the following: for each seed in the queue, edit the neighbouring cells in the array, something like Grid[i+1][j].Type = GREEN;
And here is my problem: how do I do that, given the above code?
Thanks for your patience.
In C++11
for(const Seed& seed: SeedsToUpdate){
if (seed.i + 1 < ROW){
Grid[seed.i+1][seed.j].type = seed.type
}
}
C++03 with Boost
BOOST_FOREACH(const Seed& seed, SeedsToUpdate){
if (seed.i + 1 < ROW){
Grid[seed.i+1][seed.j].type = seed.type
}
}
In C++03 (without Boost)
for(std::queue<Seed>::const_iter it = SeedsToUpdate.begin(); it != SeedsToUpdate.end(); ++it) {
const Seed& seed = *it;
if (seed.i + 1 < ROW){
Grid[seed.i+1][seed.j].type = seed.type
}
}
Also you should be using std::array/boost::array instead of raw arrays.
its pretty straight forward actually. Inside your inner loop, do something line
if (i+1 < ROW) {
Grid[i+1][j].Type = GREEN;
SeedsToUpdate.push(Grid[i+1][j]);
}