很菜的Sodoku Solver
其实是模拟了手工填写数独的方法,用的排除法。这个代码的不足在于没有怎么规划,其实board::pencilMark()完全可以做成按行、列、正方形顺序将所有的方格的pencil mark全部填好。稍加改动,可以解16*16或8*8的数独。
-
using namespace std;
-
-
class cell
-
{
-
private:
-
int number;
-
int pencil;
-
public:
-
bool getPencil(int num);
-
bool setPencil(int num);
-
bool isHavingPencil(void);
-
int getAllPencil(void);
-
bool erasePencil(int num);
-
int getNumber(void);
-
bool fillNumber(int num);
-
bool initCell(int num);
-
bool clearPencil(void);
-
protected:
-
};
-
-
bool cell::getPencil(int num)
-
{
-
return (pencil & (1<<num))?true:false;
-
}
-
-
bool cell::setPencil(int num)
-
{
-
if(!num)
-
return true;
-
if(pencil & (1<<num))
-
;
-
else
-
pencil += (1<< num);
-
return true;
-
}
-
-
bool cell::isHavingPencil(void)
-
{
-
return pencil?true:false;
-
}
-
-
int cell::getAllPencil(void)
-
{
-
return pencil;
-
}
-
-
bool cell::erasePencil(int num)
-
{
-
if(!num) //Meet zero
-
return true;
-
if(pencil & (1 << num))
-
pencil -= 1<< num;
-
return true;
-
}
-
-
int cell::getNumber(void)
-
{
-
return number;
-
}
-
-
bool cell::fillNumber(int num)
-
{
-
number = num;
-
clearPencil();
-
return true;
-
}
-
-
bool cell::initCell(int num)
-
{
-
number = num;
-
pencil = num?0:((1 << 10) - 2);
-
return true;
-
}
-
-
bool cell::clearPencil(void)
-
{
-
pencil = 0;
-
return true;
-
}
-
-
class board
-
{
-
private:
-
cell boardCells[10][10];
-
int blankCell;
-
int cellSolved;
-
public:
-
bool solveOneStep(void);
-
bool pencilMark(int x, int y);
-
bool decideNumber(void);
-
void printBoard(void);
-
bool readCell(void);
-
protected:
-
-
};
-
-
void getSquare(const int x, const int y, int & left, int & top)
-
{
-
static int coordinates[]={0,1,1,1,4,4,4,7,7,7};
-
left = coordinates[x];
-
top = coordinates[y];
-
return;
-
}
-
-
bool board::pencilMark(int x, int y) //True for having pencil mark, false for not.
-
{
-
int linearPointer, sqLinePointer, sqColumnPointer, sqLeft, sqTop;
-
int reading;
-
-
if(!(boardCells[x][y].getNumber())) //Blank Cell.
-
{
-
boardCells[x][y].initCell(0); //Initialize pencil marks.
-
//Line
-
for(linearPointer = 1; linearPointer <= 9; linearPointer ++)
-
{
-
if (linearPointer == y)
-
continue;
-
reading = boardCells[x][linearPointer].getNumber();
-
if (reading)
-
boardCells[x][y].erasePencil(reading);
-
}
-
-
//Column
-
for(linearPointer = 1; linearPointer <= 9; linearPointer ++)
-
{
-
if (linearPointer == x)
-
continue;
-
reading = boardCells[linearPointer][y].getNumber();
-
if (reading)
-
boardCells[x][y].erasePencil(reading);
-
}
-
-
//Square
-
getSquare(x, y, sqLeft, sqTop);
-
for(sqLinePointer = 0; sqLinePointer < 3; sqLinePointer ++)
-
{
-
if (x - sqLeft == sqLinePointer)
-
continue;
-
for(sqColumnPointer = 0; sqColumnPointer < 3; sqColumnPointer ++)
-
{
-
if(y - sqTop == sqColumnPointer)
-
continue;
-
reading = boardCells[sqLeft + sqLinePointer][sqTop + sqColumnPointer].getNumber();
-
if(reading)
-
boardCells[x][y].erasePencil(reading);
-
}
-
}
-
}
-
else
-
return true;
-
return boardCells[x][y].isHavingPencil();
-
}
-
-
bool board::decideNumber(void) //True for progress, false for no.
-
{
-
int x, y, marks;
-
bool retlog;
-
-
cellSolved = 0;
-
-
//Calculate pencil marks.
-
for(x = 1; x <= 9; x++)
-
{
-
for(y = 1; y <= 9; y++)
-
{
-
retlog = pencilMark(x, y);
-
if(!retlog)
-
goto noSolution;
-
}
-
}
-
-
//Search for single pencil mark.
-
for(x = 1; x <= 9; x++)
-
{
-
for(y = 1; y<= 9; y++)
-
{
-
if(boardCells[x][y].getNumber()) //Already have number
-
continue;
-
marks = boardCells[x][y].getAllPencil();
-
if(!(marks & (marks - 1))) // Only have one number.
-
{
-
switch(marks)
-
{
-
case 2:
-
boardCells[x][y].initCell(1);break;
-
case 4:
-
boardCells[x][y].initCell(2);break;
-
case 8:
-
boardCells[x][y].initCell(3);break;
-
case 16:
-
boardCells[x][y].initCell(4);break;
-
case 32:
-
boardCells[x][y].initCell(5);break;
-
case 64:
-
boardCells[x][y].initCell(6);break;
-
case 128:
-
boardCells[x][y].initCell(7);break;
-
case 256:
-
boardCells[x][y].initCell(8);break;
-
case 512:
-
boardCells[x][y].initCell(9);break;
-
default:
-
cout << "ERROR! ";
-
}
-
blankCell--;
-
cellSolved++;
-
}
-
}
-
}
-
if(cellSolved)
-
return true;
-
-
int searchNum;
-
int markCount;
-
int lastPos, lastSqX, lastSqY;
-
int linearIndex, sqRowIndex, sqColumnIndex, sqLeft, sqTop;
-
//Search for only candidates.
-
-
//By Row
-
for(x = 1; x <= 9; x++)
-
{
-
for(searchNum = 1; searchNum <= 9; searchNum ++)
-
{
-
markCount = 0;
-
lastPos = 0;
-
for(linearIndex = 1; linearIndex <= 9; linearIndex++)
-
{
-
if(boardCells[x][linearIndex].getPencil(searchNum))
-
{
-
markCount ++;
-
lastPos = linearIndex;
-
}
-
}
-
if(markCount == 1)
-
{
-
boardCells[x][lastPos].initCell(searchNum);
-
goto foundSolution;
-
}
-
}
-
}
-
-
//By Column
-
for(y = 1; y <= 9; y++)
-
{
-
for(searchNum = 1; searchNum <= 9; searchNum ++)
-
{
-
markCount = 0;
-
lastPos = 0;
-
for(linearIndex = 1; linearIndex <= 9; linearIndex++)
-
{
-
if(boardCells[linearIndex][y].getPencil(searchNum))
-
{
-
markCount ++;
-
lastPos = linearIndex;
-
}
-
}
-
if(markCount == 1)
-
{
-
boardCells[lastPos][y].initCell(searchNum);
-
goto foundSolution;
-
}
-
}
-
}
-
-
//By Square
-
for(sqLeft = 1; sqLeft < 9; sqLeft += 3)
-
{
-
for(sqTop = 1; sqTop < 9; sqTop += 3)
-
{
-
for(searchNum = 1; searchNum <= 9; searchNum ++)
-
{
-
markCount = 0;
-
lastSqX = 0, lastSqY = 0;
-
for(sqRowIndex = 0; sqRowIndex < 3; sqRowIndex ++)
-
{
-
for(sqColumnIndex = 0; sqColumnIndex < 3; sqColumnIndex++)
-
{
-
if(boardCells[sqLeft + sqRowIndex][sqTop + sqColumnIndex].getPencil(searchNum))
-
{
-
markCount ++;
-
lastSqX = sqRowIndex, lastSqY = sqColumnIndex;
-
}
-
}
-
}
-
if(markCount == 1)
-
{
-
boardCells[sqLeft + lastSqX][sqTop + lastSqY].initCell(searchNum);
-
goto foundSolution;
-
}
-
}
-
}
-
}
-
-
if(blankCell) //Not solved yet.
-
cout << "Cannot solve. " << endl;
-
return false;
-
-
foundSolution:
-
cellSolved ++;
-
blankCell --;
-
return true;
-
-
noSolution:
-
cout << "No Solution!!" << endl;
-
return false;
-
-
}
-
-
bool board::solveOneStep(void)
-
{
-
int x, y;
-
for(x = 1; x <= 9; x++)
-
for(y = 1; y<= 9; y++)
-
pencilMark(x,y);
-
return decideNumber();
-
}
-
-
bool board::readCell(void)
-
{
-
int x, y, recv;
-
blankCell = 0;
-
for(x = 1; x <= 9; x++)
-
for(y = 1; y <= 9; y++)
-
{
-
cin >> recv;
-
boardCells[x][y].initCell(recv);
-
if(recv==0)
-
blankCell++;
-
}
-
return true;
-
}
-
-
void board::printBoard(void)
-
{
-
int x, y, num;
-
num = 0;
-
for(x = 1; x <= 9; x++)
-
{
-
for(y = 1; y <= 9; y++)
-
{
-
num = boardCells[x][y].getNumber();
-
cout << " " << num;
-
}
-
cout << "\n";
-
}
-
}
-
-
int _tmain(void)
-
{
-
board game;
-
int counter = 0;
-
-
cout << "VIKTOR\'S SODUKU SOLVER VER 1.00A SEPT 7, 2008\n";
-
cout << "Input soduku, 0 for blank\n";
-
-
game.readCell();
-
cout << "Your initial soduku is: \n\n";
-
game.printBoard();
-
-
while(game.solveOneStep())
-
{
-
counter ++;
-
/*DEBUG CODE
-
cout << "The " << counter << " step of soduku is: \n\n";
-
game.printBoard();
-
*/
-
}
-
-
cout << "Your soduku is solved after " << counter << " steps as follows: \n" ;
-
game.printBoard();
-
-
return 0;
-
}
-
-