Advertisement
Guest User

day15

a guest
Dec 15th, 2018
329
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.07 KB | None | 0 0
  1. local grid, units;
  2. local function loadinput()
  3.     grid, units = {}, {}
  4.     for line in getinput():gmatch("[^\n]+") do
  5.         local t = {}
  6.         grid[#grid+1] = t
  7.         for c in line:gmatch(".") do
  8.             t[#t+1] = c
  9.             if c == "E" or c == "G" then
  10.                 units[#units+1] = {kind = c, health = 200, x = #t, y = #grid}
  11.             end
  12.         end
  13.     end
  14. end
  15.  
  16. local function getunit(y, x)
  17.     for _, unit in pairs(units) do
  18.         if unit.y == y and unit.x == x and unit.health > 0 then
  19.             return unit
  20.         end
  21.     end
  22. end
  23.  
  24. local function drawgrid()
  25.     for y = 1, #grid do
  26.         local data = ""
  27.         for x = 1, #grid[y] do
  28.             if grid[y][x] == "E" or grid[y][x] == "G" then
  29.                 local unit = getunit(y, x) or {health = 0}
  30.                 data = data.." "..grid[y][x].."("..unit.health..")"
  31.             end
  32.         end
  33.         print(table.concat(grid[y], "")..data)
  34.     end
  35. end
  36.  
  37. local function open(y, x)
  38.     if not grid[y] then return false end
  39.     return grid[y][x] == "."
  40. end
  41.  
  42. local function priority(y1, x1, y2, x2)
  43.     if y1 == y2 then return x1 < x2 end
  44.     return y1 < y2
  45. end
  46.  
  47. local function step(atk)
  48.     for _, u in pairs(units) do
  49.         u.moved = false
  50.     end
  51.     for y = 1, #grid do
  52.         for x = 1, #grid[y] do
  53.             local y = y
  54.             local c = grid[y][x]
  55.             if c == "E" or c == "G" then
  56.                 local gcount, ecount = 0, 0
  57.                 for y = 1, #grid do
  58.                     for x = 1, #grid[y] do
  59.                         if grid[y][x] == "E" then
  60.                             ecount = ecount + 1
  61.                         elseif grid[y][x] == "G" then
  62.                             gcount = gcount + 1
  63.                         end
  64.                     end
  65.                 end
  66.                 if gcount == 0 or ecount == 0 then return "end" end
  67.                 local thisunit = getunit(y, x)
  68.                 if not thisunit.moved then
  69.                     thisunit.moved = true
  70.                     local enemy = (c == "E" and "G" or "E")
  71.                     local adjacent = {}
  72.                     local function checkneighbor(y, x)
  73.                         if not grid[y] then return end
  74.                         if grid[y][x] == enemy then
  75.                             adjacent[#adjacent+1] = {y = y, x = x, unit = getunit(y, x)}
  76.                         end
  77.                     end
  78.                     local function checkneighbors(y, x)
  79.                         checkneighbor(y-1, x)
  80.                         checkneighbor(y, x-1)
  81.                         checkneighbor(y, x+1)
  82.                         checkneighbor(y+1, x)
  83.                     end
  84.                     checkneighbors(y, x)
  85.                     if #adjacent == 0 then
  86.                         local targets = {}
  87.                         local function addtarget(y, x)
  88.                             if open(y, x) then
  89.                                 targets[#targets+1] = {y = y, x = x}
  90.                             end
  91.                         end
  92.                         for _, u in pairs(units) do
  93.                             if u.health > 0 and u.kind == enemy then
  94.                                 local Y, X = u.y, u.x
  95.                                 addtarget(Y+1, X)
  96.                                 addtarget(Y, X-1)
  97.                                 addtarget(Y, X+1)
  98.                                 addtarget(Y-1, X)
  99.                             end
  100.                         end
  101.                         local paths = {}
  102.                         for _, e in pairs(targets) do
  103.                             local visited = {[y] = {[x] = true}}
  104.                             local solution;
  105.                             local stack = {{y = y, x = x}}
  106.                             repeat
  107.                                 local newstack = {}
  108.                                 local function checkpos(y, x, p)
  109.                                     if open(y, x) and (not visited[y] or not visited[y][x]) then
  110.                                         local newpos = {y = y, x = x, parent = p}
  111.                                         newstack[#newstack+1] = newpos
  112.                                         visited[y] = visited[y] or {}
  113.                                         visited[y][x] = true
  114.                                         if y == e.y and x == e.x then
  115.                                             solution = solution or newpos
  116.                                         end
  117.                                     end
  118.                                 end
  119.                                 for _, p in pairs(stack) do
  120.                                     local y, x = p.y, p.x
  121.                                     checkpos(y-1, x, p)
  122.                                     checkpos(y, x-1, p)
  123.                                     checkpos(y, x+1, p)
  124.                                     checkpos(y+1, x, p)
  125.                                 end
  126.                                 stack = newstack
  127.                             until solution or #stack == 0
  128.                             if solution then
  129.                                 local list = {solution}
  130.                                 while list[1].parent do
  131.                                     table.insert(list, 1, list[1].parent)
  132.                                 end
  133.                                 paths[#paths+1] = {path = list, target = e}
  134.                             end
  135.                         end
  136.                         table.sort(paths, function(a, b)
  137.                             if #a.path == #b.path then
  138.                                 return priority(a.target.y, a.target.x, b.target.y, b.target.x)
  139.                             end
  140.                             return #a.path < #b.path
  141.                         end)
  142.                         local path = paths[1]
  143.                         if path then
  144.                             local step = path.path[2]
  145.                             grid[y][x] = "."
  146.                             grid[step.y][step.x] = c
  147.                             y, x = step.y, step.x
  148.                             thisunit.y, thisunit.x = y, x
  149.                             adjacent = {}
  150.                             checkneighbors(y, x)
  151.                         end
  152.                     end
  153.                     table.sort(adjacent, function(a, b)
  154.                         if a.unit.health == b.unit.health then
  155.                             return priority(a.y, a.x, b.y, b.x)
  156.                         end
  157.                         return a.unit.health < b.unit.health
  158.                     end)
  159.                     local victim = adjacent[1] and adjacent[1].unit
  160.                     if victim then
  161.                         victim.health = victim.health - (c == "E" and atk or 3)
  162.                         if victim.health <= 0 then
  163.                             if grid[victim.y][victim.x] == "E" then return "killed" end
  164.                             grid[victim.y][victim.x] = "."
  165.                         end
  166.                     end
  167.                 end
  168.             end
  169.         end
  170.     end
  171. end
  172.  
  173. local function getoutcome(atk)
  174.     local rounds = 0
  175.     loadinput()
  176.     while true do
  177.         print(rounds, atk)
  178.         local v = step(atk)
  179.         if v == "killed" then
  180.             return "killed"
  181.         elseif v ~= "end" then
  182.             rounds = rounds + 1
  183.         else
  184.             break
  185.         end
  186.     end
  187.     local healthsum = 0
  188.     for _, u in pairs(units) do
  189.         if u.health > 0 then
  190.             healthsum = healthsum + u.health
  191.         end
  192.     end
  193.     return healthsum*rounds
  194. end
  195. for atk = 4, 100 do
  196.     local result = getoutcome(atk)
  197.     if result ~= "killed" then
  198.         drawgrid()
  199.         print(atk, result)
  200.         break
  201.     end
  202. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement