-- see if the file exists local function file_exists(file) local f = io.open(file, "rb") if f then f:close() end return f ~= nil end -- get all lines from a file, returns an empty -- list/table if the file does not exist local function lines_from(file) if not file_exists(file) then return {} end local lines = {} for line in io.lines(file) do lines[#lines + 1] = line end return lines end -- tests the functions above local file = "input" local lines = lines_from(file) -- Solution Starts here ---@diagnostic disable-next-line: redefined-local local function count_xmas_at_index(lines, line_idx, char_idx) local up_idx = line_idx - 1 local down_idx = line_idx + 1 local right_idx = char_idx + 1 local left_idx = char_idx - 1 local char_count = {} char_count["M"] = 0 char_count["S"] = 0 if up_idx >= 1 then if right_idx <= #lines[up_idx] then local key = lines[up_idx]:sub(right_idx, right_idx) if char_count[key] ~= nil then char_count[key] = char_count[key] + 1 end end if left_idx >= 1 then local key = lines[up_idx]:sub(left_idx, left_idx) if char_count[key] ~= nil then char_count[key] = char_count[key] + 1 end end end if down_idx <= #lines then if right_idx <= #lines[down_idx] then local key = lines[down_idx]:sub(right_idx, right_idx) if char_count[key] ~= nil then char_count[key] = char_count[key] + 1 end end if left_idx >= 1 then local key = lines[down_idx]:sub(left_idx, left_idx) if char_count[key] ~= nil then char_count[key] = char_count[key] + 1 end end end if char_count["M"] == 2 and char_count["S"] == 2 then return true end return false end local xmas_count = 0 -- print all line numbers and their contents ---@diagnostic disable-next-line: unused-local for line_idx, line in ipairs(lines) do for char_idx in line:gmatch("()A") do if count_xmas_at_index(lines, line_idx, char_idx) then xmas_count = xmas_count + 1 end end end io.output():write(xmas_count)