My Neural Network is only learning some data sets - c++

I've created the following NN that should be learning based on back propagation.
I've peiced it together from a lot of reading and a bunch of different tutorials.
To test, I've tried giving it the XOR problem. Each data set is 2 inputs and 2 outputs. The two inputs are both either a 1 or 0, and the two outputs should indicate whether a 0 should be output (the first output) or a 1 should be output (the second output).
What's happening when I give it the following data:
___________________________________________________________________________
| Input 1 | Input 2 | Expected 1 | Expected 2 | NN Output 1 | NN Output 2 |
|-------------------------------------------------------------------------|
| 0 | 1 | 1 | 0 | 0.49 | 0.50 |
| 1 | 0 | 1 | 0 | 0.98 | 0.01 |
| 1 | 1 | 0 | 1 | 0.01 | 0.98 |
| 0 | 0 | 0 | 1 | 0.49 | 0.50 |
---------------------------------------------------------------------------
What is hopefully clear in the above is that for two of the problems given it; it's sort of worked, assuming there's a margin of error, getting within 0.01 of the answer is pretty good.
But for the other two answers, it's way off. Sure a step-function would result correctly, but it's basically saying there's a 50/50 split.
This is with 100,000 epochs and a learning rate of 0.03 and what you see above was the actual training data.
If I increase the learning rate to 0.9; the results are different but also make me question things:
___________________________________________________________________________
| Input 1 | Input 2 | Expected 1 | Expected 2 | NN Output 1 | NN Output 2 |
|-------------------------------------------------------------------------|
| 0 | 1 | 1 | 0 | 0.99 | 0.00 |
| 1 | 0 | 1 | 0 | 0.99 | 0.00 |
| 1 | 1 | 0 | 1 | 0.49 | 0.99 |
| 0 | 0 | 0 | 1 | 0.00 | 0.99 |
---------------------------------------------------------------------------
Much better; but there's still the weird output for the 1,1 input.
My code is fairly short, here below. It's the complete code:
#include <iostream>
#include <array>
#include <random>
#include <vector>
class RandomGenerator
{
public:
RandomGenerator(const double min, const double max)
:
m_ran(),
m_twister(m_ran()),
m_distrib(min,max)
{
}
double operator()(void) { return m_distrib(m_twister); }
private:
std::random_device m_ran;
std::mt19937_64 m_twister;
std::uniform_real_distribution<double> m_distrib;
} randGen(-2,2);
double sigmoid(const double x)
{
return 1.0 / (1.0 + std::exp(-x));
}
double softplus(const double x)
{
return std::log(1.0 + std::exp(x));
}
double step(const double x)
{
return x > 0 ? 1 : 0;
}
template<int NumInputs, double(*ActivationFunction)(const double)>
class Neuron
{
public:
void SetInput(const std::size_t index, const double value)
{
m_inputsAndWeights[index].value = value;
}
double GetInput(const std::size_t index) const { return m_inputsAndWeights[index].value; }
void SetWeight(const std::size_t index, const double weight)
{
m_inputsAndWeights[index].weight = weight;
}
double GetWeight(const std::size_t index) const { return m_inputsAndWeights[index].weight; }
void SetBiasWeight(const double weight) { m_biasWeight = weight; }
double GetBiasWeight() const { return m_biasWeight; }
double GetOutput() const
{
double output = 0;
for(const auto& p : m_inputsAndWeights)
output += p.value * p.weight;
output += 1.0 * m_biasWeight;
return ActivationFunction(output);
}
private:
struct DataPair
{
double value;
double weight;
};
std::array<DataPair,NumInputs> m_inputsAndWeights;
double m_biasWeight;
};
template<std::size_t NumInputs, std::size_t NumOutputs>
class NeuralNetwork
{
public:
static constexpr NumHidden() { return (NumInputs+NumOutputs) / 2; }
SetInputs(std::array<double,NumInputs> inputData)
{
for(auto& i : m_hiddenNeurons)
{
for(auto index = 0; index < inputData.size(); ++index)
i.SetInput(index,inputData[index]);
}
}
std::array<double,NumOutputs> GetOutputs() const
{
std::array<double,NumOutputs> outputs;
for(auto i = 0; i < NumOutputs; ++i)
{
outputs[i] = m_outputNeurons[i].GetOutput();
}
return outputs;
}
void PassForward(std::array<double,NumInputs> inputData)
{
SetInputs(inputData);
for(auto i = 0; i < NumHidden(); ++i)
{
for(auto& o : m_outputNeurons)
{
o.SetInput(i,m_hiddenNeurons[i].GetOutput());
}
}
}
void Train(std::vector<std::array<double,NumInputs>> trainingData,
std::vector<std::array<double,NumOutputs>> targetData,
double learningRate, std::size_t numEpochs)
{
for(auto& h : m_hiddenNeurons)
{
for(auto i = 0; i < NumInputs; ++i)
h.SetWeight(i,randGen());
h.SetBiasWeight(randGen());
}
for(auto& o : m_outputNeurons)
{
for(auto h = 0; h < NumHidden(); ++h)
o.SetWeight(h,randGen());
o.SetBiasWeight(randGen());
}
for(std::size_t e = 0; e < numEpochs; ++e)
{
for(std::size_t dataIndex = 0; dataIndex < trainingData.size(); ++dataIndex)
{
PassForward(trainingData[dataIndex]);
std::array<double,NumHidden()+1> deltaHidden;
std::array<double,NumOutputs> deltaOutput;
for(auto i = 0; i < NumOutputs; ++i)
{
auto output = m_outputNeurons[i].GetOutput();
deltaOutput[i] = output * (1.0 - output) * (targetData[dataIndex][i] - output);
}
for(auto i = 0; i < NumHidden(); ++i)
{
double error = 0;
for(auto j = 0; j < NumOutputs; ++j)
{
error += m_outputNeurons[j].GetWeight(i) * deltaOutput[j];
}
auto output = m_hiddenNeurons[i].GetOutput();
deltaHidden[i] = output * (1.0 - output) * error;
}
for(auto i = 0; i < NumOutputs; ++i)
{
for(auto j = 0; j < NumHidden(); ++j)
{
auto currentWeight = m_outputNeurons[i].GetWeight(j);
m_outputNeurons[i].SetWeight(j,currentWeight + learningRate * deltaOutput[i] * m_hiddenNeurons[j].GetOutput());
}
auto currentWeight = m_outputNeurons[i].GetBiasWeight();
m_outputNeurons[i].SetBiasWeight(currentWeight + learningRate * deltaOutput[i] * (1.0*currentWeight));
}
for(auto i = 0; i < NumHidden(); ++i)
{
for(auto j = 0; j < NumInputs; ++j)
{
auto currentWeight = m_hiddenNeurons[i].GetWeight(j);
m_hiddenNeurons[i].SetWeight(j,currentWeight + learningRate * deltaHidden[i] * m_hiddenNeurons[i].GetInput(j));
}
auto currentWeight = m_hiddenNeurons[i].GetBiasWeight();
m_hiddenNeurons[i].SetBiasWeight(currentWeight + learningRate * deltaHidden[i] * (1.0*currentWeight));
}
}
}
}
private:
std::array<Neuron<NumInputs,sigmoid>,NumHidden()> m_hiddenNeurons;
std::array<Neuron<NumHidden(),sigmoid>,NumOutputs> m_outputNeurons;
};
int main()
{
NeuralNetwork<2,2> NN;
std::vector<std::array<double,2>> trainingData = {{{0,1},{1,0},{1,1},{0,0}}};
std::vector<std::array<double,2>> targetData = {{{1,0},{1,0},{0,1},{0,1}}};
NN.Train(trainingData,targetData,0.03,100000);
for(auto i = 0; i < trainingData.size(); ++i)
{
NN.PassForward(trainingData[i]);
auto outputs = NN.GetOutputs();
for(auto o = 0; o < outputs.size(); ++o)
{
std::cout << "Out " << o << ":\t" << outputs[o] << std::endl;
}
}
return 0;
}

