【原创】|日历拼图游戏的解决方案(C语言-进阶应用)-详解连载1_zhuyi8120的博客-CSDN博客
【原创】|日历拼图游戏的解决方案(C语言-进阶应用)-详解连载2_zhuyi8120的博客-CSDN博客
【原创】|日历拼图游戏的解决方案(C语言-进阶应用)-详解连载3_zhuyi8120的博客-CSDN博客
【原创】|源码全文-日历拼图游戏的解决方案(C语言-进阶应用)-详解连载5_zhuyi8120的博客-CSDN博客
上面是之前的内容,这些连载是一个整体。
今天(12月9日)的拼图
今天(12月9日)的计算
C语言实现6:比对方块和底盘
1、单次比对
单次比对方块和底盘是比较容易的。方法是:先定位好起始的比对点,一般是从(0,0)开始,然后在方块的长和宽方向顺次比较,如果遇到了方块和底盘都不是‘-’的情形,就用一个变量(counti)记录下来(counti++),然后,再通过比较这个变量(counti==0)来判断在这个定位点能否插入方块。
如果这个变量为0,即表示可以插入(counti==0为真),就记录下插入的方块的点和数据。
如果不能(counti>0),就转到下一个起始点,比如,从(0,0)转到(0,1)。
这项功能可以简单的用for循环完成的。
读者可以想一下,还有没有其他方法实现这样的特点。
2、在方块的搜索范围内的所有比对
图13:蓝色为可以插入A方块原始状态(不含其他变体)的所有起始点
在图12我们已经展示过搜索范围,即使已经有可以插入的点了,我们还是要继续完成搜索范围的所有可以插入的点,对于所有可以插入的点都记录下来。之所以要这样做,是为了解决整个问题的。因为在底盘插入了一些方块后,并不一定就可以插入后面的方块,当出现无法插入后面的方块时,就要回退到上一个方块,让上一个方块调整位置。上一个方块要调整到哪一个位置,这时候,如果又让这个方块在搜索范围内重新搜索一次,一是浪费运算时间,二是我们无法判断已经尝试过的是哪些起始点。
所以,我们要一次性在搜索范围内记录好所有可以插入的点,并记录下来,然后,再依次逐个去尝试。
比如,插入第一个方块A时,在原始状态(不包括变体)在总共可以有图示的这些点。
然后,除了原始状态外,还需要把其他变体的可以插入的点也记录下来。因为我们面对的不是不同变体,而是一个方块。所以,同一个方块的不同变体,都是要记录在一起去逐个尝试的。
这点非常重要,因为笔者没注意到这点,前期尝试时,总是失败,分析了好久,才知道问题点在这里。
相关的代码前期如下:
for(ib=0;ib<8;ib++){
for (j=0;j<=8-xlng[0][ib];j++){
for(k=0;k<=8-ylng[0][ib];k++){
//test for fit
counti=0;
for(ii=0;ii<xlng[0][ib];ii++){
for(jj=0;jj<ylng[0][ib];jj++) {
if ((ctemp[j+ii][k+jj]!='-')&&(b[0][ib][ii][jj]!='-')){
counti++;
}// jj if
}//for jj
}//for ii
//when it fit
if(counti==0){
//未完...
代码段7:方块和底盘比对代码
搜索分析:
为了完成整个拼图,需要对所有可能的方式都进行尝试。
尝试的方式,在上文已有描述。
以下主要分析指针链的设置。
图14:指针链的整体设计
创建一个结构,里面带有至少3个指针,以实现上述的功能。
1、每一个方块,第一个符合比对条件的,同时设置为该方块的0号指针,并且把上一个方块的指针的next链接给它,它的pre连接上一个方块的指针。此时,它的right指针和next指针设置为空。对于初始时的指针,就把head(头指针)的next指向它,把它的pre指针指向头指针。
设置头指针是很重要的。虽然采用一些技巧可以使用(0,0)号来充当头指针,但不建议这样做。为了节省这点空间,而进行相对复杂的操作,这样可能会导致一些莫名其妙的结果,以后翻查会很麻烦。
在找到这个方块的第二个符合比对条件的,就设置为1号指针,1号指针的pre、right和next指针均为空,现在只有0号指针的right指针是指向它的,它没有任何指向。
再找到这个方块的第三个符合比对条件的,就设置为2号指针,和1号指针一样,pre、right、next指针均为空,也只有1号指针的right指针指向它。
这样,顺次把这个方块的所有可能都用right指针串起来。
最后一种可能的right指针都是空的了。
如果我们能够顺利的一直找到第8个方块的合适放置位置,我们的任务就完成了。
2、当其中一个方块(比如到了第1号方块)在上一个方块的一种可能(比如(1,0))的所有可能都尝试过而不能插入了,也就是这个方块的最后一种可能,这种可能的right指针已经指向NULL了,而它的所有比对的冲突都不为0(counti>0)。
这时候,上一个方块(比如第0号方块)就要换下一个可能了,在指针上,是把上一个方块的next设置为现在这个指针的right指针(比如从(0,0)调整为(0,1)),然后,再进行下一轮对放置下一个方块的搜寻。指针的操作是这样的。
图15:指针链的调整
3、当某一个方块的所有可能都尝试过之后,上一层的所有可能都尝试过了,这时候,就要调整更上一层的指针了。但如何做这个判断和在代码上如何调整,就需要读者自己先去思考了。或者看下一篇。
上述第1步和第2步的相关的代码如下:
for(ib=0;ib<8;ib++){
for (j=0;j<=8-xlng[0][ib];j++){
for(k=0;k<=8-ylng[0][ib];k++){
//test for fit
counti=0;
for(ii=0;ii<xlng[0][ib];ii++){
for(jj=0;jj<ylng[0][ib];jj++) {
if ((ctemp[j+ii][k+jj]!='-')&&(b[0][ib][ii][jj]!='-')){
counti++;
}// jj if
}//for jj
}//for ii
//when it fit
if(counti==0){
if (vartime==0){
p[0][vartime]->left=NULL;
p[0][vartime]->right =NULL;
p[0][vartime]->pre =head;
head->next=p[0][0];
p[0][vartime]->next=NULL;
}
else{
p[0][vartime]=addpointer();
p[0][vartime-1]->right =p[0][vartime];
p[0][vartime]->left =p[0][vartime-1];
p[0][vartime]->right=NULL;
p[0][vartime]->next =NULL;
}
p[0][vartime]->i=0;
p[0][vartime]->ib=ib;
p[0][vartime]->ixy=vartime;
p[0][vartime]->x=j;
p[0][vartime]->y=k;
vartime++;
}
}
}
}
tmp=addpointer();
int ibtmp=0,itmp=0,ixytmp=0;
i=0;
ib=0;
long long countii=0;
while(irsl<1){
countii++;
for(iii=0;iii<7;iii++){
for(jjj=0;jjj<7;jjj++){
ctemp[iii][jjj]='-';
}
}
ctemp[0][6]='Z';
ctemp[1][6]='Z';
ctemp[6][3]='Z';
ctemp[6][4]='Z';
ctemp[6][5]='Z';
ctemp[6][6]='Z';
ctemp[1][5]='X';
ctemp[3][1]='X';
tmp=head->next;
//init the ctemp-martix
while(tmp!=NULL){
ib=tmp->ib;
i=tmp->i;
for(ii=0;ii<xlng[ib][i];ii++){
for(jj=0;jj<ylng[ib][i];jj++){
if (b[ib][i][ii][jj]!='-'){
ctemp[tmp->x+ii][tmp->y+jj]=b[ib][i][ii][jj];
}
}//for jj
}//for ii
ibtmp=tmp->ib;
itmp=tmp->i;
ixytmp=tmp->ixy;
tmp=tmp->next;
}//first fill
i=itmp+1;
//------------------
vartime=0;
int ibb=0;
if((i==4||i==5||i==6)){
ibb=4;
}
if(i==7){
ibb=2;
}
if(i<4){
ibb=8;
}
for (ib=0;ib<ibb;ib++){
for (j=0;j<=7-xlng[ib][i];j++){
for(k=0;k<=7-ylng[ib][i];k++){
counti=0;
for(ii=0;ii<xlng[ib][i];ii++){
if(j+ii>=7){counti++;}
for(jj=0;jj<ylng[ib][i];jj++){
//printf("ii=%d,jj=%d\n",ii,jj);
if(k+jj>=7){counti++;}//if k+jj
if ((ctemp[j+ii][k+jj]!='-')&&(b[ib][i][ii][jj]!='-')){
counti++;
}
}//for jj
}//for ii
//when it fill
if(counti==0){
//printf("i=%d,ib=%d,x=%d,y=%d\n",i,ib,j,k);
if (vartime==0){
//printf("when vartime=0;ib=%d,i=%d,j=%d,k=%d\n",ib,i+1,j,k);
p[i][vartime]=addpointer();
p[i][vartime]->left=NULL;
p[i][vartime]->right =NULL;
p[i][vartime]->pre =p[itmp][ixytmp];
//printf("p[itmp+1=%d][ib=%d][vartime=%d]->pre =p[itmp=%d][ibtmp=%d][ixytmp=%d]\n",itmp+1,ib,vartime,itmp,ibtmp,ixytmp);
p[itmp][ixytmp]->next=p[i][vartime];
p[i][vartime]->right =NULL;
p[i][vartime]->next =NULL;
//printf("p[%d][%d][%d]->right=%0x\n",ib,itmp+1,vartime,p[ib][itmp+1][vartime]->right);
}
else{
//printf("when vartime>0;ib=%d,i=%d,j=%d,k=%d\n",ib,i,j,k);
p[i][vartime]=addpointer();
p[i][vartime-1]->right =p[i][vartime];
p[i][vartime]->left =p[i][vartime-1];
//printf("p[itmp+1=%d][ib=%d][vartime=%d]->pre =p[itmp+1=%d][ib=%d][vartime-1=%d]\n",itmp+1,ib,vartime,itmp+1,ib,vartime-1);
p[i][vartime]->right=NULL;
p[i][vartime]->next =NULL;
}
p[i][vartime]->i=itmp+1;
p[i][vartime]->ib=ib;
p[i][vartime]->ixy=vartime;
p[i][vartime]->x=j;
p[i][vartime]->y=k;
vartime++;
}
}
}
}
代码段8:指针的第1段和第2段调整