diff --git a/day2/part2.lua b/day2/part2.lua new file mode 100644 index 0000000..60b7706 --- /dev/null +++ b/day2/part2.lua @@ -0,0 +1,131 @@ +-- 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 + +local function splitstr(inputstr, sep) + if sep == nil then + sep = "%s" + end + local t = {} + for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do + t[#t + 1] = str + end + return t +end + +-- tests the functions above +local file = "input" +local lines = lines_from(file) + +local reports = {} +for _, line in ipairs(lines) do + local raw_report = splitstr(line) + for i, v in ipairs(raw_report) do + raw_report[i] = tonumber(v) + end + + reports[#reports + 1] = raw_report +end + +-- return the sign of a number +local function sign(number) + if number > 0 then + return 1 + elseif number == 0 then + return 0 + else + return -1 + end +end + +function table.shallow_copy(t) + local t2 = {} + for k, v in pairs(t) do + t2[k] = v + end + return t2 +end + +local function is_safe(report) + local s = nil -- keeps track of the sign over the course of a report + local unsafe = false + local unsafe_idx_1, unsafe_idx_2 + for i, v1 in ipairs(report) do + local v2 = report[i + 1] + -- if v2 doesn't exist, we are at the end of the report + if v2 ~= nil then + if s == nil then + -- if we are on the first iteration, we need to set the direction for + -- the rest of the report + s = sign(v1 - v2) + else + -- we check that the sign matches the rest of the report, breaking early if not + if sign(v1 - v2) ~= s then + unsafe = true + unsafe_idx_1, unsafe_idx_2 = i, i + 1 + break + end + end + + -- Checking if the rate of change in the report is within acceptable bounds + local distance = math.abs(v1 - v2) + if distance < 1 or distance > 3 then + unsafe = true + unsafe_idx_1, unsafe_idx_2 = i, i + 1 + break + end + end + end + + return unsafe, unsafe_idx_1, unsafe_idx_2 +end + +local function test_altered_report(report, idx) + local test_report = table.shallow_copy(report) + table.remove(test_report, idx) + + return is_safe(test_report) +end + +local safe_count = 0 +for _, report in ipairs(reports) do + local unsafe, idx1, idx2 = is_safe(report) + + if unsafe then + if not test_altered_report(report, idx1) or not test_altered_report(report, idx2) then + unsafe = false + end + end + + if not unsafe then + safe_count = safe_count + 1 + end +end + +print(safe_count) + +local function test() + return true, nil, nil +end + +if test() then + print("uwu") +end