I have done the same thing a few days ago, and I can tell you that 100 000 iterations for back propagation is not enough, if you hit some unfortunate weight initialization. Dont initialize you weights randomly, the sigmoid can easily fall into saturation for large weights, on the other hand 0 weights wont help either. I have initialized mine weights +/-(0.3, 0.7) and the convergence improved significantly.

Related

Connect 4: Drop function only works for two row

const int N = 200;
const string usr1 = "o", usr2 = "x";
void updateBoard(string a[N][N], int c, int n, string xo) {
int col = c - 1;
int row = n - 1;
for (int i = row; i >= 0; i--) {
if ((a[i][col] == usr1) || (a[i][col] == usr2)) {
a[i - 1][col] = xo;
}
if ((a[i][col] == " ")) {
a[i][col] = xo;
}
i = 0;
}
}
I don't know what's wrong, It stops at the second row, when i try to drop at third, it rewrites the value on the second...
This happens:
| x |
| x |
Want this:
| x |
| o |
| x |
I found the answer... Here's the fixed function:
bool updateBoard(string board[N][N], int col, int n, string xo) {
for (int i = n - 1; i >= 0; i--) {
if (board[i][col - 1] == "-") {
board[i][col - 1] = xo;
return true;
}
}
return false;
}

Print the shape of an X on screen

