├── doc └── intro.md ├── .gitignore ├── test └── practicalli │ └── advent_of_code_2019 │ └── 01_trinity_of_rocket_equasion_test.clj ├── deps.edn ├── CHANGELOG.md ├── README.md └── src └── practicalli └── advent_of_code_2019 ├── 01-trinity-of-rocket-equasion-data.clj └── 01_trinity_of_rocket_equasion.clj /doc/intro.md: -------------------------------------------------------------------------------- 1 | # Introduction to advent-of-code-2019.01-trinity-of-rocket-equasion 2 | 3 | TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | pom.xml 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | /.cpcache 9 | /.lein-* 10 | /.nrepl-history 11 | /.nrepl-port 12 | .hgignore 13 | .hg/ 14 | -------------------------------------------------------------------------------- /test/practicalli/advent_of_code_2019/01_trinity_of_rocket_equasion_test.clj: -------------------------------------------------------------------------------- 1 | (ns practicalli.advent-of-code-2019.01-trinity-of-rocket-equasion-test 2 | (:require [clojure.test :refer :all] 3 | [practicalli.advent-of-code-2019.01-trinity-of-rocket-equasion :as :SUT])) 4 | 5 | (deftest a-test 6 | (testing "FIXME, I fail." 7 | (is (= 0 1)))) 8 | -------------------------------------------------------------------------------- /deps.edn: -------------------------------------------------------------------------------- 1 | {:paths 2 | ["resources" "src"] 3 | 4 | :deps 5 | {org.clojure/clojure {:mvn/version "1.10.1"}} 6 | 7 | :aliases 8 | {:test 9 | {:extra-paths ["test"] 10 | :extra-deps {org.clojure/test.check {:mvn/version "0.10.0"}}} 11 | 12 | :runner 13 | {:extra-deps {com.cognitect/test-runner 14 | {:git/url "https://github.com/cognitect-labs/test-runner" 15 | :sha "76568540e7f40268ad2b646110f237a60295fa3c"}} 16 | :main-opts ["-m" "cognitect.test-runner" 17 | "-d" "test"]}}} 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). 3 | 4 | ## [Unreleased] 5 | ### Changed 6 | - Add a new arity to `make-widget-async` to provide a different widget shape. 7 | 8 | ## [0.1.1] - 2019-12-21 9 | ### Changed 10 | - Documentation on how to make the widgets. 11 | 12 | ### Removed 13 | - `make-widget-sync` - we're all async, all the time. 14 | 15 | ### Fixed 16 | - Fixed widget maker to keep working when daylight savings switches over. 17 | 18 | ## 0.1.0 - 2019-12-21 19 | ### Added 20 | - Files from the new template. 21 | - Widget maker public API - `make-widget-sync`. 22 | 23 | [Unreleased]: https://github.com/your-name/advent-of-code-2019.01-trinity-of-rocket-equasion/compare/0.1.1...HEAD 24 | [0.1.1]: https://github.com/your-name/advent-of-code-2019.01-trinity-of-rocket-equasion/compare/0.1.0...0.1.1 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advent-of-code-2019 2 | 3 | Solving the [Advent of Code challenges from 2019](https://adventofcode.com/2019). 4 | 5 | Taking examples from across the community and comparing them. 6 | 7 | ## Installation 8 | 9 | Clone the project with your favourite git client, eg. Magit. 10 | 11 | https://github.com/practicalli/advent-of-code-2019 12 | 13 | 14 | ## Solving the challenges 15 | 16 | Open the project in your favourite editor or REPL and run the `-main` function in each namespace to generate the result. 17 | 18 | $ clj -m practicalli.advent-of-code-2019.01-trinity-of-rocket-equasion 19 | 20 | The puzzle data is in a sibling namespace, postfixed with the name `-data.clj`. Simply replace your own data in the `(def data)` expression 21 | 22 | You can also just explore the different functions and approaches by evaluating the code. 23 | 24 | 25 | ## Testing the code 26 | 27 | Run the unit tests (if we write any) using the Cognitect test runner (automatically installs itself on first run): 28 | 29 | $ clj -A:test:runner 30 | 31 | ## License 32 | 33 | Copyright © 2019 Practicalli 34 | 35 | Distributed under the Creative Commons Attribution Share-Alike 4.0 International 36 | -------------------------------------------------------------------------------- /src/practicalli/advent_of_code_2019/01-trinity-of-rocket-equasion-data.clj: -------------------------------------------------------------------------------- 1 | (ns practicalli.advent-of-code-2019.01-trinity-of-rocket-equasion-data) 2 | 3 | 4 | (def puzzle-input 5 | [92349 6 | 57040 7 | 64079 8 | 121555 9 | 143735 10 | 64642 11 | 104858 12 | 144446 13 | 88871 14 | 62338 15 | 113424 16 | 59960 17 | 53999 18 | 86867 19 | 67224 20 | 124130 21 | 108921 22 | 130492 23 | 120361 24 | 74426 25 | 70397 26 | 88106 27 | 125442 28 | 74237 29 | 137818 30 | 66633 31 | 71756 32 | 143276 33 | 143456 34 | 135698 35 | 121124 36 | 67739 37 | 112861 38 | 78572 39 | 73565 40 | 111899 41 | 57543 42 | 130314 43 | 121605 44 | 121426 45 | 117143 46 | 129957 47 | 98042 48 | 104760 49 | 144846 50 | 131238 51 | 101076 52 | 53328 53 | 83592 54 | 104077 55 | 101952 56 | 54137 57 | 115363 58 | 60556 59 | 133086 60 | 113361 61 | 117829 62 | 75003 63 | 93729 64 | 140022 65 | 126219 66 | 59907 67 | 140589 68 | 91812 69 | 50485 70 | 56232 71 | 92858 72 | 106820 73 | 123423 74 | 98553 75 | 135315 76 | 95583 77 | 72278 78 | 98702 79 | 55709 80 | 146773 81 | 89719 82 | 134752 83 | 79562 84 | 70455 85 | 88468 86 | 139824 87 | 138646 88 | 117516 89 | 123267 90 | 113754 91 | 120353 92 | 139145 93 | 53219 94 | 63053 95 | 131434 96 | 91705 97 | 53650 98 | 145234 99 | 78461 100 | 119587 101 | 108976 102 | 113613 103 | 121790 104 | 120366 105 | ]) 106 | -------------------------------------------------------------------------------- /src/practicalli/advent_of_code_2019/01_trinity_of_rocket_equasion.clj: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ;; Advent of Clojure Code 2019 3 | ;; 4 | ;; Author: @practicalli 5 | ;; 6 | ;; Day 1: The Tyranny of the Rocket Equation 7 | ;; Parts 1 & 2 8 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 9 | 10 | 11 | (ns practicalli.advent-of-code-2019.01-trinity-of-rocket-equasion 12 | (:gen-class) 13 | (:require [practicalli.advent-of-code-2019.01-trinity-of-rocket-equasion-data :as data])) 14 | 15 | ;; Part 1 - calculating total fuel 16 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 17 | 18 | ;; Santa has become stranded at the edge of the Solar System while delivering presents to other planets! To accurately calculate his position in space, safely align his warp drive, and return to Earth in time to save Christmas, he needs you to bring him measurements from fifty stars. 19 | 20 | ;; Collect stars by solving puzzles. Two puzzles will be made available on each day in the Advent calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants one star. Good luck! 21 | 22 | ;; The Elves quickly load you into a spacecraft and prepare to launch. 23 | 24 | ;; At the first Go / No Go poll, every Elf is Go until the Fuel Counter-Upper. They haven't determined the amount of fuel required yet. 25 | 26 | ;; Fuel required to launch a given module is based on its mass. Specifically, to find the fuel required for a module, take its mass, divide by three, round down, and subtract 2. 27 | 28 | ;; For example: 29 | 30 | ;; For a mass of 12, divide by 3 and round down to get 4, then subtract 2 to get 2. 31 | ;; For a mass of 14, dividing by 3 and rounding down still yields 4, so the fuel required is also 2. 32 | ;; For a mass of 1969, the fuel required is 654. 33 | ;; For a mass of 100756, the fuel required is 33583. 34 | 35 | 36 | ;; The Fuel Counter-Upper needs to know the total fuel requirement. To find it, individually calculate the fuel needed for the mass of each module (your puzzle input), then add together all the fuel values. 37 | 38 | ;; What is the sum of the fuel requirements for all of the modules on your spacecraft? 39 | 40 | ;; To begin, get your puzzle input. 41 | 42 | 43 | (defn fuel-for-module 44 | "Calculate the fuel for a given module based on its mass. 45 | 46 | Divide mass by 3, round down to Integer then subtract 2 47 | 48 | Argument: mass - an integer 49 | Return: fuel-required - as an integer" 50 | [module-mass] 51 | #_(/ module-mass 3) ;; we could divide then round down, but quot is simpler 52 | (- (quot module-mass 3) 2)) 53 | 54 | #_(fuel-for-module 14) 55 | #_(fuel-for-module 100756) 56 | 57 | (defn solve-part-1 58 | "Calculate the fuel required for each module, 59 | and return the total amount of fuel required 60 | for all modules" 61 | [puzzle-input] 62 | (reduce + (map fuel-for-module puzzle-input))) 63 | 64 | (map fuel-for-module data/puzzle-input) 65 | 66 | 67 | (solve-part-1 data/puzzle-input) 68 | 69 | 70 | (defn -main 71 | "Run me and I will tell you the answer to the problem, eventually" 72 | [& args] 73 | (solve-part-1 data/puzzle-input)) 74 | 75 | #_(-main) 76 | 77 | 78 | 79 | 80 | ;; Part Two 81 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 82 | 83 | ;; During the second Go / No Go poll, the Elf in charge of the Rocket Equation Double-Checker stops the launch sequence. Apparently, you forgot to include additional fuel for the fuel you just added. 84 | 85 | ;; Fuel itself requires fuel just like a module - take its mass, divide by three, round down, and subtract 2. However, that fuel also requires fuel, and that fuel requires fuel, and so on. Any mass that would require negative fuel should instead be treated as if it requires zero fuel; the remaining mass, if any, is instead handled by wishing really hard, which has no mass and is outside the scope of this calculation. 86 | 87 | ;; So, for each module mass, calculate its fuel and add it to the total. Then, treat the fuel amount you just calculated as the input mass and repeat the process, continuing until a fuel requirement is zero or negative. For example: 88 | 89 | ;; A module of mass 14 requires 2 fuel. This fuel requires no further fuel (2 divided by 3 and rounded down is 0, which would call for a negative fuel), so the total fuel required is still just 2. 90 | ;; At first, a module of mass 1969 requires 654 fuel. Then, this fuel requires 216 more fuel (654 / 3 - 2). 216 then requires 70 more fuel, which requires 21 fuel, which requires 5 fuel, which requires no further fuel. So, the total fuel required for a module of mass 1969 is 654 + 216 + 70 + 21 + 5 = 966. 91 | ;; The fuel required by a module of mass 100756 and its fuel is: 33583 + 11192 + 3728 + 1240 + 411 + 135 + 43 + 12 + 2 = 50346. 92 | 93 | ;; What is the sum of the fuel requirements for all of the modules on your spacecraft when also taking into account the mass of the added fuel? (Calculate the fuel requirements for each module separately, then add them all up at the end.) 94 | 95 | 96 | ;; Visualising the results with Quil 97 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 98 | 99 | ;; http://www.quil.info/sketches/local/0622589e4acd61f73d86eff09064deff308553905d58dfc10448cf244ce9fa24 100 | 101 | 102 | ;; Taking a low level loop recur approach 103 | ;; find the fuel for the mass, 104 | ;; then find the fuel for the fuel 105 | ;; keep going until no more fuel is needed for the fuel 106 | 107 | (defn total-fuel-for-module 108 | "Calculate the fuel for a given module based on its mass. Then calculate the fuel for the fuel. 109 | 110 | `quot` is used to divide mass by 3 and return a whole number, then subtract 2 to get the amount of fuel required 111 | 112 | Argument: mass - an integer 113 | Return: total - total fuel-required as an integer" 114 | 115 | [module-mass] 116 | (loop [mass module-mass 117 | fuel (- (quot mass 3) 2) 118 | total 0] 119 | (if (<= fuel 5) 120 | (+ total fuel) 121 | (recur fuel 122 | (- (quot fuel 3) 2) 123 | (+ total fuel))))) 124 | 125 | 126 | ;; Two quick tests 127 | 128 | (total-fuel-for-module 14) 129 | 130 | (total-fuel-for-module 1969) 131 | 132 | 133 | ;; The total fuel for all the modules 134 | 135 | (reduce + 136 | (map total-fuel-for-module data/puzzle-input)) 137 | 138 | 139 | 140 | 141 | ;; Using transducers to solve the challenge 142 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 143 | 144 | ;; What are tranducers 145 | ;; A general pupose way of applying algorithmic transformations. 146 | ;; They are a recipe on how to transform data, 147 | ;; without knowing what that data is. 148 | 149 | ;; Some of the `clojure.core` functions act as a transducer 150 | 151 | (map total-fuel-for-module ,,,,) 152 | 153 | ;; Previously we covered reduce and how it iterates 154 | ;; a function over a collection of values 155 | 156 | ;; That function can be simple: 157 | (reduce * [1 2 3 4 5]) 158 | 159 | ;; Or we can write our own function 160 | 161 | (reduce custom-algorithm (range 1000)) 162 | 163 | ;; Custom functions can become quite involved 164 | ;; especially with nested expressions 165 | ;; but its the same principle. 166 | (reduce + 167 | (filter odd? 168 | (map #(+ 7 %) 169 | (range 100)))) 170 | 171 | ;; A reducing function is just the way of referring 172 | ;; to a function passed to `reduce` 173 | ;; In the above example, the whole expression starting 174 | ;; with filter is the reducing function 175 | 176 | 177 | ;; We could abstract that algorithm and make it 178 | ;; easier to use elsewhere. 179 | 180 | (def algorithm 181 | (comp (map #(+ 7 %) ,,,) 182 | (filter odd?) 183 | ,,,, 184 | ,,,)) 185 | 186 | ;; Notice that (filter odd?) and `(map #(+ 7 %))` 187 | ;; to not take any values as arguments, they are missing 188 | ;; `map` and `filter` return a transducer when only 189 | ;; given a single function as an argument (eg. no value) 190 | 191 | ;; Now the `transduce` function can be used 192 | ;; with our `algorithm` to transform data 193 | 194 | (transduce algorithm + (range 100)) 195 | ;; => 2800 196 | 197 | ;; We get the same results as the reduce 198 | ;; however our code is more adaptable 199 | 200 | ;; An initial value can also be added 201 | (transduce algorithm + -1000 (range 100)) 202 | 203 | 204 | ;; Define a name for our transformation 205 | ;; comp sends the results of the first argument, `map` 206 | ;; to the second argument, `take` 207 | 208 | (def add-values 209 | (comp (map #(+ % 7)) 210 | (take 12))) 211 | 212 | ;; The transformation is then applied over the 213 | ;; collection of values 214 | ;; the results are reduced using the `*` function 215 | 216 | (transduce add-values * [1 2 3 4 5]) 217 | 218 | 219 | ;; Back to the Advent of code challenge 220 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 221 | 222 | ;; We have our simple function to calculate 223 | ;; the fuel required for a given mass 224 | 225 | (defn fuel-required 226 | [mass] 227 | (- (quot mass 3) 2)) 228 | 229 | 230 | ;; We can see the the individual fuel values for each mass 231 | (map fuel-required data/puzzle-input) 232 | 233 | ;; and get the total 234 | 235 | (reduce + 236 | (map fuel-required data/puzzle-input)) 237 | 238 | ;; We could convert this into a transformation 239 | ;; passing just the `fuel-required` function to `map` 240 | ;; which then returns a transducer 241 | 242 | (def xform 243 | (comp 244 | (map fuel-required))) 245 | 246 | ;; Then use transduce to apply the transformation 247 | ;; and `+` as the final reducing function 248 | ;; to get the total fuel required 249 | (transduce xform + data/puzzle-input) 250 | 251 | ;; As its simple, we could just write it out in one expression 252 | (transduce (map fuel-required) + data/puzzle-input) 253 | 254 | 255 | 256 | ;; Using transduce for part 2 257 | ;; using our existing fuel calculation function 258 | 259 | (transduce (map total-fuel-for-module) 260 | + 261 | data/puzzle-input) 262 | 263 | 264 | ;; Using an iterate approach, we get the same results 265 | 266 | (defn fuel-delta [mass] 267 | (->> (iterate fuel-required mass) 268 | (rest) 269 | (take-while pos?) 270 | (reduce +))) 271 | 272 | (transduce (map fuel-delta) + data/puzzle-input) 273 | ;; => 5055835 274 | 275 | 276 | 277 | (defn fuel* 278 | [mass] 279 | (->> (iterate fuel mass) 280 | (drop 1) 281 | (take-while pos?) 282 | (apply +))) 283 | 284 | 285 | ;; Final thoughts 286 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 287 | 288 | ;; The advantage of using transduce over reduce? 289 | ;; - speed & memory 290 | ;; - fewer allocations for intermediate structures 291 | --------------------------------------------------------------------------------