Advertisement
partyboy1a

yoshiscookies.lua

Jan 29th, 2013
122
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 14.88 KB | None | 0 0
  1. USE_PICOSAT = false
  2. USE_MINISAT = true
  3. dofile("SAT-solver-framework.lua")
  4.  
  5. -- use a -1 to add a "yoshi" tile
  6.  
  7. --[[
  8. puzzle_to_solve = {
  9. {1,5,4,5,2},
  10. {4,2,1,4,5},
  11. {5,1,4,5,1},
  12. {2,4,5,2,4},
  13. {4,1,2,5,2}
  14. }
  15. --]]
  16.  
  17. puzzle_to_solve = {
  18. {1,1,1,1,1,2},
  19. {2,2,2,2,5,3},
  20. {3,3,3,3,5,4},
  21. {4,4,4,4,5,1}
  22. }
  23.  
  24. -- how many steps can be performed?
  25. steps = 9
  26.  
  27. -- playing field has 8 rows and 8 columns
  28. -- 5 different tile types can appear on the field
  29. -- "yoshi" counts as all tile types at once,
  30. -- and sets an extra bit.
  31. original_rows = #puzzle_to_solve
  32. original_cols = #puzzle_to_solve[1]
  33. original_ttypes = 5
  34.  
  35. if original_rows < original_cols then original_rows = original_cols end
  36. if original_rows > original_cols then original_cols = original_rows end
  37. assert(original_rows == original_cols, "sorry, some part of the code requires original_rows==original_cols")
  38. assert(original_rows >= 2 and original_cols >= 2, "puzzles with only one row or one column are pointless...")
  39. assert(original_ttypes >= 2, "there must be at least 2 different tiles!")
  40.  
  41. rows = original_rows
  42. cols = original_cols
  43. ttypes = original_ttypes + 1
  44.  
  45. NewVar("rotate",{steps, rows})
  46. NewVar("rotate_colbit",steps)
  47. NewVar("rotate_directionbit",steps)
  48. NewVar("always_true")
  49. UnitClause(Var.always_true, true)
  50. NewVar("always_false")
  51. UnitClause(Var.always_false, false)
  52. NewVar("playingfield", {steps+1, rows, cols, ttypes})
  53. NewVar("AtLeastTwoRows", steps)
  54. NewVar("AtLeastTwoRows_help", {steps, cols})
  55. NewVar("AtLeastTwoCols", steps)
  56. NewVar("AtLeastTwoCols_help", {steps, rows})
  57. NewVar("row_is_in_use", {steps+1, rows+1})
  58. NewVar("col_is_in_use", {steps+1, cols+1})
  59. NewVar("delete_row_help", {steps, rows, original_ttypes})
  60. NewVar("delete_row", {steps, rows})
  61. NewVar("delete_col_help", {steps, cols, original_ttypes})
  62. NewVar("delete_col", {steps, cols})
  63. NewVar("rotate_is_allowed", steps)
  64.  
  65. -- initialize with the given pattern
  66. for r = 1, rows do for c = 1, cols do for ttype = 1, ttypes do
  67.     if r <= #puzzle_to_solve and c <= #puzzle_to_solve[1] then
  68.         local is_of_this_type = (puzzle_to_solve[r][c] == ttype or puzzle_to_solve[r][c] == -1)
  69.         UnitClause(Var.playingfield[1][r][c][ttype], is_of_this_type)
  70.     else
  71.         UnitClause(Var.playingfield[1][r][c][ttype], true)
  72.     end
  73. end end end
  74.  
  75. for step = 1, steps+1 do
  76.  
  77.     -- Var.row_is_in_use
  78.     for r = 1, rows do
  79.         cl = NewClause()
  80.         for c = 1, cols do
  81.             ExtendClause(cl, Var.playingfield[step][r][c][ttypes], false)
  82.         end
  83.         AddIfAndOnlyIfClause(
  84.             "ALL of",{
  85.             Var.row_is_in_use[step][r], true},
  86.             "if and only if",
  87.             "ONE of",
  88.             cl
  89.         )
  90.     end
  91.     UnitClause(Var.row_is_in_use[step][rows+1], false)
  92.  
  93.     -- Var.col_is_in_use
  94.     for c = 1, cols do
  95.         cl = NewClause()
  96.         for r = 1, rows do
  97.             ExtendClause(cl, Var.playingfield[step][r][c][ttypes], false)
  98.         end
  99.         AddIfAndOnlyIfClause(
  100.             "ALL of",{
  101.             Var.col_is_in_use[step][c], true},
  102.             "if and only if",
  103.             "ONE of",
  104.             cl
  105.         )
  106.     end
  107.     UnitClause(Var.col_is_in_use[step][cols+1], false)
  108.  
  109. end
  110.  
  111.  
  112. for step = 1, steps do
  113.  
  114. print("writing clauses for step "..step.." of "..steps.."...")
  115.  
  116. -- disallow undoing a rotation
  117. if step >= 2 then
  118. for r = 1, rows do
  119. for _,colbit in pairs{true,false} do
  120. for _,dbit in pairs{true,false} do
  121.  
  122.     AddIfThenClause(
  123.         "if ALL",{
  124.         Var.rotate[step][r], true,
  125.         Var.rotate_colbit[step], colbit,
  126.         Var.rotate_directionbit[step], dbit},
  127.         "then ONE",{
  128.         Var.rotate[step-1][r], false,
  129.         Var.rotate_colbit[step-1], not colbit,
  130.         Var.rotate_directionbit[step-1], dbit}
  131.     )
  132. end end end end
  133.  
  134. -- Var.AtLeastTwoCols
  135. cl_over_all_c = NewClause()
  136. for ignore_c = 1, cols do
  137.     cl_help = NewClause()
  138.     for c = 1, cols do
  139.         if c ~= ignore_c then
  140.             ExtendClause(cl_help, Var.col_is_in_use[step][c], true)
  141.         end
  142.     end
  143.     AddIfAndOnlyIfClause(
  144.         "ALL of",{
  145.         Var.AtLeastTwoCols_help[step][ignore_c], true},
  146.         "if and only if",
  147.         "ONE of",
  148.         cl_help
  149.     )
  150.  
  151.     ExtendClause(cl_over_all_c, Var.AtLeastTwoCols_help[step][ignore_c], true)
  152. end
  153. AddIfAndOnlyIfClause(
  154.     "ALL of",{
  155.     Var.AtLeastTwoCols[step], true},
  156.     "if and only if",
  157.     "ALL of",
  158.     cl_over_all_c
  159. )
  160.  
  161. -- Var.AtLeastTwoRows[step]==true <=> at least 2(Var.col_is_in_use[step][c], c = 1, cols)
  162. cl_over_all_r = NewClause()
  163. for ignore_r = 1, rows do
  164.     cl_help = NewClause()
  165.     for r = 1, rows do
  166.         if r ~= ignore_r then
  167.             ExtendClause(cl_help, Var.row_is_in_use[step][r], true)
  168.         end
  169.     end
  170.     AddIfAndOnlyIfClause(
  171.         "ALL of",{
  172.         Var.AtLeastTwoRows_help[step][ignore_r], true},
  173.         "if and only if",
  174.         "ONE of",
  175.         cl_help
  176.     )
  177.  
  178.     ExtendClause(cl_over_all_r, Var.AtLeastTwoRows_help[step][ignore_r], true)
  179. end
  180. AddIfAndOnlyIfClause(
  181.     "ALL of",{
  182.     Var.AtLeastTwoRows[step], true},
  183.     "if and only if",
  184.     "ALL of",
  185.     cl_over_all_r
  186. )
  187.  
  188.  
  189. -- Var.delete_row
  190. for r = 1, rows do
  191.     cl_delete_row_r = NewClause()
  192.  
  193.     for ttype = 1, original_ttypes do
  194.         cl_help = NewClause()
  195.         ExtendClause(cl_help, Var.AtLeastTwoCols[step], true) -- don't delete if there is no second column
  196.         ExtendClause(cl_help, Var.row_is_in_use[step][r], true) -- don't delete an already empty row
  197.         for c = 1, cols do
  198.             ExtendClause(cl_help, Var.playingfield[step][r][c][ttype], true) -- if all tiles on a row are of the same type, delete it.
  199.         end
  200.    
  201.         AddIfAndOnlyIfClause(
  202.             "ALL of",
  203.             cl_help,
  204.             "if and only if",
  205.             "ALL of",{
  206.             Var.delete_row_help[step][r][ttype], true}
  207.         )
  208.        
  209.         ExtendClause(cl_delete_row_r, Var.delete_row_help[step][r][ttype], true)
  210.     end
  211.    
  212.     AddIfAndOnlyIfClause(
  213.         "ONE of",
  214.         cl_delete_row_r,
  215.         "if and only if",
  216.         "ALL of",{
  217.         Var.delete_row[step][r], true}
  218.     )
  219.        
  220. end
  221.  
  222. -- Var.delete_col
  223. for c = 1, cols do
  224.     cl_delete_col_c = NewClause()
  225.  
  226.     for ttype = 1, original_ttypes do
  227.         cl_help = NewClause()
  228.         ExtendClause(cl_help, Var.AtLeastTwoRows[step], true)
  229.         ExtendClause(cl_help, Var.col_is_in_use[step][c], true)
  230.         for r = 1, rows do
  231.             ExtendClause(cl_help, Var.playingfield[step][r][c][ttype], true)
  232.         end
  233.    
  234.         AddIfAndOnlyIfClause(
  235.             "ALL of",
  236.             cl_help,
  237.             "if and only if",
  238.             "ALL of",{
  239.             Var.delete_col_help[step][c][ttype], true}
  240.         )
  241.        
  242.         ExtendClause(cl_delete_col_c, Var.delete_col_help[step][c][ttype], true)
  243.     end
  244.  
  245.     AddIfAndOnlyIfClause(
  246.         "ONE of",
  247.         cl_delete_col_c,
  248.         "if and only if",
  249.         "ALL of",{
  250.         Var.delete_col[step][c], true,
  251.         }
  252.     )
  253.  
  254. --  UnitClause(Var.delete_col[step][c], false)
  255. end
  256.  
  257. -- rotate is only allowed if nothing is to be deleted (helper variable setup)
  258. cl = NewClause()
  259. for r = 1, rows do
  260.     ExtendClause(cl, Var.delete_row[step][r], false)
  261. end
  262. for c = 1, cols do
  263.     ExtendClause(cl, Var.delete_col[step][c], false)
  264. end
  265. AddIfAndOnlyIfClause(
  266.     "ALL of",{
  267.     Var.rotate_is_allowed[step], true},
  268.     "if and only if",
  269.     "ALL of",
  270.     cl
  271. )
  272.  
  273. -- allow only one rotate at once
  274. for r1 = 1, rows-1 do for r2 = r1+1, rows do
  275.     AddSimpleClause({
  276.         Var.rotate[step][r1], false,
  277.         Var.rotate[step][r2], false}
  278.     )
  279. end end
  280. -- disallow rotate if something is deleted
  281. cl = NewClause()
  282. for r = 1, rows do
  283.     ExtendClause(cl, Var.rotate[step][r], false)
  284. end
  285. AddIfThenClause(
  286.     "if ONE",{
  287.     Var.rotate_is_allowed[step],false},
  288.     "then ALL",
  289.     cl
  290. )
  291. -- disallow rotating an empty row, and
  292. -- disallow rotating rows if there is only one column
  293. for r = 1, rows do
  294.     AddIfThenClause(
  295.         "if ALL",{
  296.         Var.rotate[step][r], true,
  297.         Var.rotate_colbit[step], false},
  298.         "then ALL",{
  299.         Var.row_is_in_use[step][r], true,
  300.         Var.AtLeastTwoCols[step], true}
  301.     )
  302. end
  303. -- disallow rotating an empty col
  304. for c = 1, cols do
  305.     AddIfThenClause(
  306.         "if ALL",{
  307.         Var.rotate[step][c], true,
  308.         Var.rotate_colbit[step], true},
  309.         "then ALL",{
  310.         Var.col_is_in_use[step][c], true,
  311.         Var.AtLeastTwoRows[step], true}
  312.     )
  313. end
  314.  
  315. -- take care about all "trivial" cases of rotation...
  316. for ttype = 1, ttypes do for r = 1, rows do for c = 1, cols do
  317.     AddIfThenClause(
  318.         "if ONE",{
  319.         Var.row_is_in_use[step][r], false,
  320.         Var.col_is_in_use[step][c], false},
  321.         "then ALL",{
  322.         Var.playingfield[step+1][r][c][ttype], true}
  323.     )
  324.  
  325.     for _,b in pairs({true, false}) do
  326.         -- if rotate doesn't match row and column number,
  327.         -- then nothing is rotated!
  328.  
  329.         AddIfThenClause(
  330.             "if ALL", {
  331.             Var.rotate_is_allowed[step], true,
  332.             Var.rotate[step][r], false,
  333.             Var.rotate[step][c], false,
  334.             Var.playingfield[step][r][c][ttype], b},
  335.             "then ALL", {
  336.             Var.playingfield[step+1][r][c][ttype], b}
  337.         )
  338.         -- if rotate_colbit==true, and rotate[c]==false
  339.         -- then nothing is rotated
  340.         AddIfThenClause(
  341.             "if ALL", {
  342.             Var.rotate_is_allowed[step], true,
  343.             Var.rotate_colbit[step], true,
  344.             Var.rotate[step][c], false,
  345.             Var.playingfield[step][r][c][ttype], b},
  346.             "then ALL", {
  347.             Var.playingfield[step+1][r][c][ttype], b}
  348.         )
  349.    
  350.         -- if rotate_colbit==false, and rotate[r]==false
  351.         -- then nothing is rotated
  352.         AddIfThenClause(
  353.             "if ALL", {
  354.             Var.rotate_is_allowed[step], true,
  355.             Var.rotate_colbit[step], false,
  356.             Var.rotate[step][r], false,
  357.             Var.playingfield[step][r][c][ttype], b},
  358.             "then ALL", {
  359.             Var.playingfield[step+1][r][c][ttype], b}
  360.         )
  361.     end
  362. end end end
  363.  
  364. -- take care about all non-trivial cases
  365.  
  366. -- rotate a ROW
  367. -- (a few thousand clauses...)
  368. for ttype = 1, ttypes do
  369. for r = 1, rows do
  370. for c = 1, cols do
  371. for new_c = 1, cols do
  372. for _,b in pairs({true,false}) do
  373. if c ~= new_c then
  374.  
  375.     -- rotate a row RIGHT
  376.     cl = {
  377.         Var.row_is_in_use[step][r], true,
  378.         Var.col_is_in_use[step][c], true,
  379.         Var.rotate[step][r], true,
  380.         Var.rotate_colbit[step], false,
  381.         Var.rotate_directionbit[step], false}
  382.    
  383.     if new_c > c then
  384.         for k = c + 1, new_c - 1 do
  385.             ExtendClause(cl, Var.col_is_in_use[step][k], false)
  386.         end
  387.     else
  388.         for k = 1, new_c - 1 do
  389.             ExtendClause(cl, Var.col_is_in_use[step][k], false)
  390.         end
  391.         for k = c + 1, cols do
  392.             ExtendClause(cl, Var.col_is_in_use[step][k], false)
  393.         end
  394.     end
  395.     ExtendClause(cl, Var.col_is_in_use[step][new_c], true)
  396.     ExtendClause(cl, Var.playingfield[step][r][c][ttype], b)
  397.     AddIfThenClause(
  398.         "if ALL",
  399.         cl,
  400.         "then",{
  401.         Var.playingfield[step+1][r][new_c][ttype], b}
  402.     )
  403.  
  404.     -- rotate a row LEFT
  405.     cl = {
  406.         Var.row_is_in_use[step][r], true,
  407.         Var.col_is_in_use[step][c], true,
  408.         Var.rotate[step][r], true,
  409.         Var.rotate_colbit[step], false,
  410.         Var.rotate_directionbit[step], true}
  411.    
  412.     if new_c < c then
  413.         for k = new_c + 1, c - 1 do
  414.             ExtendClause(cl, Var.col_is_in_use[step][k], false)
  415.         end
  416.     else
  417.         for k = 1, c - 1 do
  418.             ExtendClause(cl, Var.col_is_in_use[step][k], false)
  419.         end
  420.         for k = new_c + 1, cols do
  421.             ExtendClause(cl, Var.col_is_in_use[step][k], false)
  422.         end
  423.     end
  424.     ExtendClause(cl, Var.col_is_in_use[step][new_c], true)
  425.     ExtendClause(cl, Var.playingfield[step][r][c][ttype], b)
  426.     AddIfThenClause(
  427.         "if ALL",
  428.         cl,
  429.         "then",{
  430.         Var.playingfield[step+1][r][new_c][ttype], b}
  431.     )
  432.  
  433. end end end end end end
  434.  
  435. -- rotate a COL
  436. -- (a few thousand clauses...)
  437. for ttype = 1, ttypes do
  438. for r = 1, rows do
  439. for c = 1, cols do
  440. for new_r = 1, rows do
  441. for _,b in pairs({true,false}) do
  442. if r ~= new_r then
  443.  
  444.     -- rotate a col DOWN
  445.     cl = {
  446.         Var.row_is_in_use[step][r], true,
  447.         Var.col_is_in_use[step][c], true,
  448.         Var.rotate[step][c], true,
  449.         Var.rotate_colbit[step], true,
  450.         Var.rotate_directionbit[step], false}
  451.    
  452.     if new_r > r then
  453.         for k = r + 1, new_r - 1 do
  454.             ExtendClause(cl, Var.row_is_in_use[step][k], false)
  455.         end
  456.     else
  457.         for k = 1, new_r - 1 do
  458.             ExtendClause(cl, Var.row_is_in_use[step][k], false)
  459.         end
  460.         for k = r + 1, rows do
  461.             ExtendClause(cl, Var.row_is_in_use[step][k], false)
  462.         end
  463.     end
  464.     ExtendClause(cl, Var.row_is_in_use[step][new_r], true)
  465.     ExtendClause(cl, Var.playingfield[step][r][c][ttype], b)
  466.     AddIfThenClause(
  467.         "if ALL",
  468.         cl,
  469.         "then",{
  470.         Var.playingfield[step+1][new_r][c][ttype], b}
  471.     )
  472.  
  473.     -- rotate a col UP
  474.     cl = {
  475.         Var.row_is_in_use[step][r], true,
  476.         Var.col_is_in_use[step][c], true,
  477.         Var.rotate[step][c], true,
  478.         Var.rotate_colbit[step], true,
  479.         Var.rotate_directionbit[step], true}
  480.    
  481.     if new_r < r then
  482.         for k = new_r + 1, r - 1 do
  483.             ExtendClause(cl, Var.row_is_in_use[step][k], false)
  484.         end
  485.     else
  486.         for k = 1, r - 1 do
  487.             ExtendClause(cl, Var.row_is_in_use[step][k], false)
  488.         end
  489.         for k = new_r + 1, rows do
  490.             ExtendClause(cl, Var.row_is_in_use[step][k], false)
  491.         end
  492.     end
  493.     ExtendClause(cl, Var.row_is_in_use[step][new_r], true)
  494.     ExtendClause(cl, Var.playingfield[step][r][c][ttype], b)
  495.     AddIfThenClause(
  496.         "if ALL",
  497.         cl,
  498.         "then",{
  499.         Var.playingfield[step+1][new_r][c][ttype], b}
  500.     )
  501.  
  502. end end end end end end
  503.  
  504. for ttype = 1, ttypes do for r = 1, rows do for c = 1, cols do
  505.     AddIfThenClause(
  506.         "if ONE", {
  507.         Var.delete_row[step][r], true,
  508.         Var.delete_col[step][c], true},
  509.         "then ALL",{
  510.         Var.playingfield[step+1][r][c][ttype], true}
  511.     )
  512. end end end
  513.  
  514. for ttype = 1, ttypes do for r = 1, rows do for c = 1, cols do for _,b in pairs{true,false} do
  515.     AddIfThenClause(
  516.         "if ALL", {
  517.         Var.rotate_is_allowed[step], false,
  518.         Var.delete_row[step][r], false,
  519.         Var.delete_col[step][c], false,
  520.         Var.playingfield[step][r][c][ttype], b},
  521.         "then ALL",{
  522.         Var.playingfield[step+1][r][c][ttype], b}
  523.     )
  524. end end end end
  525.  
  526. end
  527.  
  528. --UnitClause(Var.rotate[1][6], true)
  529. --UnitClause(Var.rotate_colbit[1], true)
  530. --UnitClause(Var.rotate_directionbit[1], false)
  531.  
  532. for r = 1, rows do
  533.     UnitClause(Var.row_is_in_use[steps+1][r], false)
  534. end
  535. for c = 1, cols do
  536.     UnitClause(Var.col_is_in_use[steps+1][c], false)
  537. end
  538.  
  539. WriteSATfile()
  540. if USE_PICOSAT then
  541.     os.execute("picosat satfile.cnf >solutionfile")
  542. elseif USE_MINISAT then
  543.     os.execute("minisat satfile.cnf solutionfile")
  544. end
  545. ParseSolution()
  546. --PrintSolution()
  547. for step = 1, steps do
  548.     print("step "..step..": ")
  549.     print()
  550.     s = "STATE   : "
  551.     for c = 1, cols do
  552.         if Sol.col_is_in_use[step][c]==false then
  553.             s = s .. " empty "
  554.         else
  555.             if Sol.delete_col[step][c] then
  556.                 s = s .. "del"
  557.             else
  558.                 s = s .. "   "
  559.             end
  560.             if Sol.rotate[step][c] and Sol.rotate_colbit[step] then
  561.                 if Sol.rotate_directionbit[step]==true then
  562.                     s = s .. " r^ "
  563.                 else
  564.                     s = s .. " rV "
  565.                 end
  566.             else
  567.                 s = s .. "    "
  568.             end
  569.         end
  570.         s = s .. ": "
  571.     end
  572.     print(s)
  573.     s = "--------:"
  574.     for c = 1, cols do s = s .. "--------:" end
  575.     print(s)
  576.     for r = 1, rows do
  577.         s = ""
  578.         if Sol.row_is_in_use[step][r]==false then
  579.             s = s .. " empty "
  580.         else
  581.             if Sol.delete_row[step][r] then
  582.                 s = s .. "del"
  583.             else
  584.                 s = s .. "   "
  585.             end
  586.             if Sol.rotate[step][r] and not Sol.rotate_colbit[step] then
  587.                 if Sol.rotate_directionbit[step]==false then
  588.                     s = s .. " r> "
  589.                 else
  590.                     s = s .. " <r "
  591.                 end
  592.             else
  593.                 s = s .. "    "
  594.             end
  595.         end
  596.         s = s .. " : "
  597.         for c = 1, cols do
  598.             for ttype = 1, ttypes do
  599.                 if Sol.playingfield[step][r][c][ttype] then s = s .. ttype else s = s .. " " end
  600.             end
  601.             s = s .. " : "
  602.         end
  603.         print(s)
  604.  
  605.         s = "--------:"
  606.         for c = 1, cols do s = s .. "--------:" end
  607.         print(s)
  608.     end
  609. end
  610.  
  611. print("step "..(steps+1)..":")
  612. print()
  613.  
  614. for r = 1, rows do
  615.     s = ""
  616.     for c = 1, cols do
  617.         for ttype = 1, ttypes do
  618.             if Sol.playingfield[steps+1][r][c][ttype] then s = s .. ttype else s = s .. " " end
  619.         end
  620.         s = s .. " "
  621.     end
  622.     print(s)
  623. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement