I had an assignment to replicate mancala. The rules of the game are slightly different from original, and are the following:
The active player removes all stones from a pit on their side of the board and distributes them counter-clockwise around the board.
Distribution includes the player's goal, but not the opponent's goal.
If distribution ends in the player's goal, they take another turn.
If distribution ends on the player's side, in a previously empty pit, the last stone and any stones immediately across the board are moved to active player's goal (and their turn ends).
If a player's side of the board is empty (not including their goal), any remaining stones are collected by the opponent and the game is over.
I failed the assignment a while back and I'm still trying to figure out why I'm wrong. The program has correct output but my school requires us to use a programming tool called valgrind and that's where the issue comes from.
Why would valgrind give me this error
==5098== Conditional jump or move depends on uninitialised value(s)
==5098== at 0x49ACB33: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (locale_facets.tcc:892)
==5098== by 0x49BC4FC: put (locale_facets.h:2395)
==5098== by 0x49BC4FC: std::ostream& std::ostream::_M_insert<long>(long) (ostream.tcc:73)
==5098== by 0x10948C: Mancala::getBoard[abi:cxx11]() (in /home/oddstap/Documents/2.C /Projects/malacala/Newest mancala/new/mancala)
==5098== by 0x1092B7: main (in /home/oddstap/Documents/2.C /Projects/malacala/Newest mancala/new/mancala)
==5098==
==5098== Use of uninitialised value of size 8
==5098== at 0x49AB01B: int std::__int_to_char<char, unsigned long>(char*, unsigned long, char const*, std::_Ios_Fmtflags, bool) (locale_facets.tcc:821)
==5098== by 0x49ACB5E: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (locale_facets.tcc:894)
==5098== by 0x49BC4FC: put (locale_facets.h:2395)
==5098== by 0x49BC4FC: std::ostream& std::ostream::_M_insert<long>(long) (ostream.tcc:73)
==5098== by 0x10948C: Mancala::getBoard[abi:cxx11]() (in /home/oddstap/Documents/2.C /Projects/malacala/Newest mancala/new/mancala)
==5098== by 0x1092B7: main (in /home/oddstap/Documents/2.C /Projects/malacala/Newest mancala/new/mancala)
==5098==
==5098== Conditional jump or move depends on uninitialised value(s)
==5098== at 0x49AB02D: int std::__int_to_char<char, unsigned long>(char*, unsigned long, char const*, std::_Ios_Fmtflags, bool) (locale_facets.tcc:824)
==5098== by 0x49ACB5E: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (locale_facets.tcc:894)
==5098== by 0x49BC4FC: put (locale_facets.h:2395)
==5098== by 0x49BC4FC: std::ostream& std::ostream::_M_insert<long>(long) (ostream.tcc:73)
==5098== by 0x10948C: Mancala::getBoard[abi:cxx11]() (in /home/oddstap/Documents/2.C /Projects/malacala/Newest mancala/new/mancala)
==5098== by 0x1092B7: main (in /home/oddstap/Documents/2.C /Projects/malacala/Newest mancala/new/mancala)
==5098==
==5098== Conditional jump or move depends on uninitialised value(s)
==5098== at 0x49ACB94: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (locale_facets.tcc:914)
==5098== by 0x49BC4FC: put (locale_facets.h:2395)
==5098== by 0x49BC4FC: std::ostream& std::ostream::_M_insert<long>(long) (ostream.tcc:73)
==5098== by 0x10948C: Mancala::getBoard[abi:cxx11]() (in /home/oddstap/Documents/2.C /Projects/malacala/Newest mancala/new/mancala)
==5098== by 0x1092B7: main (in /home/oddstap/Documents/2.C /Projects/malacala/Newest mancala/new/mancala)
==5098==
mancala.h
#include <iostream>
#include <sstream>
class Mancala
{
int gameBoard[14];
int playerS;
int getGoal(int p);
public:
Mancala();
std::string getBoard();
int getPlayer();
int getScore(int player);
bool move(int n);
};
mancala.cpp
#include <ios>
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
#include "mancala.h"
Mancala::Mancala()
{
playerS = 0;
for (int i{0}; i < 14; i) //set up the intial board
{
if (i == 6 || i == 13)
{
gameBoard[i] = 0;
}
else
{
gameBoard[i] = 4;
}
}
}
std::string Mancala::getBoard() //return the gameboard in the correct mancala format
{
std::stringstream ss;
ss << std::setw(2) << std::right << gameBoard[13];
ss << " |";
for (int i{0}; i < 6; i)
{
ss << std::setw(3) << std::right << gameBoard[12 - i];
}
ss << " |";
if (playerS == 0)
{
ss << " *\n - |";
}
else if (playerS == 1)
{
ss << " -\n * |";
}
else
{
ss << " -\n - |";
}
for (int j{0}; j < 6; j)
{
ss << std::setw(3) << std::right << gameBoard[j];
}
ss << " |" << std::setw(3) << std::right << gameBoard[6] << "\n";
return ss.str();
}
int Mancala::getPlayer()
{
return playerS;
}
int Mancala::getScore(int player)
{
return gameBoard[getGoal(player)];
}
int Mancala::getGoal(int p)
{
if (p == 0)
{
return 6;
}
else
{
return 13;
}
}
bool Mancala::move(int n)
{
int pos = getGoal(playerS) - n;
int current = gameBoard[pos];
gameBoard[pos] = 0;
if (current == 0) //this isn't an allowed move
{
return false;
}
for (int i{0}; i < current; i)
{
pos = (pos 1) % 14;
if (playerS == 1 && pos == 6) //skips other goal
{
pos;
}
gameBoard[pos];
}
int mirror{gameBoard[12 - pos]};
if (gameBoard[pos] == 1 && playerS == 0 && pos < 6)
{
gameBoard[pos] = 0;
gameBoard[6] = (mirror 1);
gameBoard[12 - pos] = 0;
playerS = 1 - playerS;
}
if (gameBoard[pos] == 1 && playerS == 1 && pos > 6) //tests for player 1
{
gameBoard[pos] = 0;
gameBoard[13] = (1 mirror);
gameBoard[12 - pos] = 0;
playerS = 1 - playerS;
}
if (pos != getGoal(playerS))
{
playerS = 1 - playerS; //change turns
}
int count{};
int count1{};
for (int k{0}; k < 6; k) //lines 123-159 test each side of board for a 0. If whole side is 0, other player wins and collects all marbles on their side
{
if (gameBoard[k] == 0)
{
count;
} else{
count = 0;
}
}
for (int l{0}; l < 6; l)
{
if (gameBoard[12 - l] == 0)
{
count;
} else{
count1 = 0;
}
}
if (count >= 6)
{
playerS = -1;
for (int m{0}; m < 6; m)
{
gameBoard[13] = gameBoard[12 - m];
gameBoard[12 - m] = 0;
}
} else if (count1 >= 6){
playerS = -1;
for (int z{0}; z < 6; z)
{
gameBoard[6] = gameBoard[z];
gameBoard[z] = 0;
}
}
return true;
}
main.cpp
#include <ios>
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
#include "mancala.h"
int main()
{
Mancala m;
int moves[] = { 4,1,5,3,2 };
for (int i:moves){
m.move(i);
std::cout << m.getBoard() << "\n";
}
}
CodePudding user response:
I had difficulty myself to find the issue.
The main difficulty was that valgrind effectively found a problem at this line :
ss << std::setw(2) << std::right << gameBoard[13];
but this was not the real place where the mistake happens.
It does not happen often (but it happens !), but valgrind missed an out-of-bound access before, in move(.)
function:
int mirror{gameBoard[12 - pos]};
when pos == 13
.
When valgrind misses to find the place where the error occurs, I generally find difficult (and slow) to use the debugger.
Instead, I found more rapidly the problem by inserting some outputs inside the code.
The problem seems to be solved with:
int mirror = 0;
if (pos <= 12) mirror = gameBoard[12 - pos];