From 51d44d4ad36111ca793ca61346b876eae2181dda Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Mon, 2 Dec 2024 07:41:09 +0200 Subject: [PATCH 1/2] feat(aoc2024): day2 part1 --- aoc2024.ps1 | 4 +- visp/examples/aoc2024/common.visp | 3 + visp/examples/aoc2024/day2.visp | 92 +++++++++++++++++++ visp/examples/aoc2024/inputs/day2_example.txt | 6 ++ visp/lib/core.visp | 3 + 5 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 visp/examples/aoc2024/day2.visp create mode 100644 visp/examples/aoc2024/inputs/day2_example.txt diff --git a/aoc2024.ps1 b/aoc2024.ps1 index 4c3143a..bd6c791 100644 --- a/aoc2024.ps1 +++ b/aoc2024.ps1 @@ -6,8 +6,8 @@ param ( [switch] $All, [switch] $NoBuild, [ValidateSet( - "day1" - # , "day2", "day3", "day4", "day5", "day6", "day7", "day8", "day9" + "day1" , "day2" + # , "day3", "day4", "day5", "day6", "day7", "day8", "day9" # , "day10", "day11", "day12", "day13", "day14", "day15", "day16" # , "day17", "day18", "day19", "day20", "day21", "day22" # , "day23", "day24", "day25" diff --git a/visp/examples/aoc2024/common.visp b/visp/examples/aoc2024/common.visp index 01149eb..e41919a 100644 --- a/visp/examples/aoc2024/common.visp +++ b/visp/examples/aoc2024/common.visp @@ -24,6 +24,9 @@ (fn EnumareteSpanSplitChars ([ch: array] [text: ReadOnlySpan]) (.EnumerateSplitSubstrings text ch commonSplitOptions)) +(fn EnumerateSpaceSeparated ([text: ReadOnlySpan]) + (.EnumerateSplitSubstrings text [| #\space |] (bor StringSplitOptions.TrimEntries StringSplitOptions.RemoveEmptyEntries))) + (fn ReadInput ([day: string]) (let filepath (String.concat "" [| "./inputs/" day (if IS_EXAMPLE "_example" "") ".txt" |])) (printfn "file: %s" filepath) diff --git a/visp/examples/aoc2024/day2.visp b/visp/examples/aoc2024/day2.visp new file mode 100644 index 0000000..a4d3ffb --- /dev/null +++ b/visp/examples/aoc2024/day2.visp @@ -0,0 +1,92 @@ + +;; Copyright 2024 Ville Penttinen +;; Distributed under the MIT License. +;; https://github.com/vipentti/visp-fs/blob/main/LICENSE.md +;; +;; for basic syntax highlighting +;; vim: set syntax=clojure: + +;; +;; day2 +;; +;; Include common utlities +(include "./common.visp") + +;; Functions & types + +(fn ParseFile ([text: string]) + (mut lines (EnumerateSpanSplitLines text)) + + (mut data (||)) + + (Macro_ReadWhileNotEmpty [line lines] + ;; Read contents here + (mut parts (EnumerateSpaceSeparated line)) + + (mut items (||)) + + (Macro_ReadWhileNotEmpty [part parts] + (up! items (cons (span->int32 part)))) + + (up! data (cons (List.rev items))) + + ()) + + (List.rev data)) + +(fn Part1 (parsedInput) + ;; (printfn "%A" parsedInput) + + (fn IsSafeList (lst) + (-> lst + (List.pairwise) + (List.fold + #(begin + (let [(valid, validDiff) : bool * int32] %1) + + (if (not valid) + (false . 0) + (begin + (let [(lhs, rhs) : int32 * int32] %2) + (let diff (- rhs lhs)) + (let diff_sign (int32->sign diff)) + (let abs_diff (abs diff)) + (let safe (and (>= abs_diff 1) (<= abs_diff 3))) + + (cond_ + [(and safe (= validDiff 0)) + (true . diff_sign)] + + [(and safe (= validDiff diff_sign)) + (true . diff_sign) + ] + [_ (false . 0)]) + )) + + + ) (true . 0)) + fst + )) + + ;; Implement part1 + (-> parsedInput + (List.filter IsSafeList) + (List.length) + )) + +(fn Part2 (parsedInput) + ;; Implement part2 + 0) + +;; Implementation + +(let parsed (-> (ReadInput "day2") ParseFile)) + +;; Expected results +(let PART1_EXPECTED_RESULT (if IS_EXAMPLE 2 606)) +(let PART2_EXPECTED_RESULT (if IS_EXAMPLE -1 -1)) + +(WriteResult "part1" (-> parsed Part1) PART1_EXPECTED_RESULT) +(WriteResult "part2" (-> parsed Part2) PART2_EXPECTED_RESULT) + +() diff --git a/visp/examples/aoc2024/inputs/day2_example.txt b/visp/examples/aoc2024/inputs/day2_example.txt new file mode 100644 index 0000000..b49c10d --- /dev/null +++ b/visp/examples/aoc2024/inputs/day2_example.txt @@ -0,0 +1,6 @@ +7 6 4 2 1 +1 2 7 8 9 +9 7 6 2 1 +1 3 2 4 5 +8 6 4 4 1 +1 3 6 7 9 diff --git a/visp/lib/core.visp b/visp/lib/core.visp index 9466399..0ebb910 100644 --- a/visp/lib/core.visp +++ b/visp/lib/core.visp @@ -101,6 +101,9 @@ [(x, y) (gcd64 y (rem x y))] )) +(fn inline int32->sign [(a: int32)] (System.Math.Sign a)) +(fn inline int64->sign [(a: int64)] (System.Math.Sign a)) + (fn inline lcm64 (a b) (/ (* a b) (gcd64 a b))) From 346f28160ebb0ffe705a739248431a02669eecce Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Mon, 2 Dec 2024 07:49:46 +0200 Subject: [PATCH 2/2] feat(aoc2024): day2 part2 --- visp/examples/aoc2024/day2.visp | 81 +++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/visp/examples/aoc2024/day2.visp b/visp/examples/aoc2024/day2.visp index a4d3ffb..5f41220 100644 --- a/visp/examples/aoc2024/day2.visp +++ b/visp/examples/aoc2024/day2.visp @@ -34,40 +34,44 @@ (List.rev data)) +(fn IsSafeList (lst) + (-> lst + (List.pairwise) + (List.fold + #(begin + (let [(valid, validDiff) : bool * int32] %1) + + (if (not valid) + (false . 0) + (begin + (let [(lhs, rhs) : int32 * int32] %2) + (let diff (- rhs lhs)) + (let diff_sign (int32->sign diff)) + (let abs_diff (abs diff)) + (let safe (and (>= abs_diff 1) (<= abs_diff 3))) + + (cond_ + [(and safe (= validDiff 0)) + (true . diff_sign)] + + [(and safe (= validDiff diff_sign)) + (true . diff_sign) + ] + [_ (false . 0)]) + ))) (true . 0)) + fst)) + +(fn OneRemoved (lst) + (mut lists (||)) + + (for/in [idx (!r 0 .. 1 .. (dec (List.length lst)))] + (up! lists (cons (List.removeAt idx lst)))) + + lists) + (fn Part1 (parsedInput) ;; (printfn "%A" parsedInput) - (fn IsSafeList (lst) - (-> lst - (List.pairwise) - (List.fold - #(begin - (let [(valid, validDiff) : bool * int32] %1) - - (if (not valid) - (false . 0) - (begin - (let [(lhs, rhs) : int32 * int32] %2) - (let diff (- rhs lhs)) - (let diff_sign (int32->sign diff)) - (let abs_diff (abs diff)) - (let safe (and (>= abs_diff 1) (<= abs_diff 3))) - - (cond_ - [(and safe (= validDiff 0)) - (true . diff_sign)] - - [(and safe (= validDiff diff_sign)) - (true . diff_sign) - ] - [_ (false . 0)]) - )) - - - ) (true . 0)) - fst - )) - ;; Implement part1 (-> parsedInput (List.filter IsSafeList) @@ -76,7 +80,18 @@ (fn Part2 (parsedInput) ;; Implement part2 - 0) + (-> parsedInput + (List.filter #(begin + (let origSafe (IsSafeList %1)) + (if origSafe + true + (begin + (-> (OneRemoved %1) + (List.exists IsSafeList)) + )) + )) + (List.length) + )) ;; Implementation @@ -84,7 +99,7 @@ ;; Expected results (let PART1_EXPECTED_RESULT (if IS_EXAMPLE 2 606)) -(let PART2_EXPECTED_RESULT (if IS_EXAMPLE -1 -1)) +(let PART2_EXPECTED_RESULT (if IS_EXAMPLE 4 644)) (WriteResult "part1" (-> parsed Part1) PART1_EXPECTED_RESULT) (WriteResult "part2" (-> parsed Part2) PART2_EXPECTED_RESULT)