I have been searching for a Sudoku Solving Algorithm for a while and I found this code. But I have some difficulties. I can't understand it. If there are conflicts with all numbers between 1 and 9 in a single cell, the program should stop, right? But it continues. Can somebody explain me how the code works, please? Here it is:
bool Sudoku::Help_Solve(int i, int j)
{
int nextrow, nextcol;
while(change[i][j] == 1) //We find the first cell in which we can change the number
{
j++;
if(j > 9)
{
j = 1;
i++;
}
if(i > 9) return true;
}
for(int p = 1; p <= 9; p++)
{
if(Game.Check_Conflicts(p, i, j)) //We are checking for conflicts
{
board[i][j] = p;
nextrow = i;
nextcol = j+1;
if(nextcol > 9)
{
nextcol = 1;
nextrow++;
}
if(nextcol == 1 && nextrow == 10) return true;
if(Game.Help_Solve(nextrow, nextcol)) return true;
}
}
board[i][j] = 0;
return false;
}
Not enough code to explain properly, what happens in Game.Check_Conflicts(p, i, j), is this function getting called recursively?
Here is the whole code if you want to see it:
#include <iostream>
#include <iomanip>
#include <time.h>
#include <cstdlib>
#include <windows.h>
using namespace std;
class Sudoku
{
private:
int board[9][9];
int change[9][9];
public:
Sudoku();
void Print_Board();
void Add_First_Cord();
bool Help_Solve(int i, int j);
bool Check_Conflicts(int p, int i, int j);
};
Sudoku Game;
void setcolor(unsigned short color) //The function that you'll use to
{ //set the colour
HANDLE hcon = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hcon,color);
}
Sudoku::Sudoku()
{
for(int i = 0; i <= 9; i++)
for(int j = 0; j <= 9; j++)
board[i][j] = 0;
}
void Sudoku::Print_Board()
{
for(int i = 1; i <= 9; i++)
{
for(int j = 1; j <= 9; j++)
{
if(change[i][j] == 1)
{
setcolor(12);
cout << board[i][j] << " ";
setcolor(7);
}
else cout << board[i][j] << " ";
if(j%3 == 0) cout << "| ";
}
cout << endl;
if(i%3 == 0) cout << "------+-------+--------" << endl;
}
}
void Sudoku::Add_First_Cord()
{
board[1][1] = 5; change[1][1] = 1;
board[1][2] = 3; change[1][2] = 1;
board[1][5] = 7; change[1][5] = 1;
board[2][1] = 6; change[2][1] = 1;
board[2][4] = 1; change[2][4] = 1;
board[2][5] = 9; change[2][5] = 1;
board[2][6] = 5; change[2][6] = 1;
board[3][2] = 9; change[3][2] = 1;
board[3][3] = 8; change[3][3] = 1;
board[3][8] = 6; change[3][8] = 1;
board[4][1] = 8; change[4][1] = 1;
board[4][5] = 6; change[4][5] = 1;
board[4][9] = 3; change[4][9] = 1;
board[5][1] = 4; change[5][1] = 1;
board[5][4] = 8; change[5][4] = 1;
board[5][6] = 3; change[5][6] = 1;
board[5][9] = 1; change[5][9] = 1;
board[6][1] = 7; change[6][1] = 1;
board[6][5] = 2; change[6][5] = 1;
board[6][9] = 6; change[6][9] = 1;
board[7][2] = 6; change[7][2] = 1;
board[7][7] = 2; change[7][7] = 1;
board[7][8] = 8; change[7][8] = 1;
board[8][4] = 4; change[8][4] = 1;
board[8][5] = 1; change[8][5] = 1;
board[8][6] = 9; change[8][6] = 1;
board[8][9] = 5; change[8][9] = 1;
board[9][5] = 8; change[9][5] = 1;
board[9][8] = 7; change[9][8] = 1;
board[9][9] = 9; change[9][9] = 1;
}
bool Sudoku::Check_Conflicts(int p, int i, int j)
{
for(int k = 1; k <= 9; k++)
if(board[i][k] == p) return false;
for(int q = 1; q <= 9; q++)
if(board[q][j] == p) return false;
/*
*00
000
000
*/
if((j == 1 || j == 4 || j == 7) && (i == 1 || i == 4 || i == 7))
{
if(board[i][j+1] == p || board[i][j+2] == p || board[i+1][j] == p ||
board[i+2][j] == p || board[i+1][j+1] == p || board[i+1][j+2] == p ||
board[i+2][j+1] == p || board[i+2][j+2] == p)return false;
}
/*
000
000
*00
*/
if((j == 1 || j == 4 || j == 7) && (i == 3 || i == 6 || i == 9))
{
if(board[i-1][j] == p || board[i-2][j] == p || board[i][j+1] == p ||
board[i][j+2] == p || board[i-1][j+1] == p || board[i-1][j+2] == p ||
board[i-2][j+1] == p || board[i-2][j+2] == p)return false;
}
/*
000
*00
000
*/
if((j == 1 || j == 4 || j == 7) && (i == 2 || i == 5 || i == 8))
{
if(board[i-1][j] == p || board[i-1][j+1] == p || board[i-1][j+2] == p ||
board[i][j+1] == p || board[i][j+2] == p || board[i+1][j] == p ||
board[i+1][j+1] == p || board[i+1][j+2] == p)return false;
}
/*
0*0
000
000
*/
if((j == 2 || j == 5 || j == 8) && (i == 1 || i == 4 || i == 7))
{
if(board[i][j-1] == p || board[i][j+1] == p || board[i+1][j+1] == p ||
board[i+1][j-1] == p || board[i+1][j] == p || board[i+2][j-1] == p ||
board[i+2][j] == p || board[i+2][j+1] == p)return false;
}
/*
000
0*0
000
*/
if((j == 2 || j == 5 || j == 8) && (i == 2 || i == 5 || i == 8))
{
if(board[i-1][j] == p || board[i-1][j-1] == p || board[i-1][j+1] == p ||
board[i][j+1] == p || board[i][j-1] == p || board[i+1][j+1] == p ||
board[i+1][j] == p || board[i+1][j-1] == p)return false;
}
/*
000
000
0*0
*/
if((j == 2 || j == 5 || j == 8) && (i == 3 || i == 6 || i == 9))
{
if(board[i][j-1] == p || board[i][j+1] == p || board[i-1][j] == p ||
board[i-1][j+1] == p || board[i-1][j-1] == p || board[i-2][j] == p ||
board[i-2][j+1] == p || board[i-2][j-1] == p) return false;
}
/*
00*
000
000
*/
if((j == 3 || j == 6 || j == 9) && (i == 1 || i == 4 || i == 7))
{
if(board[i][j-1] == p || board[i][j-2] == p || board[i+1][j] == p ||
board[i+1][j-1] == p || board[i+1][j-2] == p || board[i+2][j] == p ||
board[i+2][j-1] == p || board[i+2][j-2] == p) return false;
}
/*
000
00*
000
*/
if((j == 3 || j == 6 || j == 9) && (i == 2 || i == 5 || i == 8))
{
if(board[i-1][j] == p || board[i-1][j-1] == p || board[i-1][j-2] == p ||
board[i][j-1] == p || board[i][j-2] == p || board[i+1][j] == p ||
board[i+1][j-1] == p || board[i+1][j-2] == p) return false;
}
/*
000
000
00*
*/
if((j == 3 || j == 6 || j == 9) && (i == 3 || i == 6 || i == 9))
{
if(board[i][j-1] == p || board[i][j-2] == p || board[i-1][j] == p ||
board[i-1][j-1] == p || board[i-1][j-2] == p || board[i-2][j] == p ||
board[i-2][j-1] == p || board[i-2][j-2] == p) return false;
}
return true;
}
bool Sudoku::Help_Solve(int i, int j)
{
int nextrow, nextcol;
while(change[i][j] == 1)
{
j++;
if(j > 9)
{
j = 1;
i++;
}
if(i > 9) return true;
}
for(int p = 1; p <= 9; p++)
{
if(Game.Check_Conflicts(p, i, j))
{
board[i][j] = p;
nextrow = i;
nextcol = j+1;
if(nextcol > 9)
{
nextcol = 1;
nextrow++;
}
if(nextcol == 1 && nextrow == 10) return true;
if(Game.Help_Solve(nextrow, nextcol)) return true;
}
}
board[i][j] = 0;
return false;
}
int main()
{
Game.Add_First_Cord();
Game.Help_Solve(1, 1);
Game.Print_Board();
system("pause");
return 0;
}
It looks like Sudoku::Check_Conflicts returns true if the number CAN be placed there, or false if it CAN'T be placed there due to a simple conflict. A different function name could maybe better self-document the code.
The thing is rhat I can't understand why it continues if in the end it
returns false :/
It doesn't ALWAYS return at the bottom of the function tho':
bool Sudoku::Help_Solve(int i, int j)
{
int nextrow, nextcol;
while(change[i][j] == 1) //We find the first cell in which we can change the number
{
j++;
if(j > 9)
{
j = 1;
i++;
}
if(i > 9) return true;
-------------------------^^^^
returns true if we have filled all squares.
}
for(int p = 1; p <= 9; p++)
{
if(Game.Check_Conflicts(p, i, j)) //We are checking for conflicts
{
board[i][j] = p;
nextrow = i;
nextcol = j+1;
if(nextcol > 9)
{
nextcol = 1;
nextrow++;
}
if(nextcol == 1 && nextrow == 10) return true;
-----------------------------------------------------^^^^
returns when we have filled everything!
if(Game.Help_Solve(nextrow, nextcol)) return true;
---------------------------------------------------------^^^^
returns if we filled at the next level of solution.
}
}
board[i][j] = 0;
return false;
-----------^^^^^ returns if we failed to fill the whole thing.
}
As someone else mentioned in a comment, there are some trivial things that can be done to improve on the algorithm - such as looking for the "most suitable place to fill first" [which doesn't improve the worst case, but it does improve the typical case].
I have written a Sudoku solver that uses a similar algorithm, but it tries to find the cell with the lowest number of candidates (possible numbers to go in the that cell) and only tries recursively if there are multiple choices.
Related
I am new to c++ and qt, but I want to learn. The essence of the problem: the application hangs when you click on the button, although before some edits worked adequately (rolling back edits did not help). As far as I understand it is because of the while loop, but nowhere can I find an answer on how to fix it.
The program itself, what I need to implement, is to write the interaction of predators and herbivores, for a start on a primitive level.
So, please help me with the problem of hanging the application.
Creating classes
class Grass
{...};
class Predator
{...};
class Herbivorous
{...};
Button click processing
void MainWindow::on_pushButton_clicked()
{
int kol_grass = ui->lineEdit_11->text().toInt(), kol_weeks = 0, t, t_x, t_y, kol_H = ui->lineEdit->text().toInt(), kol_P = ui->lineEdit_2->text().toInt(), k = 0, kk = 0;
list<Herbivorous> lst_H;
list<Predator> lst_P;
list<Grass> lst_G;
int kol_die_P_hungry = 0, kol_die_H_hungry = 0, kol_die_P_age = 0, kol_die_H_age = 0, eaten = 0;
int years = 0;
qsrand(QDateTime::currentMSecsSinceEpoch());
//resize dynamic lists
lst_H.resize(kol_H);
lst_P.resize(kol_P);
lst_G.resize(kol_grass);
//creating list iterators
list<Herbivorous>::iterator i = lst_H.begin();
list<Herbivorous>::iterator j = lst_H.begin();
list<Predator>::iterator ii = lst_P.begin();
list<Predator>::iterator jj = lst_P.begin();
list<Grass>::iterator grass_it = lst_G.begin();
//creating grass objects
for (; grass_it != lst_G.end(); grass_it++)
{
//...
}
grass_it = lst_G.begin();
//creating herbivore objects
for (; i != lst_H.end(); i++)
{
//...
}
//creating predator objects
for (; ii != lst_P.end(); ii++)
{
//...
}
i = lst_H.begin();
ii = lst_P.begin();
Then the same cycle
Apparently, the application hangs, when you click on the button. What am I doing wrong?
//as long as both animal species are alive, simulate life
while (lst_H.size() > 0 && lst_P.size() > 0)
{
//grass rendering
for (; grass_it != lst_G.end(); grass_it++)
{
if (grass_it->GetValue() != .0)
{
QTableWidgetItem * grass = new QTableWidgetItem();
grass->setBackground(Qt::green);
ui->tableWidget->setItem(grass_it->GetY(), grass_it->GetX(), grass);
}
}
grass_it = lst_G.begin();
//once a month grass replenishment
if (kol_weeks % 4 == 0)
{
grass_it = lst_G.begin();
for(; grass_it != lst_G.end(); grass_it++)
{
grass_it->Recovery();
}
grass_it = lst_G.begin();
}
//once a month check for starvation
if (kol_weeks % 4 == 0)
{
i = lst_H.begin();
for (; i != lst_H.end(); i++)
{
if (i->GetHungry() <= 0)
{
i->SetInLife(false);//смерть от голода
kol_die_H_hungry++;
}
else
{
i->SetAge(i->GetAge() + 1);//+1 год
}
}
i = lst_H.begin();
ii = lst_P.begin();
for (; ii != lst_P.end(); ii++)
{
if (ii->GetHungry() <= 0)
{
ii->SetInLife(false);//смерть от голода
kol_die_P_hungry++;
}
else
{
ii->SetAge(ii->GetAge() + 1);//+1 год
}
}
ii = lst_P.begin();
}
//once a year old age check
if (kol_weeks == 48)
{
i = lst_H.begin();
kol_weeks = 0;
years++;
for (; i != lst_H.end(); i++)
{
if (i->GetAge() >= ui->lineEdit_3->text().toInt())
{
i->SetInLife(false);//смерть от старости
kol_die_H_age++;
}
else
{
i->SetAge(i->GetAge() + 1);//+1 год
}
}
i = lst_H.begin();
ii = lst_P.begin();
for (; ii != lst_P.end(); ii++)
{
if ((ii->GetAge() >= ui->lineEdit_10->text().toInt()) || (ii->GetHungry() <= 0))
{
ii->SetInLife(false);//смерть от старости или от голода
kol_die_P_age++;
}
else
{
ii->SetAge(ii->GetAge() + 1);//+1 год
}
}
ii = lst_P.begin();
}
//movement of herbivores
for (; i != lst_H.end(); i++)
{
QTableWidgetItem * noherbivorous = new QTableWidgetItem();
noherbivorous->setBackground(Qt::black);
ui->tableWidget->setItem(i->GetY(), i->GetX(), noherbivorous);
if (i->GetInLife() == true)
{
i->Direction();
i->Hungry();
QTableWidgetItem * herbivorous = new QTableWidgetItem();
herbivorous->setBackground(Qt::white);
ui->tableWidget->setItem(i->GetY(), i->GetX(), herbivorous);
}
}
//moving predators
for (; ii != lst_P.end(); ii++)
{
QTableWidgetItem * nopredator = new QTableWidgetItem();
nopredator->setBackground(Qt::black);
ui->tableWidget->setItem(ii->GetY(), ii->GetX(), nopredator);
if (ii->GetInLife() == true)
{
ii->Direction();
ii->Hungry();
QTableWidgetItem * predator = new QTableWidgetItem();
predator->setBackground(Qt::red);
ui->tableWidget->setItem(ii->GetY(), ii->GetX(), predator);
}
}
lst_H.remove_if([] (Herbivorous a) {return (a.GetInLife() == false);});//the removal of dead
lst_P.remove_if([] (Predator a) {return (a.GetInLife() == false);});//the removal of dead
i = lst_H.begin();
j = lst_H.begin();
//death of parents and birth of children (herbivores)
for (; i != lst_H.end(); i++)
{
for (; j != lst_H.end(); j++)
{
if ((i->GetNumber() != j->GetNumber()) && (i->GetInLife() == true) && (j->GetInLife() == true) && (i->GetAge() >= i->GetMin_Rep()) && (i->GetAge() <= i->GetMax_Rep()) && (j->GetAge() >= j->GetMin_Rep()) && (j->GetAge() <= j->GetMax_Rep()))
{
t_x = i->GetX() - j->GetX();
t_y = i->GetY() - j->GetY();
if (((t_x == 1) || (t_x == -1) || (t_x == 0)) && ((t_y == 1) || (t_y == -1) || (t_y == 0)))
{
i->SetInLife(false);
j->SetInLife(false);
//creating children
t = qrand() % (4 + 1);//от 0 до 4 детей
for (int u = 0; u < t; u++)
{
Herbivorous child;
child.SetInLife(true);
child.SetX(qrand() % (234 + 1));//рандом
child.SetY(qrand() % (144 + 1));//рандом
child.SetAge(1);
child.SetFood(ui->lineEdit_6->text().toDouble());
child.SetNumber(kk);
child.SetMax_Rep(ui->lineEdit_4->text().toInt());
child.SetMin_Rep(ui->lineEdit_5->text().toInt());
k++;
lst_H.push_back(child);
}
}
}
}
j = lst_H.begin();
}
ii = lst_P.begin();
jj = lst_P.begin();
//death of parents and birth of children (predators)
for (; ii != lst_P.end(); ii++)
{
for (; jj != lst_P.end(); jj++)
{
if ((ii->GetNumber() != jj->GetNumber()) && (ii->GetInLife() == true) && (jj->GetInLife() == true) && (ii->GetAge() >= ii->GetMin_Rep()) && (ii->GetAge() <= ii->GetMax_Rep()) && (jj->GetAge() >= jj->GetMin_Rep()) && (jj->GetAge() <= jj->GetMax_Rep()))
{
t_x = ii->GetX() - jj->GetX();
t_y = ii->GetY() - jj->GetY();
if (((t_x == 1) || (t_x == -1) || (t_x == 0)) && ((t_y == 1) || (t_y == -1) || (t_y == 0)))
{
ii->SetInLife(false);
jj->SetInLife(false);
//creating children
t = qrand() % (4 + 1);//от 0 до 4 детей
for (int u = 0; u < t; u++)
{
Predator child;
child.SetInLife(true);
child.SetX(qrand() % (234 + 1));//рандом
child.SetY(qrand() % (144 + 1));//рандом
child.SetAge(1);
child.SetFood(ui->lineEdit_8->text().toDouble());
child.SetNumber(k);
child.SetMax_Rep(ui->lineEdit_9->text().toInt());
child.SetMin_Rep(ui->lineEdit_7->text().toInt());
kk++;
lst_P.push_back(child);
}
}
}
}
jj = lst_P.begin();
}
ii = lst_P.begin();
j = lst_H.begin();
//hunting of predators on herbivores
for (; ii != lst_P.end(); ii++)
{
if (ii->GetHungry() < 1)
{
for (; j != lst_H.end(); j++)
{
if ((ii->GetInLife() == true) && (j->GetInLife() == true))
{
t_x = ii->GetX() - j->GetX();
t_y = ii->GetY() - j->GetY();
if (((t_x == 1) || (t_x == -1) || (t_x == 0)) && ((t_y == 1) || (t_y == -1) || (t_y == 0)))
{
j->SetInLife(false);
ii->SetHungry(ii->GetHungry() + 1);
eaten++;
}
}
}
}
j = lst_H.begin();
}
grass_it = lst_G.begin();
//hunting herbivores on the grass
for (; j != lst_H.end(); j++)
{
if (j->GetHungry() < 1)
{
for (; grass_it != lst_G.end(); grass_it++)
{
if ((grass_it->GetValue() > 0) && (j->GetInLife() == true) && (j->GetX() == grass_it->GetX()) && (j->GetY() == grass_it->GetY()))
{
if (grass_it->GetValue() > 0.5)
{
j->SetHungry(j->GetHungry() + 0.5);
grass_it->SetValue(grass_it->GetValue() - 0.5);
}
else
{
j->SetHungry(j->GetHungry() + grass_it->GetValue());
grass_it->SetValue(0);
}
}
}
}
j = lst_H.begin();
}
i = lst_H.begin();
ii = lst_P.begin();
grass_it = lst_G.begin();
//summary of interim results
ui->label_11->setText("The number of herbivores: " + QString::number(lst_H.size()));
...
QEventLoop loop;
QTimer::singleShot(100, &loop, SLOT(quit()));
loop.exec();
kol_weeks++;
}
}```
Question:
https://www.spoj.com/problems/BALNUM/
My Solution:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
string s;
vector<ll>v;
ll dp[20][2][3][3][3][3][3][3][3][3][3][3][2];
ll solve(ll i,ll less,ll start,ll m0,ll m1,ll m2,ll m3,ll m4,ll m5,ll m6,ll m7,ll m8,ll m9){
if(i == s.size()){
if((m1 == 2 or m1 == 0) and (m3 == 2 or m3 == 0) and (m5 == 2 or m5 == 0) and (m7 == 2 or m7 == 0) and (m9 == 2 or m9 == 0) and (m0 == 1 or m0 == 0) and (m2 == 1 or m2 == 0) and (m4 == 1 or m4 == 0) and (m6 == 1 or m6 == 0) and (m8 == 1 or m8 == 0)){
return 1;
}
return 0;
}
ll &ret = dp[i][less][m0][m1][m2][m3][m4][m5][m6][m7][m8][m9][start];
if(ret != -1) return ret;
ll k = less ? 9 : v[i];
ll ans = 0;
for(ll j = 1; j <= k; j++){
if(j == 1){
ans += solve(i+1,less | (j < v[i]),0,m0,((m1+1)%3 == 0) ? 1:(m1+1)%3,m2,m3,m4,m5,m6,m7,m8,m9);
}else if(j == 2){
ans += solve(i+1,less | (j < v[i]),0,m0,m1,((m2+1)%3 == 0) ? 1:(m2+1)%3,m3,m4,m5,m6,m7,m8,m9);
}else if(j == 3){
ans += solve(i+1,less | (j < v[i]),0,m0,m1,m2,((m3+1)%3 == 0) ? 1:(m3+1)%3,m4,m5,m6,m7,m8,m9);
}else if(j == 4){
ans += solve(i+1,less | (j < v[i]),0,m0,m1,m2,m3,((m4+1)%3 == 0) ? 1:(m4+1)%3,m5,m6,m7,m8,m9);
}else if(j == 5){
ans += solve(i+1,less | (j < v[i]),0,m0,m1,m2,m3,m4,((m5+1)%3 == 0) ? 1:(m5+1)%3,m6,m7,m8,m9);
}else if(j == 6){
ans += solve(i+1,less | (j < v[i]),0,m0,m1,m2,m3,m4,m5,((m6+1)%3 == 0) ? 1:(m6+1)%3,m7,m8,m9);
}else if(j == 7){
ans += solve(i+1,less | (j < v[i]),0,m0,m1,m2,m3,m4,m5,m6,((m7+1)%3 == 0) ? 1:(m7+1)%3,m8,m9);
}else if(j == 8){
ans += solve(i+1,less | (j < v[i]),0,m0,m1,m2,m3,m4,m5,m6,m7,((m8+1)%3 == 0) ? 1:(m8+1)%3,m9);
}else if(j == 9){
ans += solve(i+1,less | (j < v[i]),0,m0,m1,m2,m3,m4,m5,m6,m7,m8,((m9+1)%3 == 0) ? 1:(m9+1)%3);
}
}
if(!start){
ans += solve(i+1,less | (0 < v[i]),0,((m0+1)%3 == 0) ? 1:(m0+1)%3,m1,m2,m3,m4,m5,m6,m7,m8,m9);
}
if(start){
ans += solve(i+1,1,1,0,0,0,0,0,0,0,0,0,0);
}
return ret = ans;
}
int main(){
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
ll t;
cin>>t;
while(t--){
ll x;
cin>>x;
--x;
s = to_string(x);
memset(dp,-1,sizeof(dp));
v.clear();
for(char c:s) v.push_back(c-'0');
ll a=solve(0,0,1,0,0,0,0,0,0,0,0,0,0);
cin>>s;
memset(dp,-1,sizeof(dp));
v.clear();
for(char c:s) v.push_back(c-'0');
ll b=solve(0,0,1,0,0,0,0,0,0,0,0,0,0);
cout<<b-a<<endl;
}
}
Here the array i use for memoization is dp[20][2][3][3][3][3][3][3][3][3][3][3][2] (20 is max length of integer A or B)
Is the time complexity O(n) with a very high constant (like 2*3*3*3*3*3*3*3*3*3*3*2) where n is max length of integer A or B?
Its T * ( N * (2^2 * 3^10 * 9) + C ), The constant factor is really huge, but overall i think you can say that the time complexity is T * N * (a huge constant factor).
So you could say its O(T*N).
I am in need of help for this code that i am working on for a assignment. I am have the issue where if i have any X's on the board that is either in the left 2 columns it will display a X in the row above. I used my debugger and it seems that it is trying to access something outside the array bounds, but it shouldnt be. any advice on how to do this?
#include <iostream>
using namespace std;
void printTTT(char a[3][3]);
void insertX(/*PASS BY REFERENCE*/);
void insertO(char (&arr)[3][3]);
void checkForWin(/*PASS BY REFERENCE*/); // IGNORE THIS FOR NOW
int main() {
char TTTarray[3][3] = { { 'X','-','-' },
{ '-','-','-' },
{ 'X','-','-' } };
//char TTTarray[3][3] = { {'-','X','-'},
// {'-','X','-'},
// {'-','-','O'}};
//char TTTarray[3][3] = { {'-','-','-'},
// {'-','X','-'},
// {'-','O','-'}};
//char TTTarray[3][3] = { {'X','-','X'},
// {'-','-','-'},
// {'O','-','-'}};
//char TTTarray[3][3] = { {'X','-','X'},
// {'O','X','-'},
// {'O','-','O'}};
//insertX(/*CALL*/);
//OR
insertO(TTTarray);
printTTT(TTTarray);
/*****************
I have included the declaratoin of the array, initialized to - for each spot.
The '-' represents an empty position. You should fill it with either a
capital 'O' or a capital 'X'. I have also included a number of initialized arrays
to test; just comment out the ones you don't want for that moment
*****************/
return 0;
}
void printTTT(char a[3][3])
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
cout << a[i][j];
}
cout << endl;
}
}
void insertX(/*PASS BY REFERENCE*/) {
}
void insertO(char (&arr)[3][3])
{
int x1x;
int x1y;
//int x2x;
//int x2y;
for (int i = 0; i < 3; i++)
{
int go = 0;
for (int j = 0; j < 3; j++)
{
if (arr[i][j] == '-')
{
x1x = i;
x1y = j;
// looking for 2 x's for the block lol
if (x1x == 0 && go == 0)
{
if (arr[x1x][x1y + 1] == 'X' && arr[x1x][x1y + 2] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
if (arr[x1x][x1y - 1] == 'X' && arr[x1x][x1x + 1] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
if (arr[x1x][x1y - 1] == 'X' && arr[x1x][x1x - 2] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
}
if (x1x == 1 && go == 0)
{
if (arr[x1x][x1y + 1] == 'X' && arr[x1x][x1y + 2] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
if (arr[x1x][x1y - 1] == 'X' && arr[x1x][x1x + 1] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
if (arr[x1x][x1y - 1] == 'X' && arr[x1x][x1x - 2] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
}
if (x1x == 2 && go == 0)
{
if (arr[x1x][x1y + 1] == 'X' && arr[x1x][x1y + 2] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
if (arr[x1x][x1y - 1] == 'X' && arr[x1x][x1x + 1] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
if (arr[x1x][x1y - 1] == 'X' && arr[x1x][x1x - 2] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
}
if (x1y == 0 && go == 0)
{
if (arr[x1x + 1][x1y] == 'X' && arr[x1x + 2][x1y] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
if (arr[x1x - 1][x1y] == 'X' && arr[x1x + 1][x1x] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
if (arr[x1x - 1][x1y] == 'X' && arr[x1x - 2][x1x] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
}
if (x1y == 1 && go == 0)
{
if (arr[x1x + 1][x1y] == 'X' && arr[x1x + 2][x1y] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
if (arr[x1x - 1][x1y] == 'X' && arr[x1x + 1][x1x] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
if (arr[x1x - 1][x1y] == 'X' && arr[x1x - 2][x1x] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
}
if (x1y == 2 && go == 0)
181,1-8 83%
{
if (arr[x1x + 1][x1y] == 'X' && arr[x1x + 2][x1y] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
if (arr[x1x - 1][x1y] == 'X' && arr[x1x + 1][x1x] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
if (arr[x1x - 1][x1y] == 'X' && arr[x1x - 2][x1x] == 'X')
{
arr[i][j] = 'O';
go = 1;
}
}
}
}
}
}
Take a look at these lines from your insertD function:
if (x1x == 0 && go == 0)
{
if (arr[x1x][x1y + 1] == 'X' && arr[x1x][x1y + 2] == 'X')
In this case you have checked that x1x is zero, but you haven't checked x1y. So in this case you will go out of bounds if x1y is non-zero.
A couple of lines below you have
if (arr[x1x][x1y - 1] == 'X' && arr[x1x][x1x + 1] == 'X')
This will go out of bounds too, when x1y is zero.
You need to add more checks, or rethink the logic.
this code attempts to solve the 4 queens problem, placing 4 queens on a 4*4 chessboard without any of them being able to capture eachother
#include <iostream>
using namespace std;
int Place(int Chess[][4], int collumn, int i);
bool Check(int Chess[][4], int collumn, int i);
int findrow(int Chess[][4], int collumn);
const int size = 3;
int main()
{
int Chess[4][4];
int collumn;
int i = 0;
collumn = 0;
for(int s = 0; s < 4; s++)
{
for(int j = 0; j < 4; j ++)
{
Chess[s][j] = 0;
}
}
//Chess[0][0] = 1;
//Chess[3][3] = 1;
//if(Check(Chess, 3, 3) == false)
Place(Chess, collumn, i);
for(int z = 0; z < 4; z++)
{
for(int a = 0; a < 4; a++)
{
if(Chess[z][a] == 1)
cout<<"Row: "<<z<<"Collumn: "<<a<<"."<<endl;
}
cout<<endl;
}
system("pause");
return 0;
}
int Place(int Chess[][4], int collumn, int i)
{
if(collumn > size)
return 0;
while(i <= size)
{
if(Check(Chess, collumn, i) == true)
{
//cout<<"hi"<<endl;
Chess[collumn][i] = 1;
return(Place(Chess, (collumn + 1), i));
}
i ++;
}
if(i>= size)
{
//cout<<"hilo"<<endl;
return Place(Chess, collumn-1, findrow(Chess, collumn-1));
}
}
bool Check(int Chess[][4], int collumn, int i)//checks to see if it can be captured
{// very inneficitnt
int x = collumn;// this is so we can now work in terms of x and y
int y = i;
bool found = true;
// checks all the diagonal captures
if(Chess[x -1 ][y -1]== 1&& x>=1 && y >=1 )
found = false;
if(Chess[x -2 ][y - 2]== 1&& x>=2 && y>=2 )
found = false;
if(Chess[x - 3][y - 3]== 1 && x>=3 && y>=3 )
found = false;
if(Chess[x + 1][y - 1] == 1&& x<=2 && y>=1 )
found = false;
if(Chess[x + 2][y -2] == 1&& x<=1 && y>=2)
found = false;
if(Chess[x + 3][y - 3] == 1 && x<=0 && y>=3)
found = false;
if(Chess[x + 1][y + 1] == 1 && x<=2 && y<=2)
found = false;
if(Chess[x + 2][y + 2] == 1&& x<=1 && y<=1)
found = false;
if(Chess[x + 3][y + 3] == 1 && x<=0 && y<=0 )
found = false;
if(Chess[x -1 ][y + 1]== 1 && x>=1 && y<=2 )
found = false;
if(Chess[x - 2][y + 2] == 1&& x>=2 && y<=1 )
found = false;
if(Chess[x - 3][y + 3] == 1&& x>=3 && y<=0)
found = false;
//checks all the horizontal captures. We don't need to check for vertical captures
if(Chess[x + 1][y] == 1 && x<=2)
found = false;
if(Chess[x + 2][y] == 1&& x<=1 )
found = false;
if(Chess[x+3][y] == 1 && x<=0)
found = false;
if(Chess[x -1 ][y] == 1&& x>=1)
found = false;
if(Chess[x-2][y] == 1&& x>=2 )
found = false;
if(Chess[x-3][y] == 1 && x>=3)
found = false;
if(found == false)
return false;
if(found == true)
return true;
}
int findrow(int Chess[][4], int collumn)
{
for(int z = 0; z < 4; z++)
{
if(Chess[collumn][z] == 1)
{
Chess[collumn][z] = 0;
return z;
}
}
}
The first thing I see is a probable out-of-bounds access:
if(Chess[x -1 ][y -1]== 1&& x>=1 && y >=1 )
What if the value of x is 0? You are accessing Chess[-1][y], which is out of bounds. Your if statement does not stop this, even with the x>=1 condition.
The if will first test the Chess[x-1][y-1]==1 condition. If you want this to not happen, place the test for x>=1 before Chess[x-1][y-1]==1.
But even with this, that entire section of code looks suspicious. I wouldn't be surprised if there were more out-of-bounds accesses.
I'm trying to make a Sudoku Solving program for a couple of days but I'm stuck with the methods. I found this algorithm here but I don't really understand it:
start at the first empty cell, and put 1 in it.
Check the entire board, and see if there are any conflicts
If there are coflicts on the board, increase the number in the current cell by 1 (so change 1 to 2, 2 to 3, etc)
If the board is clean move, start at step one again.
If all nine possible numbers on a given cell cause a conflict in the board, then you set this cell back to empty, go back to the previous cell, and start again from step 3 (this is where the 'backtracking' comes in).
Here is my code. I think something is wrong with my Help_Solve(...) function. Can you help me to identify the problem, please?
#include <iostream>
#include <iomanip>
#include <time.h>
#include <cstdlib>
#include <windows.h>
using namespace std;
class Sudoku
{
private:
int board[9][9];
int change[9][9];
public:
Sudoku();
void Print_Board();
void Add_First_Cord();
void Solve();
void Help_Solve(int i, int j);
bool Check_Conflicts(int p, int i, int j);
};
Sudoku Game;
void setcolor(unsigned short color) //The function that you'll use to
{ //set the colour
HANDLE hcon = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hcon,color);
}
Sudoku::Sudoku()
{
for(int i = 1; i <= 9; i++)
for(int j = 1; j <= 9; j++)
board[i][j] = 0;
}
void Sudoku::Print_Board()
{
for(int i = 1; i <= 9; i++)
{
for(int j = 1; j <= 9; j++)
{
if(change[i][j] == 1)
{
setcolor(12);
cout << board[i][j] << " ";
setcolor(7);
}
else cout << board[i][j] << " ";
if(j%3 == 0) cout << "| ";
}
cout << endl;
if(i%3 == 0) cout << "------+-------+---------" << endl;
}
}
void Sudoku::Add_First_Cord()
{
board[1][1] = 5; change[1][1] = 1;
board[1][2] = 3; change[1][2] = 1;
board[1][5] = 7; change[1][5] = 1;
board[2][1] = 6; change[2][1] = 1;
board[2][4] = 1; change[2][4] = 1;
board[2][5] = 9; change[2][5] = 1;
board[2][6] = 5; change[2][6] = 1;
board[3][2] = 9; change[3][2] = 1;
board[3][3] = 8; change[3][3] = 1;
board[3][8] = 6; change[3][8] = 1;
board[4][1] = 8; change[4][1] = 1;
board[4][5] = 6; change[4][5] = 1;
board[4][9] = 3; change[4][9] = 1;
board[5][1] = 4; change[5][1] = 1;
board[5][4] = 8; change[5][4] = 1;
board[5][6] = 3; change[5][6] = 1;
board[5][9] = 1; change[5][9] = 1;
board[6][1] = 7; change[6][1] = 1;
board[6][5] = 2; change[6][5] = 1;
board[6][9] = 6; change[6][9] = 1;
board[7][2] = 6; change[7][2] = 1;
board[7][7] = 2; change[7][7] = 1;
board[7][8] = 8; change[7][8] = 1;
board[8][4] = 4; change[8][4] = 1;
board[8][5] = 1; change[8][5] = 1;
board[8][6] = 9; change[8][6] = 1;
board[8][9] = 5; change[8][9] = 1;
board[9][5] = 8; change[9][5] = 1;
board[9][8] = 7; change[9][8] = 1;
board[9][9] = 9; change[9][9] = 1;
}
bool Sudoku::Check_Conflicts(int p, int i, int j)
{
for(int k = 1; k <= 9; k++)
if(board[i][k] == p) return false;
for(int q = 1; q <= 9; q++)
if(board[q][j] == p) return false;
/*
*00
000
000
*/
if((j == 1 || j == 4 || j == 7) && (i == 1 || i == 4 || i == 7))
{
if(board[i][j+1] == p || board[i][j+2] == p || board[i+1][j] == p ||
board[i+2][j] == p || board[i+1][j+1] == p || board[i+1][j+2] == p ||
board[i+2][j+1] == p || board[i+2][j+2] == p)return false;
}
/*
000
000
*00
*/
if((j == 1 || j == 4 || j == 7) && (i == 3 || i == 6 || i == 9))
{
if(board[i-1][j] == p || board[i-2][j] == p || board[i][j+1] == p ||
board[i][j+2] == p || board[i-1][j+1] == p || board[i-1][j+2] == p ||
board[i-2][j+1] == p || board[i-2][j+2] == p)return false;
}
/*
000
*00
000
*/
if((j == 1 || j == 4 || j == 7) && (i == 2 || i == 5 || i == 8))
{
if(board[i-1][j] == p || board[i+1][j] == p || board[i-1][j+1] == p ||
board[i][j+1] == p || board[i+1][j+1] == p || board[i+1][j+2] == p ||
board[i][j+2] == p || board[i+1][j+2] == p)return false;
}
/*
0*0
000
000
*/
if((j == 2 || j == 5 || j == 8) && (i == 1 || i == 5 || i == 7))
{
if(board[i-1][j] == p || board[i+1][j] == p || board[i-1][j+1] == p ||
board[i][j+1] == p || board[i+1][j+1] == p || board[i+1][j+2] == p ||
board[i][j+2] == p || board[i+1][j+2] == p)return false;
}
/*
000
0*0
000
*/
if((j == 2 || j == 5 || j == 8) && (i == 2 || i == 5 || i == 8))
{
if(board[i-1][j] == p || board[i-1][j-1] == p || board[i-1][j+1] == p ||
board[i][j+1] == p || board[i][j-1] == p || board[i+1][j+1] == p ||
board[i][j] == p || board[i+1][j-1] == p)return false;
}
/*
000
000
0*0
*/
if((j == 2 || j == 5 || j == 8) && (i == 3 || i == 6 || i == 9))
{
if(board[i][j-1] == p || board[i][j+1] == p || board[i-1][j] == p ||
board[i-1][j+1] == p || board[i-1][j-1] == p || board[i-2][j] == p ||
board[i-1][j+1] == p || board[i-2][j-1] == p) return false;
}
/*
00*
000
000
*/
if((j == 3 || j == 6 || j == 9) && (i == 1 || i == 4 || i == 7))
{
if(board[i][j-1] == p || board[i][j-2] == p || board[i+1][j] == p ||
board[i+1][j-1] == p || board[i+1][j-2] == p || board[i+2][j] == p ||
board[i+2][j-1] == p || board[i+2][j-2] == p) return false;
}
/*
000
00*
000
*/
if((j == 3 || j == 6 || j == 9) && (i == 2 || i == 5 || i == 8))
{
if(board[i-1][j] == p || board[i-1][j-1] == p || board[i-1][j-2] == p ||
board[i][j-1] == p || board[i][j-2] == p || board[i+1][j] == p ||
board[i+1][j-1] == p || board[i+1][j-2] == p) return false;
}
/*
000
000
00*
*/
if((j == 3 || j == 6 || j == 9) && (i == 3 || i == 6 || i == 9))
{
if(board[i][j-1] == p || board[i][j-1] == p || board[i-1][j] == p ||
board[i-1][j-1] == p || board[i-1][j-2] == p || board[i-2][j] == p ||
board[i-2][j-1] == p || board[i-2][j-2] == p) return false;
}
return true;
}
void Sudoku::Help_Solve(int i, int j)
{
if(j <= 0)
{
i = i-1;
j = 9;
}
if(change[i][j] == 1) return Game.Help_Solve(i, j-1);
for(int p = 1; p <= 9; p++)
if(Game.Check_Conflicts(p, i, j))
{
board[i][j] = p;
return;
}
return Game.Help_Solve(i, j-1);
}
void Sudoku::Solve()
{
for(int i = 1; i <= 9; i++)
{
for(int j = 1; j <= 9; j++)
{
if(board[i][j] == 0 && change[i][j] == 0)
{
Game.Help_Solve(i, j);
}
}
}
for(int i = 1; i <= 9; i++)
for(int j = 1; j <= 9; j++)
if(board[i][j] == 0) Game.Help_Solve(i, j);
}
int main()
{
Game.Add_First_Cord();
Game.Solve();
Game.Print_Board();
system("pause");
return 0;
}
Edit: I need to use recursion right? But maybe the parameters I give to the function are wrong. I really don't know. In Add_First_Cord() I declare the starting values that every sudoku has in the beginning. Here are the values that I use: http://bg.wikipedia.org/wiki/%D0%A4%D0%B0%D0%B9%D0%BB:Sudoku-by-L2G-20050714.gif. I expect to see the solved sudoku as it is shown in wikipedia. But some solved values are right others are not. Here is what I get in the console
Suggested Approach
Implement a generic graph search algorithm
could use either IDFS or A* graph search
I would prefer the second
do this for a general directed graph
node type TNode
node successor function TNode => vector<TNode>
Define your Sudoku states
a state is a 9x9 array with a number 1, 2, ..., or 9 or a blank in each position
Define what a goal Sudoku state is
all 81 cells filled in
all 9 rows have numbers {1, 2, ..., 9} in them
all 9 columns have numbers {1, 2, ..., 9} in them
all 9 3x3 squares have numbers {1, 2, ..., 9} in them
Define your valid Sudoku state successor function
a state S can have number N added at row I, column J if:
cell (I,J) is empty
there is no other N in row I
there is no other N in column J
there is no other N in the 3x3 square containing (I,J)
the state successor function maps a state S to the vector of states that satisfy these rules
Apply your generic graph search algorithm (1) to the Sudoku state graph (2-4)
(optional) If you do choose to use A* graph search, you can also define a heuristic on your Sudoku state space to potentially drastically increase performance
how to design the heuristic is another whole problem, that's more of an art than a science
Current Approach
Your current approach mixes the specification of the graph to be searched and the implementation of the search algorithm. You're going to have a lot of difficulty if you mix those two. This problem naturally separates into two distinct pieces -- the algorithm and the graph -- so you can and should exploit that in your implementation. It will make it much simpler.
The other benefit you get if you go with this separation is that you will be able to reuse your graph search algorithm on a huge number of problems - very cool!
The following assumes you are trying to solve a given board, not generate a puzzle.
Basic (simple) approach
Create a class whose objects can hold a board (here called board_t). This class may internally use array, but must support copying boards.
Have a function void solve(board_t const& board); which repeats the following for each number n:
Copies your input
Enters n in the first empty cell of the copied board
If the copied board is a solution, print the solution and return.
Else If the board is still viable (e.g. no conflicts):
call solve(copied_board)
Performance
This is a recursive backtracking solution, which performs horribly for hard problems. You can significantly speed it up by proper pruning or deductive steps (e.g. if you end up with 8 numbers in a row after inserting one, you can immediately enter the ninth without any kind of search).
Reasoning
While certainly not an impressive technique, it has a high probability of working correctly, since you will only ever be modifying a copy to add a single value. This prevents corruption of your data structures (one problem your idea has is that it will destroy the numbers it finds when backtracking, are not necessarily the ones you just inserted, but may be part of the initial puzzle).
Improving performance is quite simple, once you start picking more intelligent heuristics (e.g. instead of testing the square in order, you could pick the ones with the fewest remaining moves and try to get them out of the way - or do the reverse...) or start doing a bit of deduction and pruning.
Note: The Algorithm Design Manual uses a Soduko solver to show the impact of these techniques on backtracking.
There is one very important modification to recursive algorithms: Use most constrained first approach. This means first to solve a cell with smallest number of possible candidates (when direct row/column/block conflicts are removed).
Another modification is: Change the board in-place; do not copy it. In each recursive call you modify only one cell on the board, and that cell used to be empty. If that call doesn't end up in a solved board somewhere down the recursive call tree, just clear the cell again before returning - this returns the board into original state.
You can find a very short and fast solution in C# on address: Sudoku Solver. It solves arbitrary sudoku board in about 100 steps only, all thanks to the most constrained first heuristic.
This is a classic Constraint Satisfaction Problem. I recommend doing some research on the topic to figure out the successful strategy. You will need to use AC-3 ( Arc Consistency 3) algorithm along with the backtracking techniques to solve the problem.