Advertisement
partyboy1a

DenkiBlocks-WIP2.lua

Jan 13th, 2016
142
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 22.09 KB | None | 0 0
  1. -- Denki Blocks! Solver WIP2
  2. --
  3. -- usable but too slow, too many clauses and variables right now...
  4. --
  5.  
  6. USE_WINDOWS = true
  7. USE_LINUX = false
  8. dofile("SAT-solver-framework.lua")
  9. USE_MINISAT = true
  10.  
  11. -- for a small test.
  12. -- sorry, the more complex puzzles don't work
  13. ROWS = 4
  14. COLUMNS = 4
  15. BITS = 4
  16. LevelLayout = {
  17. "r__r",
  18. "_y_y",
  19. "___b",
  20. "rXb_"
  21. }
  22. ColorsToConnect = {
  23. r = {number=1,r=1,c=1}, y={number=2,r=2,c=2}, b={number=3,r=3,c=4}}
  24. OtherColors = {}
  25. MaximumTurns = 5
  26.  
  27.  
  28. --[[
  29. --4x49
  30. LevelLayout = {
  31. "________________",
  32. "______X_________",
  33. "________________",
  34. "________________",
  35. "_yByByBy________",
  36. "_BBBBBBB________",
  37. "_yBy_B__________",
  38. "_BBB_ByByByBy___",
  39. "_yBy_BBBBBBBB_X_",
  40. "_BBB_ByByByBy___",
  41. "_______B________",
  42. "_______B___X____",
  43. "______BBB_______",
  44. "______yBy_______",
  45. "______BBB_______",
  46. "________________"
  47. }
  48. ROWS=16
  49. COLUMNS=16
  50. BITS=7
  51. ColorsToConnect={y={number=1,r=5,c=2}}
  52. OtherColors={B = {number=2,r=0,c=0}}
  53. MaximumTurns=45
  54. --]]
  55.  
  56. --[[
  57. --7x13
  58. ROWS = 16
  59. COLUMNS = 16
  60. BITS = 5   -- math.ceil( ln(total movable tiles) / ln(2) )
  61.  
  62. LevelLayout = {
  63. "________________",
  64. "__rr_yyyyyy_bb__",
  65. "__rr________bb__",
  66. "XXXXXXX__XXXXXXX",
  67. "______X__X______",
  68. "__yy__X__X__yy__",
  69. "__yy__X__X__yy__",
  70. "______X__X______",
  71. "_bbbb_X__X_rrrr_",
  72. "______X__X______",
  73. "__yy__X__X__yy__",
  74. "__yy__X__X__yy__",
  75. "______X__X______",
  76. "XX__XXX__XXX__XX",
  77. "________________",
  78. "________________"
  79. }
  80.  
  81. ColorsToConnect = {
  82. r = {number=1,r=9,c=12}, y = {number=2,r=2,c=9}, b = {number=3,r=9,c=3}}
  83. OtherColors = {}
  84. MaximumTurns = 70
  85. --]]
  86.  
  87. -- ugly code, but #ColorsToConnect == 0, so we need to count by hand
  88. TotalColors = 0
  89. TotalColorsToConnect = 0
  90. for _,_ in pairs(ColorsToConnect) do
  91.     TotalColors = TotalColors + 1
  92.     TotalColorsToConnect = TotalColorsToConnect + 1
  93. end
  94. for _,_ in pairs(OtherColors) do TotalColors = TotalColors + 1 end
  95.  
  96. function CheckLayout()
  97.     local found = {}
  98.     for r = 1, ROWS do
  99.         assert(type(LevelLayout[r]) == "string", "type mismatch!")
  100.         assert(string.len(LevelLayout[r]) == COLUMNS, "string does not have the right length!")
  101.         for c = 1, COLUMNS do
  102.             local s = string.sub(LevelLayout[r],c,c)
  103.             assert(
  104.                 s == "_"
  105.                 or s == "X"
  106.                 or ColorsToConnect[ s ] ~= nil
  107.                 or OtherColors[ s ] ~= nil,
  108.                 "LevelLayout["..r.."]["..c.."] unknown color "..s.."!")
  109.             found[s] = true
  110.         end
  111.     end
  112.     local foundnum = {}
  113.     for key,val in pairs(ColorsToConnect) do
  114.         assert(found[key], "ColorsToConnect includes color "..key.." which is not in the puzzle!")
  115.         foundnum[val.number] = true
  116.     end
  117.     for i = 1, TotalColorsToConnect do
  118.         assert(foundnum[i], "color number "..i.." should exist!")
  119.     end
  120.    
  121.     for key,val in pairs(OtherColors) do
  122.         assert(found[key], "OtherColors includes color "..key.." which is not in the puzzle!")
  123.         foundnum[val.number] = true
  124.     end
  125.     for i = 1, #OtherColors do
  126.         assert(foundnum[TotalColorsToConnect + i], "color number "..(TotalColorsToConnect+i).." should exist!")
  127.     end
  128. end
  129.  
  130. function CreateCNF()
  131.     CheckLayout()
  132.     StartAutoWrite(100000)
  133.     --A : Before rotation is done
  134.     --R : which rotation should be done? < --- THIS IS THE ONLY UNRESTRICTED VARIABLE!! ALL INPUT IS DONE HERE!!
  135.     --B : After rotation is done
  136.    
  137.     --[[
  138.     A[1] : initial state
  139.    
  140.           R[1]        move!       R[2]        move!
  141.     A[1] -----> B[1] -----> A[2] -----> B[2] ------> ...
  142.    
  143.     A[n] : state after n-1 finished moves.
  144.     B[n] : check the winning condition in turn n-1, prepare the move
  145.  
  146.     --]]
  147.     NewVar("A", {
  148.         MaximumTurns + 1,
  149.         ROWS,
  150.         COLUMNS,
  151.         -- which color? zero? free? unmovable?
  152.            TotalColors  + 1   + 1   + 1})
  153.    
  154.     IS_ZERO = TotalColors + 1
  155.     IS_FREE = TotalColors + 2
  156.     IS_UNMOVABLE = TotalColors + 3
  157.     --assert(#Var.A[1][1][1] == 6, "FAIL"..#Var.A[1][1][1])
  158.     print("parsing layout...")
  159.     -- Let's parse the layout!
  160.     for r = 1, ROWS do for c = 1, COLUMNS do
  161.         local s = string.sub(LevelLayout[r],c,c)
  162.         if s == "_" then
  163.             for entry = 1, #Var.A[1][r][c] do
  164.                 AddSimpleClause{Var.A[1][r][c][entry], entry == IS_FREE}
  165.             end
  166.         elseif s == "X" then
  167.             for entry = 1, #Var.A[1][r][c] do
  168.                 AddSimpleClause{Var.A[1][r][c][entry], entry == IS_UNMOVABLE}
  169.             end
  170.         else
  171.             local n = 0
  172.             if ColorsToConnect[s] ~= nil then
  173.                 n = ColorsToConnect[s]
  174.             else
  175.                 n = OtherColors[s]
  176.             end
  177.             assert(n ~= nil, "r="..r..",c="..c..",s="..s..", but n==nil!")
  178.             for entry = 1, #Var.A[1][r][c] do
  179.                 if entry == IS_ZERO then
  180.                     AddSimpleClause{Var.A[1][r][c][entry], r==n.r and c==n.c}
  181.                 else
  182.                     AddSimpleClause{Var.A[1][r][c][entry], n.number == entry}
  183.                 end
  184.             end
  185.         end
  186.     end end
  187.    
  188.     NewVar("R", {
  189.         MaximumTurns + 1,
  190.         2})
  191.    
  192.     NewVar("B", {
  193.         MaximumTurns + 1,
  194.         ROWS,
  195.         COLUMNS,
  196.         -- which color? zero? free? unmovable?
  197.            TotalColors  + 1   + 1   + 1
  198.        
  199.         -- these will be necessary for every single step because of the
  200.         -- possibility to connect multiple colors in the same turn
  201.         --
  202.         -- connected to zero? connection number. right less? down less?
  203.            + 1                + BITS             + BITS      + BITS
  204.         -- blocked? block number. right less? down less?                    
  205.            + 1      + BITS        + BITS      + BITS})
  206.    
  207.     print("rotation..."..total_number_of_clauses)
  208.     -- rotation helper function
  209.     local function h(rot1, rot2, r1, c1, r2, c2)
  210.         for t = 1, MaximumTurns + 1 do for entry = 1, #Var.A[1][1][1] do
  211.             AddIfThenClause(   
  212.                 "if ALL", {Var.R[t][1], rot1, Var.R[t][2], rot2, Var.A[t][r1][c1][entry], true},
  213.                 "then ALL", {Var.B[t][r2][c2][entry], true}
  214.             )
  215.             AddIfThenClause(
  216.                 "if ALL", {Var.R[t][1], rot1, Var.R[t][2], rot2, Var.A[t][r1][c1][entry], false},
  217.                 "then ALL", {Var.B[t][r2][c2][entry], false}
  218.             )
  219.         end end
  220.     end
  221.     for r = 1, ROWS do for c = 1, COLUMNS do
  222.         -- rotate 0 degrees
  223.         h(false, false, r, c, r, c)
  224.         -- 90 degrees right
  225.         h(false, true, r, c, c, ROWS + 1 - r)
  226.         -- 180 degrees right
  227.         h(true, false, r, c, ROWS + 1 - r, COLUMNS + 1 - c)
  228.         -- 270 degrees right
  229.         h(true, true,  r, c, COLUMNS + 1 - c, r)
  230.     end end
  231.    
  232.     IS_CONNECTED_TO_ZERO = TotalColors + 4
  233.     B_CONNECTION_NUMBER_OFFSET = TotalColors + 4 + 1
  234.     B_CONNECTION_NUMBER_COMPARE_RIGHT_OFFSET = B_CONNECTION_NUMBER_OFFSET + BITS
  235.     B_CONNECTION_NUMBER_COMPARE_DOWN_OFFSET = B_CONNECTION_NUMBER_OFFSET + BITS + BITS
  236.     IS_BLOCKED = TotalColors + 4 + 3*BITS + 1
  237.     B_BLOCK_NUMBER_OFFSET = TotalColors + 4 + 3*BITS + 1 + 1
  238.     B_BLOCK_NUMBER_COMPARE_RIGHT_OFFSET = B_BLOCK_NUMBER_OFFSET + BITS
  239.     B_BLOCK_NUMBER_COMPARE_DOWN_OFFSET  = B_BLOCK_NUMBER_OFFSET + BITS + BITS
  240.    
  241.     print("compare numbers..."..total_number_of_clauses)
  242.     -- compare number helper function
  243.     local function h(t,r1,c1,r2,c2,number_offset,compare_offset)
  244.         local V1 = Var.B[t][r1][c1]
  245.         local V2 = Var.B[t][r2][c2]
  246.        
  247.         -- n(V) := 1 * V[number_offset]   +  2 * V[number_offset+1]
  248.         --       + 4 * V[number_offset+2] +  8 * V[number_offset+3]
  249.         --       +16 * V[number_offset+4] + 32 * V[number_offset+5]
  250.         --       +64 * V[number_offset+6] +128 * V[number_offset+7]
  251.         --
  252.         local n = number_offset
  253.         local c = compare_offset
  254.        
  255.         -- n(V1) > n(V2) ?
  256.        
  257.         -- least significant bit
  258.         -- for the one-bit numbers a and b, a > b if and only if a == 1, b == 0
  259.         AddIfAndOnlyIfClause("ALL of", {V1[n], true, V2[n], false}, "if and only if", "ALL of", {V1[c], true})
  260.        
  261.         for b = 1, BITS - 1 do
  262.             -- x + n(V1) > x + n(V2)    <=> n(V1) > n(V2)
  263.             AddIfThenClause("if ALL", {V1[n+b], true, V2[n+b], true,   V1[c+b-1], true}, "then ALL", {V1[c+b], true})
  264.             AddIfThenClause("if ALL", {V1[n+b], true, V2[n+b], true,   V1[c+b-1], false}, "then ALL", {V1[c+b], false})
  265.             AddIfThenClause("if ALL", {V1[n+b], false, V2[n+b], false, V1[c+b-1], true}, "then ALL", {V1[c+b], true})
  266.             AddIfThenClause("if ALL", {V1[n+b], false, V2[n+b], false, V1[c+b-1], false}, "then ALL", {V1[c+b], false})
  267.            
  268.             -- x + n(V1) > n(V2) if x > n(V2)
  269.             AddIfThenClause("if ALL", {V1[n+b], true, V2[n+b], false}, "then ALL", {V1[c+b], true})
  270.             -- n(V1) <= x + n(V2) if x > n(V1)
  271.             AddIfThenClause("if ALL", {V1[n+b], false, V2[n+b], true}, "then ALL", {V1[c+b], false})
  272.         end
  273.     end
  274.     for t = 1, MaximumTurns + 1 do for r = 1, ROWS do for c = 1, COLUMNS - 1 do
  275.         h(t, r, c, r, c+1, B_CONNECTION_NUMBER_OFFSET, B_CONNECTION_NUMBER_COMPARE_RIGHT_OFFSET)
  276.         h(t, r, c, r, c+1, B_BLOCK_NUMBER_OFFSET, B_BLOCK_NUMBER_COMPARE_RIGHT_OFFSET)
  277.     end end end
  278.     for t = 1, MaximumTurns + 1 do for r = 1, ROWS - 1 do for c = 1, COLUMNS do
  279.         h(t, r, c, r+1, c, B_CONNECTION_NUMBER_OFFSET, B_CONNECTION_NUMBER_COMPARE_DOWN_OFFSET)
  280.         h(t, r, c, r+1, c, B_BLOCK_NUMBER_OFFSET, B_BLOCK_NUMBER_COMPARE_DOWN_OFFSET)
  281.     end end end
  282.    
  283.     for t = 1, MaximumTurns + 1 do r = 1, ROWS do for b = 0, BITS-1 do
  284.         AddSimpleClause{Var.B[t][r][COLUMNS][B_BLOCK_NUMBER_COMPARE_RIGHT_OFFSET + b], false}
  285.     end end end
  286.     for t = 1, MaximumTurns + 1 do c = 1, COLUMNS do for b = 0, BITS-1 do
  287.         AddSimpleClause{Var.B[t][ROWS][c][B_BLOCK_NUMBER_COMPARE_DOWN_OFFSET + b], false}
  288.     end end end
  289.    
  290.     -- check if the tile to the right has the same color
  291.     NewVar("RSC", {
  292.         MaximumTurns + 1,
  293.         ROWS,
  294.         COLUMNS - 1})
  295.    
  296.     -- check if the tile to the bottom has the same color
  297.     NewVar("DSC", {
  298.         MaximumTurns + 1,
  299.         ROWS - 1,
  300.         COLUMNS})
  301.    
  302.     print("check same color..."..total_number_of_clauses)
  303.     local function h(V,t,r1,c1,r2,c2)
  304.         AddIfThenClause(
  305.             "if ALL", {V[t][r1][c1], true},
  306.             "then ALL", {
  307.                 Var.B[t][r1][c1][IS_FREE], false,
  308.                 Var.B[t][r1][c1][IS_UNMOVABLE], false,
  309.                 Var.B[t][r2][c2][IS_FREE], false,
  310.                 Var.B[t][r2][c2][IS_UNMOVABLE], false})
  311.                
  312.         for col = 1, TotalColors do
  313.             AddSimpleClause{
  314.                 V[t][r1][c1], false,
  315.                 Var.B[t][r1][c1][col], false,
  316.                 Var.B[t][r1][c1][col], true}
  317.             AddSimpleClause{
  318.                 V[t][r1][c1], false,
  319.                 Var.B[t][r1][c1][col], true,
  320.                 Var.B[t][r2][c2][col], false}
  321.             AddSimpleClause{
  322.                 V[t][r1][c1], true,
  323.                 Var.B[t][r1][c1][col], false,
  324.                 Var.B[t][r2][c2][col], false}
  325.         end
  326.     end
  327.     -- 6420 clauses... for each turn!
  328.     for t = 1, MaximumTurns + 1 do for r = 1, ROWS do for c = 1, COLUMNS do    
  329.         if c < COLUMNS then h(Var.RSC,t,r,c,r,c+1) end
  330.         if r < ROWS then    h(Var.DSC,t,r,c,r+1,c) end
  331.     end end end
  332.    
  333.     --[[
  334.         now the "blocked" check and the "connection" check
  335.         tile r,c is blocked if
  336.             - tile r,c+1 is either unmovable or blocked
  337.             or
  338.             - it has the same color as tile r+1,c which is blocked
  339.             or
  340.             - it has the same color as tile r-1,c which is blocked
  341.             or
  342.             - it has the same color as tile r,c-1 which is blocked
  343.        
  344.         it would be a valid assignment to declare all tiles to be blocked up to now.
  345.         to make sure that all movable tiles get moved, the following is done:
  346.        
  347.             - every tile gets a "blockedness" number
  348.             - (1) if tile r,c+1 is unmovable, or if c == COLUMNS, and tile r,c is not free, then tile r,c is blocked
  349.             - (2) if tiles r1,c1 and r2,c2 are neighbors of the same color, then
  350.                     tile r1,c1 is blocked if and only if tile r2,c2 is blocked
  351.                 and tile r1,c1 is connected to the reference tile if and only if tile r2,c2 is connected to the reference tile
  352.             - (3) if tile r,c is blocked then:
  353.                 -  c == COLUMNS
  354.                 or
  355.                 - tile r,c+1 is unmovable
  356.                 or
  357.                 - the left, upper or lower neighbor has the same color
  358.                         and a lower blockedness number
  359.                 or
  360.                 - the right neighbor has a lower blockedness number
  361.                
  362.                   if tile r,c is connected to zero then:
  363.                 - it is the zero tile
  364.                 or
  365.                 - the left, right, top, or bottom neighbor
  366.                    has the same color AND a lower connection number
  367.             - (4) the reference tile of each color is connected to itself
  368.             - (5) a free tile is never blocked or unmovable
  369.     --]]
  370.    
  371.     print("check blocked...(1)"..total_number_of_clauses)
  372.     --(1)
  373.     for t = 1, MaximumTurns + 1 do for r = 1, ROWS do
  374.         AddSimpleClause{Var.B[t][r][COLUMNS][IS_BLOCKED], true, Var.B[t][r][COLUMNS][IS_FREE], true, Var.B[t][r][COLUMNS][IS_UNMOVABLE], true}
  375.         --(4)
  376.         for c = 1, COLUMNS do
  377.             AddSimpleClause{Var.B[t][r][c][IS_ZERO], false, Var.B[t][r][c][IS_CONNECTED_TO_ZERO], true}
  378.         end
  379.     end end
  380.     for t = 1, MaximumTurns + 1 do for r = 1, ROWS do for c = 1, COLUMNS - 1 do
  381.         AddIfThenClause("if ALL", {Var.B[t][r][c+1][IS_UNMOVABLE], true, Var.B[t][r][c][IS_FREE], false}, "then ALL", {Var.B[t][r][c][IS_BLOCKED], true})
  382.         AddIfThenClause("if ALL", {Var.B[t][r][c+1][IS_BLOCKED], true, Var.B[t][r][c][IS_FREE], false}, "then ALL", {Var.B[t][r][c][IS_BLOCKED], true})
  383.     end end end
  384.    
  385.     print("check blocked...(2)"..total_number_of_clauses)
  386.     --(2)
  387.     for t = 1, MaximumTurns + 1 do for r = 1, ROWS do for c = 1, COLUMNS - 1 do
  388.         AddIfThenClause("if ALL", {Var.RSC[t][r][c], true, Var.B[t][r][c][IS_BLOCKED], true}, "then ALL", {Var.B[t][r][c+1][IS_BLOCKED], true})
  389.         AddIfThenClause("if ALL", {Var.RSC[t][r][c], true, Var.B[t][r][c][IS_BLOCKED], false}, "then ALL", {Var.B[t][r][c+1][IS_BLOCKED], false})
  390.         AddIfThenClause("if ALL", {Var.RSC[t][r][c], true, Var.B[t][r][c][IS_CONNECTED_TO_ZERO], true}, "then ALL", {Var.B[t][r][c+1][IS_CONNECTED_TO_ZERO], true})
  391.         AddIfThenClause("if ALL", {Var.RSC[t][r][c], true, Var.B[t][r][c][IS_CONNECTED_TO_ZERO], false}, "then ALL", {Var.B[t][r][c+1][IS_CONNECTED_TO_ZERO], false})
  392.     end end end
  393.     for t = 1, MaximumTurns + 1 do for r = 1, ROWS - 1 do for c = 1, COLUMNS do
  394.         AddIfThenClause("if ALL", {Var.DSC[t][r][c], true, Var.B[t][r][c][IS_BLOCKED], true}, "then ALL", {Var.B[t][r+1][c][IS_BLOCKED], true})
  395.         AddIfThenClause("if ALL", {Var.DSC[t][r][c], true, Var.B[t][r][c][IS_BLOCKED], false}, "then ALL", {Var.B[t][r+1][c][IS_BLOCKED], false})
  396.         AddIfThenClause("if ALL", {Var.DSC[t][r][c], true, Var.B[t][r][c][IS_CONNECTED_TO_ZERO], true}, "then ALL", {Var.B[t][r+1][c][IS_CONNECTED_TO_ZERO], true})
  397.         AddIfThenClause("if ALL", {Var.DSC[t][r][c], true, Var.B[t][r][c][IS_CONNECTED_TO_ZERO], false}, "then ALL", {Var.B[t][r+1][c][IS_CONNECTED_TO_ZERO], false})
  398.     end end end
  399.    
  400.     print("check blocked...(3)"..total_number_of_clauses)
  401.     --(3)
  402.     -- many many distinct cases... so evil!
  403.     -- there should be some better way to encode this
  404.    
  405.     -- prevent out-of-bound errors
  406.     --
  407.     -- if we write Var.B[t][r-1][c][number] and r == 1,
  408.     -- we get an "attempt to index field ? (a nil value) error"
  409.     -- even if we check that r > 1 beforehand. This can
  410.     -- be prevented only if it is encapsulated with a function call
  411.     --
  412.     -- try the following minimal example:
  413.    
  414.     --[[
  415. t = {"hi"}
  416.  
  417. -- works!
  418. function h(b,f)
  419.     if b then return f() else return "no!" end
  420. end
  421.  
  422. print(t[1]..","..tostring(t[2])..h(false, function() return t[2][1] end))
  423.  
  424. -- does not work! attempt to index field ? (a nil value)
  425. function h(b,f)
  426.     if b then return f else return "no!" end
  427. end
  428.  
  429. print(t[1]..","..tostring(t[2])..h(false, t[2][1]))
  430.     --]]
  431.    
  432.     function OOB_catcher(b, f)
  433.         if b then return f() else return nil end
  434.     end
  435.    
  436.     -- how beautiful, 7 loops!
  437.     -- there will be some duplicate clauses, it is easier
  438.     -- to let the solver remove them than to handle this here.
  439.     for t = 1, MaximumTurns + 1 do
  440.     for r = 1, ROWS do
  441.     for c = 1, COLUMNS do
  442.    
  443.     for _,b1 in pairs{true,false} do
  444.     for _,b2 in pairs{true,false} do
  445.     for _,b3 in pairs{true,false} do
  446.        
  447.         -- there is one reference tile of each color.
  448.         -- if the puzzle is solved, all tiles are connected to the reference tile
  449.         --
  450.         -- if a tile is connected to the reference tile,
  451.         --      - it is the reference tile itself
  452.         --   OR - it is connected to a tile with a lower connection number.
  453.         -- it would make sense that the reference tile has connection number zero but that isnt enforced.
  454.         for _,b4 in pairs{true,false} do
  455.             local function h(cl, a1, a2)
  456.                 cl[#cl+1] = a1
  457.                 cl[#cl+1] = a2
  458.             end
  459.            
  460.             local cl1 = {Var.B[t][r][c][IS_CONNECTED_TO_ZERO], true}
  461.             if r > 1 then h(cl1, Var.DSC[t][r-1][c], b1) end
  462.             if r < ROWS then h(cl1, Var.DSC[t][r][c], b2) end
  463.             if c > 1 then h(cl1, Var.RSC[t][r][c-1], b3) end
  464.             if c < COLUMNS then h(cl1, Var.RSC[t][r][c], b4) end
  465.            
  466.             local cl2 = {Var.B[t][r][c][IS_ZERO], true}
  467.             --[[up   ]] if r > 1 and b1 then h(cl2, Var.B[t][r-1][c][B_CONNECTION_NUMBER_COMPARE_DOWN_OFFSET + BITS - 1], false) end
  468.             --[[down ]] if r < ROWS and b2 then h(cl2, Var.B[t][r][c][B_CONNECTION_NUMBER_COMPARE_DOWN_OFFSET + BITS - 1], true) end
  469.             --[[left ]] if c > 1 and b3 then h(cl2, Var.B[t][r][c-1][B_CONNECTION_NUMBER_COMPARE_RIGHT_OFFSET + BITS - 1], false) end
  470.             --[[right]] if c < COLUMNS and b4 then h(cl2, Var.B[t][r][c][B_CONNECTION_NUMBER_COMPARE_RIGHT_OFFSET + BITS - 1], true) end
  471.            
  472.             AddIfThenClause("if ALL", cl1, "then ONE", cl2)
  473.         end
  474.         -- if a tile is blocked then:
  475.         --     - the tile to its right is unmovable
  476.         --  OR - its right neighbor is not free and has a lower blockedness number
  477.         --  OR - its left, top, or bottom neighbor has the same color AND a lower blockedness number
  478.         if c < COLUMNS then
  479.             local function h(cl, a1, a2)
  480.                 cl[#cl+1] = a1
  481.                 cl[#cl+1] = a2
  482.             end
  483.            
  484.             for _,b4 in pairs{true,false} do
  485.                 local cl1 = {Var.B[t][r][c][IS_BLOCKED], true}
  486.                 if r > 1 then h(cl1, Var.DSC[t][r-1][c], b1) end
  487.                 if r < ROWS then h(cl1, Var.DSC[t][r][c], b2) end
  488.                 if c > 1 then h(cl1, Var.RSC[t][r][c-1], b3) end
  489.                 h(cl1, Var.B[t][r][c+1][IS_FREE], b4)
  490.                
  491.                 local cl2 = {Var.B[t][r][c+1][IS_UNMOVABLE], true}     
  492.                 if r > 1 and b1    then h(cl2, Var.B[t][r-1][c][B_BLOCK_NUMBER_COMPARE_DOWN_OFFSET + BITS - 1], false) end -- less or equal is enough to prevent loops
  493.                 if r < ROWS and b2 then h(cl2, Var.B[t][r][c][B_BLOCK_NUMBER_COMPARE_DOWN_OFFSET + BITS - 1], true) end
  494.                 if c > 1 and b3    then h(cl2, Var.B[t][r][c-1][B_BLOCK_NUMBER_COMPARE_RIGHT_OFFSET + BITS - 1], false) end
  495.                 if not b4          then h(cl2, Var.B[t][r][c][B_BLOCK_NUMBER_COMPARE_RIGHT_OFFSET + BITS - 1], true) end
  496.                
  497.                 AddIfThenClause("if ALL", cl1, "then ONE", cl2)
  498.             end
  499.         end
  500.        
  501.     end end end end end end
  502.    
  503.     --(5)
  504.     for t = 1, MaximumTurns + 1 do for r = 1, ROWS do for c = 1, COLUMNS do
  505.         AddSimpleClause{Var.B[t][r][c][IS_FREE], false,    Var.B[t][r][c][IS_UNMOVABLE], false}
  506.         AddSimpleClause{Var.B[t][r][c][IS_BLOCKED], false, Var.B[t][r][c][IS_FREE], false}
  507.     end end end
  508.    
  509.     print("move!..."..total_number_of_clauses)
  510.     -- now make the move!
  511.     for t = 1, MaximumTurns do
  512.     for r = 1, ROWS do
  513.     for entry = 1, #Var.A[1][1][1] do
  514.     for _,b in pairs{true, false} do
  515.        
  516.         for c = 1, COLUMNS do
  517.             -- a blocked tile or an unmovable tile stays in place
  518.             for _,e1 in pairs{IS_BLOCKED, IS_UNMOVABLE} do
  519.                 AddIfThenClause("if ALL", {Var.B[t][r][c][e1], true, Var.B[t][r][c][entry], b},
  520.                     "then ALL", {Var.A[t+1][r][c][entry], b})
  521.             end
  522.            
  523.             -- otherwise:
  524.                 -- if the tile to the left is neither blocked nor unmovable, move!
  525.            
  526.             if c > 1 then
  527.                 AddIfThenClause(
  528.                     "if ALL", {
  529.                     Var.B[t][r][c][IS_UNMOVABLE], false,
  530.                     Var.B[t][r][c][IS_BLOCKED], false,
  531.                     Var.B[t][r][c-1][IS_UNMOVABLE], false,
  532.                     Var.B[t][r][c-1][IS_BLOCKED], false,
  533.                     Var.B[t][r][c-1][entry], b},
  534.                     "then ALL", {
  535.                     Var.A[t+1][r][c][entry], b}
  536.                 )
  537.                
  538.                 -- if the tile to the left is blocked or unmovable, this tile becomes free!
  539.                 if b then
  540.                     AddIfThenClause(
  541.                         "if ALL", {
  542.                         Var.B[t][r][c][IS_UNMOVABLE], false,
  543.                         Var.B[t][r][c][IS_BLOCKED], false,
  544.                         Var.B[t][r][c-1][IS_UNMOVABLE], true},
  545.                         "then ALL", {
  546.                         Var.A[t+1][r][c][entry], entry == IS_FREE}
  547.                     )
  548.                     AddIfThenClause(
  549.                         "if ALL", {
  550.                         Var.B[t][r][c][IS_UNMOVABLE], false,
  551.                         Var.B[t][r][c][IS_BLOCKED], false,
  552.                         Var.B[t][r][c-1][IS_BLOCKED], true},
  553.                         "then ALL", {
  554.                         Var.A[t+1][r][c][entry], entry == IS_FREE}
  555.                     )
  556.                 end
  557.             else
  558.                 -- if there is no tile to the left, there is new free space!
  559.                 if b then
  560.                     AddIfThenClause(
  561.                         "if ALL", {
  562.                         Var.B[t][r][c][IS_UNMOVABLE], false,
  563.                         Var.B[t][r][c][IS_BLOCKED], false},
  564.                         "then ALL", {
  565.                         Var.A[t+1][r][c][entry], entry == IS_FREE}
  566.                     )
  567.                 end
  568.             end
  569.         end
  570.        
  571.     end end end end
  572.    
  573.     print("winning condition check!.."..total_number_of_clauses)
  574.     -- finally, check the winning condition. so easy now!
  575.     local V = Var.B[MaximumTurns+1]
  576.     for r = 1, ROWS do for c = 1, COLUMNS do
  577.         local cl = {V[r][c][IS_FREE], true, V[r][c][IS_UNMOVABLE], true, V[r][c][IS_CONNECTED_TO_ZERO], true}
  578.         for col = TotalColorsToConnect + 1, TotalColors do
  579.             cl[#cl+1] = V[r][c][col]
  580.             cl[#cl+1] = true
  581.         end
  582.         AddSimpleClause(cl)
  583.     end end
  584.     print("done!.."..total_number_of_clauses)
  585. end
  586.  
  587. function MovementPattern()
  588.     local num = {
  589.         [false] = {[false] = 0, [true]  = 1},
  590.         [true] = {[false] = 2, [true] = 3 }}
  591.     local name = {[0] = "right", "up", "left", "down"}
  592.    
  593.     --[[
  594.     -- this is how R was used
  595.     for r = 1, ROWS do for c = 1, COLUMNS do
  596.         -- rotate 0 degrees
  597.         h(false, false, r, c, r, c)
  598.         -- 90 degrees right
  599.         h(false, true, r, c, c, ROWS + 1 - r)
  600.         -- 180 degrees right
  601.         h(true, false, r, c, ROWS + 1 - r, COLUMNS + 1 - c)
  602.         -- 270 degrees right
  603.         h(true, true,  r, c, COLUMNS + 1 - c, r)
  604.     end end --]]
  605.    
  606.     now = 0
  607.     ret = {}
  608.     for t = 1, #Sol.R do
  609.         now = (now + num[Sol.R[t][1]][Sol.R[t][2]]) % 4
  610.         ret[#ret+1] = name[now]
  611.     end
  612.     return ret
  613. end
  614.  
  615. CreateCNF()
  616. WriteSATfile()
  617. if USE_PICOSAT then
  618.     os.execute("picosat satfile.cnf >solutionfile")
  619. elseif USE_MINISAT then
  620.     os.execute("minisat satfile.cnf solutionfile")
  621. end
  622. ParseSolution()
  623. for i,m in ipairs(MovementPattern()) do
  624.     for r = 1, ROWS do
  625.         local s = ""
  626.         for c = 1, COLUMNS do
  627.             for entry = 1, #Sol.A[1][1][1] do
  628.                 if Sol.A[i][r][c][entry] then s = s .. entry else s = s .. " " end
  629.                 end
  630.             s = s.."|"
  631.         end
  632.         print(s)
  633.     end
  634.     print (i..": "..m)
  635.     for r = 1, ROWS do
  636.         local s = ""
  637.         for c = 1, COLUMNS do
  638.             for entry = 1, #Sol.A[1][1][1] do
  639.                 if Sol.B[i][r][c][entry] then s = s .. entry else s = s .. " " end
  640.             end
  641.             if c < COLUMNS then if Sol.RSC[i][r][c] then  s = s.."---" else s = s .. " ; " end end
  642.         end
  643.         print(s)
  644.         s = " "
  645.         spaces = #Sol.A[1][1][1]+3
  646.         for c = 1, COLUMNS do
  647.             if r < ROWS then
  648.                 if Sol.DSC[i][r][c] then s = s .. "|" end
  649.             else
  650.                 s = s .. " "
  651.             end
  652.             if Sol.B[i][r][c][IS_BLOCKED] then s = s .. "B" else s = s .. " " end
  653.             local n = 0
  654.             local f = 1
  655.             for b = 0, BITS - 1 do
  656.                 if Sol.B[i][r][c][B_BLOCK_NUMBER_OFFSET + b] then n = n + f end
  657.                 f = f * 2
  658.             end
  659.             s = s..n
  660.             s = s .. string.rep(" ", c*spaces-2-string.len(s)).."/ "
  661.         end
  662.        
  663.         print(s)
  664.         print()
  665.     end
  666.     print()
  667. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement