app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.17.0/lZFLstMUCUvd5bjnnpYromZJXkQUrdhbva4xdBInicE.tar.br", } import pf.Stdout import "data.txt" as data : Str main = lines = Str.splitOn data "\n" |> List.dropLast 1 levels = List.map lines \l -> Str.splitOn l " " |> List.keepOks Str.toU8 part1 = List.keepIf levels \l -> isSafe l Bool.false Stdout.line! "Safe Reports, Part 1: $(Num.toStr (List.len part1))" # my algorithm doesn't work great with tolerating the first or 2nd elements, so just run it again with those elements dropped and no dampening part2 = List.keepIf levels \l -> (isSafe l Bool.true) || (isSafe (List.dropAt l 0) Bool.false) || (isSafe (List.dropAt l 1) Bool.false) Stdout.line! "Safe Reports, Part 2: $(Num.toStr (List.len part2))" isSafe = \line, isDampening -> List.walkWithIndexUntil line { value: 0, direction: Unset, valid: Bool.true, skipped: 0 } \state, value, idx -> if idx == 0 then # on first iteration, can't fail, just return Continue { state & value, direction: Unset } else diff = Num.absDiff value state.value if diff < 1 || diff > 3 then # always check diff if isDampening && state.skipped == 0 then Continue { state & skipped: 1 } else Break { state & valid: Bool.false } else direction = if value > state.value then Ascending else Descending if idx == 1 then # on 2nd iteration, we don't check for direction change Continue { state & value, direction } else if state.direction != direction then if isDampening && state.skipped == 0 then Continue { state & skipped: 1 } else Break { state & valid: Bool.false } else Continue { state & value, direction } |> .valid