/* solver.c */ /* Last Change: 2019/07/29 (Mon) 09:32:40. */ #include #include #include #include #include"solver.h" #include"io.h" /* #include */ /* #include */ #define DEBUG 1 #define ABS(a) ((a) < 0 ? - (a) : (a)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) /* short int connected[MAXLINE+1]={0}; //if line connected:2, if one end:1, otherwize:0 */ short int board_beta[MAXSIZE][MAXSIZE]; //big board data //edge:1~MAXLINE, line:-1~-MAXLINE, none:0, wall:SHRT_MIN short int rank[MAXBLOCK+1]; //ranking of point below, 0:unused, 1~ short int point[MAXBLOCK+1]; //XYZ //X: search priority, Y: number of edges in board, Z: number of edges in block short int first_block=1; short int costrank[1+MAXBLOCK*MAXBLOCK][2]; //ranking of cost: block being in (costrank[ranking][0],costrank[ranking][0]) short int rdm[MAXBLOCK+1]; //random no short int attempts=1; void print_board_beta(void){ short int i,j; short int minw=MAXSIZE-1,maxw=0,minh=MAXSIZE-1,maxh=0; for(i=0;imaxw) maxw=i; if(imaxh) maxh=j; if(jj) blocksrank[rdm[i]]++; /* else */ /* printf("%d %d no\n",rdm[i],rdm[j]); */ } } for(i=1;i<=blocks;i++) rank[blocksrank[i]]=i; return; } void reset(void){ //excluding init_points short int i,j; for(i=0;i0) //if edge exists point[i]+=2; if(point[i]==0) point[i]++; } update_ranks(); return; } void add_point(short int blockid){ short int i,j,k; for(i=1;i<=blocks;i++) if(i!=blockid&&point[i]>0) for(j=1;j<=4;j++) for(k=1;k<=4;k++) if(block_data[i][j][2]==block_data[blockid][k][2]&&block_data[blockid][k][2]>0) point[i]+=10; update_ranks(); return; } void sub_point(short int blockid){ short int i,j,k; for(i=1;i<=blocks;i++) if(i!=blockid&&point[i]>0) for(j=1;j<=4;j++) for(k=1;k<=4;k++) if(block_data[i][j][2]==block_data[blockid][k][2]&&block_data[blockid][k][2]>0) point[i]+=10; update_ranks(); return; } short int search_placable(short int blockid){ //calc the cost (sum of Euclidean distance of lines), returns the number of places short int cost[MAXSIZE][MAXSIZE][2]; //cost[x][y][0]:cost, cost[x][y][1]:rank short int i,j,k,l,index=0; short int place[5][2]; //(relative) place of edge #block_data[blockid][1-4][] (x,y) short int blockw=0,blockh=0; /* calc cost */ if(block_data[blockid][2][2]==-1){ //if monomino for(i=0;i=0&&board_beta[i-1][j]==0) cost[i-1][j][0]=1; if(j-1>=0&&board_beta[i][j-1]==0) cost[i][j-1][0]=1; } } }else{ for(k=1;k<=4;k++){ place[k][0]=SHRT_MIN; place[k][1]=SHRT_MIN; for(i=0;i0 && board_beta[i][j]==block_data[blockid][k][2]){ place[k][0]=i-block_data[blockid][k][0]; place[k][1]=j-block_data[blockid][k][1]; } } /* printf("%d, %d\n",place[k][0],place[k][1]); */ } for(k=1;k<=4;k++){ if(block_data[blockid][k][0]>blockw) blockw=block_data[blockid][k][0]; if(block_data[blockid][k][1]>blockh) blockh=block_data[blockid][k][1]; } /* printf("%d: %d, %d\n",blockid,blockw,blockh); */ for(i=0;i=MAXSIZE || j+blockh>=MAXSIZE) //out of board cost[i][j][0]=-1; else if( 0!=board_beta[i+block_data[blockid][1][0]] [j+block_data[blockid][1][1]] //alredy something || 0!=board_beta[i+block_data[blockid][2][0]] [j+block_data[blockid][2][1]] || 0!=board_beta[i+block_data[blockid][3][0]] [j+block_data[blockid][3][1]] || 0!=board_beta[i+block_data[blockid][4][0]] [j+block_data[blockid][4][1]]) cost[i][j][0]=-1; else{ cost[i][j][0]=0; for(k=1;k<=4;k++){ if(place[k][0]!=SHRT_MIN) cost[i][j][0]+=ABS(i-place[k][0]); if(place[k][1]!=SHRT_MIN) cost[i][j][0]+=ABS(j-place[k][1]); } if(cost[i][j][0]==0) cost[i][j][0]=MAX(MAX(ABS(i-MAXSIZE/2),ABS(j-MAXSIZE/2)),MAX(ABS(i+blockw-MAXSIZE/2),ABS(j+blockh-MAXSIZE/2)));//*100+ABS(i-MAXSIZE/2)+ABS(j-MAXSIZE/2)+ABS(i+blockw-MAXSIZE/2)+ABS(j+blockh-MAXSIZE/2); cost[i][j][0]=10000-cost[i][j][0]; /* printf("%d\n",cost[i][j][0]); */ } } } } /* calc costrank */ for(i=0;ik || (i==k&&j>l))) cost[i][j][1]++; for(i=0;i0&&avail[nowy][nowx-1]>=2) isbranch++; if(nowy>0&&avail[nowy-1][nowx]>=2) isbranch++; if(nowx=2) isbranch++; if(nowy=2) isbranch++; if(isbranch>0){ avail[nowy][nowx]=1; return 0; } if(avail[nowy][nowx]==1) avail[nowy][nowx]=2; short int i,src=0; short int searchorder[4]; //x+-,y+- /* for(i=0;i<4;i++) */ /* searchorder[i]=-1; */ if(nowx>goalx){ searchorder[src]=0; src++; }else searchorder[3+src]=0; if(nowy>goaly){ searchorder[src]=1; src++; }else searchorder[2+src]=1; if(nowx0&&available(nowx-1,nowy,0)) return 1; break; case 1: if(nowy>0&&available(nowx,nowy-1,0)) return 1; break; case 2: if(nowx0){ found=0; for(j=0;j0){ board_beta[x+block_data[blockid][1][0]] [y+block_data[blockid][1][1]]=block_data[blockid][1][2]; update_ranks(); }else{ board_beta[x+block_data[blockid][1][0]] [y+block_data[blockid][1][1]]=SHRT_MIN; } if(block_data[blockid][2][2]!=-1){ //if not monomino for(i=2;i<=4;i++) if(block_data[blockid][i][2]>0){ board_beta[x+block_data[blockid][i][0]] [y+block_data[blockid][i][1]]=block_data[blockid][i][2]; update_ranks(); }else{ board_beta[x+block_data[blockid][i][0]] [y+block_data[blockid][i][1]]=SHRT_MIN; } } add_point(blockid); return; } void remove_block(short int blockid){ //not for monomino if(point[blockid]<0) point[blockid]=-point[blockid]; board_beta[block_data[blockid][0][0]+block_data[blockid][1][0]] [block_data[blockid][0][1]+block_data[blockid][1][1]]=0; erase_line(block_data[blockid][1][2]); if(block_data[blockid][2][2]!=-1){ //if not monomino board_beta[block_data[blockid][0][0]+block_data[blockid][2][0]] [block_data[blockid][0][1]+block_data[blockid][2][1]]=0; board_beta[block_data[blockid][0][0]+block_data[blockid][3][0]] [block_data[blockid][0][1]+block_data[blockid][3][1]]=0; board_beta[block_data[blockid][0][0]+block_data[blockid][4][0]] [block_data[blockid][0][1]+block_data[blockid][4][1]]=0; erase_line(block_data[blockid][2][2]); erase_line(block_data[blockid][3][2]); erase_line(block_data[blockid][4][2]); } block_data[blockid][0][0]=-1; block_data[blockid][0][1]=-1; sub_point(blockid); return; } short int place_and_line(short int blockid){ short int i,j; if(DEBUG){ printf("#%d RANKS (rank: block, point)\n",attempts); for(i=1;i<=blocks;i++){ printf(" %d: %d, %d\n",i,rank[i],point[rank[i]]); } } if(first_block==1){ first_block--; place_block(blockid,MAXSIZE/2,MAXSIZE/2); point[blockid]=-point[blockid]; update_ranks(); if(DEBUG){ printf("#%d Block %d placed @(%d,%d)\n",attempts,blockid,block_data[blockid][0][0],block_data[blockid][0][1]); print_board_beta(); } return 1; } j=search_placable(blockid); for(i=1;i<=j;i++){ /* printf("place: block %d\n",blockid); */ place_block(blockid,costrank[i][0],costrank[i][1]); if(try_wires(blockid)){ point[blockid]=-point[blockid]; update_ranks(); return 1; } remove_block(blockid); } return 0; } void solve(short int seed){ //solver part short int i, in_process=1; srand(seed); while(in_process){ if(DEBUG){ printf("\n#%d attempt\n",attempts); } while(1){ i=rank[1]; if(block_data[i][0][0]<0){ //not placed if(!place_and_line(i)){ //if not placable point[i]+=100; if(point[i]>10000||attempts>=100){ //no answer printf("Too many trials!\n"); in_process=0; //end solver break; } shuffle_random(rand()); reset(); break; //solve from beginning } }else return; } attempts++; } return; } /* void shape(void){ */ /* return; */ /* } */ void translate(void){ //translate bigboard to minimal board short int i,j; short int minw=MAXSIZE-1,maxw=0,minh=MAXSIZE-1,maxh=0; for(i=0;imaxw) maxw=i; if(imaxh) maxh=j; if(j