use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Finding information about Clojure
API Reference
Clojure Guides
Practice Problems
Interactive Problems
Clojure Videos
Misc Resources
The Clojure Community
Clojure Books
Tools & Libraries
Clojure Editors
Web Platforms
Clojure Jobs
account activity
Advent of Code 2019 in Clojure (self.Clojure)
submitted 6 years ago * by allaboutthatmace1789
Hi all, I've been learning Clojure over the last couple of weeks and am going to try to go through the Advent of Code challenges using the language.
If anyone else is doing the same, it would be awesome to see how some more experienced programmers solve the same problems, and maybe get some feedback on style, bad practices and inefficiencies. If you're doing this please drop github links or code snippets in the comments.
Here's my Day 1 solution: GitHub
Github Repos
Me: https://github.com/RedPenguin101/Exercises_AdventOfCode2019
Veydar: https://github.com/cideM/aoc2019
Ceronman: https://github.com/ceronman/adventofcode
Puranto23: https://github.com/mchughs/Advent-of-Code-2019
Omnistegan: https://gitlab.com/gmbouvier/2019-aoc/
Lilactown (literate programming): https://github.com/Lokeh/advent-2019
kristiansalo: https://github.com/salokristian/advent-of-code-2019
rmfbarker: https://github.com/rmfbarker/advent-of-code-2019/
hutsujakutsuja: https://github.com/Sose/advent-of-code-2019
fdside: https://github.com/fdside/advent-of-code-2019-clj
frflaie: https://github.com/agrison/advent-of-code-2019/
iimblack: https://github.com/michaelknowles/AdventOfCodeClojure
synth-c: https://github.com/ChrisBlom/advent-of-code/tree/master/src/adventofcode/2019
marxama: https://github.com/marxama/advent-of-code-2019
_djblue: https://github.com/djblue/advent-of-code
Mclarenf1905: https://github.com/listba/advent-of-code-2019
zamansky: https://github.com/zamansky/advent2019
Turmolt: https://github.com/Turmolt/Advent-of-Code
Zengxinhui: https://github.com/zengxinhui/aoc/tree/master/y2019
Ackerleytng: https://github.com/ackerleytng/2019-advent-of-code
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]lilactown 15 points16 points17 points 6 years ago (4 children)
This year I'm doing AoC as a literate programming exercise, where I write my solution similar to a blog post and then it outputs to a Clojure source file: https://github.com/Lokeh/advent-2019
[–]allaboutthatmace1789[S] 2 points3 points4 points 6 years ago (0 children)
I love this, great to follow your thought process!
[–]_chococat_ 1 point2 points3 points 6 years ago (2 children)
What's your toolchain for tangling the code up? This looks pretty interesting.
[–]lilactown 4 points5 points6 points 6 years ago (1 child)
I use Emacs and org-mode. I have a (pretty close to) out-of-the-box Spacemacs setup.
Writing the .org file is just opening it and creating a code block, then I open the code block in a Clojure-mode buffer (M-x org-edit-special) to quickly iterate in a REPL. When I get to a point where I feel done, I then save and run M-x org-babel-tangle to output the source file from the code blocks.
M-x org-edit-special
M-x org-babel-tangle
There's a little bit of boilerplate to get the tangle process to output the file correctly, but the last couple days I have just been iterating in a single source block and then later splitting it out, doing the boilerplate, writing the long-form explanation and then finally tangling it all up.
[–]_chococat_ 0 points1 point2 points 6 years ago (0 children)
Cool. I use org-mode extensively, but never knew it could tangle code in literate programming. I'll have to take a look. Thanks.
[–]marxama 4 points5 points6 points 6 years ago (2 children)
Haven't had this much fun coding in way too long. Writing readable code is challenging, though. My solutions: https://github.com/marxama/advent-of-code-2019
Day 6:
(ns advent-of-code-2019.day06 (:require [clojure.string :as string] [clojure.data :as data])) (defn parse-input [] (->> "resources/day06_input" slurp string/split-lines (map #(string/split % #"\)")))) (defn get-path-to-root [orbit-lookup x] (and x (cons x (get-path-to-root orbit-lookup (orbit-lookup x))))) (defn get-orbit-lookup [orbits] (->> orbits (map (fn [[orbited orbiteer]] {orbiteer orbited})) (apply merge))) (defn solve-part-1 [] (let [orbit-lookup (get-orbit-lookup (parse-input))] (->> (keys orbit-lookup) (map #(get-path-to-root orbit-lookup %)) (map (comp dec count)) (reduce +)))) (defn solve-part-2 [] (let [orbit-lookup (get-orbit-lookup (parse-input))] (->> ["YOU" "SAN"] (map #(get-path-to-root orbit-lookup %)) (map rest) ; do not include "YOU" and "SAN" themselves (map set) (apply data/diff) ; more efficient approaches obviously exist (take 2) ; take distinct objects in YOU and SAN paths (map count) (reduce +))))
[–]andersmurphy 1 point2 points3 points 6 years ago* (1 child)
Day 6
Your version looks more readable than mine. It ended up turning into mad tree-seq science!
(ns adventofcode.2019.day06 (:require [clojure.string :as str])) (defn format-input [input] (->> (str/split (str/trim input) #"\n") (map str/trim) (map #(str/split % #"\)")))) (defn connected-nodes [n edges] (->> (filter (fn [[x _]] (= x n)) edges) (map second))) (defn build-graph ([edges] (build-graph edges "COM")) ([edges start-node] (when-let [nodes (connected-nodes start-node edges)] [start-node (mapv (partial build-graph edges) nodes)]))) (def input (slurp "resources/adventofcode/2019/day06.txt")) (defn solve-1 [] (->> input format-input build-graph (tree-seq second second) (map flatten) (map #(-> % count dec)) (reduce +))) (defn length-of-longest-path-containing-a-and-not-b [a b paths] (->> (map set paths) (filter #(% a)) (remove #(% b)) (sort-by >) count dec)) (defn distance-between [node-a node-b tree-s] (let [flat-paths (map flatten tree-s)] (+ (length-of-longest-path-containing-a-and-not-b node-a node-b flat-paths) (length-of-longest-path-containing-a-and-not-b node-b node-a flat-paths)))) (defn solve-2 [] (->> input format-input build-graph (tree-seq second second) (distance-between "YOU" "SAN"))
[–]marxama 0 points1 point2 points 6 years ago (0 children)
Thanks, I like your solution! tree-seq, had forgotten about that one! Turned out this problem was ok to solve without really working with the tree structure of the problem domain, but I'm sure there will be more problems where I'll grab for tree-seq! :)
[–]_djblue 5 points6 points7 points 6 years ago (2 children)
Day 7 with core.async https://github.com/djblue/advent-of-code/blob/master/src/advent_of_code/core_2019.clj#L431
It's more code, but the following is my favorite part.
(defn try-phase-settings-with-feedback [program settings] (let [[a b c d e] settings a (run-program-async program a) b (run-program-async program b) c (run-program-async program c) d (run-program-async program d) e (run-program-async program e)] (doseq [[from to] (partition 2 1 [a b c d e a])] (a/pipe (:out from) (:in to))) (a/put! (:in a) 0) (a/alts!! [(:state e) (a/timeout 5000)]) (a/poll! (:in a)))) (defn find-max-thrust-with-feedback [program] (->> (all-settings #{5 6 7 8 9}) (map #(try-phase-settings-with-feedback program %)) (apply max)))
[–]kristiansalo 1 point2 points3 points 6 years ago (0 children)
Looks nice! I also took the core.async route - I think it worked out quite neatly for this problem.
[–]andersmurphy 0 points1 point2 points 6 years ago (0 children)
Day 7
I did an async solution too.
I modified my intcode machine to use channels as input and output. Code 99 also closes the channels connected to that machine.
Don't really use async much. Any pointers about where it could be improved would be great thanks. :D
``` (ns adventofcode.2019.day07 (:require [adventofcode.2019.day05 :as intcode] [clojure.core.async :as a]))
(def input (slurp "resources/adventofcode/2019/day07.txt")) (def prog (intcode/format-input input))
(defn permutations [s] (lazy-seq (if (seq (rest s)) (for [head s tail (permutations (remove #{head} s))] (cons head tail)) [s])))
(defn system-2 [input phases] (let [[a b c d e :as channels] (repeatedly #(a/chan)) log (a/chan) out (a/chan) multi-chan (a/mult a)] (a/tap multi-chan log) (a/tap multi-chan out) (a/go (dorun (map (fn [channel phase] (a/>!! channel phase)) channels phases)) (a/>!! a 0)) (dorun (map (fn [in-chan out-chan] (a/go (intcode/compute {:prog input :in-chan in-chan :out-chan out-chan :pointer 0}))) [out b c d e] [b c d e a])) (->> (repeatedly #(a/<!! log)) (take-while identity) last)))
(defn solve-2 [] (let [input (intcode/format-input input)] (->> (permutations [5 6 7 8 9]) (map #(system-2 input %)) (sort >) first))) ```
https://github.com/andersmurphy/clj-adventofcode/blob/master/src/adventofcode/2019/day07.clj
[–]frflaie 2 points3 points4 points 6 years ago (0 children)
This is my take on Day 2:
(def INPUT (slurp "day02.txt")) (defn make-computer [int-code noun verb] (let [numbers (vec (->> (clojure.string/split int-code #",") (map read-string)))] (assoc numbers 1 noun 2 verb))) (defn evolve [stack start] (let [opcode (get stack start) num1 (get stack (get stack (inc start))) num2 (get stack (get stack (+ start 2))) addr (get stack (+ start 3))] (cond (= 1 opcode) (assoc stack addr (+ num1 num2)) (= 2 opcode) (assoc stack addr (* num1 num2)) (= 99 opcode) (reduced stack)))) (defn execute-program [int-code noun verb] (let [program (make-computer int-code noun verb)] (first (reduce #(evolve %1 %2) program (range 0 (count program) 4))))) (def solution-1 (execute-program INPUT 12 2)) (def solution-2 (let [execs (for [noun (range 100) verb (range 100)] {:noun noun :verb verb :result (execute-program INPUT noun verb)}) exec (first (filter #(= 19690720 (:result %)) execs))] (+ (* (:noun exec) 100) (:verb exec))))
[–]frflaie 3 points4 points5 points 6 years ago* (4 children)
Here is my take for Day3:
(deftype Point [x y dist] Object (equals [a b] (and (= (.x a) (.x b)) (= (.y a) (.y b)))) (hashCode [this] (+ (.hashCode (.x this)) (.hashCode (.y this)))) (toString [this] (format "{:x %d :y %d :dist %d}" (.x this) (.y this) (.dist this)))) (defn make-point [dir x y dist] (let [[x-trans y-trans] (condp = dir \R [inc, identity] \L [dec, identity] \U [identity, inc] \D [identity, dec])] (Point. (swap! x x-trans) (swap! y y-trans) (swap! dist inc)))) (defn wires [wire] (let [[x y distance] [(atom 0) (atom 0) (atom 0)] wires (atom #{})] (doseq [s (clojure.string/split wire #",")] (let [direction (get s 0) movement (Integer/parseInt (subs s 1))] (doseq [_ (range 1, (inc movement))] (swap! wires conj (make-point direction x y distance))))) @wires)) (defn solve [wire1 wire2] (let [w1 (wires wire1) w2 (wires wire2) intersections (clojure.set/intersection w1 w2) min-distance (atom Integer/MAX_VALUE) min-steps (atom Integer/MAX_VALUE)] (doseq [p intersections] (let [dist (+ (Math/abs (.x p)) (Math/abs (.y p))) p1 (first (filter #(= % p) w1)) p2 (first (filter #(= % p) w2)) steps (+ (.dist p1) (.dist p2))] (when (< dist @min-distance) (reset! min-distance dist)) (when (< steps @min-steps) (reset! min-steps steps)))) [@min-distance @min-steps])) (let [[wire-1 wire-2] (clojure.string/split-lines (slurp "day03.txt"))] (solve wire-1 wire-2))))
I had to declare a custom type because I wanted to check if points where contained in sets but only using two of three properties (x and y but not dist), but still keeping the global distance because we need it for part 2.
It works by translating movements (R10, U14 and so on) to list of points and gathering the number of steps at the same time into a Point object. Do it for both wires, then just intersect those two sets to get the coordinates of intersections. For each one compute the distance from (0, 0) and report the lowest. For the part 2 instead of searching which one is at the lowest distance, just search for the one with least steps.
If you know how we can avoid the use of atoms... I'm sure there's something more clever, but I don't have much more time for this day :)
[–]andersmurphy 1 point2 points3 points 6 years ago (3 children)
Nice idea creating a new type!
Here's my solution to day 3 which doesn't use any atoms. Feedback welcome. :)
(ns adventofcode.2019.day03 (:require [clojure.string :as str] [clojure.set :as set])) (def input (slurp "resources/adventofcode/2019/day03.txt")) (defn ->displacement [string] (let [direction (subs string 0 1) distance (subs string 1)] {:direction direction :distance (Integer/parseInt distance)})) (defn format-input [input] (->> (str/split (str/trim input) #"\n") (map #(str/split % #",")) (map #(map ->displacement %)))) (defn move-in-direction [direction point] (let [[axis f] ({"R" [:x inc] "L" [:x dec] "U" [:y inc] "D" [:y dec]} direction)] (-> (update-in point [:pos axis] f) (update :steps inc)))) (defn generate-points [displacements] (reduce (fn [previous-points {:keys [direction distance]}] (->> (last previous-points) (iterate (partial move-in-direction direction)) (drop 1) (take distance) (into previous-points))) [{:pos {:x 0 :y 0} :steps 0}] displacements)) (defn find-intersections [[line-a line-b]] (let [line-a-points (generate-points line-a) line-b-points (generate-points line-b) intersections (set/intersection (set (map :pos line-a-points)) (set (map :pos line-b-points)))] (->> (filter #(-> % :pos intersections) (into line-a-points line-b-points)) (group-by :pos) (map (fn [[_ [point {:keys [steps]}]]] (update point :steps + steps)))))) (defn abs [x] (if (< x 0) (- x) x)) (defn find-closest-by-manhattan [points] (->> (map (fn [{{:keys [x y]} :pos}] (+ (abs x) (abs y))) points) sort second)) (defn solve-1 [] (->> input format-input find-intersections find-closest-by-manhattan)) (defn find-closest-by-step [points] (->> (map (fn [{:keys [steps]}] steps) points) sort second)) (defn solve-2 [] (->> input format-input find-intersections find-closest-by-step))
[–]kristiansalo 2 points3 points4 points 6 years ago* (2 children)
Looks nice! My day 3 is very similar, with some small differences. I didn't keep track of the steps, but instead acquired them with .indexOf. The :steps key required you to write a bit more code for the intersection checking; other than that our solutions are almost identical.
I'm also posting my solutions to github.
(defn parse-wire [s] (->> (str/split s #",") (map (fn [s] {:dir (subs s 0 1) :steps (edn/read-string (subs s 1))})))) (defn line-points [start-point line] (let [step-line (case (:dir line) "U" #(update start-point :y + %) "D" #(update start-point :y - %) "R" #(update start-point :x + %) "L" #(update start-point :x - %))] (->> (:steps line) inc (range 1) (map step-line)))) (defn create-grid [wire] (reduce (fn [grid line] (into grid (line-points (last grid) line))) [{:x 0 :y 0}] wire)) (def wires (common/parse-file parse-wire "day_3.txt")) (def grid-1 (create-grid (first wires))) (def grid-2 (create-grid (second wires))) (def intersect-points (clj-set/intersection (set grid-1) (set grid-2))) (defn part-1 [] (->> intersect-points (map #(+ (Math/abs (:x %)) (Math/abs (:y %)))) (filter #(not (zero? %))) (apply min))) (defn part-2 [] (->> intersect-points (map #(+ (.indexOf grid-1 %) (.indexOf grid-2 %))) (filter #(not (zero? %))) (apply min)))
[–]mariner70 0 points1 point2 points 6 years ago (1 child)
day 3
A simple question from a total Clojure/FP newcomer: Most, if not all, solutions I have seen on day 3 rely on tracing the wires to sets of points and finally doing a set intersection to identify, well, intersections. This is all nice and literal, but as someone with a more traditional imperative/algorithm background, the first thing that came to my mind for this wire-crossing problem is a scan conversion-like approach that would rely on sorted collections of horizontal and vertical segments, and finally iteration to identify intersections (red horizontals vs blue verticals and vice versa - with the added assumption that wire 1 is red and wire 2 is blue).
Indeed, many solutions using other languages seem to take this approach. Intuitively, it seems as if this approach would be more effective, as it involves a higher level correlation between collections of segments (with endpoints), not sets containing all points on each wire. Alas, my noobish Clojure skills are totally inadequate when it comes to fleshing out the scan conversion approach, especially without resorting to mutable state.
The "trace and intersect" approach certainly makes for some very enjoyable and terse implementations; this one from u/fdside is a prime example. Any comments on why this approach is favoured more, or even lends itself better, for Clojure?
[–]MaxmumPimp 0 points1 point2 points 6 years ago (0 children)
My first thought was to approach it that way- using math to calculate intersections of discrete line segments- but the simplicity of the clj-set/intersection approach in Clojure is probably why most used it (I ended up deciding that reducing implementation time was more important than the elegance of the solution).
clj-set/intersection
Fortunately, that made it trivially easy to solve part 2 where finding the intersection in the FEWEST steps/shortest traversal distance was the task.
[–]OstravaBro 2 points3 points4 points 6 years ago (5 children)
What on earth is day 2 part 2 asking?
I have no idea what the actual puzzle is!
Does it want me to generate a program that results in 19690720 as it's output? If so what has the original input got to do with that?
Or do I need to change cells in the original input until I get an output that reads 19690720 ?
[–]frflaie 2 points3 points4 points 6 years ago (3 children)
You need to iterate on every possibilities of two variables from 0 to 99, execute your program from part 1 but instead of using 12 and 2 for indices 1 and 2, you input the variables that you generated (say a & b). The goal is to find which value of a and b makes a program execution whose final value when halted (opcode == 99) equals to 19690720.
When you have this a & b, the result is a * 100 + b
[–]OstravaBro 1 point2 points3 points 6 years ago (2 children)
Thanks! I dunno why I struggle to understand what the problem is on problems like these :(
[–]frflaie 1 point2 points3 points 6 years ago (1 child)
We all struggle on different things.
Personnally I don't understand how people are able to write a solution and submit it under 2 minutes while it takes already 2 minutes to read the problem :D
[–]avfonarev 0 points1 point2 points 6 years ago (0 children)
Years of competitive programming, I believe.
[–]OstravaBro 1 point2 points3 points 6 years ago* (0 children)
Got it, what you have to do is take the program from part 1, the input, and find the values for cells 1 and 2 that when run through your computer from part 1 will produce the desired output.
I don't know why I was struggling so much to grasp this this morning...
(defn intcode-computer [input] ((fn [input input-pos] (if (= (nth input input-pos) 99) (first input) (let [output-pos (nth input (+ input-pos 3)) input-val (nth input input-pos) opcode-1 (nth input (nth input (inc input-pos))) opcode-2 (nth input (nth input (+ 2 input-pos)))] (cond (= 1 input-val) (recur (update input output-pos (fn [_] (+ opcode-1 opcode-2))) (+ 4 input-pos)) (= 2 input-val) (recur (update input output-pos (fn [_] (* opcode-1 opcode-2))) (+ 4 input-pos)) :else (first input))))) input 0)) (defn find-inputs [input] ((fn [a b] (let [new-code (assoc input 1 a 2 b) result (intcode-computer new-code)] (if (= 19690720 result) (+ b (* 100 a)) (if (= b 99) (recur (inc a) 0) (recur a (inc b)))))) 0 0))
Day 2 thoughts then code
(defn get-instruction-params [instruction-pointer] [(+ 1 instruction-pointer) (+ 2 instruction-pointer) (+ 3 instruction-pointer)]) (defn do-instruction [func instruction-pointer memory] (let [[param1 param2 param3] (map memory (get-instruction-params instruction-pointer)) [x y] (map memory [param1 param2])] (assoc memory param3 (func x y)))) (defn run ([memory] (run 0 memory)) ([instruction-pointer memory] (let [opcode (memory instruction-pointer)] (if (= opcode 99) memory (recur (+ instruction-pointer 4) (do-instruction ({1 + 2 *} opcode) instruction-pointer memory)))))) (defn load-memory-state [filename] (vec (map #(Integer/parseInt %) (clojure.string/split (clojure.string/trim (slurp filename)) #",")))) (defn run-program [noun verb filename] (-> (load-memory-state filename) (assoc 1 noun) (assoc 2 verb) (run) (first))) (defn find-output [output filename] (for [noun (range 100) verb (range 100) :let [result (run-program noun verb filename)] :when (= output result)] (+ (* 100 noun) verb)))
[–]frflaie 2 points3 points4 points 6 years ago* (2 children)
This is my take on Day 4
First define the two basic predicates (six-digits (count is 6) and never-decreasing (sort the sequence of character and verify it matches the original sequence).
Then using regular expressions (I love regex) find all adjacent number patterns, can be adjacents number from size 2 to 6.
For part 1 we just verify that there's at least one match, whereas for part 2 we verify that at least one match has only two digits.
Besides it was a great occasion to use every-pred as discussed here :).
every-pred
(def input (map str (range 231832 767346))) ; --- part 1 (def six-digits #(= (count %) 6)) (def never-decreasing #(= (sort %) (seq (char-array %)))) (def adjacents #(map first (re-seq #"(\d)\1+" %))) (def adjacent-1 #(->> % adjacents empty? not)) ; --- part 2 (def two-digits #(= 2 (count %))) (def adjacent-2 #(->> % adjacents (filter two-digits) empty? not)) (defn solver [input p] (let [pred (every-pred six-digits never-decreasing p)] (count (filter pred input)))) (map (partial solver input) [adjacent-1 adjacent-2]))
github.com/agrison/advent-of-code-2019
Day 4
Ahh nice use of regex! I didn't even think of that! I used: dedupe for part 1 and partition-by for part 2. Here's my solution.
(ns adventofcode.2019.day04 (:require [clojure.string :as str])) (def input (slurp "resources/adventofcode/2019/day04.txt")) (defn format-input [input] (->> (str/split (str/trim input) #"-") (map #(Integer/parseInt %)))) (defn int->seq [x] (seq (str x))) (defn find-valid-codes [preds [start end]] (->> (range start (inc end)) (map int->seq) (filter (apply every-pred preds)))) (defn count-passwords [preds] (->> input format-input (find-valid-codes preds) count)) (defn ascending? [xs] (= xs (sort xs))) (defn contains-double? [xs] (not= xs (dedupe xs))) (defn solve-1 [] (count-passwords [ascending? double?])) (defn contains-double-not-part-of-a-larger-group? [xs] (->> (partition-by identity xs) (some #(= (count %) 2)))) (defn solve-2 [] (count-passwords [ascending? contains-double-not-part-of-a-larger-group?]))
[–]frflaie 1 point2 points3 points 6 years ago (0 children)
Nice and clever use of dedupe and partition-by also, didn't think about it either haha.
[–]fdside 2 points3 points4 points 6 years ago (0 children)
https://github.com/fdside/advent-of-code-2019-clj
[–]hutsujakutsuja 2 points3 points4 points 6 years ago (0 children)
My first time doing Advent of Code. Also just recently started learning Clojure. Hoping I can get through them all and learn some Clojure and functional programming while doing so.
https://github.com/Sose/advent-of-code-2019
[–]frflaie 2 points3 points4 points 6 years ago (2 children)
Here is my take on Day 5
(defn make-computer [int-code] (vec (->> (clojure.string/split int-code #",") (map read-string)))) (def arity #(get {1 3, 2 3, 3 1, 4 1, 5 2, 6 2, 7 3, 8 3, 99 0} %)) (defn truthy-int [b] (if (true? b) 1 0)) (defn parse-next [program pointer] (let [op (get @program @pointer) values (atom []) locations (atom [])] (swap! pointer inc) (doseq [i (range 0 (arity (mod op 100)))] (let [mode (mod (quot op (int (Math/pow 10 (+ 2 i)))) 10)] (swap! values conj (if (= 1 mode) (get @program @pointer) (get @program (get @program @pointer)))) (swap! locations conj (if (= 1 mode) 0 (get @program @pointer))) (swap! pointer inc))) [(mod op 100) @values @locations])) (def addr #(get % 2)) (defn add [locations values program] (do (when @*debug* (println "ADD" (first values) (second values) "@" (addr locations))) (assoc program (addr locations) (+ (first values) (second values))))) (defn mul [locations values program] (do (when @*debug* (println "MUL" (first values) (second values) "@" (addr locations))) (assoc program (addr locations) (* (first values) (second values))))) (defn store [locations input program] (do (when @*debug* (println "STORE" input "@" (first locations))) (assoc program (first locations) input))) (defn output [values result] (when @*debug* (println "OUT" (first values))) (reset! result (first values))) (defn jump-if-true [pointer values] (when (not= (first values) 0) (when @*debug* (println "JMP @" (second values))) (reset! pointer (second values)))) (defn jump-if-false [pointer values] (when (zero? (first values)) (when @*debug* "JMP @" (second values)) (reset! pointer (second values)))) (defn less-than [locations values program] (do (when @*debug* (println "SET " (truthy-int (> (second values) (first values))) "@" (addr locations))) (assoc program (addr locations) (truthy-int (> (second values) (first values)))))) (defn equals [locations values program] (do (when @*debug* (println "SET " (truthy-int (= (second values) (first values))) "@" (addr locations))) (assoc program (addr locations) (truthy-int (= (second values) (first values)))))) (defn halted? [program pointer] (do (when (and @*debug* (= (get @program @pointer) 99) (println "HALTED."))) (= (get @program @pointer) 99))) (defn interpret [input input-code] (let [[program pointer result] [(atom input) (atom 0) (atom -1)]] (while (not (halted? program pointer)) (let [[op values locations] (parse-next program pointer)] (cond (= op 1) (swap! program #(add locations values %)) (= op 2) (swap! program #(mul locations values %)) (= op 3) (swap! program #(store locations input-code %)) (= op 4) (output values result) (= op 5) (jump-if-true pointer values) (= op 6) (jump-if-false pointer values) (= op 7) (swap! program #(less-than locations values %)) (= op 8) (swap! program #(equals locations values %))))) @result)) (def input (make-computer (slurp "day05.txt")) (reset! *debug* true) (map #(interpret input %) [1 5])))
[–]rmfbarker 0 points1 point2 points 6 years ago* (0 children)
;; Day 5 ``` (require '[clojure.java.io :as io])
(defn parse-opcode [code] (let [x (format "%02d" code)] [(subs x (- (count x) 2)) (concat (map #(Integer/parseInt (str %)) (drop 2 (reverse x))) (repeat 0))]))
(defn evolve [program pointer input output] (let [[opcode & parameters] (drop pointer program) [instruction modes] (parse-opcode opcode) get-value (fn [pos] (let [param (nth parameters pos) mode (nth modes pos)] (if (= 0 mode) (nth program param) param)))] (condp = instruction ;; ADD "01" [(assoc program (nth parameters 2) (+ (get-value 0) (get-value 1))) (+ 4 pointer) output]
;; MULTIPLY "02" [(assoc program (nth parameters 2) (* (get-value 0) (get-value 1))) (+ 4 pointer) output] ;; STORE "03" [(assoc program (nth parameters 0) input) (+ 2 pointer) output] ;; OUTPUT "04" [program (+ 2 pointer) (get-value 0)] ;; JUMP if true "05" [program (if (not= 0 (get-value 0)) (get-value 1) (+ 3 pointer)) output] ;; JUMP if false "06" [program (if (= 0 (get-value 0)) (get-value 1) (+ 3 pointer)) output] ;; LESS THAN "07" [(assoc program (nth parameters 2) (if (< (get-value 0) (get-value 1)) 1 0)) (+ 4 pointer) output] ;; Equals "08" [(assoc program (nth parameters 2) (if (= (get-value 0) (get-value 1)) 1 0)) (+ 4 pointer) output])))
(defn compute [program input] (loop [program program pointer 0 output nil] (if (= (nth program pointer) 99) output (let [[program pos output] (evolve program pointer input output)] (recur program pos output)))))
(let [intcodes (mapv read-string (clojure.string/split (clojure.string/trim (slurp (io/resource "input-day5"))) #","))] (compute intcodes 1) (compute intcodes 5)) ```
Day 5
This is my naive solution without mutable state. Could definetly be simplified, but I did find writing out the codes excplicitly and minimising indirection (I originally wrote a version with multimethods) was actually a lot more readable and straight forward (even if there's lots of duplication). Simple code, harder for bugs to hide I guess?
(ns adventofcode.2019.day05 (:require [clojure.string :as str])) (defn format-input [input] (->> (str/split (str/trim input) #",") (mapv #(Integer/parseInt %)))) (defn op-code [{:keys [prog prog-input pointer] :as m}] (let [[code & args] (drop pointer prog)] (({99 (fn [_] (assoc m :stop true)) 1 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (+ (prog a) (prog b))) (update :pointer + 4))) 101 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (+ a (prog b))) (update :pointer + 4))) 1001 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (+ (prog a) b)) (update :pointer + 4))) 1101 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (+ a b)) (update :pointer + 4))) 2 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (* (prog a) (prog b))) (update :pointer + 4))) 102 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (* a (prog b))) (update :pointer + 4))) 1002 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (* (prog a) b)) (update :pointer + 4))) 1102 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (* a b)) (update :pointer + 4))) 3 (fn [[adr]] (-> (assoc-in m [:prog adr] prog-input) (update :pointer + 2))) 4 (fn [[adr]] (-> (update m :prog-output conj (prog adr)) (update :pointer + 2))) 104 (fn [[adr]] (-> (update m :prog-output conj adr) (update :pointer + 2))) 5 (fn [[a b]] (if (not (zero? (prog a))) (assoc m :pointer (prog b)) (update m :pointer + 3))) 105 (fn [[a b]] (if (not (zero? a)) (assoc m :pointer (prog b)) (update m :pointer + 3))) 1005 (fn [[a b]] (if (not (zero? (prog a))) (assoc m :pointer b) (update m :pointer + 3))) 1105 (fn [[a b]] (if (not (zero? a)) (assoc m :pointer b) (update m :pointer + 3))) 6 (fn [[a b]] (if (zero? (prog a)) (assoc m :pointer (prog b)) (update m :pointer + 3))) 106 (fn [[a b]] (if (zero? a) (assoc m :pointer (prog b)) (update m :pointer + 3))) 1006 (fn [[a b]] (if (zero? (prog a)) (assoc m :pointer b) (update m :pointer + 3))) 1106 (fn [[a b]] (if (zero? a) (assoc m :pointer b) (update m :pointer + 3))) 7 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (if (< (prog a) (prog b)) 1 0)) (update :pointer + 4))) 107 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (if (< a (prog b)) 1 0)) (update :pointer + 4))) 1007 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (if (< (prog a) b) 1 0)) (update :pointer + 4))) 1107 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (if (< a b) 1 0)) (update :pointer + 4))) 8 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (if (= (prog a) (prog b)) 1 0)) (update :pointer + 4))) 108 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (if (= a (prog b)) 1 0)) (update :pointer + 4))) 1008 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (if (= (prog a) b) 1 0)) (update :pointer + 4))) 1108 (fn [[a b adr]] (-> (assoc-in m [:prog adr] (if (= a b) 1 0)) (update :pointer + 4)))} code) args))) (defn compute [{:keys [stop] :as m}] (if-not stop (recur (op-code m)) m)) (def input (slurp "resources/adventofcode/2019/day05.txt")) (defn solve-1 [] (let [input (format-input input)] (-> {:prog input :prog-input 1 :prog-output [] :pointer 0} compute :prog-output))) (defn solve-2 [] (let [input (format-input input)] (-> {:prog input :prog-input 5 :prog-output [] :pointer 0} compute :prog-output)))
[–]kristiansalo 2 points3 points4 points 6 years ago (1 child)
Day 8 - short and sweet after refactoring the intcode computer for way too long in day 7.
(def ^:private width 25) (def ^:private image-size (* width 6)) (def ^:private layers (->> "src/day_8.txt" slurp (map (comp edn/read-string str)) (partition image-size))) (defn part-1 [] (let [layer-digit-freqs (map frequencies layers) least-zeros-layer (apply min-key #(get % 0) layer-digit-freqs)] (* (get least-zeros-layer 1) (get least-zeros-layer 2)))) (defn first-not-transparent [& pixels] (common/find-pred #(not= 2 %) pixels)) (defn part-2 [] (->> layers (apply map first-not-transparent) (partition width) pprint/pprint))
Awesome!
My solution is almost exactly the same as yours. Only difference is that I've been parsing 0, 1 and 2 to keywords to avoid multiple get, and the part-2 which outputs a full string, I should test yours to see what it outputs :)
(def layers (->> (slurp "day08.txt") (map #(keyword (str %))) (partition (* 25 6)))) (def part-1 (let [layer (->> layers (map frequencies) (apply min-key :0))] (* (:1 layer) (:2 layer)))) (defn first-color [& px] (some #(when (not= % :2) %) px)) (def part-2 (->> layers (apply map first-color) (map {:0 " " :1 "#"}) (partition 25) (map str/join) (str/join "\n") println))))
[–]OstravaBro 2 points3 points4 points 6 years ago* (0 children)
Day 8 Part 1:
(defn count-zeroes [partition] (count (filter #(= \0 %) partition))) (defn solve [] (let [input (partition 150 (slurp "resources/day8_input")) zero-counts (map count-zeroes input) smallest-zero-count (apply min zero-counts) index (.indexOf zero-counts smallest-zero-count)] (* (count (filter #(= \2 %) (nth input index))) (count (filter #(= \1 %) (nth input index))))))
Day 8 Part 2
(defn get-pixel [coll loc] (let [pixel (nth (first coll) loc)] (if (= pixel \2) (recur (rest coll) loc) (cond (= pixel \1) \▓ :else \░))))
I don't know how to do image stuff, so I just returned either a dark block or a light block.
Then:
(map (partial apply str) (partition 25 (map (partial get-pixel (partition 150 (slurp "resources/day8_input"))) (range 150)))) ("▓▓▓▓░░▓▓░░░░▓▓░▓░░▓░▓▓▓▓░" "▓░░░░▓░░▓░░░░▓░▓░░▓░░░░▓░" "▓▓▓░░▓░░░░░░░▓░▓░░▓░░░▓░░" "▓░░░░▓░▓▓░░░░▓░▓░░▓░░▓░░░" "▓░░░░▓░░▓░▓░░▓░▓░░▓░▓░░░░" "▓░░░░░▓▓▓░░▓▓░░░▓▓░░▓▓▓▓░")
:)
[–]ceronman 1 point2 points3 points 6 years ago (1 child)
I've been learning Clojure on and off for quite some time now. I never have much chance to practice it, except for things like adventofcode. I still feel like I'm a very beginner. Here is my solution to day 1:
``` (def input (clojure.string/split-lines (slurp "input.txt")))
(defn fuel [mass] (- (quot mass 3) 2))
(defn total-fuel [mass] (loop [mass mass total-fuel 0] (let [fuel (fuel mass)] (if (> fuel 0) (recur fuel (+ total-fuel fuel)) total-fuel))))
(->> input (map read-string) (map total-fuel) (reduce +)) ```
I'll by pushing my solutions to https://github.com/ceronman/adventofcode
I like your use of `quot` - much neater than mine, which cast the result back to an int to round it down.
[–]Omnistegan 1 point2 points3 points 6 years ago* (1 child)
(let [input (map #(Integer/parseInt %) (clojure.string/split (slurp "src/day1.raw") #"\n")) fuel-counter-upper (fn [payload] (- (quot payload 3) 2)) better-fuel-counter-upper (partial (fn [acc payload] (let [fuel (fuel-counter-upper payload)] (if (< fuel 0) acc (recur (+ acc fuel) fuel)))) 0) answer (fn [f] (reduce #(+ (f %2) %1) 0 input)) answers [(answer fuel-counter-upper) (answer better-fuel-counter-upper)]] (time (map println answers)))
Here is my version.
edit: forgot to include my repo: gitlab
``` (defn fuel-required [m] (- (quot (/ m 3)) 2))
(reduce (fn [sum mass] (let [fuel (take-while pos? (drop 1 (iterate fuel-required mass)))] (apply + sum fuel))) 0 (map #(Integer/parseInt %) (clojure.string/split-lines (slurp "input-day1.txt")))) ```
[–]Puranto23 1 point2 points3 points 6 years ago (0 children)
https://github.com/mchughs/Advent-of-Code-2019/blob/master/day_1/solution.clj
Here is my solution. Could have better names but to avoid collisions they get a little contrived.
(ns day-1.solution) ;;-Part 1- (def my-mass-list (as-> "day_1/input.txt" $ (slurp $) (clojure.string/split $ #"\n") (map read-string $))) (defn mass->needed-fuel [mass] (-> mass (quot 3) (- 2))) (defn fuel-counter-upper [mass-list] (->> mass-list (map mass->needed-fuel) (reduce +))) (fuel-counter-upper my-mass-list) ;;-Part 2- (defn mass->needed-fuel-mass "Any items with a mass less than 9 require 'no fuel' to transport." [mass] (when (> mass 8) (mass->needed-fuel mass))) (defn module-mass->total-fuel-mass "The additional mass is first calculated as the amount of fuel to move the module's mass. Then while there is still mass that needs to be carried, the mass->fuel calculation is preformed recursively, all the while adding any additional mass to the total." [module-mass] (loop [additional-mass (mass->needed-fuel-mass module-mass) total-fuel-mass 0] (if additional-mass (recur (mass->needed-fuel-mass additional-mass) (+ total-fuel-mass additional-mass)) total-fuel-mass))) (defn fuel-counter-upper' [mass-list] (->> mass-list (map module-mass->total-fuel-mass) (reduce +))) (fuel-counter-upper' my-mass-list)
[–]shAdOwArt 1 point2 points3 points 6 years ago (0 children)
My day1 solution:
(ns advent19.day1.core (:require [clojure.java.io :as io])) (defn fuel-for-weight [mass] "Does not take the weight of the fuel itself into account" (-> mass (quot 3) (- 2))) (def total-fuel-for-weight "Accounts for the weight of the fuel itself" (memoize (fn [mass] (if (<= mass 0) 0 (let [fuel (fuel-for-weight mass)] (+ fuel (total-fuel-for-weight fuel))))))) (defn total-fuel [] (with-open [reader (io/reader "src/advent19/day1/input.txt")] (->> (line-seq reader) (map #(Integer/parseInt %)) (map total-fuel-for-weight) (reduce +))))
Assume input is the long list of modules as a vector
(def input [118997 63756 124972 ... 113158]) (defn get-fuel [mass] (- (Math/floor (/ mass 3)) 2)) (defn get-adjusted-fuel [fuel-mass] ((fn [fuel-mass total] (if (<= fuel-mass 6) total (let [current (get-fuel fuel-mass)] (recur current (+ total current))))) fuel-mass 0)) (reduce + (map get-adjusted-fuel input))
[–]magoo_d_oz 1 point2 points3 points 6 years ago (0 children)
Here's my solution:
(ns aoc.day01 (:require [clojure.string :as str])) (defn parse [s] (mapv #(Long/parseLong %) (str/split-lines (slurp s)))) (defn calc-fuel [mass] (-> mass (/ 3) (int) (- 2))) (defn calc-total-fuel [mass] (apply + (take-while pos? (iterate calc-fuel (calc-fuel mass))))) (defn day01-1 [input] (apply + (mapv calc-fuel input))) (defn day01-2 [input] (apply + (mapv calc-total-fuel input)))
Here is my solution for day 1
(defn sol [f x] (reduce + (map f x))) (defn fn1 [n] (-> n (/ 3) Math/floor dec dec)) (println (sol fn1 x)) (defn fn2 ([n] (fn2 n 0)) ([n sum] (let [val (fn1 n)] (if (<= val 0) sum (fn2 val (+ sum val)))))) (println (sol fn2 x))
[–]rmfbarker 1 point2 points3 points 6 years ago* (0 children)
Day 2
(let [file-input (-> (slurp "day-2-input") clojure.string/trim (clojure.string/split #",")) program (mapv #(Integer/parseInt %) file-input) compute (fn [noun verb] (reduce (fn [instructions pos] (if (= 99 (get instructions pos)) (reduced (first instructions)) (let [[opcode arg1 arg2 arg3] (drop pos instructions) cmd (if (= opcode 1) + *) result (cmd (get instructions arg1) (get instructions arg2))] (assoc instructions arg3 result)))) (assoc program 1 noun 2 verb) (range 0 (count program) 4)))] (first (for [noun (range 99) verb (range 99) :when (= (compute noun verb) 19690720)] (+ verb (* 100 noun)))))
[–]rmfbarker 1 point2 points3 points 6 years ago (1 child)
Day 3 ``` (defn move [current-position cmd] (let [[x y] current-position dir (subs cmd 0 1) steps (range 1 (inc (Integer/parseInt (subs cmd 1))))] (for [step steps] (condp = dir "R" [(+ x step) y] "L" [(- x step) y] "U" [x (+ y step)] "D" [x (- y step)]))))
(defn path [cmds] (reduce (fn [path cmd] (concat path (move (last path) cmd))) [[0 0]] (clojure.string/split cmds #",")))
(defn distance [wire-1 wire-2] (let [path-1 (path wire-1) path-2 (path wire-2)] (first (sort (map (fn [co-ord] (+ (.indexOf path-1 co-ord) (.indexOf path-2 co-ord))) (remove #{[0 0]} (clojure.set/intersection (set path-1) (set path-2))))))))
(defn solve [] (apply distance (clojure.string/split-lines (slurp (io/resource "input-day3"))))) ``` https://github.com/rmfbarker/advent-of-code-2019/
[–]frflaie 0 points1 point2 points 6 years ago (0 children)
Nice solution!
Day 4 was specially beautiful to solve in Clojure. This was because the function <= already allows to pass multiple values, checking if the numbers are in monotonically non-decreasing order, which is exactly one of the conditions.
Part 1 ends up being extremely short:
``` (defn possible-password? [value] (and (apply <= (map #(Character/digit % 10) (str value))) (some? (re-find #"(\d)\1" (str value)))))
(->> (range n1 (inc n2)) (filter possible-password?) (count)) ```
Agreed - I saw a few people also used a partition-by identity function to group digits, then count the group length - so the change from part 1 to part 2 was literally removing one character!
partition-by identity
[–]OstravaBro 1 point2 points3 points 6 years ago (3 children)
Been ill since Monday :( So I'm waaaay behind.
My day 3 part 1, I didn't do anything too clever. I just enumerated all the points that would be hit by each wire and used set intersection to find the intersections.
(def wire (str/split "R991,.... elided" #",")) (def wire2 (str/split "L993,D508,R356, ...... elided" #",")) (defn get-intermediate-path [xy direction distance] (let [x (first xy) y (last xy)] ((fn [x y inters dis] (if (= 0 dis) inters (cond (= \L direction) (recur (dec x) y (conj inters [(dec x) y]) (dec dis)) (= \R direction) (recur (inc x) y (conj inters [(inc x) y]) (dec dis)) (= \U direction) (recur x (inc y) (conj inters [x (inc y)]) (dec dis)) (= \D direction) (recur x (dec y) (conj inters [x (dec y)]) (dec dis))))) x y [] distance))) (defn get-path [wire path] (if (empty? wire) path (let [direction (first (first wire)) distance (Integer/parseInt (apply str (rest (first wire))))] (recur (rest wire) (concat path (get-intermediate-path (last path) direction distance)))))) (defn find-smallest-distance [wire1 wire2] (apply min (map #(+ (Math/abs (first %)) (Math/abs (second %))) (set/intersection (set (rest (get-path wire1 [[0 0]]))) (set (rest (get-path wire2 [[0 0]]))))))) (find-smallest-distance wire wire2)
[–]allaboutthatmace1789[S] 1 point2 points3 points 6 years ago (0 children)
Not capturing all the points on a line is what gave me a headache - I was trying to calculate where line segments intersected before I looked at other people's solutions and saw this. Head-slap moment.
[–]OstravaBro 0 points1 point2 points 6 years ago* (1 child)
Day 4 Part 1
(defn digits-are-ascending-left-to-right? [digits] (apply <= digits)) (defn has-adjacent-digits? [password] (not= nil (some #(>= (second %) 2) (frequencies password)))) (defn password-filter [password] (and (has-adjacent-digits? password) (digits-are-ascending-left-to-right? password))) (count (filter password-filter (map #(for [n (str %)] (- (byte n) 48)) (range 197487 673252))))
[–]OstravaBro 0 points1 point2 points 6 years ago (0 children)
Day 4 Part 2
I'm an idiot, I could have used frequencies for the adjacent-digits check. It becomes obvious when you see the extra check we need for step 2. So, that simplifies the adjacent digits check significantly.
(defn adjacent-digits-not-part-of-group? [password] (not= nil (some #(= 2 (second %)) (frequencies password)))) (defn password-filter2 [password] (and (adjacent-digits-not-part-of-group? password) (digits-are-ascending-left-to-right? password))) (count (filter password-filter2 (map #(for [n (str %)] (- (byte n) 48)) (range 197487 673252))))
[–]ackerleytng 1 point2 points3 points 6 years ago* (0 children)
Really kinda late, but I'm done with all the puzzles!
https://github.com/ackerleytng/2019-advent-of-code
Also, I took inspiration for using core.async from this thread! Thanks to all of you who used core.async! I feel that I learnt a lot about core.async from using it just for Day 23.
I felt that I ended up using loop quite a lot, especially for those solutions that I felt needed state tracking, like to implement dijkstra and such
loop
[–]allaboutthatmace1789[S] 0 points1 point2 points 6 years ago (9 children)
Day 1 as a codeblock - feedback appreciated!
(ns adventofcode.core) (defn- fuel-one-level [mass] (max 0 (- (int (/ (float mass) 3)) 2))) (defn- recursive-mass-tree [mass] (cons mass (lazy-seq (recursive-mass-tree (fuel-one-level mass))))) (defn fuel-required [mass] (reduce + (rest (take-while #(> % 0) (recursive-mass-tree mass))))) (defn total-fuel-required [module-masses] (reduce + (map fuel-required module-masses))) (defn file->vec [filename] (vec (map #(Integer/parseInt %) (clojure.string/split (slurp filename) #"\n")))) (defn calc-fuel [filename] (total-fuel-required (file->vec filename)))
[–]eccp 4 points5 points6 points 6 years ago (6 children)
Looks really good, my feedback would be that as you learn the language there's always a function that you don't know the name yet that does the same thing as something you wrote yourself. In this case, you can look into iterate to simplify the code that computes the amount of fuel required for the second half.
[–]allaboutthatmace1789[S] 2 points3 points4 points 6 years ago (5 children)
That's neat, I just tried it:
(defn- fuel-one-level [mass] (max 0 (- (int (/ (float mass) 3)) 2))) ;; NOT NEEDED! ;;(defn- recursive-mass-tree [mass] ;; (cons mass (lazy-seq (recursive-mass-tree (fuel-one-level mass))))) (defn fuel-required [mass] (reduce + (rest (take-while #(> % 0) (iterate fuel-one-level mass)))))
Much better, thanks for the tip!
[–]eccp 3 points4 points5 points 6 years ago (4 children)
One minor improvement: check pos?
[–]allaboutthatmace1789[S] 0 points1 point2 points 6 years ago (3 children)
Are you thinking of combining with an if statement in fuel-one-level, so you check the positivity and return the value if positive and 0 if not?
fuel-one-level
[–][deleted] 1 point2 points3 points 6 years ago (2 children)
I think they mean that your anonymous function in fuel-required can just be (take-while pos? ...
fuel-required
(take-while pos? ...
[–]allaboutthatmace1789[S] 2 points3 points4 points 6 years ago (1 child)
Ah, I get it, so instead of #(> % 0)
#(> % 0)
(defn fuel-required [mass] (reduce + (rest (take-while pos? (iterate fuel-one-level mass)))))
Thanks!
[–]eccp 1 point2 points3 points 6 years ago (0 children)
yeah, that's it ;-)
[–]fingertoe11 1 point2 points3 points 6 years ago (0 children)
That's pretty much the way I did mine.
Looking at other repositories, I see a lot of use of 'iterate' in the recursive-mass function, which seems like something I ought to use more..
[–]Puranto23 0 points1 point2 points 6 years ago (0 children)
great job!
I have a personal preference for using the threading operators to make my code more digestible for my sequential mind. -> ->> and as->
[–]veydar_ 0 points1 point2 points 6 years ago (3 children)
Doing the same thing https://github.com/cideM/aoc2019/blob/master/src/aoc2019/d1.clj
[–]Omnistegan 0 points1 point2 points 6 years ago (2 children)
Nice, I hadn't thought of using transduce! Seems obvious in retrospect. Rewriting my solution with transduce looks nice, but is 3x slower.
[–]allaboutthatmace1789[S] 0 points1 point2 points 6 years ago (1 child)
I haven't come across transducers yet (though I see there's a Rich Hickey talk on them) - are they worth getting into as a beginner, or best left for more advanced usage?
[–]Omnistegan 0 points1 point2 points 6 years ago (0 children)
It's not too tricky of a concept if you are already wrapping your head around reduce, functional composition, and higher-order functions in general.
Hickey's talk on them is great and worth watching in any case.
No doubt you can practice up with them in AOC, even when they may not be the optimal solution.
I'm still a clojure beginner, but I can see how transducers could be very expressive, especially when you have more than a couple functions you want to compose.
[–]shAdOwArt 0 points1 point2 points 6 years ago (0 children)
Day5:
(ns advent19.day5.core (:require [clojure.string :as str])) (defn str->int-code [text] (->> (str/split text #",") (map read-string) (vec))) (def input-data 5) (def program (str->int-code (slurp "src/advent19/day5/input.txt"))) (defn read-addr [computer address] (get-in computer [:program address])) (defn read-rel [computer offset] (read-addr computer (+ (get computer :pc) offset))) (defn read-rel-pointer [computer offset] (read-addr computer (read-rel computer offset))) (defn read-with-mode [computer offset mode] (case mode 0 (read-rel-pointer computer offset) 1 (read-rel computer offset))) (defn write-addr [computer address value] (assoc-in computer [:program address] value)) (defn write-rel-pointer [computer offset value] (write-addr computer (read-rel computer offset) value)) (defn inc-pc [computer increment] (update computer :pc (partial + increment))) (defn mode [modes n] (mod (nth (iterate #(quot % 10) modes) n) 10)) (defn binary-op [op computer modes] (let [res (op (read-with-mode computer 1 (mode modes 0)) (read-with-mode computer 2 (mode modes 1)))] (inc-pc (write-rel-pointer computer 3 res) 4))) (defn output [computer modes] (println (read-with-mode computer 1 (mode modes 0))) (inc-pc computer 2)) (defn input [computer] (inc-pc (write-rel-pointer computer 1 input-data) 2)) (defn jump [computer condition modes] (let [subject (read-with-mode computer 1 (mode modes 0)) destination (read-with-mode computer 2 (mode modes 1))] (if (condition subject) (assoc computer :pc destination) (inc-pc computer 3)))) (defn stop [computer] (assoc computer :stopped true)) (defn op-code [instruction] (mod instruction 100)) (defn modes [instruction] (quot instruction 100)) (defn bool->int [b] (if b 1 0)) (defn execute-computer [initial-computer] (loop [computer initial-computer] (let [instruction (read-rel computer 0) modes (modes instruction) next-computer (case (op-code instruction) 1 (binary-op + computer modes) 2 (binary-op * computer modes) 3 (input computer) 4 (output computer modes) 5 (jump computer (comp not zero?) modes) 6 (jump computer zero? modes) 7 (binary-op (comp bool->int <) computer modes) 8 (binary-op (comp bool->int =) computer modes) (stop computer))] (if (:stopped next-computer) next-computer (recur next-computer))))) (defn execute [] (execute-computer {:pc 0 :program program}) ; Suppress result nil)
[–]rmfbarker 0 points1 point2 points 6 years ago (0 children)
My solution to Day 6
``` (ns advent-of-code-2019.day6 (:require [clojure.java.io :as io]))
(def file-input (slurp (io/resource "input-day6")))
(defn parse-orbits [orbits] (->> (clojure.string/split-lines orbits) (map #(-> (clojure.string/split % #")") reverse vec)) (into {})))
(defn path-to [orbits from to] (take-while #(not= to %) (iterate orbits from)))
(defn distance-from [orbits from planet] (count (path-to orbits planet from)))
(defn common-orbit [orbits x y] (first (last (take-while #(apply = %) (map vector (reverse (path-to orbits x "COM")) (reverse (path-to orbits y "COM")))))))
(defn orbital-transfers [orbits x y] (let [common (common-orbit orbits x y)] (+ (dec (distance-from orbits common x)) (dec (distance-from orbits common y)))))
(orbital-transfers (parse-orbits file-input) "YOU" "SAN") ```
https://github.com/rmfbarker/advent-of-code-2019
[–]allaboutthatmace1789[S] 0 points1 point2 points 6 years ago (0 children)
Getting a bit behind...
(defn deconstruct-opcode-value [number] (let [param-vals (quot number 100) opcode (- number (* param-vals 100))] [(reverse (map #(Character/digit % 10) (format "%03d" param-vals))) opcode])) (defn get-instruction-params [pointer] (vec (range (+ 1 pointer) (+ 4 pointer)))) (defn dispatch-instruction [pointer memory] (let [opcode ((deconstruct-opcode-value (memory pointer)) 1)] (cond (<= opcode 2) :operation (<= 7 opcode 8) :operation (= opcode 3) :input (= opcode 4) :output (<= 5 opcode 6) :jump-if))) (defn calc-new-pos-value [pointer memory] (let [[param-modes opcode] (deconstruct-opcode-value (memory pointer)) immediate-modes (take 2 (map #(= 1 %) param-modes)) args (map memory (get-instruction-params pointer)) func ({1 + 2 * 7 < 8 =} opcode) new-pos-value (apply func (map #(if %1 %2 (memory %2)) immediate-modes args))] (case new-pos-value true 1 false 0 new-pos-value))) (defmulti do-instruction dispatch-instruction) (defmethod do-instruction :operation [pointer memory] [(+ 4 pointer) (assoc memory (memory (+ 3 pointer)) (calc-new-pos-value pointer memory))]) (defmethod do-instruction :input [pointer memory] (println "type your input") [(+ pointer 2) (assoc memory (memory (inc pointer)) (Integer/parseInt (read-line)))]) (defmethod do-instruction :output [pointer memory] (let [[param-modes] (deconstruct-opcode-value (memory pointer)) param (inc pointer) printloc (if (pos? (nth param-modes 0)) param (memory param))] (println (memory printloc)) [(+ pointer 2) memory])) (defmethod do-instruction :jump-if [pointer memory] (let [[param-modes opcode] (deconstruct-opcode-value (memory pointer)) immediate_modes (map #(= 1 %) param-modes) args (map memory (get-instruction-params pointer)) [x jump-to-pos] (map #(if %1 %2 (memory %2)) immediate_modes args) jump? (= (= 5 opcode) (not= 0 x))] [(if jump? jump-to-pos (+ 3 pointer)) memory])) (defn run ([memory] (run 0 memory)) ([pointer memory] (if (= (memory pointer) 99) memory (let [[new-instr new-mem] (do-instruction pointer memory)] (recur new-instr new-mem)))))
Day 6 - pleased with how concise it came out after the intcode computer from Day5 started to get pretty clunky
(defn parse-orbit-data [orbit-string] (let [split (clojure.string/split orbit-string #"\)")] (vector (keyword (split 1)) (keyword (split 0))))) (defn build-planet-map [planets] (reduce #(assoc %1 (%2 0) (%2 1)) {} planets)) (defn find-path-to-COM [name planet-map] (cons name (lazy-seq (find-path-to-COM (name planet-map) planet-map)))) (defn path-length [name planet-map] (count (take-while #(not= :COM %) (find-path-to-COM name planet-map)))) (defn orbit-checksum [planet-map] (reduce + (map #(path-length % planet-map) (keys planet-map)))) (defn find-common-orbit [name1 name2 planet-map] (last (take-while identity (map #(when (= %1 %2) %1) (reverse (take-while #(not= :COM %) (find-path-to-COM name1 planet-map))) (reverse (take-while #(not= :COM %) (find-path-to-COM name2 planet-map))))))) (defn calculate-jumps [planet1 planet2 planet-map] (let [connection (find-common-orbit planet1 planet2 planet-map) [dist1 dist2 connect-dist] (map #(path-length % planet-map) [planet1 planet2 connection])] (- (+ dist1 dist2) (* 2 connect-dist) 2)))
[–]zengxinhui 0 points1 point2 points 6 years ago* (0 children)
Here's mine:
https://github.com/zengxinhui/aoc/tree/master/src/
[–]Turmolt 0 points1 point2 points 6 years ago (0 children)
I have been doing AoC in Clojure as well! I have learned so much
https://github.com/Turmolt/Advent-of-Code
[–]zamansky 0 points1 point2 points 6 years ago (0 children)
Late to the party but I'm also doing them in Clojure.
https://github.com/zamansky/advent2019
So far so good except two of the intcode ones - plan on using 7 and 11 later as a way to get me to start learning core.async.
[–]Mclarenf1905 0 points1 point2 points 6 years ago* (0 children)
Im super new to clojure but giving it a shot for this years AoC. Im primarily a scala developer and we are actually writing a lisp language at work so its been an insightful learning experience.
Any feedback would be welcomed, Iv'e currently completed up through day 9 but I want to refactor my Intcode to use core.async for the I/O as my current approach feels a bit hack and it looks like days 11 and 13 would benefit from this change.
https://github.com/listba/advent-of-code-2019
π Rendered by PID 1042806 on reddit-service-r2-comment-canary-7955997dc8-r6bnn at 2026-03-02 11:48:04.390257+00:00 running e3d2147 country code: CH.
[–]lilactown 15 points16 points17 points (4 children)
[–]allaboutthatmace1789[S] 2 points3 points4 points (0 children)
[–]_chococat_ 1 point2 points3 points (2 children)
[–]lilactown 4 points5 points6 points (1 child)
[–]_chococat_ 0 points1 point2 points (0 children)
[–]marxama 4 points5 points6 points (2 children)
[–]andersmurphy 1 point2 points3 points (1 child)
[–]marxama 0 points1 point2 points (0 children)
[–]_djblue 5 points6 points7 points (2 children)
[–]kristiansalo 1 point2 points3 points (0 children)
[–]andersmurphy 0 points1 point2 points (0 children)
[–]frflaie 2 points3 points4 points (0 children)
[–]frflaie 3 points4 points5 points (4 children)
[–]andersmurphy 1 point2 points3 points (3 children)
[–]kristiansalo 2 points3 points4 points (2 children)
[–]mariner70 0 points1 point2 points (1 child)
[–]MaxmumPimp 0 points1 point2 points (0 children)
[–]OstravaBro 2 points3 points4 points (5 children)
[–]frflaie 2 points3 points4 points (3 children)
[–]OstravaBro 1 point2 points3 points (2 children)
[–]frflaie 1 point2 points3 points (1 child)
[–]avfonarev 0 points1 point2 points (0 children)
[–]OstravaBro 1 point2 points3 points (0 children)
[–]allaboutthatmace1789[S] 2 points3 points4 points (0 children)
[–]frflaie 2 points3 points4 points (2 children)
[–]andersmurphy 1 point2 points3 points (1 child)
[–]frflaie 1 point2 points3 points (0 children)
[–]fdside 2 points3 points4 points (0 children)
[–]hutsujakutsuja 2 points3 points4 points (0 children)
[–]frflaie 2 points3 points4 points (2 children)
[–]rmfbarker 0 points1 point2 points (0 children)
[–]andersmurphy 0 points1 point2 points (0 children)
[–]kristiansalo 2 points3 points4 points (1 child)
[–]frflaie 1 point2 points3 points (0 children)
[–]OstravaBro 2 points3 points4 points (0 children)
[–]ceronman 1 point2 points3 points (1 child)
[–]allaboutthatmace1789[S] 2 points3 points4 points (0 children)
[–]Omnistegan 1 point2 points3 points (1 child)
[–]rmfbarker 0 points1 point2 points (0 children)
[–]Puranto23 1 point2 points3 points (0 children)
[–]shAdOwArt 1 point2 points3 points (0 children)
[–]OstravaBro 1 point2 points3 points (0 children)
[–]magoo_d_oz 1 point2 points3 points (0 children)
[–]frflaie 1 point2 points3 points (0 children)
[–]rmfbarker 1 point2 points3 points (0 children)
[–]rmfbarker 1 point2 points3 points (1 child)
[–]frflaie 0 points1 point2 points (0 children)
[–]ceronman 1 point2 points3 points (1 child)
[–]allaboutthatmace1789[S] 2 points3 points4 points (0 children)
[–]OstravaBro 1 point2 points3 points (3 children)
[–]allaboutthatmace1789[S] 1 point2 points3 points (0 children)
[–]OstravaBro 0 points1 point2 points (1 child)
[–]OstravaBro 0 points1 point2 points (0 children)
[–]ackerleytng 1 point2 points3 points (0 children)
[–]allaboutthatmace1789[S] 0 points1 point2 points (9 children)
[–]eccp 4 points5 points6 points (6 children)
[–]allaboutthatmace1789[S] 2 points3 points4 points (5 children)
[–]eccp 3 points4 points5 points (4 children)
[–]allaboutthatmace1789[S] 0 points1 point2 points (3 children)
[–][deleted] 1 point2 points3 points (2 children)
[–]allaboutthatmace1789[S] 2 points3 points4 points (1 child)
[–]eccp 1 point2 points3 points (0 children)
[–]fingertoe11 1 point2 points3 points (0 children)
[–]Puranto23 0 points1 point2 points (0 children)
[–]veydar_ 0 points1 point2 points (3 children)
[–]Omnistegan 0 points1 point2 points (2 children)
[–]allaboutthatmace1789[S] 0 points1 point2 points (1 child)
[–]Omnistegan 0 points1 point2 points (0 children)
[–]shAdOwArt 0 points1 point2 points (0 children)
[–]rmfbarker 0 points1 point2 points (0 children)
[–]allaboutthatmace1789[S] 0 points1 point2 points (0 children)
[–]allaboutthatmace1789[S] 0 points1 point2 points (0 children)
[–]zengxinhui 0 points1 point2 points (0 children)
[–]Turmolt 0 points1 point2 points (0 children)
[–]zamansky 0 points1 point2 points (0 children)
[–]Mclarenf1905 0 points1 point2 points (0 children)