Skip to content

Instantly share code, notes, and snippets.

View Solaxun's full-sized avatar

Mark Woodworth Solaxun

View GitHub Profile
@Solaxun
Solaxun / day13.clj
Created December 15, 2018 23:08
2018 Advent of Code Day 13
(ns aoc2018-clj.day13
(:require [clojure.string :as str]
[clojure.java.io :as io]
[clojure.math.combinatorics :as combs]
[clojure.set :as set]))
(def track (str/split-lines (-> "day13.txt" io/resource slurp)))
(def race-track (mapv vec track))
(defn intersection-rule [{:keys [loc dir turn-count] :as car}]
@Solaxun
Solaxun / my-cons.clj
Last active July 3, 2020 19:29
Clojure Cons Cell
(def NIL (symbol "NIL"))
(deftype ConsCell [CAR CDR]
clojure.lang.ISeq
(cons [this x] (ConsCell. x this))
(first [this] (.CAR this))
;; next and more must return ISeq:
;; https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ISeq.java
(more [this] (if
(= (.CDR this) NIL)
@Solaxun
Solaxun / ibid.clj
Created December 5, 2019 01:08
ibid clojure - from Gene Kim's interview on the Functional Geekery podcast.
;; couldn't resist after hearing the podcast...
(defn ibid [coll]
(reduce (fn [res cur]
(if (= cur "ibid")
(conj res (last res))
(conj res cur)))
[(first coll)]
(rest coll)))
(comment
Multimethods are an open dispatch mechanism, but is closed in it's
dispatch function. If the set of dispatch types is open, so is
the multimethod.
Protocols are always open because you can always add a new type.
Multimethods require you to pick something to dispatch on that
remains open so any user can create a new one.
For dependency injection, protocols work great because you can
@Solaxun
Solaxun / multimethods-toy.clj
Last active July 20, 2020 00:27
toy multimethod implementation
;;;; machinery for multimethods
(defmacro defmethod2 [fname dispatch-val signature body]
`(swap! ~(symbol (str "multimethod-lkp-" fname)) assoc ~dispatch-val
(fn ~signature ~body)))
(defn make-generic-fn [fname dispatchfn]
`(defn ~fname [& ~'args]
(let [dispatch-val# (apply ~(symbol (str "multimethod-dispatch-" fname)) ~'args)
mm-table# (deref ~(symbol (str "multimethod-lkp-" fname)))
matching-fn# (some #(get mm-table# %) [dispatch-val# :default])]
@Solaxun
Solaxun / reify-toy.clj
Last active July 19, 2020 23:54
Toy implementation of reify, doesn't check the methods are actually part of the protocol, doesn't do namespacing, etc. Just mimicks the interface.
;;;
;;; implementation
;;;
(defn build-fn [[mname args body]]
{(keyword mname) (list 'fn mname args body)})
(defn make-generic-fn [[mname args body]]
`(defn ~mname ~args
(let [f# (get ~(first args) ~(keyword mname))]
(f# ~@args))))
@Solaxun
Solaxun / compiletime-closures.clj
Last active July 20, 2020 18:17
At runtime, the function created by the macroexpansion captures lexical scope from wherever it's called, and is stored in the atom.
(def protos (atom nil))
(defn build-func [[name args body]]
(list 'fn name args body))
(defmacro bleh [fbody]
`(let [f# ~(build-func fbody)]
(do (reset! protos f#) f#)))
(macroexpand-1 '(bleh (foo [y] (+ x y))))
@Solaxun
Solaxun / destructuring.clj
Created July 21, 2020 03:14
restructuring destructuring
(defmulti destruct-type
(fn [binding value]
(cond (sequential? binding) clojure.lang.Sequential ; order matters, vector is associative too
(associative? binding) clojure.lang.Associative
:else (type binding))))
(defn coerce-binding-type [binding-type]
(case binding-type
:strs str
:syms (fn [sym] `'~sym)
@Solaxun
Solaxun / aoc-2020-day22.clj
Created December 22, 2020 17:39
Advent of Code 2020, Day 22... can't find the bug
(def game {:player1 [26 8 2 17 19 29 41 7 25 33 50 16 36 37 32 4 46 12 21 48 11 6 13 23 9],
:player2 [27 47 15 45 10 14 3 44 31 39 42 5 49 24 22 20 30 1 35 38 18 43 28 40 34]})
;; Treating the seen rule as needing to see the exact game (both decks) twice.
;; Doesn't terminate.
(defn play-round [game]
(loop [seen #{}
{:keys [player1 player2] :as game} game]
(if (or (empty? player1) (empty? player2))
game
(let [p1 (player1 0)
@Solaxun
Solaxun / tetris.clj
Created August 14, 2021 18:24
Tetris in Clojure (basic game-play mostly done, no UI yet - switching to CLJS for that (can't use threads, reworking to use channels)
(ns tetris.game)
(def rows 20)
(def cols 10)
(def board (vec (repeat rows (vec (repeat cols " ")))))
(defn new-game-state []
{:board board
:active-piece nil
:game-over? false