require "ext" local parse_map = true local map = {} local row,col = 0,0 local start local commands = {} local function parse_command(line) local commands = {} local ccursor = line while ccursor ~= "" do if ccursor:find("^%d") then table.insert(commands,{type="walk",n=ccursor:match("^(%d+)")}) ccursor = ccursor:gsub("^(%d+)","") elseif ccursor:find("^[LR]") then table.insert(commands,{type="turn",n=ccursor:match("^([LR])")}) ccursor = ccursor:gsub("^[LR]","") end end return commands end for line in io.lines() do row = row + 1 if line ~= "" and parse_map then col = 0 for char in line:gmatch("(.)") do col = col + 1 local locf = string.format("%d,%d",row,col) if char == "." then if start == nil then start = locf end map[locf] = true elseif char == "#" then map[locf] = false end --else, it's nil end elseif line == "" and parse_map then parse_map = false elseif not parse_map then commands = parse_command(line) end end local directions = { up = {-1, 0}, down = {1,0}, left = {0,-1}, right = {0,1} } local dirmap = { [0] = { name = "right", R = 1, L = 3 }, [1] = { name = "down", R = 2, L = 0 }, [2] = { name = "left", R = 3, L = 1 }, [3] = { name = "up", R = 0, L = 2 } } local dirnames = { [directions.up] = "up", [directions.down] = "down", [directions.left] = "left", [directions.right] = "right" } local rev_dirmap = {} for i,t in pairs(dirmap) do rev_dirmap[t.name] = i end local mem_loop = {} --Planning: -- 6 <-> 7 -- 5 <-> 9 -- 13 <-> 12 -- -- 1 <-> 11 -- 2 <-> 14 -- 4 <-> 10 -- 8 <-> 3 local function find_loop_loc(sloc, direction) print("Finding loop location from",sloc,"dir",dirnames[direction]) --[[ if mem_loop[sloc] and mem_loop[sloc][direction] then return mem_loop[sloc][direction][1], mem_loop[sloc][direction][2] end ]] local srow, scol = sloc:match("(%d+),(%d+)") srow, scol = tonumber(srow),tonumber(scol) --just hard-code looping rules local rloc, rdir if srow == 1 and scol > 50 and scol <= 100 and direction == directions.up then -- 1 -> 11 print("1->11") rloc = string.format("%d,%d",100+scol,1) rdir = rev_dirmap.right elseif scol == 1 and srow > 150 and srow <= 200 and direction == directions.left then -- 11 -> 1 print("11->1") rloc = string.format("%d,%d",1,srow - 100) rdir = rev_dirmap.down elseif srow == 1 and scol > 100 and scol <= 150 and direction == directions.up then -- 2 -> 14 print("2->14") rloc = string.format("%d,%d", 200, scol - 100) rdir = rev_dirmap.up elseif srow == 200 and scol > 0 and scol <= 50 and direction == directions.down then -- 14 ->2 print("14->2") rloc = string.format("%d,%d", 1, scol + 100) rdir = rev_dirmap.down elseif scol == 51 and srow > 0 and srow <= 50 and direction == directions.left then -- 3 -> 8 print("3->8") rloc = string.format("%d,%d", (50 - srow) + 101, 1) rdir = rev_dirmap.right elseif scol == 1 and srow > 100 and srow <= 150 and direction == directions.left then -- 8 -> 3 print("8->3") rloc = string.format("%d,%d", ((150 - srow) - 100) + 101, 51) rdir = rev_dirmap.right elseif scol == 150 and srow > 0 and srow <= 100 and direction == directions.right then -- 4 -> 10 print("4->10") rloc = string.format("%d,%d", (50 - srow) + 101, 100) rdir = rev_dirmap.left elseif scol == 100 and srow > 100 and srow <= 150 and direction == directions.right then -- 10 -> 4 print("10->4") rloc = string.format("%d,%d", (151 - srow), 150) rdir = rev_dirmap.left elseif scol == 51 and srow > 50 and srow <= 100 and direction == directions.left then -- 5 -> 9 print("5->9") rloc = string.format("%d,%d", 101, srow-50) rdir = rev_dirmap.down elseif srow == 101 and scol > 0 and scol <= 50 and direction == directions.up then -- 9 -> 5 print("9->5") rloc = string.format("%d,%d", scol + 50, 51) rdir = rev_dirmap.right elseif srow == 50 and scol > 100 and scol <= 150 and direction == directions.down then -- 6 -> 7 print("6->7") rloc = string.format("%d,%d", scol - 50, 100) rdir = rev_dirmap.left elseif scol == 100 and srow > 50 and srow <= 100 and direction == directions.right then -- 7 -> 6 print("7->6") rloc = string.format("%d,%d", 50, srow + 50) rdir = rev_dirmap.up elseif srow == 150 and scol > 50 and scol <= 100 and direction == directions.down then -- 12 -> 13 print("12->13") rloc = string.format("%d,%d", scol + 100, 50) rdir = rev_dirmap.left elseif scol == 50 and srow > 150 and srow <= 200 and direction == directions.right then -- 13 -> 12 print("13->12") rloc = string.format("%d,%d", 150, srow - 100) rdir = rev_dirmap.up else error(string.format("Unknown location + direction: %d,%d %s",srow, scol, tostring(direction))) end print("Returning",rloc,rdir) assert(rloc) assert(rdir) assert(map[rloc] ~= nil) mem_loop[rloc] = mem_loop[rloc] or {} mem_loop[rloc][direction] = {rloc,rdir} return rloc, rdir end print(map) local state = { location = start, direction = 0 } print("Starting state:",state) local function open(location,direction) local crow, ccol = location:match("(%d+),(%d+)") local rrow, rcol = crow + direction[1], ccol + direction[2] local rloc = string.format("%d,%d",rrow,rcol) if map[rloc] then return rloc, rev_dirmap[dirnames[direction]] elseif map[rloc] == false then return false else local loop_loc,newdir = find_loop_loc(location,direction) assert(map[loop_loc] ~= nil) if map[loop_loc] then return loop_loc,newdir else return false end end end -- temporary function to test our cube is put togeather correctly local function exists(location,direction) assert(type(location) == "string") assert(type(direction) == "table") print("Exists",location,dirnames[direction]) local crow, ccol = location:match("(%d+),(%d+)") local rrow, rcol = crow + direction[1], ccol + direction[2] local rloc = string.format("%d,%d",rrow,rcol) print("checking existance of",rloc) if map[rloc] ~= nil then print("Exists in map") return rloc,rev_dirmap[dirnames[direction]] else print("Looping around") local loop_loc,newdir = find_loop_loc(location,direction) assert(map[loop_loc] ~= nil) assert(type(newdir) == "number") return loop_loc,newdir end end local corners = { {1,51, directions.up}, {1,100, directions.right}, {50,51}, {50,100}, {50,101}, {51,51}, {51,100}, {101,1}, {101,50}, {101,51}, {101,100}, {150,1}, {150,50}, {150,51}, {150,100}, {200,1}, {200,50} } local edges = { } --[[ -- test find_loop_loc, at each of our box corners, move around and make sure we end up back where we started for _, corner in pairs(corners) do print("Checking counter-clockwise",corner) -- counter-clockwise local s,d = corner, directions.up local ns, nd = exists(s,d) print("Returns from exists 1:",ns,nd) s = assert(e) d = directions[dirmap[d].L] e, d = exists(u,d) s = assert(e) d = directions[dirmap[d].L] e, d = exists(u,d) s = assert(e) assert(s == corner,s .. " was not " .. corner) end ]] local function run(state, instructions) local function walk(state,n) print("Walking",state,n) for i = 1, n do local dir = directions[dirmap[state.direction].name] local newloc, newdir = open(state.location,dir) --local newloc, newdir = exists(state.location,dir) if newloc then print("Walked to",newloc) state.location = newloc state.direction = newdir else break end end end local function turn(state,dir) print("Turning",state) assert(type(state.location) == "string") assert(type(state.direction) == "number") state.direction = dirmap[state.direction][dir] end while #instructions > 0 do local ins = table.remove(instructions,1) if ins.type == "walk" then walk(state,ins.n) elseif ins.type == "turn" then turn(state,ins.n) end end end -- test that it works local ghosts = { {1,51,rev_dirmap.up,"1L1L1"}, {1,51,rev_dirmap.left,"1R1R1"}, {1,100,rev_dirmap.up,"1R1R1"}, {1,100,rev_dirmap.right,"1L1L1"}, {1,101,rev_dirmap.up,"1L1L1"}, {1,101,rev_dirmap.left,"1R1R1"}, {1,150,rev_dirmap.up,"1R1R1"}, {1,150,rev_dirmap.right,"1L1L1"}, {50,51,rev_dirmap.left,"1L1L1"}, {50,51,rev_dirmap.down,"1R1R1"}, {50,100,rev_dirmap.right,"1R1R1"}, {50,100,rev_dirmap.down,"1L1L1"}, {50,150,rev_dirmap.right,"1R1R1"}, {50,150,rev_dirmap.down,"1L1L1"}, {51,51,rev_dirmap.left,"1R1R1"}, {51,51,rev_dirmap.up,"1L1L1"}, {51,100,rev_dirmap.up,"1R1R1"}, {51,100,rev_dirmap.right,"1L1L1"}, {100,51,rev_dirmap.left,"1L1L1"}, {100,51,rev_dirmap.down,"1R1R1"}, {100,100,rev_dirmap.right,"1R1R1"}, {100,100,rev_dirmap.down,"1L1L1"}, {101,1,rev_dirmap.up,"1L1L1"}, {101,1,rev_dirmap.left,"1R1R1"}, {101,50,rev_dirmap.up,"1R1R1"}, {101,50,rev_dirmap.right,"1L1L1"}, {101,51,rev_dirmap.left,"1R1R1"}, {101,51,rev_dirmap.up,"1L1L1"}, {101,100,rev_dirmap.right,"1L1L1"}, {101,100,rev_dirmap.up,"1R1R1"}, {150,1,rev_dirmap.left,"1L1L1"}, {150,1,rev_dirmap.down,"1R1R1"}, {150,50,rev_dirmap.right,"1R1R1"}, {150,50,rev_dirmap.down,"1L1L1"}, {150,51,rev_dirmap.left,"1L1L1"}, {150,51,rev_dirmap.down,"1R1R1"}, {150,100,rev_dirmap.right,"1R1R1"}, {150,100,rev_dirmap.down,"1L1L1"} } --[[ for _,ghost in pairs(ghosts) do print("=========================") print("Checking location:",ghost) local c = parse_command(ghost[4]) local locc = string.format("%d,%d",ghost[1],ghost[2]) local istate = { location = locc, direction = ghost[3] } run(istate,c) assert(istate.location == locc) end os.exit(0) ]] run(state,commands) print(state) local row, col = state.location:match("(%d+),(%d+)") print((row*1000) + (col * 4) + state.direction)