This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-12-21
Channels
- # adventofcode (20)
- # babashka (118)
- # beginners (170)
- # calva (1)
- # clojure (102)
- # clojure-europe (1)
- # clojure-nl (13)
- # clojure-uk (5)
- # clojuredesign-podcast (19)
- # code-reviews (10)
- # core-async (9)
- # cursive (7)
- # datomic (8)
- # fulcro (3)
- # malli (5)
- # mount (1)
- # off-topic (19)
- # overtone (1)
- # reagent (2)
- # reitit (2)
- # spacemacs (2)
- # sql (4)
- # tools-deps (5)
I'd like to think my parsing for it ended up fairly clean. The different arities of map are major helps in this.
My second program ended up being absurdly easy - I went with a very dumb initial heuristic thinking it would show me the next failed test, but nope, that was it
trying to write fn to translate sexpressions line (and a (not b))
into AND A J...
and those 2 mutable registers are a world of pain
You can translate boolean expressions...
using de morgan's laws to change (and (not x) (not y))
to (not (or x y))
to save register space
Any expression that has more than one non-trivial operand is going to take up both of your registers
So simplify the operands of any binary op until at least one of them is a trivial register. Unary ops can be computed with a single mutable register.
all of this is true. I wanted user not to worry about shape of the tree. But reshaping a tree with a bunch of substitution rules is not an easy task as well. but yeah, can be done for sure.
I read half the book and threw this together: https://github.com/alper/aoc2019/blob/master/3.clj Itβs a bit slow so suggestions of how to speed it up are very much welcome.
It turns out that all time is spent in generate_points_from_steps
.If anybody has a solution for this I can take a look at that would also be appreciated.
(defn generate-points-from-steps
"For a vector of steps of the form [\"R\" 10] etc.,
generates a vector of points starting from origin."
[steps]
(reduce
(fn [path step]
(into []
(concat path (loc-from-loc (last path) step))))
[origin]
steps))
can be just
(reduce
(fn [path step]
(into path
(loc-from-loc (peek path) step)))
[origin]
steps)
with 2 key improvements:
1)`peek` is constant time lookup of last element in vector (`last` is linear time)
2) into
directly into path vector bypasses concat
and scans only new lock-from-loc
segment. Where concat
does not scan for concatting, but then scans entire seq: both old path
and new lock-from-lock
to put them into empty []
.so in your code - each next iteration you scan old path
segment twice: for last and after concat, instead of nonce
I think this:
(first (sort
(fn [p1 p2] (< (dist-to-origin p1) (dist-to-origin p2))
points)))
can be this:
(->> points
(sort-by dist-to-origin <)
(first))
(defn loc-from-loc
"Loc is a hash with :x and :y, step is a vector with a direction string and an integer. Returns a list of locations that have been stepped over."
[loc step]
(case (first step)
"R" (map (fn [step] (update loc :x + step)) (range 1 (+ (second step) 1)))
"L" (map (fn [step] (update loc :x - step)) (range 1 (+ (second step) 1)))
"U" (map (fn [step] (update loc :y + step)) (range 1 (+ (second step) 1)))
"D" (map (fn [step] (update loc :y - step)) (range 1 (+ (second step) 1)))))
can be shorter with destructuring:
(defn loc-from-loc
"Loc is a hash with :x and :y, step is a vector with a direction string and an integer.
Returns a list of locations that have been stepped over."
[loc [dir len]]
(let [offsets (range 1 (+ 1 len))]
(case dir
"R" (map (fn [step] (update loc :x + step)) offsets)
"L" (map (fn [step] (update loc :x - step)) offsets)
"U" (map (fn [step] (update loc :y + step)) offsets)
"D" (map (fn [step] (update loc :y - step)) offsets))))
Just removing last
and concat
resulted in a 20x speed gain:
Elapsed time: 7390.580613 msecs Elapsed time: 372.936439 msecs