|
|
|
|
@ -4,7 +4,7 @@ Load map |
|
|
|
|
#+begin_src emacs-lisp :results none |
|
|
|
|
(require 'dash) |
|
|
|
|
(with-temp-buffer |
|
|
|
|
(insert-file-contents "input-test2") |
|
|
|
|
(insert-file-contents "input") |
|
|
|
|
(goto-char (point-min)) |
|
|
|
|
(replace-regexp "^\\(#.*#\\)$" "\"\\1\"") |
|
|
|
|
(goto-char (point-min)) |
|
|
|
|
@ -75,45 +75,72 @@ associated scores; |
|
|
|
|
(explore start '(1 0) 0) |
|
|
|
|
#+end_src |
|
|
|
|
|
|
|
|
|
For debugging, print the map |
|
|
|
|
#+begin_src emacs-lisp |
|
|
|
|
(defun plot (p s) |
|
|
|
|
(goto-line (+ (cadr p) 1)) |
|
|
|
|
(move-to-column (car p)) |
|
|
|
|
(insert s) |
|
|
|
|
(delete-char 1)) |
|
|
|
|
|
|
|
|
|
(defun print-map (p) |
|
|
|
|
(with-temp-buffer |
|
|
|
|
(-each data (lambda (x) (insert x) (insert "\n"))) |
|
|
|
|
(-each book (lambda (x) (if (cdr x) (plot (caar x) ?x) |
|
|
|
|
(plot (caar x) ?!)))) |
|
|
|
|
(plot p ?@) |
|
|
|
|
(write-file "tmp")) ) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#+end_src |
|
|
|
|
|
|
|
|
|
#+RESULTS: |
|
|
|
|
: print-map |
|
|
|
|
|
|
|
|
|
In principle the above would work as-is, but it is not very efficient. |
|
|
|
|
In the version below, we record dead-ends and partial solutions |
|
|
|
|
#+begin_src emacs-lisp |
|
|
|
|
(defun >nil (a b) |
|
|
|
|
(when b |
|
|
|
|
(or (not a) (> a b)))) |
|
|
|
|
(when (numberp b) |
|
|
|
|
(or (not (numberp a)) (> a b)))) |
|
|
|
|
|
|
|
|
|
(defun subtract-nil (a b) |
|
|
|
|
(when (and a b) |
|
|
|
|
(when (and (numberp a) (numberp b)) |
|
|
|
|
(- a b))) |
|
|
|
|
|
|
|
|
|
(defun +nil (a b) |
|
|
|
|
(when (and a b) |
|
|
|
|
(when (and (numberp a) (numberp b)) |
|
|
|
|
(+ a b))) |
|
|
|
|
|
|
|
|
|
(defun neighbour-maybe (p dir newdir) |
|
|
|
|
(if (not (equal dir newdir)) p |
|
|
|
|
(neighbour p newdir))) |
|
|
|
|
|
|
|
|
|
(defun explore (p dir score &optional past) |
|
|
|
|
(defun forward-dirs (dir olddir) |
|
|
|
|
(if (not (equal dir olddir)) (list dir) |
|
|
|
|
(cons dir (--filter (= (dot it dir) 0) '((0 1) (0 -1) (-1 0) (1 0)))))) |
|
|
|
|
|
|
|
|
|
(defun explore (p dir old-dir score &optional past) |
|
|
|
|
"Explore the maze starting at position P and in the direction |
|
|
|
|
DIR. Returns nil if we will dead-end or loop or the score |
|
|
|
|
if we reach the end" |
|
|
|
|
(if (eq (thing-at p) 'end) score |
|
|
|
|
(if (assoc (list p dir) book) (+nil score (cdr (assoc (list p dir) book))) ; check the book for this position and direction |
|
|
|
|
(unless (-contains-p (cdr past) p) ; loop |
|
|
|
|
(let* ((forward-dirs (--filter (>= (dot it dir) 0) '((0 1) (0 -1) (-1 0) (1 0)))) |
|
|
|
|
(acceptable-dirs (--filter (not (eq (thing-at (neighbour p it)) 'wall)) forward-dirs)) |
|
|
|
|
(new-score (-min-by #'>nil (-map (lambda (newdir) |
|
|
|
|
(explore (neighbour-maybe p dir newdir) newdir |
|
|
|
|
(+ score (if (equal newdir dir) 1 1000)) |
|
|
|
|
(cons p past))) |
|
|
|
|
acceptable-dirs)))) |
|
|
|
|
(push (cons (list p dir) (subtract-nil new-score score)) book) |
|
|
|
|
new-score))))) |
|
|
|
|
|
|
|
|
|
(setq book nil) |
|
|
|
|
(explore start '(1 0) 0) |
|
|
|
|
(if (-contains-p (cdr past) p) 'loop |
|
|
|
|
(let* ((acceptable-dirs (--filter (not (eq (thing-at (neighbour p it)) 'wall)) (forward-dirs dir old-dir))) |
|
|
|
|
(new-score (-min-by #'>nil (-map (lambda (newdir) |
|
|
|
|
(explore (neighbour-maybe p dir newdir) newdir dir |
|
|
|
|
(+ score (if (equal newdir dir) 1 1000)) |
|
|
|
|
(-distinct (cons p past)))) |
|
|
|
|
acceptable-dirs)))) |
|
|
|
|
(when (not (eq new-score 'loop)) (push (cons (list p dir) (subtract-nil new-score score)) book)) |
|
|
|
|
new-score))))) |
|
|
|
|
|
|
|
|
|
(setq book nil) |
|
|
|
|
(explore start '(1 0) '(1 0) 0) |
|
|
|
|
#+end_src |
|
|
|
|
|
|
|
|
|
#+RESULTS: |
|
|
|
|
: 11048 |
|
|
|
|
|
|
|
|
|
(print-map) |
|
|
|
|
|