00001
00010 #include <stdlib.h>
00011
00012 #include "../libcnf/libcnf.h"
00013 #include "slitherlink.h"
00014
00015
00016
00017 #define HORIZONTAL 0
00018 #define VERTICAL 1
00019 #define HORIZONTAL_EDGE_INDEX 2
00020 #define VERTICAL_EDGE_INDEX 3
00021 #define HORIZONTAL_EDGE_SENSE 4
00022 #define VERTICAL_EDGE_SENSE 5
00023
00024 #define NUMBERING 2
00025 #define SENSE 4
00026
00027
00032 struct coord
00033 {
00037 int orientation;
00038 unsigned int x;
00039 unsigned int y;
00040 };
00041
00042
00043
00044
00045
00046
00047
00048
00049
00058 void getHneighbours(Slitherlink * sl,
00059 unsigned int i, unsigned int j,
00060 std::vector<coord> * neighbours1,
00061 std::vector<coord> * neighbours2 )
00062 {
00063 neighbours1->clear();
00064 neighbours2->clear();
00065 if (i > 0) {
00066 coord c;
00067 c.orientation = VERTICAL;
00068 c.x = i-1; c.y = j+1;
00069 neighbours1->push_back(c);
00070 }
00071 if (j < sl->getWidth()-1) {
00072 coord c;
00073 c.orientation = HORIZONTAL;
00074 c.x = i; c.y = j+1;
00075 neighbours1->push_back(c);
00076 }
00077 if (i < sl->getHeight()) {
00078 coord c;
00079 c.orientation = VERTICAL;
00080 c.x = i; c.y = j+1;
00081 neighbours1->push_back(c);
00082 }
00083 if (i < sl->getHeight()) {
00084 coord c;
00085 c.orientation = VERTICAL;
00086 c.x = i; c.y = j;
00087 neighbours2->push_back(c);
00088 }
00089 if (j > 0) {
00090 coord c;
00091 c.orientation = HORIZONTAL;
00092 c.x = i; c.y = j-1;
00093 neighbours2->push_back(c);
00094 }
00095 if (i > 0) {
00096 coord c;
00097 c.orientation = VERTICAL;
00098 c.x = i-1; c.y = j;
00099 neighbours2->push_back(c);
00100 }
00101 }
00102
00103
00112 void getVneighbours(Slitherlink * sl,
00113 unsigned int i, unsigned int j,
00114 std::vector<coord> * neighbours1,
00115 std::vector<coord> * neighbours2 )
00116 {
00117 neighbours1->clear();
00118 neighbours2->clear();
00119 if (j > 0) {
00120 coord c;
00121 c.orientation = HORIZONTAL;
00122 c.x = i; c.y = j-1;
00123 neighbours1->push_back(c);
00124 }
00125 if (i > 0) {
00126 coord c;
00127 c.orientation = VERTICAL;
00128 c.x = i-1; c.y = j;
00129 neighbours1->push_back(c);
00130 }
00131 if (j < sl->getWidth()) {
00132 coord c;
00133 c.orientation = HORIZONTAL;
00134 c.x = i; c.y = j;
00135 neighbours1->push_back(c);
00136 }
00137 if ((i < sl->getHeight()) && (j < sl->getWidth())) {
00138 coord c;
00139 c.orientation = HORIZONTAL;
00140 c.x = i+1; c.y = j;
00141 neighbours2->push_back(c);
00142 }
00143 if (i < sl->getHeight()-1) {
00144 coord c;
00145 c.orientation = VERTICAL;
00146 c.x = i+1; c.y = j;
00147 neighbours2->push_back(c);
00148 }
00149 if (i < sl->getHeight() && j>0) {
00150 coord c;
00151 c.orientation = HORIZONTAL;
00152 c.x = i+1; c.y = j-1;
00153 neighbours2->push_back(c);
00154 }
00155 }
00156
00157
00169 void addContinuityAxioms(cnf::Formula * form, int edgeCode,
00170 std::vector<coord> neighbours)
00171 {
00172
00173 form->newClause();
00174 form->addLitCode((-1)*edgeCode);
00175 for (unsigned int k=0; k<neighbours.size(); k++)
00176 form->addLit(neighbours[k].orientation, true,
00177 neighbours[k].x, neighbours[k].y);
00178 form->pushClause();
00179
00180 if (neighbours.size() > 1)
00181 for (unsigned int k=0; k<neighbours.size()-1; k++)
00182 for (unsigned int l=k+1; l<neighbours.size(); l++)
00183 {
00184 form->newClause();
00185 form->addLitCode((-1)*edgeCode);
00186 form->addLit(neighbours[k].orientation,false,
00187 neighbours[k].x, neighbours[k].y);
00188 form->addLit(neighbours[l].orientation,false,
00189 neighbours[l].x, neighbours[l].y);
00190 form->pushClause();
00191 }
00192 }
00193
00194
00195
00196
00197
00198
00199
00211 std::vector<int> hintNeighbours(cnf::VariableSet * vars,
00212 unsigned int i, unsigned int j)
00213 {
00214 std::vector<int> neighbours(4);
00215 neighbours[0] = vars->getVarCode(HORIZONTAL,i,j);
00216 neighbours[1] = vars->getVarCode( VERTICAL,i,j+1);
00217 neighbours[2] = vars->getVarCode(HORIZONTAL,i+1,j);
00218 neighbours[3] = vars->getVarCode( VERTICAL,i,j);
00219 return neighbours;
00220 }
00221
00222
00227 void addHintAxioms0(cnf::Formula * form, Slitherlink * sl,
00228 cnf::VariableSet * vars, unsigned int i,
00229 unsigned int j)
00230 {
00231 std::vector<int> neighbours = hintNeighbours(vars,i,j);
00232 for (unsigned int k=0; k<4; k++)
00233 {
00234 form->newClause();
00235 form->addLitCode((-1)*neighbours[k]);
00236 form->pushClause();
00237 }
00238 }
00239
00240
00247 void addHintAxioms1(cnf::Formula * form, Slitherlink * sl,
00248 cnf::VariableSet * vars, unsigned int i,
00249 unsigned int j)
00250 {
00251 std::vector<int> neighbours = hintNeighbours(vars,i,j);
00252
00253 form->newClause();
00254 for (unsigned int k=0; k<4; k++)
00255 form->addLitCode(neighbours[k]);
00256 form->pushClause();
00257
00258 for (unsigned int k=0; k<3; k++)
00259 for (unsigned int l=k+1; l<4; l++)
00260 {
00261 form->newClause();
00262 form->addLitCode((-1)*neighbours[k]);
00263 form->addLitCode((-1)*neighbours[l]);
00264 form->pushClause();
00265 }
00266 }
00267
00268
00275 void addHintAxioms2(cnf::Formula * form, Slitherlink * sl,
00276 cnf::VariableSet * vars, unsigned int i,
00277 unsigned int j)
00278 {
00279 std::vector<int> neighbours = hintNeighbours(vars,i,j);
00280
00281
00282 for (unsigned int k=0; k<2; k++)
00283 for (unsigned int l=k+1; l<3; l++)
00284 for (unsigned int m=l+1; m<4; m++)
00285 {
00286
00287 form->newClause();
00288 form->addLitCode(neighbours[k]);
00289 form->addLitCode(neighbours[l]);
00290 form->addLitCode(neighbours[m]);
00291 form->pushClause();
00292
00293 form->newClause();
00294 form->addLitCode((-1)*neighbours[k]);
00295 form->addLitCode((-1)*neighbours[l]);
00296 form->addLitCode((-1)*neighbours[m]);
00297 form->pushClause();
00298 }
00299 }
00300
00301
00307 void addHintAxioms3(cnf::Formula * form, Slitherlink * sl,
00308 cnf::VariableSet * vars, unsigned int i,
00309 unsigned int j)
00310 {
00311 std::vector<int> neighbours = hintNeighbours(vars,i,j);
00312
00313 form->newClause();
00314 for (unsigned int k=0; k<4; k++)
00315 form->addLitCode((-1)*neighbours[k]);
00316 form->pushClause();
00317
00318 for (unsigned int k=0; k<3; k++)
00319 for (unsigned int l=k+1; l<4; l++)
00320 {
00321 form->newClause();
00322 form->addLitCode(neighbours[k]);
00323 form->addLitCode(neighbours[l]);
00324 form->pushClause();
00325 }
00326 }
00327
00328
00329 void addHintAxioms(cnf::Formula * form, Slitherlink * sl,
00330 cnf::VariableSet * vars, unsigned int i,
00331 unsigned int j)
00332 {
00333 switch (sl->getHint(i,j))
00334 {
00335 case (-1): break;
00336 case (0): { addHintAxioms0(form,sl,vars,i,j); break; }
00337 case (1): { addHintAxioms1(form,sl,vars,i,j); break; }
00338 case (2): { addHintAxioms2(form,sl,vars,i,j); break; }
00339 case (3): { addHintAxioms3(form,sl,vars,i,j); break; }
00340 }
00341 }
00342
00343
00344
00345
00346
00347
00348
00359 void addContinuityAndNumberingAxioms(cnf::Formula * form, int orientation,
00360 unsigned int i, unsigned int j,
00361 unsigned int maxLoopSize)
00362
00363 {
00364
00365 form->newClause();
00366 form->addLit(orientation,false,i,j);
00367 for (unsigned int k=0; k<maxLoopSize; k++)
00368 form->addLit(orientation+NUMBERING,true,i,j,k);
00369 form->pushClause();
00370
00371 for (unsigned int k=0; k<maxLoopSize; k++)
00372 {
00373 form->newClause();
00374 form->addLit(orientation+NUMBERING,false,i,j,k);
00375 form->addLit(orientation,true,i,j);
00376 form->pushClause();
00377 }
00378 }
00379
00380
00391 void addIncreasingIndexAxioms(cnf::Formula * form, int orientation,
00392 unsigned int i, unsigned int j,
00393 unsigned int index,
00394 bool isNeighboursGreater, bool sense,
00395 std::vector<coord> neighbours)
00396 {
00397 if ((index != 0) || (isNeighboursGreater))
00398 {
00399 unsigned int neighboursIndex =
00400 (isNeighboursGreater) ? index+1 : index-1;
00401
00402 form->newClause();
00403 form->addLit(orientation+NUMBERING,false,i,j,index);
00404 form->addLit(orientation+SENSE,!sense,i,j);
00405 for (unsigned int k=0; k<neighbours.size(); k++)
00406 {
00407 form->addLit(neighbours[k].orientation+NUMBERING,true,
00408 neighbours[k].x,neighbours[k].y,neighboursIndex);
00409 if (isNeighboursGreater)
00410 form->addLit(neighbours[k].orientation+NUMBERING,true,
00411 neighbours[k].x,neighbours[k].y,0);
00412 }
00413 form->pushClause();
00414 }
00415
00416 }
00417
00418
00426 void placeZero(cnf::Formula * form, Slitherlink * sl,
00427 cnf::VariableSet * vars,
00428 unsigned int i, unsigned int j)
00429 {
00430 std::vector<int> neighbours(4);
00431 neighbours[0] = vars->getVarCode(HORIZONTAL_EDGE_INDEX,i ,j ,0);
00432 neighbours[1] = vars->getVarCode( VERTICAL_EDGE_INDEX,i ,j+1,0);
00433 neighbours[2] = vars->getVarCode(HORIZONTAL_EDGE_INDEX,i+1,j ,0);
00434 neighbours[3] = vars->getVarCode( VERTICAL_EDGE_INDEX,i ,j ,0);
00435
00436 form->newClause();
00437 form->addLitCode(neighbours[0]);
00438 form->addLitCode(neighbours[1]);
00439 form->addLitCode(neighbours[2]);
00440 form->addLitCode(neighbours[3]);
00441 form->pushClause();
00442
00443 for (unsigned int k=0; k<3; k++)
00444 for (unsigned int l=k+1; l<4; l++)
00445 {
00446 form->newClause();
00447 form->addLitCode((-1)*neighbours[k]);
00448 form->addLitCode((-1)*neighbours[l]);
00449 form->pushClause();
00450 }
00451
00452 for (unsigned int k=0; k<=sl->getHeight(); k++)
00453 for (unsigned int l=0; l<sl->getWidth(); l++)
00454 if ((l!=j) || ((k!=i) && (k!=i+1)) )
00455 {
00456 form->newClause();
00457 form->addLit(HORIZONTAL_EDGE_INDEX,false,k,l,0);
00458 form->pushClause();
00459 }
00460 for (unsigned int k=0; k<sl->getHeight(); k++)
00461 for (unsigned int l=0; l<=sl->getWidth(); l++)
00462 if ((k!=i) || ((l!=j) && (l!=j+1)) )
00463 {
00464 form->newClause();
00465 form->addLit(VERTICAL_EDGE_INDEX,false,k,l,0);
00466 form->pushClause();
00467 }
00468 }
00469
00470
00471
00472
00473
00474
00475 int main(int argc, char * argv[])
00476 {
00477
00478 if (argc <= 2)
00479 {
00480 std::cout<<"Wrong number of argument!"<<std::endl
00481 <<"./i2f <slitherlink to solve> <where to put "
00482 <<"the dimacs>"<<std::endl;
00483 exit(1);
00484 }
00485 std::ifstream * input = new std::ifstream(argv[1]);
00486 std::ofstream * output = new std::ofstream(argv[2]);
00487
00488
00489 Slitherlink * sl = new Slitherlink();
00490 sl->parseInput(input);
00491 free(input);
00492
00493
00494 unsigned int maxLoopSize = sl->getHeight()*sl->getWidth()*4;
00495
00496 cnf::VariableSet * vars = new
00497 cnf::VariableSet(sl->getHeight()+1,sl->getWidth());
00498
00499 vars->addVars(sl->getHeight(),sl->getWidth()+1);
00500
00501 vars->addVars(sl->getHeight()+1,sl->getWidth(),maxLoopSize+1);
00502
00503 vars->addVars(sl->getHeight(),sl->getWidth()+1,maxLoopSize+1);
00504
00505 vars->addVars(sl->getHeight()+1,sl->getWidth());
00506
00507 vars->addVars(sl->getHeight(),sl->getWidth()+1);
00508
00509
00510 cnf::Formula* form = new cnf::Formula(vars,output,
00511 "formula modeling a slitherlink");
00512
00513
00514 std::vector<coord> neighbours1;
00515 std::vector<coord> neighbours2;
00516 int edgeCode;
00517
00518 for (unsigned int i=0; i <= sl->getHeight(); i++)
00519 for (unsigned int j=0; j < sl->getWidth(); j++)
00520 {
00521 edgeCode = vars->getVarCode(0,i,j);
00522 getHneighbours(sl,i,j, &neighbours1,&neighbours2);
00523 addContinuityAxioms(form,edgeCode,neighbours1);
00524 addContinuityAxioms(form,edgeCode,neighbours2);
00525 addContinuityAndNumberingAxioms(form,HORIZONTAL,i,j,
00526 maxLoopSize);
00527 for (unsigned int index=0; index<maxLoopSize; index++)
00528 {
00529
00530 addIncreasingIndexAxioms(form,HORIZONTAL,i,j,
00531 index, false,true,
00532 neighbours1);
00533 addIncreasingIndexAxioms(form,HORIZONTAL,i,j,
00534 index, true,true,
00535 neighbours2);
00536
00537 addIncreasingIndexAxioms(form,HORIZONTAL,i,j,
00538 index, true,false,
00539 neighbours1);
00540 addIncreasingIndexAxioms(form,HORIZONTAL,i,j,
00541 index, false,false,
00542 neighbours2);
00543 }
00544 }
00545
00546 for (unsigned int i=0; i < sl->getHeight(); i++)
00547 for (unsigned int j=0; j <= sl->getWidth(); j++)
00548 {
00549 edgeCode = vars->getVarCode(1,i,j);
00550 getVneighbours(sl,i,j, &neighbours1,&neighbours2);
00551 addContinuityAxioms(form,edgeCode,neighbours1);
00552 addContinuityAxioms(form,edgeCode,neighbours2);
00553 addContinuityAndNumberingAxioms(form,VERTICAL,i,j,
00554 maxLoopSize);
00555 for (unsigned int index=0; index<maxLoopSize; index++)
00556 {
00557
00558 addIncreasingIndexAxioms(form,VERTICAL,i,j,
00559 index, false,true,
00560 neighbours1);
00561 addIncreasingIndexAxioms(form,VERTICAL,i,j,
00562 index, true ,true,
00563 neighbours2);
00564
00565 addIncreasingIndexAxioms(form,VERTICAL,i,j,
00566 index, true ,false,
00567 neighbours1);
00568 addIncreasingIndexAxioms(form,VERTICAL,i,j,
00569 index, false,false,
00570 neighbours2);
00571 }
00572 }
00573
00574 bool zeroHasBeenPut = false;
00575 for (unsigned int i=0; i<sl->getHeight(); i++)
00576 for (unsigned int j=0; j<sl->getWidth(); j++)
00577 {
00578 addHintAxioms(form,sl,vars,i,j);
00579 if ((!zeroHasBeenPut) && (sl->getHint(i,j)>0))
00580 {
00581 placeZero(form,sl,vars,i,j);
00582 zeroHasBeenPut = true;
00583 }
00584 }
00585
00586
00587
00588 form->flushCNF();
00589
00590 return 0;
00591 }