CaptainSpaceCat

2048 Heuristic AI

Feb 24th, 2017
177
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.51 KB | None | 0 0
  1. local maxNum = 2
  2. local score = 0
  3. local won, showWin = false, true
  4. local w, h = term.getSize()
  5. local midW, midH = math.floor(w/2), math.floor(h/2)
  6. local gametab = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}
  7. local colTab = {
  8.     [0] = colors.black,
  9.     [2] = colors.white,
  10.     [4] = colors.white,
  11.     [8] = colors.orange,
  12.     [16] = colors.orange,
  13.     [32] = colors.red,
  14.     [64] = colors.red,
  15.     [128] = colors.yellow,
  16.     [256] = colors.yellow,
  17.     [512] = colors.yellow,
  18.     [1024] = colors.yellow,
  19.     [2048] = colors.yellow,
  20.     [4096] = colors.green,
  21.     [8192] = colors.purple
  22. }
  23. local glitchWorkaround = {
  24.     [0] = " ",
  25.     [2] = "2",
  26.     [4] = "4",
  27.     [8] = "8",
  28.     [16] = "16",
  29.     [32] = "32",
  30.     [64] = "64",
  31.     [128] = "128",
  32.     [256] = "256",
  33.     [512] = "512",
  34.     [1024] = "1024",
  35.     [2048] = "2048",
  36.     [4096] = "4096",
  37.     [8192] = "8192"
  38. }
  39.  
  40. local function initialTiles(numtab)
  41.     local y, x
  42.     for i = 1, 2 do
  43.         repeat
  44.             x = math.random(1, 4)
  45.             y = math.random(1, 4)
  46.         until numtab[y][x] == 0
  47.         numtab[y][x] = 2
  48.     end
  49. end
  50.  
  51. local function spawnTile(tileNum, numtab)
  52.     local availableSpots = {}
  53.     for y = 1, 4 do
  54.         for x = 1, 4 do
  55.             if numtab[y][x] == 0 then
  56.                 availableSpots[#availableSpots + 1] = {y, x}
  57.             end
  58.         end
  59.     end
  60.     local choice = availableSpots[math.random(1, #availableSpots)]
  61.     numtab[choice[1]][choice[2]] = tileNum
  62. end
  63.  
  64. local function eventHandler(events, numtab, virtual)
  65.     virtual = virtual or false
  66.     local points = 0
  67.     if true then
  68.         local changed = false
  69.         if events == 1 then --up
  70.             for x = 1, 4 do
  71.                 local moveMode = false
  72.                 for y = 2, 4 do
  73.                     for i = 0, y - 2 do
  74.                         if numtab[y - i][x] == 0 then
  75.                         elseif numtab[y - 1 - i][x] == 0 then
  76.                             numtab[y - 1 - i][x] = numtab[y - i][x]
  77.                             numtab[y - i][x] = 0
  78.                             changed = true
  79.                         elseif not moveMode and numtab[y - 1 - i][x] == numtab[y - i][x] then
  80.                             numtab[y - 1 - i][x] = numtab[y - i][x] * 2
  81.                             points = points + numtab[y - i][x] * 2
  82.                             numtab[y - i][x] = 0
  83.                             changed = true
  84.                             moveMode = true
  85.                             break
  86.                         else moveMode = false; break end
  87.                     end
  88.                 end
  89.             end
  90.         elseif events == 2 then --right
  91.             for y = 1, 4 do
  92.                 local moveMode = false
  93.                 for x = 3, 1, -1 do
  94.                     for i = 0, 3 - x do
  95.                         if numtab[y][x + i] == 0 then
  96.                         elseif numtab[y][x + 1 + i] == 0 then
  97.                             numtab[y][x + 1 + i] = numtab[y][x + i]
  98.                             numtab[y][x + i] = 0
  99.                             changed = true
  100.                         elseif not moveMode and numtab[y][x + 1 + i] == numtab[y][x + i] then
  101.                             numtab[y][x + 1 + i] = numtab[y][x + i] * 2
  102.                             points = points + numtab[y][x + i] * 2
  103.                             numtab[y][x + i] = 0
  104.                             changed = true
  105.                             moveMode = true
  106.                             break
  107.                         else moveMode = false; break end
  108.                     end
  109.                 end
  110.             end
  111.         elseif events == 3 then --down
  112.             for x = 1, 4 do
  113.                 local moveMode = false
  114.                 for y = 3, 1, -1 do
  115.                     for i = 0, 3 - y do
  116.                         if numtab[y + i][x] == 0 then
  117.                         elseif numtab[y + 1 + i][x] == 0 then
  118.                             numtab[y + 1 + i][x] = numtab[y + i][x]
  119.                             numtab[y + i][x] = 0
  120.                             changed = true
  121.                         elseif not moveMode and numtab[y + 1 + i][x] == numtab[y + i][x] then
  122.                             numtab[y + 1 + i][x] = numtab[y + i][x] * 2
  123.                             points = points + numtab[y + i][x] * 2
  124.                             numtab[y + i][x] = 0
  125.                             changed = true
  126.                             moveMode = true
  127.                             break
  128.                         else moveMode = false; break end
  129.                     end
  130.                 end
  131.             end
  132.         elseif events == 4 then --left
  133.             for y = 1, 4 do
  134.                 local moveMode = false
  135.                 for x = 2, 4 do
  136.                     for i = 0, x - 2 do
  137.                         if numtab[y][x - i] == 0 then
  138.                         elseif numtab[y][x - 1 - i] == 0 then
  139.                             numtab[y][x - 1 - i] = numtab[y][x - i]
  140.                             numtab[y][x - i] = 0
  141.                             changed = true
  142.                         elseif not moveMode and numtab[y][x - 1 - i] == numtab[y][x - i] then
  143.                             numtab[y][x - 1 - i] = numtab[y][x - i] * 2
  144.                             points = points + numtab[y][x - i] * 2
  145.                             numtab[y][x - i] = 0
  146.                             changed = true
  147.                             moveMode = true
  148.                             break
  149.                         else moveMode = false; break end
  150.                     end
  151.                 end
  152.             end
  153.         end
  154.         if changed then
  155.             if not virtual then
  156.                 local c = math.random(1, 10)
  157.                 if c == 10 then spawnTile(4, numtab) else spawnTile(2, numtab) end
  158.             else
  159.                 --choose worst possible spot
  160.             end
  161.         end
  162.     end
  163.     if not virtual then score = score + points end
  164.     return points
  165. end
  166.  
  167. local function checkState(numtab)
  168.     for y = 1, 4 do
  169.         for x = 1, 4 do
  170.             if numtab[y][x] > maxNum then maxNum = numtab[y][x] end
  171.             if numtab[y][x] == 2048 then won = true end
  172.         end
  173.     end
  174.     local flag = false
  175.     for y = 1, 4 do
  176.         for x = 1, 4 do
  177.             if numtab[y][x] == 0 then
  178.                 flag = true
  179.             elseif y > 1 and numtab[y - 1][x] == numtab[y][x] then
  180.                 flag = true
  181.             elseif y < 4 and numtab[y + 1][x] == numtab[y][x] then
  182.                 flag = true
  183.             elseif x > 1 and numtab[y][x - 1] == numtab[y][x] then
  184.                 flag = true
  185.             elseif x < 4 and numtab[y][x + 1] == numtab[y][x] then
  186.                 flag = true
  187.             end
  188.             if flag then break end
  189.         end
  190.     end
  191.     if not flag then return false end
  192.     return true
  193. end
  194.  
  195. local function printTiles(numtab, dir)
  196.     dir = dir or 0
  197.     if maxNum == 16384 then
  198.         term.setBackgroundColor(colors.black)
  199.         term.clear()
  200.         term.setCursorPos(1, 1)
  201.         error("ERROR: User is too f*cking good at this... failure to parse awesomeness level...")
  202.     end
  203.     term.setBackgroundColor(colTab[maxNum])
  204.     term.clear()
  205.     paintutils.drawFilledBox(midW - 7, midH - 8, midW + 10, midH + 14, colors.gray)
  206.     for y = 1, 4 do
  207.         for x = 1, 4 do
  208.             paintutils.drawFilledBox(midW - 10 + x*4, midH - 11 + y*4, midW - 11 + (x+1)*4, midH - 12 + (y+1)*4, colTab[numtab[y][x]])
  209.             term.setCursorPos(midW - 10 + x*4, midH - 10 + y*4)
  210.             if numtab[y][x] == 2 or numtab[y][x] == 4 then
  211.                 term.setTextColor(colors.black)
  212.             else term.setTextColor(colors.white) end
  213.             term.write(glitchWorkaround[numtab[y][x]])
  214.         end
  215.     end
  216.     term.setBackgroundColor(colTab[maxNum])
  217.     term.setTextColor(colTab[maxNum] == colors.white and colors.black or colors.white)
  218.     term.setCursorPos(w - 4, 1)
  219.     term.write("Score")
  220.     term.setCursorPos(w - #tostring(score) + 1, 2)
  221.     term.write(score)
  222.     if dir > 0 then
  223.         term.setCursorPos(2, 10)
  224.         term.setBackgroundColor(colors.black)
  225.         term.setTextColor(colors.white)
  226.         if dir == 1 then write("up")
  227.         elseif  dir == 2 then write("right")
  228.         elseif  dir == 3 then write("down")
  229.         elseif  dir == 4 then write("left") end
  230.     end
  231. end
  232.  
  233. local function copyTab(a, b)
  234.     for i = 1, #a do
  235.         for v = 1, #a[1] do
  236.             b[i][v] = a[i][v]
  237.         end
  238.     end
  239. end
  240.  
  241. local function checkEqual(a, b)
  242.     for i = 1, #a do
  243.         for v = 1, #a[1] do
  244.             if b[i][v] ~= a[i][v] then return false end
  245.         end
  246.     end
  247.     return true
  248. end
  249.  
  250. function countScore(numtab)
  251.     --local weight = {{1, .95, .9, .85}, {.65, .7, .75, .8}, {.6, .55, .5, .45}, {.25, .3, .35, .4}}
  252.     local weight = {{1, .95, .9, .85}, {.65, .7, .75, .8}, {.6, .55, .5, .45}, {.25, .3, .35, .4}}
  253.     local total = 0
  254.     for i = 1, #numtab do
  255.         for v = 1, #numtab[1] do
  256.             total = total + numtab[i][v]*weight[i][v]
  257.         end
  258.     end
  259.     return total
  260. end
  261.  
  262. function countEmptySpaces(numtab)
  263.     local total = 0
  264.     for i = 1, #numtab do
  265.         for v = 1, #numtab[1] do
  266.             if numtab[i][v] == 0 then total = total + 1 end
  267.         end
  268.     end
  269.     return total
  270. end
  271.  
  272. function penalty(numtab)
  273.     total = 0
  274.     order = {{1, 1}, {1, 2}, {1, 3}, {1, 4}, {2, 4}, {2, 3}, {2, 2}, {2, 1}, {3, 1}, {3, 2}, {3, 3}, {3, 4}, {4, 4}, {4, 3}, {4, 2}, {4, 1}}
  275.     for i = 2, #order do
  276.         if numtab[order[i][1]][order[i][2]] > numtab[order[i-1][1]][order[i-1][2]] then
  277.             total = total + numtab[order[i][1]][order[i][2]]*.5
  278.         end
  279.     end
  280.     return total
  281. end
  282.  
  283. function bonus(numtab)
  284.     local total = 0
  285.     for i = 1, #numtab do
  286.         for v = 1, #numtab[1] do
  287.             if i > 1 then
  288.                 if numtab[i-1][v] == 2*numtab[i-1][v] then
  289.                     total = total + numtab[i][v]*.1
  290.                 end
  291.             end
  292.         end
  293.     end
  294.     return total
  295. end
  296.  
  297. function heuristicScore(numtab, layer)
  298.     if checkEqual(numtab, gametab) then return 0 end
  299.     if layer == 1 then
  300.         return countScore(numtab) - penalty(numtab)
  301.     else
  302.         return computeChoice(numtab, layer-1)
  303.     end
  304. end
  305.  
  306. function computeChoice(numtab, layer)
  307.     layer = layer or 1
  308.     local choices = {}
  309.     for i = 1, 4 do
  310.         local potential = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}
  311.         copyTab(numtab, potential)
  312.         extrascore = eventHandler(i, potential, true)
  313.         choices[i] = heuristicScore(potential, layer)
  314.     end
  315.     local priority = {1, 4, 2, 3}
  316.     local decision = priority[1]
  317.     for i = 2, 4 do
  318.         if choices[priority[i]] > choices[decision] then decision = priority[i] end
  319.     end
  320.     return decision
  321. end
  322.  
  323. initialTiles(gametab)
  324. local gameState = true
  325. local prevDir = 0
  326. while gameState do
  327.     if won and showWin then
  328.         printTiles(gametab)
  329.         term.setBackgroundColor(colors.yellow)
  330.         term.setTextColor(colors.white)
  331.         for i = 0, 1 do
  332.             term.setCursorPos(1, midH + i)
  333.             term.clearLine()
  334.         end
  335.         term.setCursorPos(midW, midH)
  336.         term.write("2048")
  337.         term.setCursorPos(midW - 2, midH + 1)
  338.         term.write("Victory!")
  339.         sleep(.5)
  340.         coroutine.yield("key")
  341.         showWin = false
  342.     end
  343.     printTiles(gametab, prevDir)
  344.     coroutine.yield("key")
  345.     --local events = {os.pullEvent()}
  346.     local compChoice = computeChoice(gametab)
  347.     prevDir = compChoice
  348.     eventHandler(compChoice, gametab)
  349.     gameState = checkState(gametab)
  350. end
  351. printTiles(gametab)
  352. term.setBackgroundColor(colors.red)
  353. term.setTextColor(colors.white)
  354. for i = 0, 1 do
  355.     term.setCursorPos(1, midH + i)
  356.     term.clearLine()
  357. end
  358. term.setCursorPos(midW - #tostring(score)/2 + 2, midH)
  359. term.write(score)
  360. term.setCursorPos(midW - 2, midH + 1)
  361. term.write("You Lose")
  362. sleep(.5)
  363. coroutine.yield("key")
  364. term.setBackgroundColor(colors.black)
  365. term.clear()
  366. term.setCursorPos(1, 1)
Add Comment
Please, Sign In to add comment