I want to print an X on screen like this:
* *
* *
* *
*
* *
* *
* *
I tried with this code:
int main(){
bool back = false;
for (int i = 0; i < 7; ++i) {
if (i == 4)
back = true;
if (!back){
for (int j = 0; j < i; ++j) {
cout << " ";
}
} else{
for (int j = 7-i-1; j > 0; --j) {
cout << " ";
}
}
cout << "*" << endl;
}
}
The result is missing the right half:
*
*
*
*
*
*
*
The problem is that I can't figure out how to print the spaces between the stars and the stars that follow them.
A more educational approach to solving this problem requires 2 loops.
The first for loop controls the height of the output, i.e. the number of lines printed. Each iteration prints a single line and ends it with a std::endl.
The second is a nested for loop, which controls the width and prints characters horizontally, i.e. it prints asterisk(s) and spaces for that line. Each iteration prints either a space or an asterisk.
This illustration might help to understand the values of the variables when x_size = 5:
(width)
0 1 2 3 4
(height) ---------------------
0 | * | | | | * | asterisk_pos = 0, end_pos = 4, inc = 1
---------------------
1 | | * | | * | | asterisk_pos = 1, end_pos = 3, inc = 1
---------------------
2 | | | * | | | asterisk_pos = 2, end_pos = 2, inc = 1
---------------------
3 | | * | | * | | asterisk_pos = 1, end_pos = 3, inc = -1
---------------------
4 | * | | | | * | asterisk_pos = 0, end_pos = 4, inc = -1
---------------------
Source code:
int main()
{
int x_size = 7; // size of the drawing
int asterisk_pos = 0; // initial position of the asterisk
int inc = 1; // amount of increment added to asterisk_pos after an entire line has been printed
// height is the line number
for (int height = 0; height < x_size; height++)
{
// width is the column position of the character that needs to be printed for a given line
for (int width = 0; width < x_size; width++)
{
int end_pos = (x_size - width) - 1; // the position of the 2nd asterisk on the line
if (asterisk_pos == width || asterisk_pos == end_pos)
cout << "*";
else
cout << " ";
}
// print a new line character
cout << std::endl;
/* when the middle of x_size is reached,
* it's time to decrease the position of the asterisk!
*/
asterisk_pos += inc;
if (asterisk_pos > (x_size/2)-1)
inc *= -1;
}
return 0;
}
Output with x_size = 7:
* *
* *
* *
*
* *
* *
* *
Output with x_size = 3:
* *
*
* *
Observe the sequence in each line. Look at the first part you have:
0 space, 1 *, 5 spaces, 1 *, 0 space
1 space, 1 *, 3 spaces, 1 *, 1 space
2 spaces, 1 *, 1 space, 1 *, 2 spaces
Then for line i: i spaces followed by 1 * followed by 5-2 i spaces, followed by 1 *, followed by i spaces
Then the following should work:
for (int line=0; line<3; line++) {
for (int n=0; n<line; n++) cout << ' ';
cout << '*';
for (int n=0; n<5-2*line; n++) cout << ' ';
cout << '*';
for (int n=0; n<line; n++) cout << ' ';
cout << endl;
}
The middle line 3 is obvious, and the following is the reverse of the first part.
Another way is to observe sequence of positions of *: (0,6) (1,5) (2,4) (3,3) (4,2) (5,1) (6,0), thus:
for (int line=0; line<7; line++) {
int pos1 = line;
int pos2 = 6-line;
for (int n=0; n<7; n++) {
if (n==pos1 || n==pos2) cout << '*';
else cout << ' ';
}
cout << endl;
}
You can then obviously remove pos1 and pos2...
spaces between in upper part are decreasing by 2 and start with line - 2
spaces between in down part are incensing by 2
here how I solve your problem
void printSpaces(int count)
{
for (int i = 0; i < count; ++i) {
cout << " ";
}
}
int main()
{
int lines = 7;
int spaceBefore = 0;
int spaceBetween = lines - 2;
bool backword = false;
for (int i = 0; i < lines; ++i)
{
printSpaces(spaceBefore);
cout << "*";
if (spaceBetween > 0)
{
printSpaces(spaceBetween);
cout << "*";
}
else
{
backword = true;
}
cout << "\n";
spaceBefore = backword ? spaceBefore-1 : spaceBefore+1;
spaceBetween = backword ? spaceBetween+2 : spaceBetween-2;
}
return 0;
}
The pattern consists of two equations: x = y and x + y = 4
Just loop through the axes and plot the points that fall on any of the lines.
( y )
0 1 2 3 4
( x ) ---------------------
0 | * | | | | * |
---------------------
1 | | * | | * | |
---------------------
2 | | | * | | |
---------------------
3 | | * | | * | |
---------------------
4 | * | | | | * |
---------------------
Two Equations
x = y
x + y = 4
#include <iostream>
int main() {
int num_lines = 7;
auto on_line1 = [](int x, int y) {
return x == y;
};
auto on_line2 = [num_lines](int x, int y) {
return (x + y) == (num_lines - 1);
};
for(int x = 0; x < num_lines; x++) { // Simple looping
for(int y = 0; y < num_lines; y++) { // through the axes
if(on_line1(x, y) or on_line2(x, y)) { // If on any of the line
std::cout << '*'; // Then plot it
} else {
std::cout << ' '; // Else leave it
}
}
std::cout << '\n';
}
return 0;
}
PS: I copied the ascii table from the other answer.
If you're not required to loop you can create a string and print it.
#include <iostream>
#include <string>
int main(int argc, char * argv[]){
std::string myX("* *\n * * \n * * \n * \n * * \n * * \n* *\n");
std::cout << myX;
return 0;
}

Gaussian Elimination: Inverse 4x4 Matrix

Question
The following will give me an identity matrix for the variable "cur", and will attempt to give me the inverse for the variable "tmp", but will fail. Can anyone tell me what I did wrong?
P.S. The matrix is column major.
Matrix Input
1 | 0 | 0 | 0
0 | -4.37114e-08 | 1 | 0
0 | -1 | -4.37114e-08 | 0
0 | 0 | 0 | 1
Matrix Output
1 | 0 | 0 | 0
0 | 0 | 0 | 0
0 | 1 | 0 | 0
0 | 0 | 0 | 1
Desired Output
1 | 0 | 0 | 0
0 | -4.3711399999999916e-8 | -0.9999999999999981 | 0
0 | 0.999999999999998 | -4.3711399999999916e-8 | 0
0 | 0 | 0 | 1
#include <iostream>
template <typename T>
class Matrix
{
public:
T matrix[4][4];
Matrix(T matrix[4][4])
: matrix()
{
for (unsigned int y = 0; y < 4; ++y)
{
for (unsigned int x = 0; x < 4; ++x)
{
this->matrix[y][x] = matrix[y][x];
}
}
}
Matrix()
: matrix()
{
T zero = static_cast<T>(0);
T one = static_cast<T>(1);
matrix[0][0] = one;
matrix[1][0] = zero;
matrix[2][0] = zero;
matrix[3][0] = zero;
matrix[0][1] = zero;
matrix[1][1] = one;
matrix[2][1] = zero;
matrix[3][1] = zero;
matrix[0][2] = zero;
matrix[1][2] = zero;
matrix[2][2] = one;
matrix[3][2] = zero;
matrix[0][3] = zero;
matrix[1][3] = zero;
matrix[2][3] = zero;
matrix[3][3] = one;
}
Matrix<T> GetInverse() const
{
T zero = static_cast<T>(0);
T one = static_cast<T>(1);
Matrix<T> tmp;
Matrix<T> cur;
for (unsigned int y = 0; y < 4; ++y)
{
for (unsigned int x = 0; x < 4; ++x)
{
cur.matrix[y][x] = matrix[y][x];
}
}
cur.Print();
for (unsigned int x = 0; x < 4; x++)
{
if (cur.matrix[x][x] != zero)
{
T denominator = cur.matrix[x][x];
for (unsigned int a = x; a < 4; ++a)
{
cur.matrix[x][a] = cur.matrix[x][a] / denominator;
}
for (unsigned int a = 0; a < 4; ++a)
{
tmp.matrix[x][a] = tmp.matrix[x][a] / denominator;
}
}
for (unsigned int y = 0; y < 4; ++y)
{
if (y != x && cur.matrix[y][x] != 0)
{
T difference = cur.matrix[y][x];
for (unsigned int a = x; a < 4; ++a)
{
cur.matrix[y][a] = (cur.matrix[y][a] - difference) * cur.matrix[x][a];
}
for (unsigned int a = 0; a < 4; ++a)
{
tmp.matrix[y][a] = (tmp.matrix[y][a] - difference) * tmp.matrix[x][a];
}
}
}
}
cur.Print();
tmp.Print();
return tmp;
}
void Print()
{
for (unsigned int y = 0; y < 4; ++y)
{
for (unsigned int x = 0; x < 4; ++x)
{
std::cout << matrix[y][x];
if (x < 3)
std::cout << " | ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
}
int main()
{
float matrix[4][4];
matrix[0][0] = 1.0f;
matrix[0][1] = 0.0f;
matrix[0][2] = 0.0f;
matrix[0][3] = 0.0f;
matrix[1][0] = 0.0f;
matrix[1][1] = -4.37114e-08;
matrix[1][2] = 1.0f;
matrix[1][3] = 0.0f;
matrix[2][0] = 0.0f;
matrix[2][1] = -1.0f;
matrix[2][2] = -4.37114e-08;
matrix[2][3] = 0.0f;
matrix[3][0] = 0.0f;
matrix[3][1] = 0.0f;
matrix[3][2] = 0.0f;
matrix[3][3] = 1.0f;
Matrix<float> inverseMatrix(matrix);
inverseMatrix.GetInverse();
return 0;
}
First of all, your class is not a proper class. Before you go trying to figure out algorithmic or operational errors, you can turn it into far more sensible code that will be much easier to debug.
Right now, your Matrix class doesn't define an object really, but just a set of operations to be used on 2D arrays. A good object has attributes and data, and then special functions to work from that data. I would read a bit of an introduction at https://en.wikipedia.org/wiki/Object-oriented_programming
What you want is something like
// Matrix.h
template <typename T>
class Matrix {
public:
// exactly how you choose to construct the object is up to you
// i.e. if you want to pass a 2d array as a parameter or something
Matrix(T inputMatrix[4][4]) {
for (int column = 0; column < 4; ++column) {
for (int row = 0; row < 4; ++row) {
matrix[column][row] = inputMatrix[column][row];
}
}
}
Matrix reduce() {
// will return a new Matrix object
. . .
}
Matrix inverse() {
// probably will end up calling reduce()
. . .
}
void print() {
. . .
}
// any other operations you want to do on matrices
private:
T matrix[4][4];
};
So that when you want do your operations, it is really easy and straightforward:
#include "Matrix.h"
int main() {
float matrix[4][4] = {
{ 1.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, -4.37114e-08, 1.0f, 0.0f },
{ 0.0f, -1.0f, -4.37114e-08, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f };
Matrix<float> A = Matrix<float>(matrix);
Matrix<float> B = A.inverse();
B.print();
return 0;
}

Remove if conditions from simple function

I need to remove as many if conditions as possible from the two functions below:
inline int inc_with_1bit_saturation(int counter)
{
if (counter == 1)
return --counter;
return ++counter;
}
void branch_prediction_1bit_saturation(int* input, int* output, int size)
{
int counter = 0;
for (int i = 0; i < size; ++i)
{
if (input[i] != counter)
{
counter = inc_with_1bit_saturation(counter);
output[i] = 0;
}
else output[i] = 1;
}
}
How can I do that and what if branch is absolutely necessary and cannot be removed and which one can be replaced by simple bitwise operations or something like that?
Update 1
According to User JSF's great tip, the code is now looking like this:
void branch_prediction_1bit_saturation(int* input, int* output, int size)
{
int counter = 0;
for (int i = 0; i < size; ++i)
{
if (input[i] != counter)
{
counter = 1 - counter;
output[i] = 0;
}
else output[i] = 1;
}
}
Update 2
Thanks to Cantfindname, the code became like this:
void branch_prediction_1bit_saturation(int* input, int* output, int size)
{
int counter = 0;
for (int i = 0; i < size; ++i)
{
output[i] = counter == input[i];
counter = output[i] * counter + (1 - output[i])*(1 - counter);
}
}
And this completely solves the question.
For the if statement inside the loop:
output[i] = (int)(input[i]==counter);
counter = output[i]*counter + (1-output[i])*(1-counter) //used JSF's trick
True converts to 1 and false to 0, according to this: bool to int conversion
function inc_with_1bit_saturation is equivalent of modulo 2. So you can replace
counter = inc_with_1bit_saturation(counter);
With
counter = (counter+1) % 2;
void branch_prediction_1bit_saturation(int* input, int* output, int size) {
int counter = 0;
for (int i = 0; i < size; ++i)
{
output[i] = (int)!((!!input[i]) ^ counter);
counter = (int)((!!input[i]) & counter) | ((!!input[i]) & !counter);
}
}
A is logic input[i];
B is logic counter;
The truth table for input[i] != counter is:
A B
0 0 | 0 --> (0 & 0) | (0 & !0) = 0 | 0 = 0
0 1 | 0 --> (0 & 1) | (0 & !1) = 0 | 0 = 0
1 0 | 1 --> (1 & 0) | (1 & !0) = 0 | 1 = 1
1 1 | 1 --> (1 & 1) | (1 & !1) = 1 | 0 = 1
The truth table for output[i]
A B
0 0 | 1 --> !(0 ^ 0) = !(0) = 1
0 1 | 0 --> !(0 ^ 1) = !(1) = 0
1 0 | 0 --> !(1 ^ 0) = !(1) = 0
1 1 | 1 --> !(1 ^ 1) = !(0) = 1
:)

Sudoku recursive backtracking, unrecursing too early

So I am writing a sudoku solver in C++ and have run into a little snag. Below is my solve board code. It works for the first 3 rows of the puzzle, but unrecurses when hitting the end of the 4th row. Looking at the code on gdb it hits the end of the 4th row, backtracks to 6th column, tries and then unrecurses out to the end.
A couple of other notes about the code is the matrix which holds the sudoku board begins at 1,1 not 0,0. So when solveBoard is initially called the parameters are (1, 1, 0). I have also attached the setCell and checkConflicts functions for more insight on there. I have three vectors rowConf,colConf and squConf to store the values that have already been placed in the respective row, column, or square. I have been at this for hours and cannot get it to go past the 3rd row. Any assistance is greatly appreicated. Thanks!
EDIT: Added clearCell()
bool board::solveBoard(int i, int j, int count)
{
if (j > 9)
{
j = 1;
i++;
printBoard();
if (isSolved())
{
printBoard();
cout <<"The Board has been solved!" <<endl
<<" The number of recursive calls was: " <<count <<endl;
return true;
}
}
if (isBlank(i, j))
{
for (int n = 1; n < 10; n++)
{
if (setCell(i, j, (char)n + '0'))
{
if (solveBoard(i, j + 1, count + 1))
{
return true;
}
}
}
}
else
{
return (solveBoard(i, j + 1, count + 1));
}
clearCell(i, j);
return false;
}
bool board::setCell(int i, int j, char val)
{
int intVal;
intVal = atoi(&val);
if (i >= 1 && i <= BoardSize && j >= 1 && j <= BoardSize &&
intVal >= 1 && intVal <= BoardSize)
{
if (!(checkConflicts(intVal, i, j, squareNumber(i, j))))
{
return false;
}
value[i][j] = intVal;
// Set flags of the conflicts
rowConf[i][intVal] = true;
colConf[j][intVal] = true;
squConf[squareNumber(i, j)][intVal] = true;
return true;
}
else
{
throw rangeError("bad value in setCell");
}
}
bool board::checkConflicts(int val, int i, int j, int k)
{
if (i < 1 && i > BoardSize && j < 1 && j > BoardSize &&
k < 1 && k > BoardSize && val < 1 && val > BoardSize)
{
throw rangeError("bad value in checkConflicts()");
}
if (rowConf[i][val] || colConf[j][val] || squConf[k][val])
{
return false;
}
else
{
return true;
}
}
Initial Board:
-----------------------------
| 3 | 8 | -----------------------------
| | 7 | 5 -----------------------------
| 1 | | -----------------------------
-----------------------------
| | | 3 6 -----------------------------
| 2 | 4 | -----------------------------
| 7 | | -----------------------------
-----------------------------
| | 6 | 1 3 -----------------------------
| 4 5 | 2 | -----------------------------
| | | 8 -----------------------------
-----------------------------
Final Output:
-----------------------------
| 3 2 4 | 1 8 5 | 6 7 9 -----------------------------
| 6 8 9 | 7 2 3 | 4 1 5 -----------------------------
| 1 5 7 | 4 9 6 | 2 8 3 -----------------------------
-----------------------------
| | | 3 6 -----------------------------
| 2 | 4 | -----------------------------
| 7 | | -----------------------------
-----------------------------
| | 6 | 1 3 -----------------------------
| 4 5 | 2 | -----------------------------
| | | 8 -----------------------------
-----------------------------
void board::clearCell(int i, int j)
{
int intVal;
if (i >= 1 && i <= BoardSize && j >= 1 && j <= BoardSize)
{
if (value[i][j] != -1)
{
intVal = value[i][j];
rowConf[i][intVal] = false;
colConf[j][intVal] = false;
squConf[squareNumber(i, j)][intVal] = false;
value[i][j] = -1;
}
}
else
{
throw rangeError("bad value in setCell");
}
}
Your problem is most likely here:
if (isBlank(i, j))
{
for (int n = 1; n < 10; n++)
{
if (setCell(i, j, (char)n + '0'))
{
if (solveBoard(i, j + 1, count + 1))
{
return true;
}
}
}
}
Somehow it is going through this section, which is why it isn't going through the else in the end, but since it hasn't returned before, it gets stuck.
This needs more debugging, but here is an idea that could lead to a solution:
if (isBlank(i, j))
{
for (int n = 1; n < 10; n++)
{
if (setCell(i, j, (char)n + '0'))
{
if (solveBoard(i, j + 1, count + 1))
{
return true;
} else {
echo 'Looks like it ended on the farthest-level..';
}
} else {
echo 'Looks like it ended on the second-farthest level.';
}
}
The atoi function expects a string as an argument, that is an array of chars terminated with character '\0', ASCII NUL. You give a parameter being a pointer to a character (equivalent to some arrray of chars) but do not guarantee it is zero-terminated. Please replace intVal = atoi(&val); with intVal = (int)val - '0';
And your checkConflicts should have || operators instead of && in the first if.
These are probably not reasons of the error but certainly need correction.