我最近一直在用c ++开发数独游戏。我使用SFML制作了它的图形版本,它运行得很好。但是,我需要实现一个解决数独的算法,而不是一个强力算法(所以回溯对我来说不起作用; /)。我已经阅读了许多方法来解决它,并且我遇到了不同的算法名称(例如Dancing Links),以及仅描述搜索如何工作而不提供任何特定信息的算法用c ++实现它。 (即为每个单独的"桶"分配一个表或一个可能的数字列表,并搜索解决方案,还有人提到所谓的A *算法?)
所以这是我的问题,什么样的算法相当容易实现,不回溯?哪里可以找到有关如何在c ++中使用它的具体信息?提前致谢。 我的程序在一个二维数组上工作,但如果需要,我可以以某种方式将桶变成结构。
答案 0 :(得分:2)
Peter Norvig建议使用消除过程(约束传播),然后搜索。他的文章here提供了非常详尽的解释。
在约束传播中,您使用以下策略:
(1) If a square has only one possible value, then eliminate that value from the square's peers.
(2) If a unit has only one possible place for a value, then put the value there.
现在,在 O(N)时间内很容易找到拼图中最初填充的正方形。将它们全部放入队列中。如果它们的邻居在传播约束后只有一个值,则将其添加到队列中。重复,直到队列为空。
现在要解决这个难题,或者通过传播约束不能取得进一步的进展。
如果拼图没有解决,您可以使用更高级的算法,或者像Norvig建议的那样,使用回溯。由于回溯是在拼图空间的一个典型小部分上进行的,因此您不会使用蛮力。
答案 1 :(得分:1)
说明
矿井数独以 2D 数组9x9
的形式存储,该数组由32位无符号整数组成,其中每一位都有自己的用途。低10位保留给已放置的数字(使用9位),下10位保留给可能的数字(可以放置在此处...尚未排除),最后一位告诉其固定单元格,而一位告诉是否存在错误(与另一个单元冲突)。
您可以想象我的代码归结为一堆二进制操作...这本身带来了一些问题,但解决了其他问题...
求解器
正如评论中提到的,我为此使用规则和确定性方法(无回溯)。该算法是这样的:
术语和约定
董事会的地址:
x = <0,9)
y = <0,9)
现在规则:
单个字符在row / col / sqr中必须唯一
因此,如果我们得到的单元格只有一个放置的值,则不可能再有另一个这样的值出现在相同的row / col / sqr中,因此请像下面的示例一样清除它:
如果我们得到的单元格只剩下一个可能的数字
这很简单,如果我们从其他规则中清除了足够多的数字,有时我们将只有一个选择。一旦检测到,将其放置并完成细胞...
仅在单个正方形的单行/行中具有相同的可能数字
如果找到,请清除其他正方形的行/列,因为它们不能再放置该数字。
在单行/ col / sqr中发现相同的配对
如果检测到,则清除其余部分。请注意,配对必须完全相同(单元中可能没有其他可能的数字)
此规则可以扩展为3个三元组,但从未见过这样做的机会,因为基本规则之前已经解决了它们,而且概率很小...
以下是 C ++ / VCL 的小代码(规则4尚未实现):
//---------------------------------------------------------------------------
#ifndef _sudoku_h
#define _sudoku_h
//---------------------------------------------------------------------------
// set numbers
const DWORD _sudoku_1 =(1<< 0); // set numbers (used)
const DWORD _sudoku_a1 =(1<<10); // possible numbers (unused)
const DWORD _sudoku_fix =(1<<20); // read only?
const DWORD _sudoku_err =(1<<21); // error?
const DWORD _sudoku_2=(_sudoku_1<<1);
const DWORD _sudoku_3=(_sudoku_1<<2);
const DWORD _sudoku_4=(_sudoku_1<<3);
const DWORD _sudoku_5=(_sudoku_1<<4);
const DWORD _sudoku_6=(_sudoku_1<<5);
const DWORD _sudoku_7=(_sudoku_1<<6);
const DWORD _sudoku_8=(_sudoku_1<<7);
const DWORD _sudoku_9=(_sudoku_1<<8);
const DWORD _sudoku_n=_sudoku_1|_sudoku_2|_sudoku_3|_sudoku_4|_sudoku_5|_sudoku_6|_sudoku_7|_sudoku_8|_sudoku_9;
const DWORD _sudoku_a2=(_sudoku_a1<<1);
const DWORD _sudoku_a3=(_sudoku_a1<<2);
const DWORD _sudoku_a4=(_sudoku_a1<<3);
const DWORD _sudoku_a5=(_sudoku_a1<<4);
const DWORD _sudoku_a6=(_sudoku_a1<<5);
const DWORD _sudoku_a7=(_sudoku_a1<<6);
const DWORD _sudoku_a8=(_sudoku_a1<<7);
const DWORD _sudoku_a9=(_sudoku_a1<<8);
const DWORD _sudoku_an=_sudoku_a1|_sudoku_a2|_sudoku_a3|_sudoku_a4|_sudoku_a5|_sudoku_a6|_sudoku_a7|_sudoku_a8|_sudoku_a9;
//---------------------------------------------------------------------------
class sudoku
{
public:
DWORD map[9][9];
Graphics::TBitmap *bmp;
bool _redraw,_render_an;
int x0,y0; // grid start
int x1,y1; // grid end
int sz; // grid size
int yb; // y of buttons panel
int selx,sely,selb; // mouse selection
TShiftState sh0;
int _debug_N;
sudoku();
sudoku(sudoku& a) { *this=a; }
~sudoku();
sudoku* operator = (const sudoku *a) { *this=*a; return this; }
// sudoku* operator = (const sudoku &a) { ...copy... return this; }
// GUI/interface
void init(int *S); // init with linear mapped 1D array 0 is empty space, 1..9 is fixed cell
void draw();
void resize(int xs,int ys);
void mouse(int mx,int my,TShiftState sh);
void key(WORD key,TShiftState sh);
void load(AnsiString filename);
void save(AnsiString filename);
void set(int x,int y,DWORD m); // set map[x][y]|=m
void rst(int x,int y,DWORD m); // clear map[x][y]-=m
void xor(int x,int y,DWORD m); // xor map[x][y]^=m
// solver
void s_init(); // reset/init state from fixed cells only
void s_check(); // check for errors
void solve(); // solve the puzzle from scratch
};
//---------------------------------------------------------------------------
sudoku::sudoku()
{
int i,j;
_render_an=false;
_redraw=false;
selx=-1;
sely=-1;
selb=-1;
bmp=new Graphics::TBitmap;
for (i=0;i<9;i++)
for (j=0;j<9;j++)
map[i][j]=0;
}
//---------------------------------------------------------------------------
sudoku::~sudoku()
{
if (bmp) delete bmp; bmp=NULL;
}
//---------------------------------------------------------------------------
void sudoku::init(int *S)
{
int x,y,a;
for (a=0,y=0;y<9;y++)
for (x=0;x<9;x++,a++)
if (S[a]) map[x][y]=(_sudoku_1<<(S[a]-1))|_sudoku_fix;
else map[x][y]=0;
s_init();
_debug_N=0;
}
//---------------------------------------------------------------------------
void sudoku::draw()
{
if (bmp==NULL) return;
AnsiString s;
int i,j,k,x,y;
DWORD a;
// clear
bmp->Canvas->Brush->Color=clLtGray;
bmp->Canvas->Brush->Style=bsSolid;
bmp->Canvas->FillRect(Rect(0,0,bmp->Width,bmp->Height));
bmp->Canvas->Brush->Color=clWhite;
bmp->Canvas->FillRect(Rect(x0,y0,x1,y1));
// selection
if ((selx>=0)&&(selx<9))
if ((sely>=0)&&(sely<9))
{
x=x0+(selx*sz);
y=y0+(sely*sz);
bmp->Canvas->Brush->Color=clSilver;
bmp->Canvas->FillRect(Rect(x,y,x+sz,y+sz));
}
// buttons
bmp->Canvas->Pen ->Width=2;
bmp->Canvas->Brush->Color=clWhite;
bmp->Canvas->FillRect(Rect(x0,yb,x1,yb+sz));
if ((selb>=0)&&(selb<9))
{
x=x0+(selb*sz);
bmp->Canvas->Brush->Color=clDkGray;
bmp->Canvas->FillRect(Rect(x,yb,x+sz,yb+sz));
}
for (j=0,i=0;i<=9;i++,j+=sz)
{
bmp->Canvas->MoveTo(x0+j,yb);
bmp->Canvas->LineTo(x0+j,yb+sz);
}
bmp->Canvas->MoveTo(x0,yb);
bmp->Canvas->LineTo(x1,yb);
bmp->Canvas->MoveTo(x0,yb+sz);
bmp->Canvas->LineTo(x1,yb+sz);
// major grid
bmp->Canvas->Pen ->Color=clBlack;
for (j=0,i=0;i<=3;i++,j+=3*sz)
{
bmp->Canvas->MoveTo(x0,y0+j);
bmp->Canvas->LineTo(x1,y0+j);
bmp->Canvas->MoveTo(x0+j,y0);
bmp->Canvas->LineTo(x0+j,y1);
}
// minor grid
bmp->Canvas->Pen ->Width=1;
for (j=0,i=0;i<9;i++,j+=sz)
{
bmp->Canvas->MoveTo(x0,y0+j);
bmp->Canvas->LineTo(x1,y0+j);
bmp->Canvas->MoveTo(x0+j,y0);
bmp->Canvas->LineTo(x0+j,y1);
}
// big numbers
bmp->Canvas->Brush->Style=bsClear;
bmp->Canvas->Font->Height=sz-4;
for (i=0;i<9;i++)
for (j=0;j<9;j++)
{
a=map[i][j]; if (_render_an) a>>=10; a&=_sudoku_n; if (!a) continue;
if (DWORD(map[i][j]&_sudoku_err)!=0) bmp->Canvas->Font->Color=clRed;
else if (DWORD(map[i][j]&_sudoku_fix)!=0) bmp->Canvas->Font->Color=clBlack;
else bmp->Canvas->Font->Color=clBlue;
for (k=0;k<9;k++)
if (a==(_sudoku_1<<k))
{
s=k+1;
x=x0+(i*sz)+((sz-bmp->Canvas->TextWidth (s))>>1);
y=y0+(j*sz)+((sz-bmp->Canvas->TextHeight(s))>>1);
bmp->Canvas->TextOutA(x,y,s);
break;
}
}
// small numbers
bmp->Canvas->Brush->Style=bsClear;
i=(sz-4)/3;
const int dx[9]={-i,0,+i,-i,0,+i,-i,0,+i};
const int dy[9]={+i,+i,+i,0,0,0,-i,-i,-i};
bmp->Canvas->Font->Height=i;
for (i=0;i<9;i++)
for (j=0;j<9;j++)
{
a=map[i][j]; if (_render_an) a>>=10; a&=_sudoku_n; if (!a) continue;
for (k=0;k<9;k++) if (a==(_sudoku_1<<k)) { k=-1; break; } if (k<0) continue;
if (DWORD(map[i][j]&_sudoku_fix)!=0) bmp->Canvas->Font->Color=clBlack;
else if (DWORD(map[i][j]&_sudoku_err)!=0) bmp->Canvas->Font->Color=clRed;
else bmp->Canvas->Font->Color=clBlue;
for (k=0;k<9;k++)
if (DWORD(a&(_sudoku_1<<k))!=0)
{
s=k+1;
x=x0+(i*sz)+((sz-bmp->Canvas->TextWidth (s))>>1)+dx[k];
y=y0+(j*sz)+((sz-bmp->Canvas->TextHeight(s))>>1)+dy[k];
bmp->Canvas->TextOutA(x,y,s);
}
}
// info
x=5; y=5; i=20; y-=i;
bmp->Canvas->Font->Color=clBlack;
bmp->Canvas->TextOutA(x,y+=i,AnsiString().sprintf("N:%i",_debug_N));
bmp->Canvas->TextOutA(x,y+=i,AnsiString().sprintf("%ix%i",selx,sely));
if (_render_an) bmp->Canvas->TextOutA(x,y+=i,"an");
// button numbers
bmp->Canvas->Font->Height=sz-4;
a=0;
if ((selx>=0)&&(selx<9))
if ((sely>=0)&&(sely<9))
a=map[selx][sely]&_sudoku_n;
for (i=0;i<9;i++)
{
s=i+1;
x=x0+(i*sz)+((sz-bmp->Canvas->TextWidth (s))>>1);
y=yb +((sz-bmp->Canvas->TextHeight(s))>>1);
if (DWORD(a&(_sudoku_1<<i))!=0) bmp->Canvas->Font->Color=clBlack;
else bmp->Canvas->Font->Color=clLtGray;
bmp->Canvas->TextOutA(x,y,s);
}
bmp->Canvas->Brush->Style=bsSolid;
}
//---------------------------------------------------------------------------
void sudoku::resize(int xs,int ys)
{
bmp->SetSize(xs,ys);
_redraw=true;
int w=8;
x0=(xs-w-w )/ 9;
y0=(ys-w-w-w)/10;
sz=x0; if (sz>y0) sz=y0;
x0=(xs-( 9*sz))/2;
y0=(ys-(10*sz)-w)/2;
x1=x0+(9*sz);
y1=y0+(9*sz);
yb=y1+w;
}
//---------------------------------------------------------------------------
void sudoku::mouse(int mx,int my,TShiftState sh)
{
int q0=sh0.Contains(ssLeft);
int q1=sh .Contains(ssLeft);
if ((mx< x0)||(mx>=x1)) return;
if ((my>=y0)&&(my< y1))
if ((!q0)&&(q1))
{
selx=(mx-x0)/sz;
sely=(my-y0)/sz;
_redraw=true;
}
if ((my>=yb)&&(my< yb+sz))
{
selb=(mx-x0)/sz;
_redraw=true;
if ((!q0)&&(q1))
if ((selx>=0)&&(selx<9))
if ((sely>=0)&&(sely<9))
xor(selx,sely,_sudoku_1<<selb);
}
else{
_redraw|=selb!=-1;
selb=-1;
}
sh0=sh;
}
//---------------------------------------------------------------------------
void sudoku::key(WORD key,TShiftState sh)
{
// toggle (un)used number
int a=-1;
if ((key>='1')&&(key<='9')) a=key-'1'; // 0..9
if ((key>=97)&&(key<=105)) a=key-97; // num0..num9
if (a>=0)
if ((selx>=0)&&(selx<9))
if ((sely>=0)&&(sely<9))
{
if (_render_an) a+=10;
xor(selx,sely,_sudoku_1<<(a));
}
// navigate selection cell
if ((key>=37)&&(key<=40)) // arrows
{
if (key==37) { selx--; _redraw=true; }
if (key==39) { selx++; _redraw=true; }
if (key==38) { sely--; _redraw=true; }
if (key==40) { sely++; _redraw=true; }
if (selx<0) selx=0; if (selx>8) selx=8;
if (sely<0) sely=0; if (sely>8) sely=8;
}
if (key== 27) { _redraw=true; selx=-1; sely=-1; } // esc clear selection
if (key== 32) { solve(); } // space apply solving rules
if (key==112) { _redraw=true; _render_an=!_render_an; } // F1 used/unused numbers mode
if (key==113) { _redraw=true; save("map000.dat"); } // F2 save
if (key==116) { _redraw=true; load("map000.dat"); } // F5 load
if (key==119) { _redraw=true; s_init(); } // F8 restart
// debug
if (key==107) { _debug_N++; solve(); } // num+
if (key==109) { _debug_N--; solve(); } // num-
}
//---------------------------------------------------------------------------
void sudoku::load(AnsiString filename)
{
int hnd,x,y;
hnd=FileOpen(filename,fmOpenRead);
if (hnd<0) return;
for (x=0;x<9;x++)
for (y=0;y<9;y++)
FileRead(hnd,&map[x][y],sizeof(map[0][0]));
FileClose(hnd);
_redraw=true;
}
//---------------------------------------------------------------------------
void sudoku::save(AnsiString filename)
{
int hnd,x,y;
hnd=FileCreate(filename);
if (hnd<0) return;
for (x=0;x<9;x++)
for (y=0;y<9;y++)
FileWrite(hnd,&map[x][y],sizeof(map[0][0]));
FileClose(hnd);
}
//---------------------------------------------------------------------------
void sudoku::set(int x,int y,DWORD m)
{
if ((x<0)||(x>=9)||(y<0)||(y>=9)) return;
if (DWORD(map[x][y]&m)!=0) return;
if (DWORD(map[x][y]&_sudoku_fix)!=0) return;
map[x][y]|=m;
s_check();
_redraw=true;
}
//---------------------------------------------------------------------------
void sudoku::rst(int x,int y,DWORD m)
{
if ((x<0)||(x>=9)||(y<0)||(y>=9)) return;
if (DWORD(map[x][y]&m==0)) return;
if (DWORD(map[x][y]&_sudoku_fix)!=0) return;
map[x][y]|=m;
map[x][y]^=m;
s_check();
_redraw=true;
}
//---------------------------------------------------------------------------
void sudoku::xor(int x,int y,DWORD m)
{
if ((x<0)||(x>=9)||(y<0)||(y>=9)) return;
if (DWORD(map[selx][sely]&m)==0) set(selx,sely,m);
else rst(selx,sely,m);
}
//---------------------------------------------------------------------------
void sudoku::s_init()
{
int x,y;
DWORD a,b;
for (x=0;x<9;x++)
for (y=0;y<9;y++)
{
a=map[x][y];
if (DWORD(a&_sudoku_fix)==0) a =_sudoku_an;
else { a&=_sudoku_n|_sudoku_fix; a|=(a<<10)&_sudoku_an; }
map[x][y]=a;
}
s_check();
_redraw=true;
}
//---------------------------------------------------------------------------
void sudoku::s_check()
{
int x,y,_x,_y,xx,yy,k,n[10];
DWORD a,b,m[9][9];
// iterate xx,yy through adjacent cells to x,y (included)
#define row(y) for (yy=y,xx=0;xx<9;xx++)
#define col(x) for (xx=x,yy=0;yy<9;yy++)
#define sqr(x,y) for (_x=(x/3)*3,_y=(y/3)*3,xx=_x;xx<_x+3;xx++) for (yy=_y;yy<_y+3;yy++)
// init m[][] with singleton used numbers from map[][] and clear error
for (x=0;x<9;x++ ) for (y=0;y<9;y++ ){ m[x][y]=0; a=map[x][y]&_sudoku_n; map[x][y]&=0xFFFFFFFF^_sudoku_err; for (b=_sudoku_1,k=1;k<=9;k++,b<<=1) if (a==b) m[x][y]=k; }
// compute histogram n[] // check for error (count>1) and flag it for rendering
for (y=0;y<9;y++ ){ for (xx=0;xx<=9;xx++) n[xx]=0; row( y) n[m[xx][yy]]++; n[0]=0; row( y) if (n[m[xx][yy]]>1) map[xx][yy]|=_sudoku_err; }
for (x=0;x<9;x++ ) { for (xx=0;xx<=9;xx++) n[xx]=0; col(x ) n[m[xx][yy]]++; n[0]=0; col(x ) if (n[m[xx][yy]]>1) map[xx][yy]|=_sudoku_err; }
for (x=0;x<9;x+=3) for (y=0;y<9;y+=3){ for (xx=0;xx<=9;xx++) n[xx]=0; sqr(x,y) n[m[xx][yy]]++; n[0]=0; sqr(x,y) if (n[m[xx][yy]]>1) map[xx][yy]|=_sudoku_err; }
#undef row
#undef col
#undef sqr
}
//---------------------------------------------------------------------------
void sudoku::solve()
{
int k,n[9],nx[9],ny[9];
DWORD a,b;
int x,y,_x,_y,xx,yy;
DWORD checksum0,checksum;
// is a single bit set from _sudoku1.._sudoku_9?
#define single(a) for (b=_sudoku_1;b<=_sudoku_9;b<<=1) if (a==b)
// iterate xx,yy through adjacent cells to x,y (included)
#define row(y) for (yy=y,xx=0;xx<9;xx++)
#define col(x) for (xx=x,yy=0;yy<9;yy++)
#define sqr(x,y) for (_x=(x/3)*3,_y=(y/3)*3,xx=_x;xx<_x+3;xx++) for (yy=_y;yy<_y+3;yy++)
s_init();
// solve main loop
for (checksum0=0,_debug_N=0;;_debug_N++)
{
// compute checksum and stop if not changed
for (checksum=0,a=1,x=0;x<9;x++)
for (y=0;y<9;y++,a++)
checksum+=map[x][y]&(_sudoku_n|_sudoku_an)*a;
if (checksum==checksum0) break;
checksum0=checksum;
// #1 clear singleton used numbers in (un)used numbers of adjacent cells
for (x=0;x<9;x++)
for (y=0;y<9;y++)
{
a=map[x][y]&_sudoku_n;
single(a)
{
b=a<<10;
map[x][y]&=0xFFFFFFFF^_sudoku_an;
map[x][y]|=b;
b^=0xFFFFFFFF;
row( y) if (xx!=x) map[xx][yy]&=b;
col(x ) if (yy!=y) map[xx][yy]&=b;
sqr(x,y) if ((xx!=x)||(yy!=y)) map[xx][yy]&=b;
break;
}
}
// #2 find if just single occurence in adjacent cells
// clear histogram n[] compute histogram n[] // handle single occurence by clearing all other adjacent cells
for (y=0;y<9;y++ ){ for (xx=0;xx<9;xx++) n[xx]=0; row( y) { a=map[xx][yy]; a=(a|(a>>10))&_sudoku_n; for (b=0;b<9;b++) if (DWORD(a&(_sudoku_1<<b))!=0) { n[b]++; nx[b]=xx; ny[b]=yy; }} for (b=_sudoku_1|_sudoku_a1,k=0;k<9;k++,b<<=1) if (n[k]==1) row( y) if (DWORD(map[xx][yy]&_sudoku_fix)==0) if ((xx==nx[k])&&(yy==ny[k])) map[xx][yy]&=0xFFFFFFFF^(_sudoku_n|_sudoku_an)^b; else map[xx][yy]&=0xFFFFFFFF^b; }
for (x=0;x<9;x++ ) { for (xx=0;xx<9;xx++) n[xx]=0; col(x ) { a=map[xx][yy]; a=(a|(a>>10))&_sudoku_n; for (b=0;b<9;b++) if (DWORD(a&(_sudoku_1<<b))!=0) { n[b]++; nx[b]=xx; ny[b]=yy; }} for (b=_sudoku_1|_sudoku_a1,k=0;k<9;k++,b<<=1) if (n[k]==1) col(x ) if (DWORD(map[xx][yy]&_sudoku_fix)==0) if ((xx==nx[k])&&(yy==ny[k])) map[xx][yy]&=0xFFFFFFFF^(_sudoku_n|_sudoku_an)^b; else map[xx][yy]&=0xFFFFFFFF^b; }
for (x=0;x<9;x+=3) for (y=0;y<9;y+=3){ for (xx=0;xx<9;xx++) n[xx]=0; sqr(x,y) { a=map[xx][yy]; a=(a|(a>>10))&_sudoku_n; for (b=0;b<9;b++) if (DWORD(a&(_sudoku_1<<b))!=0) { n[b]++; nx[b]=xx; ny[b]=yy; }} for (b=_sudoku_1|_sudoku_a1,k=0;k<9;k++,b<<=1) if (n[k]==1) sqr(x,y) if (DWORD(map[xx][yy]&_sudoku_fix)==0) if ((xx==nx[k])&&(yy==ny[k])) map[xx][yy]&=0xFFFFFFFF^(_sudoku_n|_sudoku_an)^b; else map[xx][yy]&=0xFFFFFFFF^b; }
// #3 if the same number only in single row/col for single square clear the row/col for other squares
for (x=0;x<9;x+=3)
for (y=0;y<9;y+=3)
{
// nx[],ny[] = histogram of x,y per each number
for (xx=0;xx<9;xx++) { nx[xx]=0; ny[xx]=0; } sqr(x,y) for (a=map[xx][yy],b=_sudoku_1|_sudoku_a1,k=0;k<9;k++,b<<=1) if (DWORD(a&b)!=0) { nx[k]|=1<<xx; ny[k]|=1<<yy; }
// check row/col for exclusive occurence and clear the rest if found
for (yy=y;yy<y+3;yy++) for (b=_sudoku_1|_sudoku_a1,k=0;k<9;k++,b<<=1) if (ny[k]==1<<yy) for (xx=0;xx<9;xx++) if ((xx<x)||(xx>=x+3)) map[xx][yy]&=0xFFFFFFFF^b;
for (xx=x;xx<x+3;xx++) for (b=_sudoku_1|_sudoku_a1,k=0;k<9;k++,b<<=1) if (nx[k]==1<<xx) for (yy=0;yy<9;yy++) if ((yy<y)||(yy>=y+3)) map[xx][yy]&=0xFFFFFFFF^b;
}
// #4 same pair only found in single row/col/sqr (clear the rest)
// [***ToDo***]
// set singleton unused numbers as used
for (x=0;x<9;x++)
for (y=0;y<9;y++)
{
a=(map[x][y]>>10)&_sudoku_n;
single(a)
{
map[x][y]&=0xFFFFFFFF^_sudoku_n;
map[x][y]|=a;
break;
}
}
}
s_check();
_redraw=true;
#undef single
#undef row
#undef col
#undef sqr
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
和用法:
//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include "sudoku.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
sudoku gam;
//---------------------------------------------------------------------------
void TForm1::draw()
{
if (gam._redraw) gam.draw();
Canvas->Draw(0,0,gam.bmp);
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
{
int S[9*9]=
{
8,0,0, 0,2,4, 0,0,3,
0,0,0, 0,0,0, 0,0,0,
0,4,0, 3,6,0, 0,0,0,
0,0,0, 0,0,0, 0,0,0,
4,6,0, 0,5,9, 0,0,8,
2,0,9, 0,0,8, 1,0,0,
3,0,0, 0,0,0, 6,0,0,
0,5,1, 7,0,0, 0,0,4,
0,9,0, 0,0,1, 3,0,0,
};
gam.init(S);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender) { draw(); }
void __fastcall TForm1::FormResize(TObject *Sender) { gam.resize(ClientWidth,ClientHeight); }
void __fastcall TForm1::tim_updTimer(TObject *Sender) { if (gam._redraw) draw(); }
void __fastcall TForm1::FormKeyDown (TObject *Sender, WORD &Key, TShiftState Shift){ gam.key(Key,Shift); }
void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X, int Y){ gam.mouse(X,Y,Shift); }
void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y){ gam.mouse(X,Y,Shift); }
void __fastcall TForm1::FormMouseUp (TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y){ gam.mouse(X,Y,Shift); }
//---------------------------------------------------------------------------
它的代码来自我的 VCL 应用程序(单个form
上带有单个timer
的应用程序),因此只需将事件移植到您的环境中,而忽略其余的事件。 sudoku类使用 VCL 封装的 GDI ,因此这是需要移植的内容(仅是矩形和文本线)。
求解器已完全包含在sudoku::solve()
中,并希望其注释足够(完全符合我上面的描述)。解决后的屏幕截图(空格键):
_debug_N
(N:7)保存解决方案所需的迭代次数。另外,我还没有做任何优化(看不到任何意义,因为求解器比我释放键要早得多)。希望这对某人有帮助。
还有很多其他规则要实现: