#+TITLE: lispy.el demo 4: Project Euler p100 and Clojure
#+LANGUAGE: en
#+OPTIONS: H:3 num:nil toc:nil
#+HTML_HEAD:
| [[https://github.com/abo-abo/lispy][Back to github]] | [[https://raw.githubusercontent.com/abo-abo/lispy/gh-pages/demo-4.org][This file in org-mode]] | [[http://abo-abo.github.io/lispy/][Function reference]] |
* Setup :noexport:
#+begin_src emacs-lisp :exports results :results silent
(defun make-html-region--replace-1 (x)
(format "%c%s"
(aref x 1)
(regexp-quote
(substring x 2 (- (length x) 1)))))
(defun make-html-region--replace-2 (x)
(format "%s%c"
(regexp-quote
(substring x 1 (- (length x) 2)))
(aref x (- (length x) 1))))
(defun make-html-cursor--replace (x)
(if (string= "|\n" x)
"\n"
(if (string= "|[" x)
"["
(format "%s"
(regexp-quote
(substring x 1))))))
(defun make-html-region (str x y)
(setq str
(replace-regexp-in-string
"|[^|~]+~"
#'make-html-region--replace-1
str))
(setq str
(replace-regexp-in-string
"~[^|~]+|\\(?:.\\|$\\)"
#'make-html-region--replace-2
str))
(replace-regexp-in-string
"|\\(.\\|\n\\)"
#'make-html-cursor--replace
str))
(setq org-export-filter-src-block-functions '(make-html-region))
(setq org-html-validation-link nil)
(setq org-html-postamble nil)
(setq org-html-preamble "")
(setq org-html-text-markup-alist
'((bold . "%s")
(code . "%s")
(italic . "%s")
(strike-through . "%s")
(underline . "%s")
(verbatim . "%s")))
(setq org-html-style-default nil)
(setq org-html-head-include-scripts nil)
#+end_src
* Intro
This demo will showcase expanding Clojure's =iterate= with Emacs macros.
* Task summary
See a step-by-step solution of https://projecteuler.net/problem=100.
* Screencast
The screencast for this demo is here: http://youtu.be/tcI4gZ3eHaw
* Step-by-step
** step 1
Start with this code (sorry for spoiling):
#+begin_src clojure
;; If a box contains twenty-one coloured discs, composed of fifteen blue
;; discs and six red discs, and two discs were taken at random, it can be
;; seen that the probability of taking two blue discs, P(BB) =
;; (15/21)×(14/20) = 1/2.
;; The next such arrangement, for which there is exactly 50% chance of
;; taking two blue discs at random, is a box containing eighty-five blue
;; discs and thirty-five red discs.
;; By finding the first arrangement to contain over 1012 =
;; 1,000,000,000,000 discs in total, determine the number of blue discs
;; that the box would contain.
;; 1+4*r+√(8*r^2+1)>2e12=x
;; 8*r^2+1>(x-1)^2+16*r^2-8*r*(x-1)
;; 8*r*r-8*r(x-1)+(x-1)^2-1<0
;; solve=> r> 292893218813
;; for blue to be integer, the req is 8*r*r+1 is square
|(defn blue [red]
(BigInteger/valueOf (/ (+ 1 (* 2 red) (Math/sqrt (+ 1 (* 8 red red)))) 2)))
(defn next-red [[a b]]
[b (- (* b 6) a)])
(defn solution []
(->> (filter #(> (+ % (blue %)) 1e12)
(map first (iterate next-red [6N 35N]))) first blue))
(solution)
#+end_src
** step 2
Fire up =cider= and eval everything with ~ejeje~.
** step 3
- ~k3f~ to jump to the =filter= statement
- ~2m~ to select the lambda
- ~n~ to copy
- ~A~ jump to beginning of defun
- ~j C-n C-n~ navigate to some empty space
** step 4
- ~( C-y C-j~
- ~(first}6N 35N~
You should now have:
#+begin_src clojure
(#(> (+ % (blue %)) 1e12)
(first [6N 35N|]))
#+end_src
** step 5
- ~C-f A~ navigate to the start
- ~e~ eval to get =false=
** step 6
- ~~ to start recording a macro
- ~fjf~ to navigate to the array
- ~2(next-red~ to wrap the array
- ~[xr~ to eval and replace
- ~A~ to navigate to the start
- ~E~ to eval and insert
- ~~ to finish the macro
** step 7
Keep spamming ~~ until you get =true=.
** step 8
- ~fj2(blue[E~ to get the solution
- ~hkE~ to double-check