Compare commits

...

44 Commits

Author SHA1 Message Date
efim
61abf66381 giving up for rest of AoC 2022 2022-12-31 15:33:45 +00:00
efim
f2c18830c2 yay, day 22. part 1 2022-12-31 14:41:30 +00:00
efim
5630acd513 day 25 part 1
unfortunately part 2 is closed until all other stars are collected.
oh, sad
2022-12-26 07:54:44 +00:00
efim
3abfbb53ca day 21, part 2 backward computation. that's hot 2022-12-25 14:54:34 +00:00
efim
f6799dd691 lets skip day 21 part 2! 2022-12-25 10:58:24 +00:00
efim
c2acd2f75a day 21 part 1, fun 2022-12-25 10:43:57 +00:00
efim
e062633074 day 20 part 2, yay 2022-12-25 09:56:18 +00:00
efim
281a0aebf4 day 20 part 2, yay 2022-12-25 09:40:10 +00:00
efim
974cc4993d day 20 kicking me with duplicates 2022-12-25 09:10:19 +00:00
efim
2eb4b5c0a5 at least part 1 of day 19 2022-12-24 12:45:54 +00:00
efim
bf52645d93 this is "optimization" 2022-12-24 10:11:53 +00:00
efim
83f65babdf not yet anything for day 19 2022-12-23 22:58:50 +00:00
efim
598500e289 day 18, part 2 complete, with a little bit ugly 2022-12-22 20:41:17 +00:00
efim
831f09c9cd day 18, part 2, not complete, before going ugly 2022-12-22 20:37:14 +00:00
efim
643bba2464 day 18, part 1, the simple one 2022-12-22 19:49:43 +00:00
efim
01d5c300d6 giving up on day 17 2022-12-20 20:34:07 +00:00
efim
69250daf63 day 16 part 2, quite stuck 2022-12-18 18:59:07 +00:00
efim
ae745dc0f2 day 17 part 1. ugh 2022-12-18 17:22:43 +00:00
efim
3126cd48ab day 16 monstrocity calculated overnight 2022-12-18 07:19:59 +00:00
efim
914abe5a1f day 16, well that was an ugly logical error 2022-12-17 15:32:11 +00:00
efim
293250c20b day 16, still not working.
trying out with smaller example.
AND. before refactoring by BAD BOOLEAN
2022-12-17 14:17:49 +00:00
efim
c2ea2ec16e day 15 part 2. using INTERVALS 2022-12-16 15:30:38 +00:00
efim
190382eddc day 15 p.1: scanners and beacons, bad solution 2022-12-16 12:13:37 +00:00
efim
6757e3ba23 day 14, part 2 - endless pyramid 2022-12-15 17:40:22 +00:00
efim
c82f5473ba day 14, falling sand part 1 2022-12-15 17:00:01 +00:00
efim
16cb2be49b day 13 - part 2, now SORT with that ORDER 2022-12-14 20:41:44 +00:00
efim
1457992342 day 13 nested lists ordering part 1 2022-12-14 20:30:45 +00:00
efim
047bc474bd day 12 - paths over grid; dfs 2022-12-14 18:31:16 +00:00
efim
f612d15eed day 11 part 2, yay 2022-12-13 06:29:13 +00:00
efim
b4f8e937c7 day 11 refactor into scratch and code 2022-12-13 05:54:07 +00:00
efim
59c9937950 part 1 of day 11. lot's of code
but then again - when I've written loop that calls all functions -
correst result from first try.
2022-12-12 19:51:25 +00:00
efim
65de39af73 day 10 cleanup 2022-12-11 18:33:10 +00:00
efim
c31d22d69d day 10 CRT and CLOG
maybe kind of cool
the addx and noop didn't have to be changed
only additional code for TICK
2022-12-11 17:17:21 +00:00
efim
5990ef5d0b day9 - line simulation
yes, maybe positive example of using macro - to allow my get-x being
used as PLACE in setf

but other modifications require variable.
and that's not quite what i want.
2022-12-10 19:45:39 +00:00
efim
3105b97f1d day 8 cleaning up code 2022-12-08 12:18:31 +00:00
efim
5efbb26239 day 8, more pain with tree heights 2022-12-08 12:02:35 +00:00
efim
7443fc80ae wow, filesystem stats was HARD 2022-12-07 20:37:14 +00:00
efim
0ad5b9d435 and day 6 is much easier.
using fset library, yay.
thank you "awesome common lisp" list.
and the DO loop.
2022-12-06 18:06:49 +00:00
efim
25709d2a43 one day later, day 5
oh, so much hashtables, this is urgh
2022-12-06 13:07:06 +00:00
efim
a0f3c07e06 day 4: number intervals overlap 2022-12-04 08:33:11 +00:00
efim
ce89746131 day 3: strings as sets, loop 2022-12-03 08:28:00 +00:00
efim
540a1a52c5 day 2: rock-paper-scissors scoring 2022-12-02 07:33:27 +00:00
efim
455cee8c79 second task of day 1, cool 2022-12-02 07:33:24 +00:00
efim
0116b13088 day 1 first simple task
trying out the loop and reading of the files
2022-12-01 13:48:22 +00:00
84 changed files with 30816 additions and 0 deletions

2251
day1-input.txt Normal file

File diff suppressed because it is too large Load Diff

125
day1.lisp Normal file
View File

@@ -0,0 +1,125 @@
(list 1 2 3)
;;; input - one number per line, different intentories separated by empty new line
;; need to find what - how much does have the intventory with maximal sum
;; so, do i have a function that takes in one string?
;; i guess it would be better to read input from the separate file
;; would also probably be better to read file line a time
(defvar current-sum 0)
(defvar current-max -1)
(with-open-file
(in "day1-input.txt")
(loop
for line = (read-line in nil nil)
while line
;; (if (eq line = "") (print "got empty line"))
;; collect line
;; do (format t "got line ~A~%" line)
;;; yay, this is somewhat what i want
;; if (string-equal line "") do (format t "got empty line ~A~% in if" line)
;; else do (format t "else branch for nonempty line ~A~%" line)
if (string-equal line "") do (progn
;; current inventory ended,
;; check whether it's new max and null accum
(if (< current-max current-sum) (setq current-max current-sum) )
(setq current-sum 0))
else do (setq current-sum (+ current-sum (parse-integer line)))
))
current-max ; i got a right answer
;; yay, now i can write a stateful function that gets one line at a time
;;
;; what i could probably do is have
;; if clauses directly in the loop
;; and additional variables defined and updated in the loop as well
(setq my-int (parse-integer "10497"))
my-int
;; let's wrap this into single function, i suppose
(defun calc-max-inventory-calories (filename)
(setq current-sum 0)
(setq current-max -1)
(with-open-file
(in filename)
(loop
for line = (read-line in nil nil)
while line
if (string-equal line "")
do (progn
;; current inventory ended,
;; check whether it's new max and null accum
(if (< current-max current-sum)
(setq current-max current-sum)
)
(setq current-sum 0))
else do (setq current-sum (+ current-sum (parse-integer line)))
))
current-max)
;; (in "day1-input.txt")
(calc-max-inventory-calories "day1-input.txt")
;;; and second task - find TOP 3 inventory sums, and what is their total
;; how'd i do that?
;; would be cool to do a class, that would be able to store the top 3
;; and would have single method to check and possibly include a new number with eviction of the lovest number
;; do I go for CLOS here?
;; ugh.
(setq my-prev-max (list 1 4 5 7))
(apply #'min my-prev-max)
(set-difference my-prev-max (list 1))
my-prev-max
(set-difference my-prev-max (list (apply #'min my-prev-max)))
;; so, i could use that on the "found max"
;; could also store "cur minmal maximul"
(defun calc-3-max-inventory-calories (filename)
(setq current-sum 0)
(setq current-3-max '())
(with-open-file
(in filename)
(loop
for line = (read-line in nil nil)
while line
if (string-equal line "")
do (progn
;; current inventory ended,
;; check whether it's new max and null accum
(setq current-3-max (cons current-sum current-3-max))
(if (< 3 (length current-3-max))
(setq current-3-max
(set-difference current-3-max (list (apply #'min current-3-max))))
)
(setq current-sum 0))
else do (setq current-sum (+ current-sum (parse-integer line)))
))
(apply #'+ current-3-max))
(append (list 12 1 14) 15)
(setq my-prepend (cons 15 (list 12 1 14)))
(apply #'+ (list 1 2 3))
(calc-3-max-inventory-calories "day1-input.txt")
current-3-max
(> 3 2)
;; ok. so notes for today:
;; 1. i'm messing up (> 3 1) in conditions
;; 2. I really should start using #'LET instead of #'SETQ
;; SETQ are for defining what? global names? these are set and available outside of the function
;; even though i didn't create them as DEFVAR? Or maybe I did, for the first function
;; ok then
;; 3. looking in Common Lisp Cookbook : https://lispcookbook.github.io/cl-cookbook/iteration.html
;; for the examples of the loops and set operations
;; and another tutorial with sample of reading the file https://riptutorial.com/common-lisp/example/10284/reading-file
;; and https://www.tutorialspoint.com/lisp/lisp_file_io.htm
;; and https://stackoverflow.com/questions/44466001/read-from-file-common-lisp
;; 4. Sad that I don't really look into the efficient ways of doing things

142
day10-input.txt Normal file
View File

@@ -0,0 +1,142 @@
addx 1
addx 5
noop
addx -1
noop
noop
addx 6
addx 15
addx -9
noop
addx -1
addx 4
addx 2
addx -22
addx 27
addx -1
addx 4
noop
addx 1
addx 2
noop
noop
noop
noop
addx 1
addx -33
addx 2
addx 5
addx 2
addx 3
addx -2
addx 7
noop
addx -2
addx -8
addx 15
addx 5
noop
noop
addx -2
addx 2
noop
noop
addx 7
addx -14
noop
addx -2
addx -17
addx 5
addx -4
noop
addx 23
addx -18
noop
noop
noop
addx 28
addx -18
addx 4
noop
noop
addx -5
addx 1
addx 10
addx 2
noop
noop
addx -30
addx 33
addx -32
noop
noop
addx -2
addx 6
addx -2
addx 4
addx 3
addx 19
addx 10
addx -5
addx -16
addx 3
addx -2
addx 17
addx -19
addx 11
addx 2
addx 9
noop
addx -4
addx -6
addx -7
addx -24
noop
addx 7
addx -2
addx 5
addx 2
addx 3
addx -2
addx 2
addx 5
addx 2
addx 7
addx -2
noop
addx 3
addx -2
addx 2
addx 7
noop
addx -2
addx -34
addx 1
addx 1
noop
noop
noop
addx 5
noop
noop
addx 5
addx -1
noop
addx 6
addx -1
noop
addx 4
addx 3
addx 4
addx -1
addx 5
noop
addx 5
noop
noop
noop
noop
noop
addx 1
noop
noop

146
day10-test.txt Normal file
View File

@@ -0,0 +1,146 @@
addx 15
addx -11
addx 6
addx -3
addx 5
addx -1
addx -8
addx 13
addx 4
noop
addx -1
addx 5
addx -1
addx 5
addx -1
addx 5
addx -1
addx 5
addx -1
addx -35
addx 1
addx 24
addx -19
addx 1
addx 16
addx -11
noop
noop
addx 21
addx -15
noop
noop
addx -3
addx 9
addx 1
addx -3
addx 8
addx 1
addx 5
noop
noop
noop
noop
noop
addx -36
noop
addx 1
addx 7
noop
noop
noop
addx 2
addx 6
noop
noop
noop
noop
noop
addx 1
noop
noop
addx 7
addx 1
noop
addx -13
addx 13
addx 7
noop
addx 1
addx -33
noop
noop
noop
addx 2
noop
noop
noop
addx 8
noop
addx -1
addx 2
addx 1
noop
addx 17
addx -9
addx 1
addx 1
addx -3
addx 11
noop
noop
addx 1
noop
addx 1
noop
noop
addx -13
addx -19
addx 1
addx 3
addx 26
addx -30
addx 12
addx -1
addx 3
addx 1
noop
noop
noop
addx -9
addx 18
addx 1
addx 2
noop
noop
addx 9
noop
noop
noop
addx -1
addx 2
addx -37
addx 1
addx 3
noop
addx 15
addx -21
addx 22
addx -6
addx 1
noop
addx 2
addx 1
noop
addx -10
noop
noop
addx 20
addx 1
addx 2
addx 2
addx -6
addx -11
noop
noop
noop

316
day10.lisp Normal file
View File

@@ -0,0 +1,316 @@
;; https://adventofcode.com/2022/day/10
;;
;; cathode ray tube. hm.
;; so, starting from 20th cycle, step by 40 and calculate the value in the Register
;; to get desired value multiply the cicle number by value.
;; and for result - sum them all
;; cool.
;;
;; main part: we need Register value "during" the 20th, etc cycle
;; so it's "end the end of 19th"
;; at 0 we have value 1
;; then each operation does some amount of ticks.
;; well,
;; i guess i could write (tick) function that increases the timer, and if timer of required time - adds current value to result
;; let's finally use CLOS?
(defclass machine ()
((clock :reader clock :initform 0)
(register :reader register :initform 1)
(accumulated-signal :reader accumulated-signal :initform 0)
(next-special-clock :reader next-special-clock :initform 20)))
(defmethod print-object ((obj machine) stream)
(print-unreadable-object (obj stream :type t)
(with-accessors ((clock clock )
(register register )
(accumulated-signal accumulated-signal)
(next-special-clock next-special-clock))
obj
(format stream "clock: ~a, register: ~a, accum: ~a; next-special: ~a" clock register accumulated-signal next-special-clock))))
(defparameter *test-machine* (make-instance 'machine))
(setf (clock *test-machine*) 7)
(setf (slot-value *test-machine* 'clock) 9)
;; can the method be private in the class?
;; so that clock would be incremented by (tick)
;; and (tick) only called from the (run-command) ?
;; and also for register to also only have reader?
;; can I disallow setting values to register?
;; they are still writeable by (slot-value) link
;; it seems that if I don't need polymorphism, I don't need DEFGENERIC
;; and can just define some functions
;; and classes don't change their scopes in any way, and don't really encapsulate their state, as slots are writeable
(defgeneric tick (obj)
(:method ((obj machine))
(incf (slot-value obj 'clock))
(when (= (next-special-clock obj) (clock obj))
(incf (slot-value obj 'accumulated-signal) (* (clock obj) (register obj)))
(update-special-clock obj))))
(tick *test-machine*)
(defparameter *test-machine* (make-instance 'machine))
(progn
(tick *test-machine*)
(print *test-machine*))
(next-special-clock *test-machine*)
(defgeneric update-special-clock (obj)
(:method ((obj machine))
(incf (slot-value obj 'next-special-clock) 40)))
(update-special-clock *test-machine*)
;; now that i'm thinking about modifying accumulated signal on tick,
;; i'm thinking about storing "next-special-clock" starting with 20, and rewriting by x + 40
;; and comparing with (1- next-special-clock) for value during that special time
;; i need to slow down. how would commands look:
;; addx 4 (tick) (tick) (set-new-value)
;; noop (tick)
;; so. if clock is at 19, meaning we endedn 19th cycle. and we start 20th which is noop
;; the tick should increase the clock
;; check if it's special. if it's 20 then add current Register * 20 and add to sum
;; now tick seems to work.
;; let's implement noop and addx
(defgeneric noop (mach)
(:method ((mach machine))
(tick mach)))
(defgeneric addx (mach num)
(:method ((mach machine) num)
(tick mach)
(tick mach)
(incf (slot-value mach 'register) num )))
(defparameter *test-machine* (make-instance 'machine))
(print *test-machine*)
(addx *test-machine* 4)
;; and all i need now is to simulate the input file
(require 'cl-ppcre)
(defun parse-command-line (line machine)
(let* ((the-split (cl-ppcre:split " " line))
(command (intern (string-upcase (first the-split)))))
(case command
('addx (addx machine (parse-integer (second the-split))))
('noop (noop machine))
(t "hello"))))
(defparameter *test-machine* (make-instance 'machine))
(print *test-machine*)
(parse-command-line "addx 31" *test-machine*)
(parse-command-line "noop" *test-machine*)
(intern "addx")
(intern "ADDX")
(string-upcase "addx")
;; now it's time to simiulate the file evaluation
(let ((my-machine (make-instance 'machine)))
(with-open-file (in "day10-test.txt")
(loop
for line = (read-line in nil nil)
while line
do (parse-command-line line my-machine))
(accumulated-signal my-machine)))
(let ((my-machine (make-instance 'machine)))
(with-open-file (in "day10-input.txt")
(loop
for line = (read-line in nil nil)
while line
do (parse-command-line line my-machine))
(accumulated-signal my-machine)))
;;; PART 2
;; suppose would want to implement the screen as a class as well?
;; it would do what?
;; it should have logic on top of the machine?
;; maybe run it's code after machine tick?
;; maybe extending machine
;; afther cycle that starts at 0 and ends at 1 first pixel finishes
;; after cycle that starts at 39 and ends at 40 last pixes finishes
;; so, yeah. if i have crt extend machine, it could have it's own special cycles
;; and tick could be extended to run after, and also produce pixel \ string \ char
;; & newline when needed - into the string buffer of crt?
(print "hello/nman")
;; i guess i could just print to terminal
;; and improvement could be configuring the output stream
(format t "hello")
(terpri)
(defclass crt (machine)
((next-special-clock :reader next-special-clock :initform 40)))
(defparameter *test-crt* (make-instance 'crt))
(update-special-clock *test-crt*)
(tick *test-crt*)
;; now on each tick i want to print a char.
;; what is the logic here?
;; on each tick print # if current clock is within +-1 of register value
;; and . otherwise
;; on the special-clock to (terpri)
;; simplified printing
(defmethod tick :before ((obj crt))
(format t "@")
(when (= (clock obj) (1- (next-special-clock obj)))
(terpri)))
(defparameter *test-crt* (make-instance 'crt))
(next-special-clock *test-crt*)
(tick *test-crt*)
(noop *test-crt*)
;; so my problem was the crt method runs "before"
;; and never reaches clock == next-special-clock
;; because when tick runs on 39 it increases clock to 40 and also increases next-sp to 80
;; but i suppose doing new line on 39 is what i want
(defun cur-pixel-in-sprite (pixel-index sprite-center)
(and (>= pixel-index (1- sprite-center))
(<= pixel-index (1+ sprite-center))))
(cur-pixel-in-sprite 0 0)
(cur-pixel-in-sprite 0 1)
(cur-pixel-in-sprite 0 2)
(defmethod tick :before ((obj crt))
(let ((pixel (if (cur-pixel-in-sprite (clock obj) (register obj))
"#"
".")))
(format t pixel))
(when (= (clock obj) (1- (next-special-clock obj)))
(incf (slot-value obj 'register) 40)
(terpri)))
(defparameter *test-crt* (make-instance 'crt))
(noop *test-crt*)
(let ((my-machine (make-instance 'crt)))
(with-open-file (in "day10-test.txt")
(loop
for line = (read-line in nil nil)
while line
do (parse-command-line line my-machine))
(accumulated-signal my-machine)))
(let ((my-machine (make-instance 'crt)))
(with-open-file (in "day10-input.txt")
(loop
for line = (read-line in nil nil)
while line
do (parse-command-line line my-machine))
(accumulated-signal my-machine)))
;;; Cleaning up:
;;; part 1
;; state of the CPU
(defclass machine ()
((clock :reader clock :initform 0)
(register :reader register :initform 1)
(accumulated-signal :reader accumulated-signal :initform 0)
(next-special-clock :reader next-special-clock :initform 20)))
(defmethod print-object ((obj machine) stream)
(print-unreadable-object (obj stream :type t)
(with-accessors ((clock clock )
(register register )
(accumulated-signal accumulated-signal)
(next-special-clock next-special-clock))
obj
(format stream "clock: ~a, register: ~a, accum: ~a; next-special: ~a" clock register accumulated-signal next-special-clock))))
;; passing of sinlge step
(defgeneric tick (obj)
(:method ((obj machine))
(incf (slot-value obj 'clock))
(when (= (next-special-clock obj) (clock obj))
(incf (slot-value obj 'accumulated-signal) (* (clock obj) (register obj)))
(update-special-clock obj))))
(defgeneric update-special-clock (obj)
(:method ((obj machine))
(incf (slot-value obj 'next-special-clock) 40)))
;; actual cpu commands in terms of ticks and register changes:
(defgeneric noop (mach)
(:method ((mach machine))
(tick mach)))
(defgeneric addx (mach num)
(:method ((mach machine) num)
(tick mach)
(tick mach)
(incf (slot-value mach 'register) num )))
(require 'cl-ppcre)
(defun parse-command-line (line machine)
(let* ((the-split (cl-ppcre:split " " line))
(command (intern (string-upcase (first the-split)))))
(case command
('addx (addx machine (parse-integer (second the-split))))
('noop (noop machine))
(t "hello"))))
;; now it's time to simiulate the file evaluation
(let ((my-machine (make-instance 'machine)))
(with-open-file (in "day10-test.txt")
(loop
for line = (read-line in nil nil)
while line
do (parse-command-line line my-machine))
(accumulated-signal my-machine)))
(let ((my-machine (make-instance 'machine)))
(with-open-file (in "day10-input.txt")
(loop
for line = (read-line in nil nil)
while line
do (parse-command-line line my-machine))
(accumulated-signal my-machine)))
;;; PART 2
(defclass crt (machine)
((next-special-clock :reader next-special-clock :initform 40)))
(defun cur-pixel-in-sprite (pixel-index sprite-center)
(and (>= pixel-index (1- sprite-center))
(<= pixel-index (1+ sprite-center))))
(defmethod tick :before ((obj crt))
(let ((pixel (if (cur-pixel-in-sprite (clock obj) (register obj))
"#"
".")))
(format t pixel))
(when (= (clock obj) (1- (next-special-clock obj)))
(incf (slot-value obj 'register) 40)
(terpri)))
;; and same code reading in commands, but with CRT results in printing
(let ((my-machine (make-instance 'crt)))
(with-open-file (in "day10-test.txt")
(loop
for line = (read-line in nil nil)
while line
do (parse-command-line line my-machine))
(accumulated-signal my-machine)))
(let ((my-machine (make-instance 'crt)))
(with-open-file (in "day10-input.txt")
(loop
for line = (read-line in nil nil)
while line
do (parse-command-line line my-machine))
(accumulated-signal my-machine)))

55
day11-input.txt Normal file
View File

@@ -0,0 +1,55 @@
Monkey 0:
Starting items: 80
Operation: new = old * 5
Test: divisible by 2
If true: throw to monkey 4
If false: throw to monkey 3
Monkey 1:
Starting items: 75, 83, 74
Operation: new = old + 7
Test: divisible by 7
If true: throw to monkey 5
If false: throw to monkey 6
Monkey 2:
Starting items: 86, 67, 61, 96, 52, 63, 73
Operation: new = old + 5
Test: divisible by 3
If true: throw to monkey 7
If false: throw to monkey 0
Monkey 3:
Starting items: 85, 83, 55, 85, 57, 70, 85, 52
Operation: new = old + 8
Test: divisible by 17
If true: throw to monkey 1
If false: throw to monkey 5
Monkey 4:
Starting items: 67, 75, 91, 72, 89
Operation: new = old + 4
Test: divisible by 11
If true: throw to monkey 3
If false: throw to monkey 1
Monkey 5:
Starting items: 66, 64, 68, 92, 68, 77
Operation: new = old * 2
Test: divisible by 19
If true: throw to monkey 6
If false: throw to monkey 2
Monkey 6:
Starting items: 97, 94, 79, 88
Operation: new = old * old
Test: divisible by 5
If true: throw to monkey 2
If false: throw to monkey 7
Monkey 7:
Starting items: 77, 85
Operation: new = old + 6
Test: divisible by 13
If true: throw to monkey 4
If false: throw to monkey 0

273
day11-scratch.lisp Normal file
View File

@@ -0,0 +1,273 @@
;; monkeys https://adventofcode.com/2022/day/11
(defparameter *test-monkey-line* "Monkey 0:
Starting items: 79, 98, 101, 66
Operation: new = old * 19
Test: divisible by 23
If true: throw to monkey 2
If false: throw to monkey 3")
;;
;; so. i'd want to parse this string into list and it be a valid macro to return a monkey class
;; and have "turn" and "round" methods over the array of monkeys
(cl-ppcre:split " " (string-upcase *test-monkey-line*))
(cl-ppcre:split "\\n" (string-upcase *test-monkey-line*))
(defparameter num-plus-newline "9
")
(format t num-plus-newline)
(parse-integer num-plus-newline) ; junk in string "9\\n"
(mapcar (lambda (str) (cl-ppcre:split " " (string-trim str) )) (cl-ppcre:split "\\n" (cl-ppcre:regex-replace-all ":" *test-monkey-line* " ")))
;; and now to have all numbers be translated into numbers, and works into symbols
;; to get single list?
;; or list per line i suppose
;; from "macro and compilation.lisp"
;; but, we coult treat arguments as lists where we define marco
(defmacro mix-and-match-2 ((x1 y1) (x2 y2))
`(list '(,x1 ,y1)
'(,x1 ,y2)
'(,x2 ,y1)
'(,x2 ,y2)))
(mix-and-match-2 (fred wilma) (tony bony))
;; so could have defmacro that takes in 4 lists, each is a line parsed
(string-trim " :" " :hello: worls: ")
(mapcar (lambda (str)
(mapcar #'parse-integer-or-symbol (cl-ppcre:split " " (string-trim " " str)))) (cl-ppcre:split "\\n" *test-monkey-line*))
;; i could first for each line to (string-trim ":," lala) if convertable to number convert to number
;; and then all stringp upcase and intern
(parse-integer "7:hello" :junk-allowed t) ; cool
(parse-integer-or-symbol "7:")
(parse-integer-or-symbol "qer")
(defparameter *test-monkey-sexp* (line-to-sexp *test-monkey-line*))
((MONKEY 0)
(STARTING |ITEMS:| 79 98 101 66)
(|OPERATION:| NEW = OLD * 19)
(|TEST:| DIVISIBLE BY 23)
(IF |TRUE:| THROW TO MONKEY 2)
(IF |FALSE:| THROW TO MONKEY 3))
(defmacro monkey-struct-to-instance (((monkey ordering-number)
(starting items &rest inventory-list)
(operation new eq old operation operation-number)
(test divisible by divisible-number)
(test tru th to monk true-monkey-number)
(test fals th to monk false-monkey-number)))
`(list 'monkey ,ordering-number 'inventory ',inventory-list 'operation '(lambda (item) (,operation item ,operation-number)) 'test ,divisible-number))
(monkey-struct-to-instance *test-monkey-sexp*)
(monkey-struct-to-instance ((MONKEY 0)
(STARTING |ITEMS:| 79 98 101 66)
(|OPERATION:| NEW = OLD * 19)
(|TEST:| DIVISIBLE BY 23)
(IF |TRUE:| THROW TO MONKEY 2)
(IF |FALSE:| THROW TO MONKEY 3)))
(defmacro list-in-list (((first second) (third fourth)))
`(list ,second ,fourth))
(list-in-list ((1 2) ("hello" "world")))
(nsubst *test-monkey-sexp*)
;; maybe do another macro on top of macro then?
(defmacro put-struct-into-macro (my-macro var)
`(,my-macro ,(eval var)))
(put-struct-into-macro monkey-struct-to-instance *test-monkey-sexp*)
;; LOL, this is certainly not the way to go
;; after getting help from CL Matrix:
;; i need to use DESTRUCTURING-BIND
(defun monkey-struct-to-instance (monkey-struct)
(destructuring-bind
((monkey ordering-number)
(starting items &rest inventory-list)
(operation new eq old operation operation-number)
(test divisible by divisible-number)
(test tru th to monk true-monkey-number)
(test fals th to monk false-monkey-number)) monkey-struct
`(list 'monkey ,ordering-number 'inventory ',inventory-list 'operation '(lambda (item) (,operation item ,operation-number)) 'test ,divisible-number)))
(monkey-struct-to-instance *test-monkey-sexp*)
;; and there's METABANG-BIND facility
;; now - have monkey class. what would connect the different data about monkey
;; and after that - initialize the array. and write functions like "step" on the monkey and "round" on the array?
;; first - let's read in a paragraph at a time?
(defparameter *11-test-input* (cl-ppcre:split "\\n\\n" (uiop:read-file-string "day11-test.txt")))
;; yay. thank you Cookbook : https://lispcookbook.github.io/cl-cookbook/files.html Reading Files
(mapcar #'monkey-struct-to-instance (mapcar #'line-to-sexp *11-test-input*))
(funcall (new-from-old-function '+ 2 'old) 7)
;; here doing eval and defun, because macro just been inserting operand1 instead of symbod to which it references?
;; this is not good, but ok =C
(rem 7 3)
(mod 7 3)
(monkey-struct-to-instance *test-monkey-sexp*)
(defparameter *test-monkey-instance*
(make-instance 'monkey
:test (lambda (num) (if (= num 4) 1 2)) :operation (lambda (num) (+ num 1))
:inventory '(1 2 3) :number 4))
(funcall (test *test-monkey-instance*) 6)
;; and i don't really need the ordering-number, but ok
(defparameter *11-test-structs*
(coerce (mapcar #'monkey-struct-to-instance (mapcar #'line-to-sexp *11-test-input*)) 'vector))
;; now i want Turn and Round
;; turn - monkey iterates over all inventory.
;; inspects -
;; - apply Operation
;; - the worry / 3 ; default by player
;; - test -> return to which monkey to send
;;
;; i probably want to not tie up "turn" with array of monkeys
;; and only reference the array when codiyng up
;; round - each monkey gets a turn.
;; monkeys receive thrown items immediately when they are thrown
(lambda (worry) (* worry 13))
(funcall (slot-value (aref *11-test-structs* 2) 'operation) 5)
(let ((old 2)) (eval (funcall '* old old)))
(funcall (test (aref *11-test-structs* 0)) 23)
;; wow. some operations are new = old * old. wow. now that's not cool
;; but can be done i think
;; yup. only with macros i guess? and unhyginic?
;; and it works, but again with eval. to create lambda from the quoted description of lambda
;; and we're back to doing the turn?
;; or do i implement methods for monkey inspect and test? ugh
(defun monkey-one-item-action (monkey)
(let ((item-worry (first (inventory monkey) )))
(when item-worry
(setf (inventory monkey) (cdr (inventory monkey)))
(setq item-worry (funcall (operation monkey) item-worry))
;; (setq item-worry (floor (/ item-worry 3)))
(incf (slot-value monkey 'inspection-counter))
;; returning (target-monkey-num thrown-item)
(list (funcall (test monkey) item-worry) item-worry))))
(defparameter *test-monkey-instance*
(make-instance 'monkey
:test (lambda (num) (if (= num 4) 9 8)) :operation (lambda (num) (+ num 1))
:inventory '(100 60 30) :number 4
:mod 5))
(monkey-one-item-action *test-monkey-instance*)
(inspection-counter *test-monkey-instance*)
(defparameter *test-monkey-turn* (monkey-turn *test-monkey-instance*))
(alexandria:hash-table-alist *test-monkey-turn*) ; looks ok, but it still should be reversed?
(alexandria:maphash-values #'reverse *test-monkey-turn*)
(reverse (gethash 8 *test-monkey-turn*))
(maphash (lambda (key value-list) (setf (gethash key *test-monkey-turn*) (reverse (gethash key *test-monkey-turn*)))) *test-monkey-turn*)
;; so MAPHASH and MAPHASH-VALUES do not change hashmap, ugh
(defparameter *test-hash* (make-hash-table :test 'equal))
(defparameter *test-hash* '(1))
(push 11 (gethash "hello" *test-hash*))
(push 11 *test-hash*)
(setf (gethash "hello" *test-hash*) (push 11 (gethash "hello" *test-hash*)))
(setf (gethash "why" *test-hash*) 11)
;; wtf. why setf doesn't change content of hash key?
;; well, that's because I use `eq for comparison. hello
;; now have function for MONKEY-TURN, returning hashmap of transferred items
(append '(1 2 3) '(5 6))
;; and now yolo try to run 20 rounds on test monkey array?
;; wait. I also need to cound "how many items did each monkey inspected"
;; let's keep it for tomorrow, ugh
;; on the next task, i'll start separating my daily scratch and final code
;; it's too much noise between the code
;; ok, added that
(sort (mapcar #'inspection-counter (coerce *11-input-structs* 'list)) #'>)
;; 329 305
(* 329 305)
;;; PART 2.
;; let's just hardcode change to "releaf level change"
;; find another way to keep your worry levels manageable.
;; otherwise turns take really long time to compute.
;; what's important is to retain all TEST - so when i make numbers smaller, they have to keep all same MOD for all same test values.
;; so, what? let's go to sleep
;; now. if i read in all those "divisible by" so. what i want is to preserve MOD x
;; so, could get lowest common multiple and get mod from that? and set it in all monkeys,
;; or better - define it as class \ static attribute
(defparameter *11-input-paragraphs*
(cl-ppcre:split "\\n\\n" (uiop:read-file-string "day11-input.txt")))
(defparameter *11-input-structs* nil)
(defparameter *11-input-structs*
(coerce (mapcar #'monkey-struct-to-instance
(mapcar #'line-to-sexp *11-input-paragraphs*)) 'vector))
(loop
for monkey across *11-input-structs*
do (when (not (= 0 (mod (mod-reductor-2 monkey) (monkey-mod monkey))))
(setf (slot-value monkey 'mod-reductor-2) (* (mod-reductor-2 monkey) (monkey-mod monkey)))))
(mod 1 3)
(setf (slot-value *test-monkey-instance* 'mod-reductor-2) 1)
;; yep.
;; now need to take mod by this one? and then it will preserve mod by any of previous, right?
(mod (+ 9699690 177) 5)
(mod 177 5)
;; now substitute my worry by mod over "common multiple" and run 20k cycles
(mod 4 7)
(progn
(defparameter *11-test-input* (cl-ppcre:split "\\n\\n" (uiop:read-file-string "day11-test.txt")))
(defparameter *11-test-structs*
(coerce (mapcar #'monkey-struct-to-instance
(mapcar #'line-to-sexp *11-test-input*)) 'vector))
;; oh, i need to reset and recalculate the lowest common multiple for test input.
;; yup
(setf (slot-value *test-monkey-instance* 'mod-reductor-2) 1)
(loop
for monkey across *11-test-structs*
do (when (not (= 0 (mod (mod-reductor-2 monkey) (monkey-mod monkey))))
(setf (slot-value monkey 'mod-reductor-2) (* (mod-reductor-2 monkey) (monkey-mod monkey)))))
(loop
for i from 1 to 10000
do (progn (monkeys-round *11-test-structs*)
(format t "turn ~a~%" i)))
(print (apply #'* (subseq (sort
(mapcar #'inspection-counter
(coerce *11-test-structs* 'list)) #'>) 0 2)))
(setf (slot-value *test-monkey-instance* 'mod-reductor-2) 1))
;; yeah

27
day11-test.txt Normal file
View File

@@ -0,0 +1,27 @@
Monkey 0:
Starting items: 79, 98
Operation: new = old * 19
Test: divisible by 23
If true: throw to monkey 2
If false: throw to monkey 3
Monkey 1:
Starting items: 54, 65, 75, 74
Operation: new = old + 6
Test: divisible by 19
If true: throw to monkey 2
If false: throw to monkey 0
Monkey 2:
Starting items: 79, 60, 97
Operation: new = old * old
Test: divisible by 13
If true: throw to monkey 1
If false: throw to monkey 3
Monkey 3:
Starting items: 74
Operation: new = old + 3
Test: divisible by 17
If true: throw to monkey 0
If false: throw to monkey 1

179
day11.lisp Normal file
View File

@@ -0,0 +1,179 @@
;; monkeys https://adventofcode.com/2022/day/11
(require 'cl-ppcre)
(defun parse-integer-or-symbol (str)
(let ((maybe-int (parse-integer str :junk-allowed t)))
(if maybe-int
maybe-int
(intern (string-upcase str)))))
(defun line-to-sexp (line)
(mapcar (lambda (str)
(mapcar #'parse-integer-or-symbol (cl-ppcre:split " " (string-trim " " str))))
(cl-ppcre:split "\\n" line)))
(defun monkey-struct-to-instance (monkey-struct)
(destructuring-bind
((monkey ordering-number)
(starting items &rest inventory-list)
(operation new eq old operation operation-number)
(test divisible by divisible-number)
(test tru th to monk true-monkey-number)
(test fals th to monk false-monkey-number)) monkey-struct
`(list 'monkey ,ordering-number 'inventory ',inventory-list 'operation '(lambda (item) (,operation item ,operation-number)) 'test ,divisible-number)))
(defclass monkey ()
((order-number :reader order-number :initarg :number)
(inventory :accessor inventory :initarg :inventory)
(operation :reader operation :initarg :operation)
(test :reader test :initarg :test)
(inspection-counter :reader inspection-counter :initform 0)
(monkey-mod :reader monkey-mod :initarg :mod)
(mod-reductor-2 :reader mod-reductor-2 :initform 1 :allocation :class)))
(defmethod print-object ((obj monkey)
stream)
(print-unreadable-object (obj stream :type t)
(with-accessors ((order-number order-number )
(inventory inventory)
(inspection-counter inspection-counter)
(monkey-mod monkey-mod)
(mod-reductor-2 mod-reductor-2))
obj
(format stream "~a, with objects: ~a; count: ~a; mod: ~a; common: ~a"
order-number inventory inspection-counter monkey-mod mod-reductor-2))))
(defun new-from-old-function (operation operand1 operand2)
(eval `(lambda (old)
(,operation ,operand1 ,operand2)))) ; unhyginic macro
(defun monkey-struct-to-instance (monkey-struct)
(destructuring-bind
((monkey ordering-number)
(starting items &rest inventory-list)
(operation new eq operand1 operation-sign operand2)
(test divisible by divisible-number)
(test tru th to monk true-monkey-number)
(test fals th to monk false-monkey-number)) monkey-struct
(let ((operation-fun (new-from-old-function operation-sign operand1 operand2))
(test-fun (lambda (item-worry)
(if (= 0 (mod item-worry divisible-number))
true-monkey-number
false-monkey-number))))
(make-instance 'monkey
:test test-fun :operation operation-fun
:inventory inventory-list :number ordering-number
:mod divisible-number))))
(defun monkey-one-item-action (monkey)
(let ((item-worry (first (inventory monkey) )))
(when item-worry
(setf (inventory monkey) (cdr (inventory monkey)))
(setq item-worry (funcall (operation monkey) item-worry))
;; (setq item-worry (floor (/ item-worry 3)))
(setq item-worry (mod item-worry (mod-reductor-2 monkey)))
(incf (slot-value monkey 'inspection-counter))
;; returning (target-monkey-num thrown-item)
(list (funcall (test monkey) item-worry) item-worry))))
(ql:quickload 'alexandria)
(defun monkey-turn (monkey)
(let ((thrown-hash (make-hash-table :test 'equal)))
(loop
for i from 1 to (length (inventory monkey))
do (let ((throw-result (monkey-one-item-action monkey)))
;; (format t "~s ~%" throw-result)
(setf (gethash (first throw-result) thrown-hash) (push (second throw-result) (gethash (first throw-result) thrown-hash)))))
(maphash (lambda (key value-list) (setf (gethash key thrown-hash) (reverse (gethash key thrown-hash)))) thrown-hash)
thrown-hash))
;; returns hashmap of which values go where
(defun monkeys-round (monkey-array)
;; for each monkey from array:
;; do it's turn, then for each record in resulting hashmap append list of transferred items to correct monkey
(loop
for monkey across monkey-array
do (let ((turn-result (monkey-turn monkey)))
(maphash
(lambda (target-monkey-num items-list)
(setf (inventory (aref monkey-array target-monkey-num)) (append (inventory (aref monkey-array target-monkey-num)) items-list)))
turn-result))))
(progn
(defparameter *11-test-structs*
(coerce (mapcar #'monkey-struct-to-instance (mapcar #'line-to-sexp *11-test-input*)) 'vector))
(loop
for i from 1 to 20
do (monkeys-round *11-test-structs*))
(sort (mapcar #'inspection-counter (coerce *11-test-structs* 'list)) #'>))
;; PART 1 on input data
(progn
(defparameter *11-input-paragraphs* (cl-ppcre:split "\\n\\n" (uiop:read-file-string "day11-input.txt")))
(defparameter *11-input-structs*
(coerce (mapcar #'monkey-struct-to-instance (mapcar #'line-to-sexp *11-input-paragraphs*)) 'vector))
(loop
for i from 1 to 20
do (progn (monkeys-round *11-input-structs*)
(format t "turn ~a~%" i)))
(apply #'* (subseq (sort (mapcar #'inspection-counter (coerce *11-input-structs* 'list)) #'>) 0 2)))
;;; PART 2.
(progn
(defparameter *11-test-input* (cl-ppcre:split "\\n\\n" (uiop:read-file-string "day11-test.txt")))
(defparameter *11-test-structs*
(coerce (mapcar #'monkey-struct-to-instance
(mapcar #'line-to-sexp *11-test-input*)) 'vector))
;; oh, i need to reset and recalculate the lowest common multiple for test input.
;; yup
(setf (slot-value *test-monkey-instance* 'mod-reductor-2) 1)
(loop
for monkey across *11-test-structs*
do (when (not (= 0 (mod (mod-reductor-2 monkey) (monkey-mod monkey))))
(setf (slot-value monkey 'mod-reductor-2) (* (mod-reductor-2 monkey) (monkey-mod monkey)))))
(loop
for i from 1 to 10000
do (progn (monkeys-round *11-test-structs*)
(format t "turn ~a~%" i)))
(print (apply #'* (subseq (sort
(mapcar #'inspection-counter
(coerce *11-test-structs* 'list)) #'>) 0 2)))
;; that's the problem with sharing slots across class
(setf (slot-value *test-monkey-instance* 'mod-reductor-2) 1)
)
(progn
(defparameter *11-input-input*
(cl-ppcre:split "\\n\\n" (uiop:read-file-string "day11-input.txt")))
(defparameter *11-input-structs*
(coerce (mapcar #'monkey-struct-to-instance
(mapcar #'line-to-sexp *11-input-input*)) 'vector))
;; oh, i need to reset and recalculate the lowest common multiple for test input.
;; yup
(setf (slot-value *test-monkey-instance* 'mod-reductor-2) 1)
(loop
for monkey across *11-input-structs*
do (when (not (= 0 (mod (mod-reductor-2 monkey) (monkey-mod monkey))))
(setf (slot-value monkey 'mod-reductor-2) (* (mod-reductor-2 monkey) (monkey-mod monkey)))))
(loop
for i from 1 to 10000
do (progn (monkeys-round *11-input-structs*)
(format t "turn ~a~%" i)))
(print (apply #'* (subseq (sort
(mapcar #'inspection-counter
(coerce *11-input-structs* 'list)) #'>) 0 2)))
;; that's the problem with sharing slots across class
(setf (slot-value *test-monkey-instance* 'mod-reductor-2) 1)
)

41
day12-input.txt Normal file
View File

@@ -0,0 +1,41 @@
abcccccccaaaaaccccaaaaaaaccccccccccccccccccccccccccccccccccccaaaaa
abaacccaaaaaaccccccaaaaaaaaaaaaaccccccccccccccccccccccccccccaaaaaa
abaacccaaaaaaaccccaaaaaaaaaaaaaacccccccccccccaacccccccccccccaaaaaa
abaacccccaaaaaacaaaaaaaaaaaaaaaacccccccccccccaacccccccccccccacacaa
abaccccccaaccaacaaaaaaaaaacccaacccccccccccccaaacccccccccccccccccaa
abcccccccaaaacccaaaaaaaaacccccccccccccaaacccaaacccccccccccccccccaa
abccccccccaaaccccccccaaaacccccccccccccaaaaacaaaccacacccccccccccccc
abccccccccaaacaaacccccaaacccccccccccccaaaaaaajjjjjkkkcccccaacccccc
abcccccaaaaaaaaaacccccaaccccccccccciiiiiijjjjjjjjjkkkcaaaaaacccccc
abcccccaaaaaaaaacccccccccccccccccciiiiiiijjjjjjjrrkkkkaaaaaaaacccc
abcccccccaaaaaccccccccccccccccccciiiiiiiijjjjrrrrrppkkkaaaaaaacccc
abcccaaccaaaaaacccccccccccaacaaciiiiqqqqqrrrrrrrrpppkkkaaaaaaacccc
abccaaaaaaaaaaaaccccacccccaaaaaciiiqqqqqqrrrrrruuppppkkaaaaacccccc
abcccaaaaaaacaaaacaaacccccaaaaaahiiqqqqtttrrruuuuupppkkaaaaacccccc
abcaaaaaaaccccaaaaaaacccccaaaaaahhqqqtttttuuuuuuuuuppkkkccaacccccc
abcaaaaaaaaccccaaaaaacccccaaaaaahhqqqtttttuuuuxxuuuppkklcccccccccc
abcaaaaaaaacaaaaaaaaaaacccccaaachhhqqtttxxxuuxxyyuuppllllccccccccc
abcccaaacaccaaaaaaaaaaaccccccccchhhqqtttxxxxxxxyuupppplllccccccccc
abaacaacccccaaaaaaaaaaaccccccccchhhqqtttxxxxxxyyvvvpppplllcccccccc
abaacccccccccaaaaaaacccccccccccchhhpppttxxxxxyyyvvvvpqqqlllccccccc
SbaaccccccaaaaaaaaaaccccccccccchhhppptttxxxEzzyyyyvvvqqqlllccccccc
abaaaaccccaaaaaaaaacccccccccccchhhpppsssxxxyyyyyyyyvvvqqqlllcccccc
abaaaacccccaaaaaaaacccccccccccgggpppsssxxyyyyyyyyyvvvvqqqlllcccccc
abaaacccaaaacaaaaaaaccccccccccgggpppsswwwwwwyyyvvvvvvqqqllllcccccc
abaaccccaaaacaaccaaaacccccccccgggppssswwwwwwyyywvvvvqqqqmmmccccccc
abaaccccaaaacaaccaaaaccaaaccccggpppssssswwswwyywvqqqqqqmmmmccccccc
abcccccccaaacccccaaacccaaacaccgggpppssssssswwwwwwrqqmmmmmccccccccc
abcccccccccccccccccccaacaaaaacgggppooosssssrwwwwrrrmmmmmcccccccccc
abcccccccccccccccccccaaaaaaaacggggoooooooorrrwwwrrnmmmdddccaaccccc
abaccccccccccccaacccccaaaaaccccggggoooooooorrrrrrrnmmddddcaaaccccc
abaccccccccaaaaaaccccccaaaaaccccggfffffooooorrrrrnnndddddaaaaccccc
abaacccccccaaaaaacccccaaaaaacccccffffffffoonrrrrrnnndddaaaaaaacccc
abaaccccccccaaaaaaaccacaaaacccccccccffffffonnnnnnnndddaaaaaaaacccc
abccccccccccaaaaaaaaaaaaaaaccccccccccccfffennnnnnnddddccaaaccccccc
abcccccccccaaaaaaacaaaaaaaaaacccccccccccffeennnnnedddccccaaccccccc
abcccccccccaaaaaaccaaaaaaaaaaaccccccccccaeeeeeeeeeedcccccccccccccc
abccccccccccccaaaccaaaaaaaaaaaccccccccccaaaeeeeeeeecccccccccccccaa
abcccccccaaccccccccaaaaaaaacccccccccccccaaaceeeeecccccccccccccccaa
abaaccaaaaaaccccccccaaaaaaaacccccccccccccaccccaaacccccccccccaaacaa
abaaccaaaaacccccaaaaaaaaaaacccccccccccccccccccccacccccccccccaaaaaa
abaccaaaaaaaaccaaaaaaaaaaaaaacccccccccccccccccccccccccccccccaaaaaa

239
day12-scratch.lisp Normal file
View File

@@ -0,0 +1,239 @@
;;; https://jira.ringcentral.com/browse/ANY-13016
;; climbind the hill - only 1 elevation higher, any elevation lower
;; only movements UP, DOWN, LEFT, RIGHT.
;; bfs should do.
;; and hide current character in order to prevent backtracking
;; so. from start (consider it to be 'a')
;; one iteration is:
;; collect neighbors, filter them to only have applicable neighbors elevation +1 or lover
;; hide current place, run dfs from the neighbors - it should return the shortest path from them or -1
;; then select shortest path add +1 and return to parent
;; not sure which structures would be more comfortable
(defparameter *day-12-test-lines*
(mapcar (lambda (line) (cl-ppcre:split "" line)) (uiop:read-file-lines "day12-test.txt")))
(defparameter *test-array* (make-array (list (length *day-12-test-lines*) (length (first *day-12-test-lines*)))))
(array-dimensions *test-array*)
(destructuring-bind (rows cols) (array-dimensions *test-array*)
(loop for row from 0 below rows do
(loop for col from 0 below cols do
(setf (aref *test-array* row col)
(nth col (nth row *day-12-test-lines*))))))
(coerce (coerce "a" 'character) 'integer)
(char-code (coerce "a" 'character))
(- "c" "a")
(- #\c #\a)
(eq #\c #\a)
(eq #\a #\a)
;; next - instead of S set a, instead of E set z
;; and store S and E coords in a parameter
(destructuring-bind (rows cols) (array-dimensions *test-array*)
(loop for row from 0 below rows do
(loop for col from 0 below cols do
(let* ((input-place-string (nth col (nth row *day-12-test-lines*)))
(input-char (coerce input-place-string 'character)))
(when (eq #\S input-char)
(setq input-char #\a)
;; set coords for start
)
(when (eq #\E input-char)
(setq input-char #\z)
;; set end coords
)
(setf (aref *test-array* row col)
input-char)))))
*test-array*
;; well. nah, using different parameters is not cool
;; next steps:
;;
;; function to get next points to check
(defun get-neighbors (row col)
(list (list row (1- col))
(list (1- row) col)
(list row (1+ col))
(list (1+ row) col)))
(defun coord-in-dimentions (coords array)
(destructuring-bind (row col) coords
(destructuring-bind (rows cols) (array-dimensions array)
(and (>= row 0)
(>= col 0)
(< row rows)
(< col cols)))))
(remove-if-not (lambda (coords) (when (coord-in-dimentions coords *array*) coords))
(get-neighbors 0 0))
(array-dimensions *array*) ; (5 8) -
(defun get-neighbors-in-array (coords array)
(remove-if-not (lambda (coords) (when (coord-in-dimentions coords array) coords))
(apply #'get-neighbors coords )))
(get-neighbors-in-array '(0 0) *array*)
(get-neighbors-in-array '(1 1) *array*)
(get-neighbors-in-array '(2 2) *array*)
;; function to filter to be inside of array
(defun move-valid-p (cur-char next-char)
(and (>= 1 (- (char-code next-char)
(char-code cur-char)))
(not (eq next-char #\%))))
(move-valid-p #\a #\a)
(move-valid-p #\a #\b)
(move-valid-p #\a #\c)
(move-valid-p #\a #\z)
(move-valid-p #\a #\%)
;; function to check if target letter valid step from current letter
;; one-step function
;; now the function would have to be recursive
(defun recursive-search-min-path (coords array end-coords)
(if (equal coords end-coords)
0
(let* ((neighbour-coords (get-neighbors-in-array coords array))
(cur-char (aref array (first coords) (second coords)))
(valid-next-steps (remove-if-not
(lambda (coords)
(let ((next-step-char
(aref array (first coords) (second coords))))
(move-valid-p cur-char next-step-char)))
neighbour-coords)))
(if (not valid-next-steps)
999999
(progn
(setf (aref array (first coords) (second coords)) #\%)
(setq lengts-from-next-steps (mapcar
(lambda (next-coords)
(recursive-search-min-path next-coords array end-coords))
valid-next-steps))
(setf (aref array (first coords) (second coords)) cur-char)
(1+ (apply #'min lengts-from-next-steps)))))))
(print (recursive-search-min-path *day-12-start-coords *array* *day-12-end-coords))
(recursive-search-min-path *day-12-start-coords *array* '(0 0))
(recursive-search-min-path *day-12-start-coords *array* '(0 1))
(recursive-search-min-path *day-12-start-coords *array* '(1 1))
;; yes. finally
(eq '(1 2) '(1 2))
(apply #'min '(1 3 -1))
(apply #'min '(-1))
(apply #'min '())
(not '())
(not '(1 2))
(defun search-min-path ()
(defun recursive-search-min-path (coords array end-coords accum-path)
(if (equal coords end-coords)
(return-from search-min-path accum-path)
(let* ((neighbour-coords (get-neighbors-in-array coords array))
(cur-char (aref array (first coords) (second coords)))
(valid-next-steps (remove-if-not
(lambda (coords)
(let ((next-step-char
(aref array (first coords) (second coords))))
(move-valid-p cur-char next-step-char)))
neighbour-coords)))
(if (not valid-next-steps)
999999
(progn
(format t "reaching coord ~a~%" coords)
(setf (aref array (first coords) (second coords)) #\%)
(setq lengts-from-next-steps (mapcar
(lambda (next-coords)
(recursive-search-min-path next-coords array end-coords (1+ accum-path)))
valid-next-steps))
(setf (aref array (first coords) (second coords)) cur-char)
(1+ (apply #'min lengts-from-next-steps)))))))
(recursive-search-min-path *day-12-start-coords *array* *day-12-end-coords 0))
(print (recursive-search-min-path *day-12-start-coords *array* *day-12-end-coords))
(print (search-min-path))
;; wait. i'm doing dfs here, right?
;; for bfs i need to queue the next points. ugh
(defun bfs-search-min-path (next-points-to-check)
(if (not next-points-to-check)
-1 ; if exhausted reachable coords
(let ((currently-checking (first next-points-to-check))
(rest-to-check (rest next-points-to-check)))
(destructuring-bind (coords accum-path) currently-checking
(if (equal coords *day-12-end-coords)
accum-path
(let* ((neighbour-coords (get-neighbors-in-array coords *array*))
(cur-char (aref *array* (first coords) (second coords)))
(valid-next-steps (remove-if-not
(lambda (coords)
(let ((next-step-char
(aref *array* (first coords) (second coords))))
(move-valid-p cur-char next-step-char)))
neighbour-coords)))
(format t "reaching coord ~a~%" coords)
(setf (aref *array* (first coords) (second coords)) #\%)
;; format is '((1 1) 4) - coords and lenght-up-to
(setq next-steps-with-length (mapcar
(lambda (next-coords)
(list next-coords (1+ accum-path)))
valid-next-steps))
;; (setf (aref *array* (first coords) (second coords)) cur-char)
;; (1+ (apply #'min lengts-from-next-steps))
(bfs-search-min-path
(concatenate 'list rest-to-check next-steps-with-length))))))))
;; so, with bfs there's no need to revert the previous chars?
(concatenate 'list '(12 3) '(5 4))
(concatenate 'list '(12 3) '())
(bfs-search-min-path (list (list *day-12-start-coords 0)))
*array*
(destructuring-bind (coords accum-path) '((1 2) 3)
`(got ,coords and ,accum-path))
;;; PART 2
;; find shortest path from every point at elevation #\a
;; so, i'd need to reuse my function from different starting points
;; and reset the array after each search
;; so. collect coords for all starting points
;; hm, yeah, only difference with just starting with all of them - need to reset the array
(defparameter *day-12-2-starting-points '())
(destructuring-bind (rows cols) (array-dimensions *array*)
(loop for row from 0 below rows do
(loop for col from 0 below cols do
(when (eq #\a (aref *array* row col))
(push `((,row ,col) 0) *day-12-2-starting-points)))))
(defparameter *day-12-2-all-trail-lengts* nil)
(setq *day-12-2-all-trail-lengts*
(loop for start-point in *day-12-2-starting-points
collect (bfs-search-min-path (list start-point))
do (restore-params)))
(first (sort *day-12-2-all-trail-lengts* #'<))

5
day12-test.txt Normal file
View File

@@ -0,0 +1,5 @@
Sabqponm
abcryxxl
accszExk
acctuvwj
abdefghi

117
day12.lisp Normal file
View File

@@ -0,0 +1,117 @@
;;; https://jira.ringcentral.com/browse/ANY-13016
;; (defparameter *day-12-file-name* "day12-test.txt")
(defparameter *day-12-file-name* "day12-input.txt")
(defparameter *day-12-lines* nil)
(defparameter *day-12-start-coords nil)
(defparameter *day-12-end-coords nil)
(defparameter *array* nil)
(defun restore-params ()
(setq *day-12-lines*
(mapcar (lambda (line) (cl-ppcre:split "" line)) (uiop:read-file-lines *day-12-file-name*)))
(setq *array* (make-array (list (length *day-12-lines*) (length (first *day-12-lines*)))))
(destructuring-bind (rows cols) (array-dimensions *array*)
(loop for row from 0 below rows do
(loop for col from 0 below cols do
(let* ((input-place-string (nth col (nth row *day-12-lines*)))
(input-char (coerce input-place-string 'character)))
(when (eq #\S input-char)
(setq input-char #\a)
(setq *day-12-start-coords (list row col))
)
(when (eq #\E input-char)
(setq input-char #\z)
(setq *day-12-end-coords (list row col))
;; set end coords
)
(setf (aref *array* row col)
input-char))))))
(restore-params)
*array*
(array-dimensions *array*)
*day-12-start-coords
*day-12-end-coords
;; yay.
(defun get-neighbors (row col)
(list (list row (1- col))
(list (1- row) col)
(list row (1+ col))
(list (1+ row) col)))
(defun coord-in-dimentions (coords array)
(destructuring-bind (row col) coords
(destructuring-bind (rows cols) (array-dimensions array)
(and (>= row 0)
(>= col 0)
(< row rows)
(< col cols)))))
(defun get-neighbors-in-array (coords array)
(remove-if-not (lambda (coords) (when (coord-in-dimentions coords array) coords))
(apply #'get-neighbors coords )))
(defun move-valid-p (cur-char next-char)
(>= 1 (- (char-code next-char)
(char-code cur-char))))
;; recursion
(defun bfs-search-min-path (next-points-to-check)
(if (not next-points-to-check)
999999 ; if exhausted reachable coords
(let ((currently-checking (first next-points-to-check))
(rest-to-check (rest next-points-to-check)))
(destructuring-bind (coords accum-path) currently-checking
(if (equal coords *day-12-end-coords)
accum-path
(let* ((neighbour-coords (get-neighbors-in-array coords *array*))
(cur-char (aref *array* (first coords) (second coords)))
(valid-next-steps (remove-if-not
(lambda (coords)
(let ((next-step-char
(aref *array* (first coords) (second coords))))
(move-valid-p cur-char next-step-char)))
neighbour-coords)))
(format t "reaching coord ~a~%" coords)
(setf (aref *array* (first coords) (second coords)) #\%)
;; format is '((1 1) 4) - coords and lenght-up-to
(setq next-steps-with-length (mapcar
(lambda (next-coords)
(list next-coords (1+ accum-path)))
valid-next-steps))
;; (setf (aref *array* (first coords) (second coords)) cur-char)
;; (1+ (apply #'min lengts-from-next-steps))
(bfs-search-min-path
(concatenate 'list rest-to-check next-steps-with-length))))))))
(bfs-search-min-path (list (list *day-12-start-coords 0)))
;; 339
;; PART 2
(defparameter *day-12-2-starting-points '())
(defparameter *day-12-2-all-trail-lengts* nil)
(progn
;; get starting points
(destructuring-bind (rows cols) (array-dimensions *array*)
(loop for row from 0 below rows do
(loop for col from 0 below cols do
(when (eq #\a (aref *array* row col))
(push `((,row ,col) 0) *day-12-2-starting-points)))))
;; calculate path lengths from all starting points
(setq *day-12-2-all-trail-lengts*
(loop for start-point in *day-12-2-starting-points
collect (bfs-search-min-path (list start-point))
do (restore-params))))
;; get shortest of them
(first (sort *day-12-2-all-trail-lengts* #'<))
;; yay. the shortest of all was 332

456
day13-input.txt Normal file
View File

@@ -0,0 +1,456 @@
(
((2))
((6))
((0 (() () (10 6) 0) (5) 5 9) ((5) 7))
((((7 10 2 0)) ((5) (10 1 7) () () 9) ((0 6 2))) ())
((5 ((9 3 4) (6 3 10) (5 9) 8) ((6 6 1) 5 10 1) 8) ((()) 3 ((3 3 7) 5 6) 3 6) () (8 (9 (7 10 2 3) 9) 10 (4 3 2 (7) 7)) (5))
(((3) ((10 3 2 2) (0 1 1) (1 3) 2) (7)) ((8 1 9) 9) (2 (7 (10 7 6) 8 0 (7 7 10 8 6)) (10 () 5)) ())
((7 6 (())) ((() 8 5) (6 (1 4 7 9) (0 5 1 10) (6) 10) ((8 2) 9 10) (4 (2 9 3) 1 (4 9 6) 10)) ((7 (9) (4 6)) ((5 4) 3 (7 10 0 0 1)) 3))
((6 5) (0 1 (5 ())))
((9) (7 (0 (1 9 4) (4 0 9))) () ())
((6 (9 2 () (9 7)) ((5 10) () (6 0 1)) 1) (((10 1))) (0) (8 (() (2 2 2 4) (8 9 0) 9) (4) 7 0) (() 9))
((4 (3 (9 9 7) (0 8 1 7 5) (2) (1 0 7 0))) (() 8 () ((9) 9 3 9 1)) () ())
(() (9 () (() () (7 4 4 5))) () (() 1 6 (1 (3 4 10) 2 (6 8 7 9 0))) (() (1 (1)) 0 9))
(((1) 10) ((6) 10) (() (7) 8 5 8) ((1 8 0 (7 0 8 4 6) 8) () () ((9 1 9) 7 (2 7 8 10) (9 1) (9 6 10))) (2 7 (7 (9 4 3 2 7) 3 8 (1 0 4)) 4))
(((() 1) (7 7 (0 1 5 0)) 2) ((6 6 (9 5 6 9) () 9) (1) 5) (() ((7 7) (7 4) (1 10 4 10) 10 0)))
((() (9 (3 2))) (0 ()))
(((3 (6 5) () 4) ((6) 9) (1 9 4 (8 2 2 4 6)) 9 ((10 7 8) (3 6 1 10 7) () (3) (10 10 4 5 7))) ((6 (10) (7 10) 4 (10 0 6 9)) 4 9 (3 1 (5 3 0 1) (4 6) 2) ((10) (6) (8 3) 2)) (((9 6 7) (3 1 1 9) 2 ()) (0 (9 5 9 5) 0 5 (4)) ((7) 3 4 1 (9)) 4 (2 2)))
((10 4 ((10)) 9 ((6) 5 6)))
(((() 1) 3) (1 0 ((1 9)) 7) ((2 8 8 9) (7) 9 4) (((9 0 4 1) (6 10 4)) (3 10 8) 8))
(((9 7 5 4 2)))
((2 10 (10 (4 10 0 8) 8)) (10 (3)) (5 10 8 ((3) () (5 0 6) (6 5) 1)) (((7 6 8) (10) (10 3 10)) ((10) () 9 6 0) 7))
((() 3 4) (2 4) () () (((2 1 4 5 10) (2 9 6)) 3 ()))
(() (() 9 ()))
((0) ((() 8 2 10) (() (7 8 9 4))) (2 ((7 10 4 0) 1 10) 10))
((((0 5 3 8) 4) (5) ((0 2 2 8 0) 8 7 (4 8 10)) 1))
((((7 6 3 6 6) 7 7 6 9) (4 (7)) 7 ((6 7 6) 10 (4 5 10 9))))
(((4 (8)) 5 (() 8 4) (9 (4 4 9 1 5) (9)) 4) (((6))) (10))
((6 0 (3 1)))
((((3 3 7 10) (8 7 8 0 4) (6 6 1 0 10)) (4 (8 6 1)) 10 5 (() (3) ())) ((0 1 8 4) (5) (0)) () ())
(((1)) (9 (7 1 5) (9 3 (1 4 5) 5) 7) (() 1) (((2 4 4) (5 10 2 7) 0 (3 2 3 0)) ((8 8) (4 5 0 7) (3 5 7 0 1)) (7 10 () 0 ()) 6 10))
((()) (5) () ((6 1 (7 10 0))) ((6 (9 10 4 9) 7 ()) 2 (6) ()))
((9 9) (10 8) (9))
((((0 6 0) 2 (8 10) (5 8 0 5)) ((5 7) 1 () 6 0)) (5 6 ((9 4) 3 (9 5 0 9 6) 1 6) 6) (2 () ((4 5 1 9 2) () (9 5 7 1)) (3 (5 6 9 10 1)) ((0 7))) (()) (10))
((0 ()) () (((1 9 1) 7) (8) ((9)) ((10 9 10 1) (0 0 8 0 1) (10 4 5 6 9) (6 6 5) 5)))
((((8 7 8 9 10) (5 1 8 5)) (3 3)))
((((9 2 9) 10 (10) () 8) ((7 10 7) 8 (4 8) 5) ((3 2 7 5 9)) 10 (9 (1) 5)) () (2) () (() (() 4)))
(((7 (0 5 7)) 6 ((4 6) 2 (7 9) 10)) (9 10) ((8 10 1) () 0 ((0 10 3 3) 0 0 9) 1) ((8) 9))
((((2 7 1 2) 5 6) (9) 8 ()))
(((10) (2 3 (6 2)) 2) (10) ())
(((6 3)) (5) () (((0 3 6 1 3) 5 7 2 6) 3 (1 7 (6 2 7) (7 7))))
(((10 () 4) 4 (10 (0 5 1 0 10) 10 5) () 10) (() (2 (4 3) 5) 5 3) (3 (7) 3 ((7)) 8))
((0 3 ((5 3 10 10))) ((9 (8) (7 3 2) 6)) (1) ((6) 3 7))
((((1 4 7 0) () 9 (5 2 4 3) (1 2 5 4 10)) 8 0 (4) ()))
((10 3 (5 2) ((4 8 4 10 6) (6 6 1 6) 8 5 0)) (0 ((1 10) () 2) 4 ((4 9 6)) 10) (3))
(() (((5 8) (2 10 2 2) (5 9 3 6 10) (8 6 8 4 7)) 10) (9 7 (2) (2 9 (3 3 1 10 10) 4 ())))
(((4 9) (10 () (7 3 5 6 2)) 2 ((8) 0)) ((0 (1 2 5 7) (10 0 3 9 7) (8) 7) 9 (3 (2 2 3 3 0)) 6) ((3 10 6 (7 4)) (2 0 1 5 10)))
((3 10 (4)) (8 (8 5)) (0 2 (1)) ((9 (4)) 2))
((0 1 (9) 9 6))
((3) () () ((5 6 (2) 1) 0 (8 (3) 1 (6)) 3 (1 10 (6 9 0))))
((10))
(((0 10 (6 1)) 7 5 ((8 2 7 3) (2 8 1))) (0 ((8 1 6 2 0)) (5 (8 0 10 7) (6) 2 1)) (7 1 3) (8 ((8 10 10) 9) 3 8 1))
((6 0 10 2))
((1 (8 ()) ((8) (3 8 10 1) (10)) 2 (1 7 3 (10 1 4) 10)))
(((6 7 10 (4 8 9 10 8))))
((9 (() (6 3 6) 3 7 (0 3 9 6)) 6))
(() (((2 5) (3 3) 9)) ())
((6 10) ())
(() ((3 (7 0 10 5 10) (2)) (8) ((10 9)) 6 ()) (2 (() 9 2 10) 2 8) (6 9 0))
((10 () () ((3 7 9 0) 6)) () ((4)) ((1 4 6 4 (10 1 0 2 2)) ((3 5 4))))
((((10 4 0) (8)) ((5 0 2 9) 9 (8 1 10 10 4) 10 4)) (8 (7)))
((((7 3) 6 (0 7 7) (9 4) (4)) ((7 4 7))))
((() (9) 4) ((2)))
((9 ()) (2) ((8 9 5 7) (() (10)) 7 ((8 1 6 3 8) (1) (6 8 10) 2 (8 5 7 4 6)) ()))
((((9 2) 4) 7 ((5 7) (0 2 4 10 7)) 9 6) () ((5) (5 0)) (7 8))
(() (10 (() () 8 () 4) 0 () ()) ((1 (6 9 6 7 6) 9 ()) 3) ((4 () () 5) 1) (0 () 2 ((9 8 6 7))))
(10 7 3 6 3)
(10 7 3 6)
((((1) (2 9 3 7 1) (0 2 10)) (4 3 3 9) 7))
((((9))) (5) (((8 9 5 7 2) 5 10) 9))
(((6) ((0 10 8 6 2) 2 1 1 (3 7)) 5) ((0 (8 3 4 6 7) (1 8 3 3 3) (5 4 8 9 4) 5) 2 2) ())
(() (1 ((4 8 6 6) (4 10 3)) (() 8 3 (2 4 4 1)) ((4 2) 9 ())) (((9) () (9) 7) 9 ((6 0) (8 1 7 4 0)) (10)) ((0) (9 6 5 (9 0 3) (1)) 1 (4 (10 9 10) 9) (10)))
((0) ())
(((9 1 7 10 (6 6))) (((6 3 2 2)) (5 9) 10 5) (((0) 3) (7 10 0) (6 (2)) (6) (2 (2 4 6) (5 6))))
((6 8) () (() 9 2 10 ((7 8 8 6))) ())
((3) (((8 1 9 4 10) (1) (10)) 6 10 ((4 6 2 7) 0 1 (3 8 6 9 6))) () ((() (5 9 3 9 3) (4 8 5 3) 3) (8 8 2 6) (2 10 3)))
(((0 () (6 1 3 1) ()) 4 (0)) (2) (6 6 6 ((1 0 2 9))) (7 7) (((7))))
(((2 5 5 3 (5 0)) ((6 7) (3) 1)) (((8 10 7 5 1) 6 (8 10))) (6 0 6) (3 ((10)) 4 4 9))
(() (9 ((8 9 10 0 8) (5 6)) 8) (((8) (4 8 9) 10) 5 1))
((9 2 ((7 9 8 9 6) 8)) (((7 3 1 8) (10) 7 (10)) 6 (() 5 6 6 1) (0 7 (10 4 3)) 7) ((0 9 () 9 (8 6 8))))
((3 4 7 7 0) ((10) 5 ((4) (10 7) (8 5 5 7) (8)) ()) ((10 (1 0) 0)))
(((7 2) ((10 6 8) (7 7 6 0) 10 (10)) (10 9 9 4 (0 1 1 4 5)) 8 (0 4)) (() 7) (((7 1)) 5) (8 0 2 ((7) (0 3 6 10)) ()) (7 1))
((4 2 (10 2 10 7 0) ((7) 1)) (6 () ((3 0)) 3 8))
(() (((6 8 0 2 1) ()) ((8 4 6) 2 (10 2 10 5 5)) (7 () (10 6 0 10)) 3 (1 4 (6))) (8 (8 (10 4) 10) (9 8 5 1 6)) ((() 4 0) 1) ((6 (10)) ((2 5 8 0)) 1 8 (() 3)))
((() ((0 7 7 1 10) 9) () (8 1)))
(() ((10 2 (2) 9 (0 2 5 9 4)) 8 10 (1 (7 9) (5) 10 (3 7 0 7 8))) () () (((10 10 2) () (2 6 6 9 5)) (3 (10 1 6) (9 5 4 3 5)) 2 (2 3 3 (4 10 7 3 4))))
((5))
((7) (2 (6 (2 4 5 6) 2 9 (4)) 7 6) (()) (7 ((10 10 3 7) 9 (9) 8) 5 () 10) ())
((4 4))
((5 0 9 5) (() 7 ((1 4 9) (10 2 3 9 1) () (3 8 5 6) 0)) () (1) (((7) (8 3 10)) 1))
(() (0) ())
(((5) 3 (() (3 10 7)) 0) (6 7 4 3 6) (3 5 ((3 1 0 4))) ((3 (7) (7 1 8 6 1) 7 ())))
((((3 1 0 3 5) 3) 9) () (() () ((4 3) (6) 4 ())) (() 10) (10 (8)))
((9 (6 7 (7 10 4 8)) 1) (9 2 ((6 1) (10) 5 10 8) ((2 7) 5 8 (1 7 1))) (() 4 ()) (((1) 9 9) () (8) (()) 3))
((((1 1 8 4) 5 () (7 8 7 5) ())) (7 ((1 0 7 8 10) (0 5 7 3 6) 4 1) 9 3 ((4 8 8 1 7) 7)) (9 1 (2) 10 10) (((7 7 7)) 2))
((()) (10 (3 () (7 0) ()) 5 ()) (0) ())
((2 3) (8) (5))
((((9 8 4) 0 6 10 (2 0 5)) 1 (8 ())) ((5 6 1)))
((6 4 10 1 4) (((10 7 4 9 7) (7 0 5 7 5) 6) 7 6 (0)) (((7 3 10 2) (9 4 1 3) ()) ((4 7 10) 9 0 (5) 7)) ((8) ((0 10) 0 8) 0 6))
((4 8))
((9 ((9 1 2 5 4) 0 (4 1 2 0) ()) (1 (3 6 9 9) 1 (2 9) (9 5 8 1)) 2 4) (8 10 ((3 0) (0 8 1 10) 6)) ())
((((3 3 8 8 7) (3 8 2 3) 8 (3 1 5 9) ()) ((7 9 4 2 3) 6 5)))
((1 (2 (2 4 8 8) 5 9)) (8) (((10) ()) 1))
((((10) (0 5 1) (4 1 3 8) 3 (0 8 5 10)) (() (8) 0 8) 3 8) ((8 5 (7 2) (1 1 8 6 1) (0 5 8)) 4 2 7) (() (4 8 (2) 6 3) 6) () (1 ((7 3 0 7 10) 0 1 4 8)))
((() 2 (3 (7 7 4 3) (9 5 3))) ((() 2 6 ()) 8 (3 7) (2) 9))
((((1 0) 2) (2 3) () ((6 1) 0 () (10 8 0) (3 0)) 1))
((() 5))
(((4 7 (10 10 5 9 2)) 10) (0 ((1 4 1 4) (3 7 2 8 0) 6 () 1) (() (0 4 6)) ()) (()) (2))
((((5 0 3) 3 6)) (6 (0)) ((0 (7 7 7 1) (6 3 7 3) (9 8) 3) 9 (3 (9 10 7 6 8) (0 3 2 0) 8 (5 4)) 8 ((9 4) (1 5 4) (0 1 1 4 5) 7)) ())
((3 0 3) (6 ((0 6 5 6) (3 2 2 4 10)) (() (8) (9 8 7) 2 2)) (() 7) ())
((2 9))
(((3 ()) 3 0) () (() () (3 0 2) ((5 0) (7 8 1 10) (6 5) (2) 3)) (((9 8 2 8))))
((3) (10) (((8 4 6 5 1) (0 2 4 0) (2 2 1 4 0) 2) (5 (3 0 0 1 10) (6 8 3 7 6) 7 2)) ((6)))
((10 4 ()) ((7 2) (9 (9) (6 3) (9 1 10) 5) 6 (() 10 (0) (7) (2 7 3)) 2) ((1 () 6 (8 5 0 3 2) (8)) ((1 3 2 1 9) (0 10) (3 0) (10))) ())
((2 () ((2 3) (5) (4))) (1 ((1 7 9 5 4) 1 () 3)) () (8 0) ())
((() ((6) 9) (6 (4 0 6) 7 9)))
((5 (() (1 1 9 3 9) (4) 9 6) 7) (6 () (10 (9 7 5) (2 2 6 7 6) (0) 4) (())) (() 9 10 (() 5 (1 5 0 4) 9) 1))
((0 (() 5 5 1 (7 5)) () 0 10) (((1 5 5 6 7) 0 (0 3) (6 4)) 0 3 6) ((1 (6 4 2 10 9)) 9 3 (8 7 (7 7 1) 5 6)) (9 0))
((((7 4) 5 (6 6 0)) (1 (8 1 6) 9) 3 ((0 10) (0 3 8) (7 3 5) 9) ()) (9 9 ((1 7 10 0 0) (2 1 1 6 4) (7 1) () (7 7 5 9 5))))
()
(((7 6 (1 8 0 7 7) (3 7 8)) ((0 6 6 2 1) 1 (5 2 5 2 8)) (() (5 0) 0 6 (9 1 2 0 0)) 4 3) (((10 9)) 10 4 (1 (10 7 1 3))) (2 6 4) (5 1 ((2 5 3 8 7) 1 7 (7 2 6 7) 1) (0)))
(() (3 10) (1 (() (2)) 5 9) (((3)) 8 0 ((0 7 10 9) 9) 2) (5 5 ((2 3) (7 7 9) 9 (4 4 0) 5)))
((5 5 8 3))
((8 4 ((6 1 7 2) (9 9 9)) ((8) 1 () 1 0) 9) ((() (9 10 9 2 5) 3) 6) (() 8) (((3) (5 10 7)) () (7 3 0 4) (6)))
(())
(((2 (4 10) (4 5 5) 1) 8 0 8) (2 ()) (((7 5 9 0))) ((10 9 (3 0 0)) () 6 6 3))
((10 8 0 (2) 8))
((4 1) ((1 (8 6 10 1) (6 6 7 4 4) () 4) 4 0))
(() (6) (((2)) 7 7) (() () (() (5) (6 6 0 2 9)) 4) (0 () 8 () 6))
((4) ((5 (2 2 7 10 0) (10 8 6 6 6)) (() (5 3)) (2 (9 5 2))))
((8 ()) (((6 2 8 3 3) 7 7 0) ((8) 3 10 0) 6) (4) (((4 2 2 0) (8) 5 2)) ((10 1 6) ((4 2)) 10))
((() 10 8) (0 9 8 ((7 5) (3 6 7 4)) 4) (6 2) (2 (4 (10 8)) 1 (3 (9 7 8 3) 4)) ((4 (3) (10 7 2 9 10)) 0 1 9))
((3) () ((10 10 (3 7 2 9 7) 8) 4 8 6) (4 () 6))
((0 5 (4 5 () (9 2) (8 2)) ((4 4) 3) (6)) ())
((3 10 8) (((1)) (2 () 1 4 (5 7 3)) (10 (7 6 8) 3 4) (10 8)) (() ((2 9) ()) 0 8) (8 6 2) ())
((5 6 (10 5 ()) (5 5 0)) ((() 9 (8 1 10 4))))
(((() 4 3) ((1 6 1) 0 4 3 ()) (()) ((7 6 2 2 0) 8 (0) 10) ()) (((0 1) ()) ((2 1 6)) (6 0) 9) ((2 0 3 (10 10 10 3 0)) 2 (0 (4 6 7 6) 2)) (((3 2 9) 3 6) 3 9) (6 ((3 3 6 8) 0) 8 ()))
((10 (4) 10 0 1) ((2 (10 10 0) 5 8) 0 6 7) (1 8 ((10 9 10) 9 2) 3) (2 10 (0 8) (8 2 1)) (() (10 6 0 5 (4 6 7 3)) (0 9 2) (2) 0))
(((5) (5 6)) (0) (9 (4 (5 10) (10 3 8 9) 6) 1) (0 8) ())
(((0 (0 9 9 1 1)) () 1 (10 ()) 4) ((5 () (1 4 6 5) ()) ()) ((3 () 0)) (4 (() (1 7 8 1))))
((((9) 9 (6 6 7 4) 0) 7 ((4 1 7 2) 0 (10 10)) ((8 4) 8 7)) (() ((4 9 0 6))) (5 (() 8 (5) 10) 4 (7 7 (8 10 6 0) 8)))
((() 4 1 ((6 1))) (8 ((10 0 4) (5 3 7 2 0) 4) 9) ((6 (7 6)) 5 (9 (4 1 6 10) (2 7 8) 9)) () (0 ((9)) 6 (2 10)))
((() 6 () 1))
((8))
((() ((10 3 5 1 1) (5 4 4 6 1) () (0 0 7 10) 7) ((4 7 2 8 1)) (2 (5 2 7 2 4) (7 0 7 9)) 1) (((1) 0 (6)) ((7 0) 10 (7 5 9)) ((3 0 2) (4 4) 7 3) 4 6) ((4 (6 0 3)) 9) (4 (8 (8 0 9 8 6))) (4 ((7 7 4) 2 () 5 3) (8 9)))
((8 8 1) (() ((1) (0 7 4))) (8 ((5 6) 7 (4 7 4) (1) 3) 1 (7) 1) (3) (2))
((8 ((2)) ((6 2) 7)) ())
((2 9 2 0) ((3 5 3) 5 9 (4 3 5)) ())
(((7 () 3 8) (7)) (10))
((3 3 4 (() 9 (10 5 1 1 8) 6 9)) ())
((7 4 3) (((6 2 5) (5 5 9 8 9) (9 7 6 9 3) (9 1 4 2) 7) 7) ((10 2 (7 2 3 7 3) (3 9 3 8)) 8))
((((7 0 3) 3 (5 5 1 2 6) (2 6 5) (9 0 8 8 6)) 2) (6 7 ((0) (5 2 0 5 0) 6 (0 2 1) (1 7 6 1))) (((8 7) 1) 5))
(() (0 10 ((9 3) 6) (4 2 (10 4 1))) (() () (4 (6 6 5) 1 6 (3)) (2 3 6) (7 ())))
((8) ((2 (5 7 5) 7 (2) 6) 6) (10 (9 1)) (3 5 ((10 9 1 2) (4 4 8) 2 8) 7) (1))
((((4))) (() (7 (8 1 10) () 10)) ((1 6 (10 7 9) 2 10) 4 7 ((7 3 5 5 6) 4 (3 10 5 6 5))) (((9 10 1 10) (10 6) (0 1 8 2 6) () 10) (() 7 (3 9 3) ()) (7 (1 0 5 3) (9 1 8 6)) 0) (2))
((0 (() 8 10 () 8) ((3 9 4 8 8) 5 (3 6 9) (4 4 1 6 8) (10 8 9)) ()) (10 ((2 2 4) 4) (2 (9 0 9) (9 8 3)) 9 ()))
((((3 3 2) 2 1 2) ((7 8) (10 2 3 10) 4 ())) ())
((((1 3) 8 0) ((3)) () (10 3) (())) (10 ((2 7 8 2 0) (5 7 3 4) (0 5 0)) 10 7 4) (() (10) 4 ((9 0 0 3 1) 1 0 4)) ((1 (6 7 5 1) 9 (6 8) 10)))
(((5 (4 0) 4 (8 2 1 7 3)) 7) (5 10 4 9) (8 2 (() (2 5 0 7) 8 3) 3 1) ((5 (0 10 10 2) (7 5 6) 0 4)) (5 ((1 7 5 9 10) () (4 4 3))))
((((8 5 9 6) 3) () ((7 0 2 4 1)) 9 6) (4 0 8 3))
(() (6 (7 (7 6 4 10 10) () 0 ()) (1) ((1 4 5 9 8) 6 (6 4 2) (5 3 7) 10)) (6 (2 3 10 (0 6 9 10)) (0) ((10 2) 4)) ((() 1 0 () 7) ((0 4) 5 (9 3 7 10 1) 2) 0 4 4))
((0 10 8) ((8 9 (1 10 9 3) 2 1)))
((5 4 4 10) (()) (4 2 (3 6 10 10 (5 7 9))) (0 4) (9 7 9 4))
(() (1 (()) 1 0 (10 ())))
(8 8 4 6)
(8 8 4 6 10)
((((6) 1 6 4 3) 9 () ((6 3 7) 3 (5 2) 0 (10 1))))
((7 5 5 7) () ((8) 3 9 8) (((7 10) (3 1 4 0)) (7 8 (3 1 10) (4) (7)) (())))
((((5 4 1 10 8) 9 (2 0 2)) ((7)) (() 2 (1 1 5 1 7) 9 (5 9 10 1 4))) ((9 6 3)) (5 (5 7 () 10 (8 1 0)) ((10 5 10) 1 10 4 (4)) 10) (1 3 9 ((0 7 7 2) 9 (4)) (0 (0 2 7 5))) (2))
((((9 1 2) (8 0) 10) 10 (() 6)) (7 7 0 4) ((2 (4)) () () 3 ((3 1 2))) ((5)) (6 5))
((((1 7 5 3)) 0 6 ((3 8 0 9 0) () (6 7 10))))
(() () (9 (0 8)) () (((0 7 7) () (2 10 2 7 6)) ((7 8 5) 5 (3 1 9 0 8) 8) (7 (8 10 6 3) 0) ()))
((6 4 3 ((7 6 10 3 8) (6 2) 1) 7) (((4 5 3 0)) (3 (1 9 10) 2 10) 6 5) () ((10) 8 (9 7) 2 ()))
((((9) 4) (3 (7 7 6)) () 7 (10 7)))
((2) (((3 4) 2 (9) (5 8 8 0 2))) (5) (1))
((((2) 7) ()))
(() (() 1 (6 (9 1 2) () (6 7) (0 7 4 3 8)) 7) (((1 7 8) 9 1 (9 2)) ((5 2 10) (6) 4)))
((10 (2 6 5 9) ((4 10 0 10 4) (8 3 3 9 7) (5 0) 8 9) 5 10))
(((2 0 (2 1 0 0 5)) 10 () 0 10))
(((3) 5 (5 (4 2 2 8)) 1 (6 ())))
(() () (6) (() (6 0 (3 8)) 5) (6 2 1 6))
((5 () 6 9 9) () (4 9) (2 (10 2) 8 0 (8)) (((5 2 10 8 10)) (6 10 (8 9 5) () (6)) 7))
((5 (10 0)) ((7 6 (6 0) 7 (4)) () 6 (5 (7 0 6 3)) (4 () 4 (1 1) 9)))
(() (((7 8) (2) (9 3 9) 8 8) ()) (((2 2 4) (2) 1 1) (4) (6 2 1)) (((5 1 0 2 0)) ((1 7 5 7) ()) () 4))
((((4 7 2 8)) ((9 3 0 7) 5 5) 1) (((2 9 2))) (((4 8 8 10 7) 4 (10 8 4 3 7)) 3) (((8 1) (10 8 2 7 8) 5 (5 8 6 9) (0 9)) 5 0) (4))
(((8) ((3 2 0 1) ()) (0 () (7) (4 5 7)) 10) (1))
((((10 4 9 6) (5 5 4 5 4) 1 (1 1 5) 8) (7) 7 (0)) (((2 8 5) (0 5 2))) ())
(() ((() 8 (2 5 3 9)) () (4) (10 7 8 8 ()) 8) ((7 2 (0 0 0 5 1) (10 2 10 5)) 6) (((3 5 3 9) 10 () 9) ()) ())
((8) ((3 (0 2 8) 8 ()) ((3 9 2 4) 1 (9 10 6)) ((7 4 6) (3 7 4) () 2) 8) () (2 (2 6)))
(() (((5 6 2 4) (1 9 10 1 10) (1 6 0 7 3)) ((10 1) (4 7 4 0 1) (3 4 4 8 7) (5 10 4 0 8)) 9 (2 9)))
(((7 8 6 8 (2 3 7 1))) (9 (5 8)) (4 5) ((())) (((0 4 8 10) 3 5 7 2) 6 (() 8 7 6) () (8 1)))
(((() 8 (1) (6 3 8 0 3) 10) (() ()) ((7) 2 () 6 ()) 3) ((2 () 4) 7 ((6 4 1 9) (4 4 1 5) (6 7 1 3) (10 1 0 8))) ((1 0 ()) ((3 5) 1) (6 7 4) (3)) (6 () (10 (8 9 3) 1 (5 3)) ((1 3 4 9 8)) (9 10 (5 1) 1)))
((0 ((7 2 1)) 0 (9) 9) (() ()))
((6 10 5 9 (() (0 9) 7)))
((7 ((4) 4 (0 6) ()) (4 3 1 5 1) (6 (10 10 1)) 0) () (((10 0 10) 4 9) 7 2 2 7) (((6 10) (9 4 9) (1 9 10 7) (7) (4 3 3 7))))
((0 9))
(((() 5 () (4 8 1) 8)) (0 4 (10 (8 5 10) (7 8)) ((7 3 7) (2 6 6 6) () (8 1))) (4 () ((9 1 2 1 5) (10 4 5 10 3) 8)))
((10 (4 (6))) ((2 (0 4 3 4 4) 4) 0 3))
((() ()) ((3 1 (3 4 10)) (1 (3 3 5 4 8)) 10) (2 7 4 ((1 4 2 8) (5 10 0 7) 2 (7 2) 1)) (() ()) (((4 0) 8 4) 9 6 ((9 2 3 3))))
(((6 5) 5) (1 7 6 5) ((10 (0 7)) 8 0 5) (((4 1)) (() (2 6 7 4 3) 6 (9 7) (0 0)) ((6 9 9) (2 4 1 2) 0 6) (3)))
((1 ((7 10) 5 10 5 (3 2 3 7)) (2 10 2 0) 10) ((8 9 (4 8) 8) ((5 7) (1 4 8 10) 1 5 7)))
(((5) (9 (8 4 10 3 10) 4) 9 4) ((2) 9) ((4 5 0 (7) (0 1)) ((0) (6 2 3 10)) 9 5 ((2 7))) ((0) (()) (()) 9 1) (8 (0 (9) () (2 4) (10 6)) 2 7 4))
((2 (1) 2 2 4) () ((9) 10 ((4 7 10 2 2) (5)) 2) ((0 (3 7 8 4) () 10) 2 (() (4 6 2 10 5) (7) 5)))
(() (10 10))
((() 9 (7 (1) 2 () (10 3 6)) 2 10))
((1) (8 10 ((7 1 6) (6) () (2)) ()) ())
((((2 6) 10 10 (10 8 8) 3) 9 ((8 9) 2 8 (0 2 2) 5) 4))
((2 8 0 0) (((7 8 8 7 10) (0 0 2 5 0))) (8 ((10 1) () (7 0 1 6) 5) (() 0) (6 4 0)) (4 (8 (3 2 0 4 5)) ()))
((()))
((0 ((5 3 4 4 2) (5 7 7 7 1) (3 1 10 3 5) 4 0) (9 7 10 (4 3 4 0 3)) 7) () (((1 10 9 0 9) 8 (2 6 0 10 7) (7) 0) 5) (()) (((6 1 4 9)) 6 ((10 8)) 4 2))
((10 (4 (5 3) 4 1) ((0 5 1 1) 4 10 (8 6 5 1)) 0) ((5 2 ()) 4 10 (()) 7))
(() ((5 0 0 7) 4) ((()) (1 ()) (6)))
(() (((4 7 7 6 10) 5)) () (5 10 ((3 0) (5 1 9 0 3) 9) 3))
((() 1 2 2 1) ((3 (0)) 1))
((2 4 (7 1 (2 1 10) 10) 7))
(() ((4 (1 8 10) (0 5) (4 7 6 3 9) 1) (1 8 (4 10) 8 (6 1 3 1)) ((2 7 5) (7 10 9 2) 2) (8) (0)) (10) (((0 5 5 4)) 9 ((8 0 1 0 9) 4) ((10) (4 1 2 0))) (((4 4 3 1 8) 9 3 (5 3))))
((() ((7 8 8 9) 2) (3 9 6) (3 8)) (3 1) (3) ((0 0 2)))
(() ((6 8) (()) () 9 (8 () 7 7 9)) ((7 0 0) (() ()) (7) ((7 0 6 1 10) 8 (1))) (3 5 () ((1 10 0) 7 (9 7 3 10) 2) 8))
(((0 (5)) 4 5 1 ((3 4) 1 (5 4 7 5 1) (1 8))) (7 (1 8 8 (3 2 8) 9) () (9 7 5)) (() 1) ())
((((1 2) (2 10)) 9 5) (((7 1 9 9) 5 0 () 7) 2 9) () (2 (3 3 (3 8 0 8 1))) (1 ((6)) ((7 10 5) 6) ()))
((6 7 6 (() (0 4) 6 2 (1 6 9))) (5 (1 (7 5 10)) 8))
(((3) 9) (2 9))
(() (8 ((9) 7)))
(() ((8 10 7 9) 8 ((4 6 4)) ((5 1 2) 4 (9 3 5 1)) 5) (() 5 ((7 5) ()) (3 0 (4 2 8 0)) 5) ((4 2 7 6 5) (3 1 5 7 (6)) 6) ((9 5) (2 (2 1) (0 9 1) 3) ((10 6 1 1) (0 9 7 6 10))))
(() ((6) 6 8) (8) (3 (1)))
(((6 () (4 0 10 4)) (7 6 2 (4 1 2))) (((6 1 1 7))) ((10 10 1) (10 4 1 10 (3 2 0 3)) 5 (() (0 10 9 2))) ())
((() 4 (5 (8 10 4) 2 4 (7 8 3 4)) 8))
((9 (5 (4 9) (8) 4 (5 10 10 5))) (5 ((0) (10 4 10 2) ()) 5 0))
(((0 10 7 1 (4 6 2)) ((9 9) 5 ())) (1 ((10 2 0 7 0)) 5 7 ()) (3 (() 8 () (7 3 4 10 1) (5 6 3)) 2) () ())
((1 5) (6 6 7) () (((9 9 7 2) 7) (0 0) 6))
(() (() 6) (2) (2 9 0 9))
((3 (2 (6) 10) (() (3) 8 5) 10) (() ((0 8 2 7 1) (6 5 1) 8 (0)) ((8 4 2 8) 0) (2) 4) () (10 (4 (4 2 2 1) 2 0 2)))
(() () (() (0 8)) () ())
((((5 7 7 2) 7 5 2 (10 2 0 2 1)) 2) (6 10 2 ()))
(((1) (8 4) ((3 7 5 2 5) 5 4 (0 4 7 0) (1 5)) 7 ((9 5 3))) ((9) () ((5 1) 5 1 6 1) (0 (10) 6 8 ()) ((9 5) (8 0) (7))) ((6 9) ((3) 6 (2 1) (0 3)) 9 () 4) (4 (7 (5 4))))
((()) ((1 8 (4 8 7)) 7) (()) ((2 (2 9 5) (2 6)) ((3) (0 10 7 9) (2 4 1 3 6)) 9) ((9 9) 2))
((10 ((2) (7 8 7 7 9) 3 (6 4 6) 6) ((10 8 2 7) 1 (8))))
((((4 7 4 0 1) 6 (9 6 8 1 3)) (() 9 ()) 3) ((9 () 5 () 3) ((1) 6) 3))
((10) () (4) (() (1 5 (5 5 6 6)) ((1 3 7) (8 6 0 3) (2 9 1)) ()))
((2 1 (6 (8) 2) (6 (9 2 0 7 3) (8 10) 2 ())))
((((1 5) 10 (4) 4) 7) ((6 3 (4 1))) (4 4 () 6))
(() (0 ((5 6 7 10) 0 (6 10 2 4 7) 4 (6 10 10)) (1 0 0 (3 7 3 6)) (3 1)) (((9 3 9))) (0 (7 8 9 (4 2 4))) (0 (2 1)))
(((1 1 () 10 (6 4)) 4) (3 6 9 ((8 9 3 1 7) 1 0 7 3)))
(((1 (8 8 4 5) ()) ((10 8 3) (3) (7 2 4 6 1) 8 (6 10)) 2) (0) (4 (2 (5 5 1 8 9) 9 8 3) (7 7 9) 7))
((10 8 7 (8)) (() ((8 8) 3 9 (10 0) 3) (8) 0 (0 (9 3 3) 8)) ((6) 3 10 7 (5)) (10) (() ()))
(((3 9) 8) (((3 3 2 8 8) 10 9) 6) (((4 2 4) (3 1 5 4 2) 4 1 1) 3 4))
(() (6) (4 ((1 2 0) (2 10) 10) 8))
(((7 2 7 0 2) ((4 4 0 1) 6 () (2 8 1))) ((0)) ((6 (9 6 9 3))) ((3 (1 5) (8 9 2 9) 7) (() (4) 10) 1 ((4 7) 0 10 6) ()))
((8 2 ((0 7 3 0 0) 3 2) (() (10) () (1)) (8 () (6 6 2 5 5) (6 9))))
(((9 (7 0 1 8) () 2 ()) (5 2 (2 7 1 9 10) 5 (0 7 8))) (5 1 ((6 10 5 5) (0) 4 0 (2 5)) 0 6) (7 7 (3 2 1)) (((9)) 9 (() (3 6 8 5 10))))
((((9 1 5 10) 9 5 (1)) ((8 2 3) (4) (8) (4 4 5 9 5)) 8 5 9) (5 (3 (2 4 5) 3 8 2) ((3 0) 1 (9) (10 1))) () (2) ())
((((2 1 5 9) 5 (5 0 5 9 1) 8 4) 6 1 4))
((((0 5 0) 0 1) ()) (((6 6) 8 (1 4) 7 (7 4 2)) () ((7) 9 10 (0 10)) (4 4 ())) (((0 5 0) 6) 0) (10) ((4 (10 0) (7) 3 (1 1 9 10)) 6 () 3 ((0 8 8 2 5) (4 6) () 10 9)))
((()) (((0 3 7 5 8) 6 6) 10 (() (7 8 10 3 9)) 1 ()))
((2 () (5 (9) 10)) (5 (()) 3 (5 3) 2) ((() 0) (8 (5 10) 8 1)))
(((1 7 (0 4 1 2) (10) 9) ((3 9 2 10) 0 () (8 0 5 7 0))))
((5 () () 8))
((5 (6 ()) ((3 0 4 4) (4 1) (1 3 2 5) 10 2) (()) ()) () (2))
((2 3 4 ((6 1 5) 0) 10))
(() ())
((10 () 5 4 ((1 5) 1 (5) 0)))
((1 ((2) 9 ())) (() 3) (3 8 (6 1)) ((1) (10) 7 8 3))
(((5) (0 6 (5 7 9) 6) ()))
((() (4) 10 (())) (2 ((10 9 1) () ()) (() 7 10 (7))) ((3)) (((4 2 5) 1 (3 6 0 1 3)) 0 ((4 4) (5 8))) (0 ((6 2 10) 7 4 () ()) (8) 2 (10 6 (8 4 2))))
((7 (5 7 2 (8 0 2 0 3) (7 5)) ()) () ((() (5 6 3)) ((5 4 1))))
(((2 (9 5 3)) 1) (((10 9 5 2) 5 6 () ()) 8 5 9) (7 (() 5)))
(((10 (3 10 0 8))) ((() 8) 1))
((4) (()) ((() 1 (7 3 1 4 0)) ((8 1 7 3) (3 8 3 7 6) (7 0 1) ()) (10 10 4 () (6))))
((7 ((1))) () (9 4 () ((5 9) (5) (3 4 4 2 4) 10 (7 0 6 1 6))) (() 2))
((7) (6 (6 0 (5 8 5 2) 10 (9 8 10 8)) 0) ((7 (3) (0 4) (7 0 6 7)) ((8 6 2 9) 4) 7) (5 ((2 8 8 6 1))))
(() (10 (9 () 5 8 3) ((10 0) (2 2 9 8 10) (5 7) (2) 2)) (((3 10 6 1 4) (5 6) () 6 (6 8 6 0))) () ())
((8 10 (6 () 2 4 6) 0 ((0 5 6 3) 5)) ((8 1) 2 () ((6 10 7 4 4) (8) (8 5 10)) (3 5 9 6)) ((9 (6)) ((10 4 2) 3 4)) ((3) 3) (() 5))
((((0 4 0 1 5) (0 10 6 10) (10 4 10) (0 2 5) (0 10 6 8)) (5 7) ((7 7 10 10) (3 0 2) 7 ())) (3 ()))
((() 0) (0 ((8 10) 3 0 10)) (5 ((5 3 5 7) 1)))
((2 (6) 8 7 1) (((10 9) (9 10 6) 5 (8)) 6 (9 (1 9) (1 9 4 8) 6) ((9 0 8 4) (7 2 8))) (3) (((5 1 1)) (9 (0 1 3) 1 (8 5)) 7 8) (4 ((6 6) 2 4 (9 1))))
((9 (8) () 2 2) (0) (4 (2 1 (6) () 10) ((1 5 8 0 10) 1 (1 8 10)) (10 1 (4) (8 5 8 5 5) 4)) (10 () 0) (6))
((((1 1 10) 8 1 (8)) (7 6 4 3) 4) (((3 2 4) 7) (10) 9 ((0 2 1 0 3) 10 2) (() (9 0 2 4 8) 1 7 0)) (((0 0 0) () 8 (7 7 7) 9) ()))
((1 (() (2 3 4 3) 3 (5 0 4 3 7) 1)) (0) () (6) (((8 6 0 3 9) 9 8 (10 3 10 10 6)) (3 (6 3 5) (4 0 7)) 8 0 (6 4 (6 6 4 8 4) (6 7 10 1 3) 9)))
((8) () (((3 7 7 7 7) 4)) (2 (7 () 3 5)))
(((() 3 9 (10 3 8 10) ()) 10 1 4) (3 (5 (0 9 8) (3 4 0 1)) ((1 6 1 7) 1 (5 4) 5) ()) ((4 (6 9) (3 10 9 0 5)) (() 5 (1 6 9 3) 6 (5 10 6 10)) (3 (0) (6 8 6 0))) (4 7) (((2) (8 5 9 1 5) (2 8 3)) 3 (0 (9 3 1 4 9) (6)) 10))
((8 () (3) 3 5) (6 1 2) () () (((4 6 10 1 3) 1 1 6) 3 () ((0 2) 5 () (5)) ((9 7 0 8))))
((10 ()) ((() 5) (4 (6 2 10 8 9) (8 4 3 10) (8 3 8 0 5)) 5 (() (2 0 10 2 5)) 7) (3 () (5 6 4) 9 0))
((((1 7 5 1 4) (5)) 0 ((5 6 6 7) (5) (4 2 8 6 6))))
((6 ((4) 10) ()) () ((3 5 (2 2 1 7) (1 8 5 1)) (0 6 (6 6 10)) 0 9 5) (()) (((6 4 8) 1 (7 7 7 0))))
((() () 8 10 2) ())
(() (8 ((4 8 2 9 3) (4 0))))
(((() 0) (() 10 8 9)) ((6 5 3 (3 7 3))) (((5 0 2 3 9) 9 8) (0 3 (3 2 5) 9) 2 3) ((2 8 0 (4 2) 2) 2 ((8 3 10 0) (3 0)) 0))
((6 ((5 4 4)) 3 7 0) (((5 0 10 9) 6 1 (10 9 5) (4 4)) (5 (1 6 9 10) () 0 ()) () 9) (1 ((5 10) 10)) (3 () ((2 10) (7 5))) ((1 (0 7 8)) ((6 0 5)) 8 8))
((4 6))
((((1) (5 0 2 7 4) (3 0 1 2)) 0 (10 (10 2) 9 (9 6 1 7) 5) ((10 0 4 4) (4) 3)) (6 2) (1 (5 9) 9 9))
(((2 (8 9 3) 4 2) (5 4 () (3 3)) 2 8) () (((8 5 6 7) (10 0) (7 2 5 5 4) 6 (3))) (0 (0 ()) ((4 7 9) 4 (3 3 8 2 8) 8) (10 () (4)) 5) (((7 10) 7 (0 3 8) (4 4 8 7)) ((2 0 5 1 5) 0 6 (4 1 8 4 5) 7) 3 (6) (8 () 2)))
((10 (1 (3 8 7 5) (2 3 3) (3 3 3)) (7 1 () (5 8 7 9))) ((4) (8 1 4 (2 3 9)) 4 (8 8 (8 10) (9 7 6))) (1 (10 1) 5) (() ((5) ()) ((10 10 5 4 10) (9 0 0 8 3) () (0 4 0 4 9) 3) 3 (() (5 0) 10 (3 5))) (((9 5 1) (4 5) 8 1)))
((()) (8 ((10 4 8 4) (1) (6 2) 7 9) 8) (7 2 ((2 3 0) (5 0)) 8) ((2) 0 4 6 7))
((1 4 ((5 10 6 5) 8) 1 10) (2) (((6 9) (3 2 9 7 6) (7 10 3)) (3 (4 3 4)) 10 4 2))
((() (3 ())) (((7 0 3 3 6)) (3 3)))
((0 9 8) (4 9 (3 (2 8 7 2)) 4) (8 0) (4 0 7 ()) ())
((8 ((2 4 0 2) (5 10 2) 9 (3 5)) 7 (5 (4 5 6 3) (4 7 10 0) 7 1)) (3 7 (2)) (((9) 3 (10 8 0))) ((4 () (9 7 0) (5 4) 8)) (() (9 (0 10 1 3) (4 5 8) 2 6) 9 (1 0 7 (0 1))))
((((6 5) (7 7) (8 5) 1 7)) (4 (0 10 9 4)) ((6 (5) 0 7 (10 9 3 6 4))) (((0 3) (1 3 3 8 0) 2 4) (9) ()) (((8) 0 (4 6 2 4 3) 3 ()) ((6 4 10 7) 2 1)))
((9))
((((8 9) (2) 7 3 7)) (() ((8) () (3 4 4 2) 2 5) 2) (3 6 10))
((() 2 1 3 ()) (10 (() (8 1) 3 8) (() () (4 7 1 6 10) (1 9 1 6))) (() 9 (1 (1 0) (4) () 7) 8) () (4))
(((6 8 9 (10 1 2 2 2) (4 0 4 2)) ((5 8 3 2 7) 9 0 1 (8 7 3 6))) ())
((1 () 4 10 ((6))))
((9 ((9 6 10) 8)) (6 (5 2 (4 9 2 7) (9 7) 10)))
)

179
day13-scratch.lisp Normal file
View File

@@ -0,0 +1,179 @@
;; https://adventofcode.com/2022/day/13
;; so, generally i need to implement calculation of ordering on the nested structures
;; each packet is a list, containst lists or integers
;; rules for comparison:
;; - if both are integers : lowest input is with lowest int
;; - if both are lists : compare lists in order by elements. if one runs out of items - it's lower
;; - if one is list and another is int : convert integer to list of one element and compare. i.e compare with head of list, and equal only if other list is of size 1
;; i'd really like to just read in Sexps
(with-open-file (in "day13-test.txt")
(read in))
;; ok, i have list of the lists \ packets
;; now i'd want to compare them pairwise. what would be process?
(defun nest-< (left right)
(cond
((and (numberp left) (numberp right)) (< left right))
((numberp left) (nest-< (list left) right))
((numberp right) (nest-< left (list right)))
((and (listp left) (listp right))
(cond
((and (not left) (not right)) nil) ; both equal and empty
((not left) t) ; only left empty, left is smaller
((not right) nil) ; only right is empty, left is bigger
(t (if (equal (first left) (first right))
(nest-< (rest left) (rest right))
(nest-< (first left) (first right))))))
(t 'default)))
(nest-< 4 3)
(nest-< 3 4)
(listp '(1 234))
(listp '())
(listp nil)
(nest-<
'(1 (2 (3 (4 (5 6 7)))) 8 9)
'(1 (2 (3 (4 (5 6 0)))) 8 9))
(nest-< '(9)
'((8 7 6)))
(nest-<
'((1) (2 3 4))
'((1) 4))
;; ok, this seems to work
;; how do i order input? hashmap would be nice?
;; if to wrap into list pairwise - should do so programmatically
(defparameter *day13-all-list* nil)
(setq *day13-all-list*
(with-open-file (in "day13-test.txt")
(read in)))
;; or i could break them into two lists? and map pairwise?
;; maybe with DO ?
(defparameter *day13-lefts* nil)
(defparameter *day13-rights* nil)
(loop for i from 0 below (length *day13-all-list*)
when (= 0 (mod i 2)) do (push (nth i *day13-all-list*) *day13-lefts*)
when (= 1 (mod i 2)) do (push (nth i *day13-all-list*) *day13-rights*))
(setq *day13-lefts* (reverse *day13-lefts*))
(setq *day13-rights* (reverse *day13-rights*))
nil
(mapcar #'nest-< *day13-lefts* *day13-rights*)
(defparameter *day13-indices* nil)
(setq *day13-indices* (loop
for i from 0 below (length *day13-lefts*)
when (nest-< (nth i *day13-lefts*) (nth i *day13-rights*))
collect (1+ i)))
(apply #'+ *day13-indices*)
(length *day13-lefts*)
(length *day13-rights*)
*day13-indices*
;; well, how should this compare:
;; [[9]]
;; [[[[8,9],[2],7,3,7]],[[],[[8],[],[3,4,4,2],2,5],2],[3,6,10]]
;; first is bigger, right?
(apply #'+ '( 2 2 2 2))
(apply #'+ *day13-indices*) ; 5739 , but not correct answer. why =C
(defparameter *day13-artem-indices* (list 1 7 11 16 18 19 20 23 26 27 28 30 33 35 37 38 39 42 43 44 45 47 50 51 52 54 55
60 61 63 66 67 70 71 74 75 78 79 81 82 83 85 86 87 88 89 91 95 97 98 99 101 103
105 108 110 111 112 113 114 115 120 122 123 127 134 136 139 140 142 144 145
146 149 150))
(ql:quickload 'fset)
(fset:set *day13-indices*)
(fset:set-difference (fset:convert 'fset:set *day13-artem-indices*)
(fset:convert 'fset:set *day13-indices*))
(print *day13-indices*)
(print *day13-artem-indices*)
;; 86, is in Artems and not in mine
;; Comparing:
(nest-<
'(NIL (6 (7 (7 6 4 10 10) NIL 0 NIL) (1) ((1 4 5 9 8) 6 (6 4 2) (5 3 7) 10))
(6 (2 3 10 (0 6 9 10)) (0) ((10 2) 4))
((NIL 1 0 NIL 7) ((0 4) 5 (9 3 7 10 1) 2) 0 4 4))
'((0 10 8) ((8 9 (1 10 9 3) 2 1))))
(length *day13-lefts*)
(numberp nil)
(not '(1))
(not '())
(print (nth 85 *day13-lefts*))
(print (nth 85 *day13-rights*))
(nest-< (nth 85 *day13-lefts*) (nth 85 *day13-rights*))
;; ((2) (((3 4) 2 (9) (5 8 8 0 2))) (5) (1))
;; ((((2) 7) NIL))
;;
;; oh. i shouldn't just compare (list left)
;; i need to pass in rest. in what way?
;; so, comparing of the rest is required
(nest-< '(2)
'((2) 7)) ; here it is...
;; so in case it IS equal in (nest-< (first left) (first right))
;; need to check tails
;; so, i need to return -1 0 and 1 i guess now
;; negative is less than
(defun nest-2-< (left right)
(cond
((and (numberp left) (numberp right)) (- left right))
((numberp left) (nest-2-< (list left) right))
((numberp right) (nest-2-< left (list right)))
((and (listp left) (listp right))
(cond
((and (not left) (not right)) 0) ; both equal and empty
((not left) -1) ; only left empty, left is smaller
((not right) 1) ; only right is empty, left is bigger
(t (if (equal (first left) (first right))
(nest-2-< (rest left) (rest right))
(let ((head-comparison (nest-2-< (first left) (first right))))
(if (= 0 head-comparison)
(nest-2-< (rest left) (rest right))
head-comparison))))))
(t 'default)))
(nest-2-< '(2)
'((2) 7)) ; here it is...
;;; PART 2
;; now working with the whole list - i need to sort it with that function
(let ((sorted (sort (copy-list *day13-all-list*) (lambda (left right)
(< (nest-2-< left right) 0)))))
(* (1+ (position '((2)) sorted :test #'equal))
(1+ (position '((6)) sorted :test #'equal))))
(sort '(5 1 432 2 14) #'>)
(sort '(5 1 432 2 14) #'<)
(< 1 2)
(find '(1 2) '(1 (1 3) (1 2)) :test #'equal)
(position '(1 2) '(1 (1 3) (1 2)) :test #'equal)

29
day13-test.txt Normal file
View File

@@ -0,0 +1,29 @@
(
((2))
((6))
(1 1 3 1 1)
(1 1 5 1 1)
((1) (2 3 4))
((1) 4)
(9)
((8 7 6))
((4 4) 4 4)
((4 4) 4 4 4)
(7 7 7 7)
(7 7 7)
()
(3)
((()))
(())
(1 (2 (3 (4 (5 6 7)))) 8 9)
(1 (2 (3 (4 (5 6 0)))) 8 9)
)

54
day13.lisp Normal file
View File

@@ -0,0 +1,54 @@
;; https://adventofcode.com/2022/day/13
;; (defparameter *day13-file-name* "day13-test.txt")
(defparameter *day13-file-name* "day13-input.txt")
(defparameter *day13-all-list* nil)
;; 5739 is too low & incorrect
;; 6398 too high
(defun nest-2-< (left right)
(cond
((and (numberp left) (numberp right)) (- left right))
((numberp left) (nest-2-< (list left) right))
((numberp right) (nest-2-< left (list right)))
((and (listp left) (listp right))
(cond
((and (not left) (not right)) 0) ; both equal and empty
((not left) -1) ; only left empty, left is smaller
((not right) 1) ; only right is empty, left is bigger
(t (if (equal (first left) (first right))
(nest-2-< (rest left) (rest right))
(let ((head-comparison (nest-2-< (first left) (first right))))
(if (= 0 head-comparison)
(nest-2-< (rest left) (rest right))
head-comparison))))))
(t 'default)))
(progn
(defparameter *day13-all-list* nil)
(setq *day13-all-list*
(with-open-file (in *day13-file-name*)
(read in)))
(defparameter *day13-lefts* nil)
(defparameter *day13-rights* nil)
(loop for i from 0 below (length *day13-all-list*)
when (= 0 (mod i 2)) do (push (nth i *day13-all-list*) *day13-lefts*)
when (= 1 (mod i 2)) do (push (nth i *day13-all-list*) *day13-rights*))
(setq *day13-lefts* (reverse *day13-lefts*))
(setq *day13-rights* (reverse *day13-rights*))
(defparameter *day13-indices* nil)
(setq *day13-indices* (loop
for i from 0 below (length *day13-lefts*)
when (< (nest-2-< (nth i *day13-lefts*) (nth i *day13-rights*)) 0)
collect (1+ i)))
(apply #'+ *day13-indices*))
;;; PART 2
(let ((sorted (sort (copy-list *day13-all-list*) (lambda (left right)
(< (nest-2-< left right) 0)))))
(* (1+ (position '((2)) sorted :test #'equal))
(1+ (position '((6)) sorted :test #'equal))))
;; 24477 yay

147
day14-input.txt Normal file
View File

@@ -0,0 +1,147 @@
502,19 -> 507,19
523,100 -> 523,104 -> 519,104 -> 519,111 -> 528,111 -> 528,104 -> 526,104 -> 526,100
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
507,117 -> 521,117 -> 521,116
517,34 -> 522,34
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
510,75 -> 510,78 -> 505,78 -> 505,84 -> 518,84 -> 518,78 -> 515,78 -> 515,75
503,34 -> 508,34
501,15 -> 506,15
523,136 -> 523,138 -> 518,138 -> 518,145 -> 535,145 -> 535,138 -> 528,138 -> 528,136
513,113 -> 513,114 -> 527,114
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
523,136 -> 523,138 -> 518,138 -> 518,145 -> 535,145 -> 535,138 -> 528,138 -> 528,136
530,150 -> 535,150
526,133 -> 526,131 -> 526,133 -> 528,133 -> 528,129 -> 528,133 -> 530,133 -> 530,129 -> 530,133
523,100 -> 523,104 -> 519,104 -> 519,111 -> 528,111 -> 528,104 -> 526,104 -> 526,100
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
510,34 -> 515,34
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
510,75 -> 510,78 -> 505,78 -> 505,84 -> 518,84 -> 518,78 -> 515,78 -> 515,75
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
524,34 -> 529,34
498,46 -> 502,46
510,46 -> 514,46
509,19 -> 514,19
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
526,133 -> 526,131 -> 526,133 -> 528,133 -> 528,129 -> 528,133 -> 530,133 -> 530,129 -> 530,133
497,13 -> 502,13
504,46 -> 508,46
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
545,155 -> 545,157 -> 541,157 -> 541,160 -> 556,160 -> 556,157 -> 550,157 -> 550,155
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
510,75 -> 510,78 -> 505,78 -> 505,84 -> 518,84 -> 518,78 -> 515,78 -> 515,75
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
507,43 -> 511,43
523,100 -> 523,104 -> 519,104 -> 519,111 -> 528,111 -> 528,104 -> 526,104 -> 526,100
506,31 -> 511,31
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
510,75 -> 510,78 -> 505,78 -> 505,84 -> 518,84 -> 518,78 -> 515,78 -> 515,75
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
507,117 -> 521,117 -> 521,116
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
534,152 -> 539,152
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
495,19 -> 500,19
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
523,136 -> 523,138 -> 518,138 -> 518,145 -> 535,145 -> 535,138 -> 528,138 -> 528,136
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
527,152 -> 532,152
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
533,148 -> 538,148
510,75 -> 510,78 -> 505,78 -> 505,84 -> 518,84 -> 518,78 -> 515,78 -> 515,75
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
516,46 -> 520,46
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
545,155 -> 545,157 -> 541,157 -> 541,160 -> 556,160 -> 556,157 -> 550,157 -> 550,155
501,119 -> 501,120 -> 512,120 -> 512,119
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
512,25 -> 517,25
526,133 -> 526,131 -> 526,133 -> 528,133 -> 528,129 -> 528,133 -> 530,133 -> 530,129 -> 530,133
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
513,31 -> 518,31
526,133 -> 526,131 -> 526,133 -> 528,133 -> 528,129 -> 528,133 -> 530,133 -> 530,129 -> 530,133
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
520,31 -> 525,31
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
482,21 -> 482,22 -> 490,22
510,75 -> 510,78 -> 505,78 -> 505,84 -> 518,84 -> 518,78 -> 515,78 -> 515,75
498,17 -> 503,17
523,136 -> 523,138 -> 518,138 -> 518,145 -> 535,145 -> 535,138 -> 528,138 -> 528,136
545,155 -> 545,157 -> 541,157 -> 541,160 -> 556,160 -> 556,157 -> 550,157 -> 550,155
513,43 -> 517,43
523,100 -> 523,104 -> 519,104 -> 519,111 -> 528,111 -> 528,104 -> 526,104 -> 526,100
505,17 -> 510,17
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
509,28 -> 514,28
545,155 -> 545,157 -> 541,157 -> 541,160 -> 556,160 -> 556,157 -> 550,157 -> 550,155
537,150 -> 542,150
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
501,43 -> 505,43
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
501,119 -> 501,120 -> 512,120 -> 512,119
507,37 -> 511,37
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
523,100 -> 523,104 -> 519,104 -> 519,111 -> 528,111 -> 528,104 -> 526,104 -> 526,100
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
501,119 -> 501,120 -> 512,120 -> 512,119
510,40 -> 514,40
488,19 -> 493,19
482,21 -> 482,22 -> 490,22
494,15 -> 499,15
523,136 -> 523,138 -> 518,138 -> 518,145 -> 535,145 -> 535,138 -> 528,138 -> 528,136
526,133 -> 526,131 -> 526,133 -> 528,133 -> 528,129 -> 528,133 -> 530,133 -> 530,129 -> 530,133
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
526,133 -> 526,131 -> 526,133 -> 528,133 -> 528,129 -> 528,133 -> 530,133 -> 530,129 -> 530,133
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
545,155 -> 545,157 -> 541,157 -> 541,160 -> 556,160 -> 556,157 -> 550,157 -> 550,155
513,97 -> 513,89 -> 513,97 -> 515,97 -> 515,94 -> 515,97 -> 517,97 -> 517,94 -> 517,97 -> 519,97 -> 519,93 -> 519,97 -> 521,97 -> 521,88 -> 521,97 -> 523,97 -> 523,94 -> 523,97
523,136 -> 523,138 -> 518,138 -> 518,145 -> 535,145 -> 535,138 -> 528,138 -> 528,136
504,40 -> 508,40
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
526,133 -> 526,131 -> 526,133 -> 528,133 -> 528,129 -> 528,133 -> 530,133 -> 530,129 -> 530,133
523,100 -> 523,104 -> 519,104 -> 519,111 -> 528,111 -> 528,104 -> 526,104 -> 526,100
545,155 -> 545,157 -> 541,157 -> 541,160 -> 556,160 -> 556,157 -> 550,157 -> 550,155
516,28 -> 521,28
545,155 -> 545,157 -> 541,157 -> 541,160 -> 556,160 -> 556,157 -> 550,157 -> 550,155
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
491,17 -> 496,17
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
526,133 -> 526,131 -> 526,133 -> 528,133 -> 528,129 -> 528,133 -> 530,133 -> 530,129 -> 530,133
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
497,72 -> 497,63 -> 497,72 -> 499,72 -> 499,65 -> 499,72 -> 501,72 -> 501,71 -> 501,72 -> 503,72 -> 503,67 -> 503,72 -> 505,72 -> 505,63 -> 505,72 -> 507,72 -> 507,71 -> 507,72 -> 509,72 -> 509,70 -> 509,72 -> 511,72 -> 511,69 -> 511,72
523,100 -> 523,104 -> 519,104 -> 519,111 -> 528,111 -> 528,104 -> 526,104 -> 526,100
513,113 -> 513,114 -> 527,114
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
510,75 -> 510,78 -> 505,78 -> 505,84 -> 518,84 -> 518,78 -> 515,78 -> 515,75
488,59 -> 488,51 -> 488,59 -> 490,59 -> 490,52 -> 490,59 -> 492,59 -> 492,55 -> 492,59 -> 494,59 -> 494,52 -> 494,59 -> 496,59 -> 496,50 -> 496,59 -> 498,59 -> 498,58 -> 498,59 -> 500,59 -> 500,56 -> 500,59 -> 502,59 -> 502,56 -> 502,59 -> 504,59 -> 504,57 -> 504,59
541,152 -> 546,152
523,136 -> 523,138 -> 518,138 -> 518,145 -> 535,145 -> 535,138 -> 528,138 -> 528,136

385
day14-scratch.lisp Normal file
View File

@@ -0,0 +1,385 @@
;; https://adventofcode.com/2022/day/14
;; so, 2d space vertical and left-right. point from which sand falls down and lines (likely horizontal || vertical) that collide with falling sand
;; gathering input. i've only thought of doing initialization in two sweeps.
;;
;; one to get "leftmost" and "rightmost", top & bottom coords.
;; so that i'm putting it all into one class that has accessors that translate it to
;; ordinary 2d array
;;
;; sand is pouring from (500, 0) - (column, row) - from
;; columns : left -> right
;; rows : top to bottom
;; top is already 0
;;
;; chars: #\. - empty space
;; #\# - stone
;; #\o - falling sand ; will not be actually stored I suppose
;; #\x - resting sand
(defclass arena ()
((grid :initarg :grid :initform (error "supply value for :grid"))
(leftmost :initarg :left :accessor leftmost)
(bottommost :initarg :bottom :accessor bottommost)
(rightmost :initarg :right :accessor rightmost)))
(defun make-arena (left right bottom)
(let ((cols-num (1+ (- right left)))
(rows-num (1+ bottom)))
(make-instance 'arena :left left :right right :bottom bottom
:grid (make-array (list rows-num cols-num)
:initial-element #\.))))
(make-array '(2 5) :initial-element "hello")
;; now. translation for coordinates, and in a way that would allow writing into place?
;; can i just defmethod getf for nonexistent place?
(defparameter *test-arena* (make-arena 100 110 7))
(setf (aref (slot-value *test-arena* 'grid) 0 4) #\*)
;; or just do through macros? nah, try functions first, it's just i liked idea of aref
;; (x y) -> (row col) in grid
(defun translate-coords (arena x y)
(list y (- x (leftmost arena))))
(destructuring-bind (rrow ccol) (translate-coords *test-arena* 104 2)
(list rrow ccol))
(defun get-place (arena x y)
(destructuring-bind (row col) (translate-coords arena x y)
(aref (slot-value arena 'grid) row col)))
(get-place *test-arena* 104 0)
(defun set-place (arena x y value)
(destructuring-bind (row col) (translate-coords arena x y)
(setf (aref (slot-value arena 'grid) row col) value)))
(set-place *test-arena* 104 1 #\&)
(slot-value *test-arena* 'grid)
;; ok. now funciton that would add lines from input?
(ql:quickload 'cl-ppcre)
(defun input-line-to-rock-coords (line)
(mapcar (lambda (coords) (mapcar #'parse-integer (cl-ppcre:split "," coords)))
(cl-ppcre:split " -> " line)))
(input-line-to-rock-coords " 503,4 -> 502,4 -> 502,9 -> 494,9 ")
;; now. i want to do first pass and find leftmost, rightmost and bottommost
(defparameter *day14-input-file* "day14-test.txt")
(mapcar #'input-line-to-rock-coords (uiop:read-file-lines *day14-input-file*))
;; now find flatten list in Alexandria
(ql:quickload 'alexandria)
(defparameter *test-input-flat-coords*
(alexandria:flatten (mapcar #'input-line-to-rock-coords (uiop:read-file-lines *day14-input-file*))))
;; well, it fully flattens it by default. maybe there it's configurable?
;; using destructuring of pairs would be better
(loop
for (x y) on *test-input-flat-coords*
by #'cddr
do (format t "x:~a y:~a~%" x y))
(loop
for (x y) on *test-input-flat-coords*
by #'cddr
minimize x
do (print x))
(loop
for (x y) on *test-input-flat-coords*
by #'cddr
minimize y
do (print y))
(loop
for (x y) on *test-input-flat-coords*
by #'cddr
collect x into x-es
collect y into y-es
finally (return (list (apply #'min x-es) (apply #'min y-es))))
;; this : I was forgetting :by #'cddr
;; here's limits
(let ((flat-coords
(alexandria:flatten (mapcar #'input-line-to-rock-coords (uiop:read-file-lines *day14-input-file*))
)))
(loop
for (x y) on flat-coords
by #'cddr
minimize x into leftmost
maximize x into rightmost
maximize y into bottommost
finally (return (list leftmost rightmost bottommost))))
;; next - build arena
;; building empty arena
(setq *test-arena*
(let ((flat-coords
(alexandria:flatten (mapcar #'input-line-to-rock-coords (uiop:read-file-lines *day14-input-file*)))))
(destructuring-bind (leftmost rightmost bottommost)
(loop
for (x y) on flat-coords
by #'cddr
minimize x into leftmost
maximize x into rightmost
maximize y into bottommost
finally (return (list leftmost rightmost bottommost)))
(make-arena leftmost rightmost bottommost))))
(slot-value *test-arena* 'grid)
;; now adding rock lines from coord list
'(((498 4) (498 6) (496 6)) ((503 4) (502 4) (502 9) (494 9)))
;; and one line is
(defparameter *test-rock-line-coords* '((498 4) (498 6) (496 6)))
(loop
for (x y) in *test-rock-line-coords*
do (format t "x:~a y:~a~%" x y))
;; can i take two at a time?
;; well, maybe use DO
(do* ((coords-list *test-rock-line-coords* (cdr coords-list))
(first-coords (first *test-rock-line-coords*) (first coords-list))
(second-coords (second *test-rock-line-coords*) (second coords-list)))
((not second-coords) "end")
(format t "~a -> ~a, in ~a~%" first-coords second-coords coords-list))
;; yup.
;; now in this DO i have "start point" -> "end point"
;; let's do separate function that
(let ((start-x 10)
(start-y 1)
(end-x 25)
(end-y 1))
(loop for x from start-x to end-x do
(loop for y from start-y to end-y do
(format t "(~a, ~a), " x y)))
(terpri))
(let ((start-x 100)
(start-y 2)
(end-x 100)
(end-y 11))
(loop for x from start-x to end-x do
(loop for y from start-y to end-y do
(format t "(~a, ~a), " x y)))
(terpri))
;; that works
(defun put-rock-line (arena start-x end-x start-y end-y)
(loop for x from start-x to end-x do
(progn
(loop for y from start-y to end-y
do (set-place arena x y #\#)))))
;; yas.
;; now do this for each pair of coords
(put-rock-line *test-arena* 101 109 1 1)
(setq *test-arena* (make-arena 100 110 7))
(slot-value *test-arena* 'grid)
(get-place *test-arena* 101 1)
(put-rock-line *test-arena* 101 109 1 1)
(set-place *test-arena* 101 1 #\#)
(set-place *test-arena* 102 1 #\#)
;; copy over previous per-2-coords-loop:
(loop
for (x y) in *test-rock-line-coords*
do (format t "x:~a y:~a~%" x y))
;; can i take two at a time?
;; well, maybe use DO
(do* ((coords-list *test-rock-line-coords* (cdr coords-list))
(first-coords (first *test-rock-line-coords*) (first coords-list))
(second-coords (second *test-rock-line-coords*) (second coords-list)))
((not second-coords) "end")
(destructuring-bind ((start-x start-y) (end-x end-y))
(list first-coords second-coords)
(put-rock-line *test-arena* start-x end-x start-y end-y) ))
;; yes
(array-dimension (make-array '(3 10)) 1)
(get-place *test-arena* 101 3)
(get-place *test-arena* 0 0)
(slot-value *test-arena* 'grid)
;; oh, it doesn't work when numbers are in wrong order.
;; ugh the LOOP for i from 9 to 3
;; how do i deal with that?
(defun put-rock-line (arena start-x end-x start-y end-y)
(let ((start-x (min start-x end-x))
(end-x (max start-x end-x))
(start-y (min start-y end-y))
(end-y (max start-y end-y)))
(loop for x from start-x to end-x do
(progn
(loop for y from start-y to end-y
do (set-place arena x y #\#))))))
(defun put-rock-chain (arena rock-coods-chain)
(do* ((coords-list rock-coods-chain (cdr coords-list))
(first-coords (first rock-coods-chain) (first coords-list))
(second-coords (second rock-coods-chain) (second coords-list)))
((not second-coords) "end")
(destructuring-bind ((start-x start-y) (end-x end-y))
(list first-coords second-coords)
(put-rock-line arena start-x end-x start-y end-y) )))
(defun put-rock-lines (arena rock-coords-lines)
(loop
for rock-coord-line in rock-coords-lines
do (put-rock-chain arena rock-coord-line)))
(defparameter *test-input-coords-chains* nil)
(setq *test-input-coords-chains*
(mapcar #'input-line-to-rock-coords
(uiop:read-file-lines *day14-input-file*)))
(slot-value *test-arena* 'grid)
(put-rock-lines *test-arena* *test-input-coords-chains*)
;; i think this works.
;; seems to be the complete initialization
;; now for the sand simulation part.
;; again, envision this as lots of loops
;; inner loop - one new sand
;; created at (500, 0), starts dropping
;; either until out-of-bounds
;; or settled by checks of lower-part
;; out-of-bounds is air
;; and . char is air
(defun is-point-air (x y arena)
(or (eq #\. (get-place arena x y))
(not (get-place arena x y))))
(is-point-air 498 4 *test-arena*)
(is-point-air 498 3 *test-arena*)
(is-point-air 500 0 *test-arena*)
(is-point-air 502 3 *test-arena*)
(is-point-air 502 4 *test-arena*)
(defun sand-check-next-move (sand-x sand-y arena)
(let* ((next-y (1+ sand-y))
(possible-next-steps (list (list sand-x next-y)
(list (1- sand-x) next-y)
(list (1+ sand-x) next-y))))
(first (remove-if-not (lambda (coords)
(is-point-air (first coords) (second coords) arena))
possible-next-steps))))
;; let's return next step or nil if it rests
(sand-check-next-move 502 3 *test-arena*)
(get-place *test-arena* 501 4)
(get-place *test-arena* 503 4)
(sand-check-next-move 500 7 *test-arena*)
(sand-check-next-move 500 8 *test-arena*)
(get-place *test-arena* 501 4)
(get-place *test-arena* 503 4)
(aref (slot-value *test-arena* 'grid) 0)
(array-storage-vector (slot-value *test-arena* 'grid))
(defun out-of-bounds (x y arena)
(not (get-place arena x y)))
;; well, this seems to work
;; now the one grain loop
(let ((arena *test-arena*))
(do*
((prev-coords nil sand-coords)
(sand-coords '(500 0) (sand-check-next-move
(first sand-coords) (second sand-coords) arena)))
((or (not sand-coords) ; sand rests
(out-of-bounds (first sand-coords) (second sand-coords) arena)) ; end condition - rest or out of bounds
(when (not sand-coords)
(set-place arena (first prev-coords) (second prev-coords) #\x)))
(format t "sc: ~a, prev: ~a~%" sand-coords prev-coords)))
(init-arena)
(slot-value *test-arena* 'grid)
(not (get-place *test-arena* 500 0 ))
(set-place *test-arena* 500 0 #\x)
(defun drop-sand-unit (arena)
(do*
((prev-coords nil sand-coords)
(sand-coords '(500 0) (sand-check-next-move
(first sand-coords) (second sand-coords) arena)))
((or (not sand-coords) ; sand rests
(out-of-bounds (first sand-coords) (second sand-coords) arena)) ; end condition - rest or out of bounds
(when (not sand-coords)
(set-place arena (first prev-coords) (second prev-coords) #\x)))
(format t "sc: ~a, prev: ~a~%" sand-coords prev-coords)))
;; ok, i got inner loop
;; now what? run that loop until the grain of sand ends up our of bounds
;; what are we calculating?
;; "how many units of sand come to rest until they start falling into abyss"
;; so. do ?
(let ((arena *test-arena*))
(do ((sand-units 0 (1+ sand-units))
(drop-result (drop-sand-unit arena) (drop-sand-unit arena)))
((not drop-result)
sand-units)))
(slot-value *test-arena* 'grid)
(defun drop-sand-unit-abyss (arena)
(do ((sand-units 0 (1+ sand-units))
(drop-result (drop-sand-unit arena) (drop-sand-unit arena)))
((not drop-result)
sand-units)))
;;; PART 2
;; let's not do floor infinite.
;; let's just give it enough left-to-right?
;; since the triangle is 2 right angle triangles, then bottom is 2x height
;; so, let's add 4x height of the floor?
;;
;; new bottommost =
(+ 2 bottommost)
;; new leftmost =
(min leftmost
(- 500 (* 2 bottommost)))
;; new rightmost =
(max rightmost
(+ 500 (* 2 bottommost)))
;; and add new rock-line?
;; just through function that adds a rockline
(slot-value *test-arena* 'grid)
;; and now i'd like a more compact printing.
;; how'd i do that?
;; surely there's a way to get access ot a slice of the 2d array?
(let* ((arena *test-arena*)
(array (slot-value arena 'grid)))
(dotimes (row (array-dimension array 0))
(dotimes (col (array-dimension array 1))
(format t "~a" (aref array row col)))
(terpri)))
(drop-sand-unit *test-arena*)

2
day14-test.txt Normal file
View File

@@ -0,0 +1,2 @@
498,4 -> 498,6 -> 496,6
503,4 -> 502,4 -> 502,9 -> 494,9

198
day14.lisp Normal file
View File

@@ -0,0 +1,198 @@
;; https://adventofcode.com/2022/day/14
(ql:quickload 'cl-ppcre)
(ql:quickload 'alexandria)
;; (defparameter *day14-input-file* "day14-test.txt")
(defparameter *day14-input-file* "day14-input.txt")
(defclass arena ()
((grid :initarg :grid :initform (error "supply value for :grid"))
(leftmost :initarg :left :accessor leftmost)
(bottommost :initarg :bottom :accessor bottommost)
(rightmost :initarg :right :accessor rightmost)))
(defun make-arena (left right bottom)
(let ((cols-num (1+ (- right left)))
(rows-num (1+ bottom)))
(make-instance 'arena :left left :right right :bottom bottom
:grid (make-array (list rows-num cols-num)
:initial-element #\.))))
(defparameter *test-arena* nil)
;; (x y) -> (row col) in grid
(defun translate-coords (arena x y)
(list y (- x (leftmost arena))))
(defun get-place (arena x y)
(destructuring-bind (row col) (translate-coords arena x y)
(when (and (<= 0 row) (<= 0 col)
(< row (array-dimension (slot-value arena 'grid) 0))
(< col (array-dimension (slot-value arena 'grid) 1))
)
(aref (slot-value arena 'grid) row col))))
(defun set-place (arena x y value)
(destructuring-bind (row col) (translate-coords arena x y)
(when (and (<= 0 row) (<= 0 col)
(< row (array-dimension (slot-value arena 'grid) 0))
(< col (array-dimension (slot-value arena 'grid) 1))
)
(setf (aref (slot-value arena 'grid) row col) value))))
(defun input-line-to-rock-coords (line)
(mapcar (lambda (coords) (mapcar #'parse-integer (cl-ppcre:split "," coords)))
(cl-ppcre:split " -> " line)))
(defparameter *test-input-flat-coords* nil)
(defun put-rock-line (arena start-x end-x start-y end-y)
(let ((start-x (min start-x end-x))
(end-x (max start-x end-x))
(start-y (min start-y end-y))
(end-y (max start-y end-y)))
(loop for x from start-x to end-x do
(progn
(loop for y from start-y to end-y
do (set-place arena x y #\#))))))
(defun put-rock-lines (arena rock-coords-lines)
(loop
for rock-coord-line in rock-coords-lines
do (put-rock-chain arena rock-coord-line)))
(defparameter *test-input-coords-chains* nil)
(defun put-rock-chain (arena rock-coods-chain)
(do* ((coords-list rock-coods-chain (cdr coords-list))
(first-coords (first rock-coods-chain) (first coords-list))
(second-coords (second rock-coods-chain) (second coords-list)))
((not second-coords) "end")
(destructuring-bind ((start-x start-y) (end-x end-y))
(list first-coords second-coords)
(put-rock-line arena start-x end-x start-y end-y) )))
;; reinit things
;; (init-arena)
(defun init-arena ()
(setq *test-input-flat-coords*
(alexandria:flatten (mapcar #'input-line-to-rock-coords
(uiop:read-file-lines *day14-input-file*))))
;; building empty arena
(setq *test-arena*
(let ((flat-coords
(alexandria:flatten (mapcar #'input-line-to-rock-coords (uiop:read-file-lines *day14-input-file*)))))
(destructuring-bind (leftmost rightmost bottommost)
(loop
for (x y) on flat-coords
by #'cddr
minimize x into leftmost
maximize x into rightmost
maximize y into bottommost
finally (return (list leftmost rightmost bottommost)))
(make-arena leftmost rightmost bottommost))))
(setq *test-input-coords-chains*
(mapcar #'input-line-to-rock-coords
(uiop:read-file-lines *day14-input-file*)))
; this is second step of initialization
(put-rock-lines *test-arena* *test-input-coords-chains*))
(defun is-point-air (x y arena)
(or (eq #\. (get-place arena x y))
(not (get-place arena x y))))
(defun sand-check-next-move (sand-x sand-y arena)
(let* ((next-y (1+ sand-y))
(possible-next-steps (list (list sand-x next-y)
(list (1- sand-x) next-y)
(list (1+ sand-x) next-y))))
(first (remove-if-not (lambda (coords)
(is-point-air (first coords) (second coords) arena))
possible-next-steps))))
(defun out-of-bounds (x y arena)
(not (get-place arena x y)))
(defun drop-sand-unit (arena)
(do*
((prev-coords nil sand-coords)
(sand-coords '(500 0) (sand-check-next-move
(first sand-coords) (second sand-coords) arena)))
((or (not sand-coords) ; sand rests
(out-of-bounds (first sand-coords) (second sand-coords) arena)) ; end condition - rest or out of bounds
(when (or (not sand-coords)
(equal prev-coords '(500 0))) ; if sand rests at entry point
(set-place arena (first prev-coords) (second prev-coords) #\x)))
;; (format t "sc: ~a, prev: ~a~%" sand-coords prev-coords)
))
(defun drop-sand-unit-abyss (arena)
(do ((sand-units 0 (1+ sand-units))
(drop-result (drop-sand-unit arena) (drop-sand-unit arena)))
((not drop-result)
sand-units)))
;; ok, could return arena
(init-arena)
(drop-sand-unit-abyss *test-arena*) ; 901
;;; PART 2
(defun init-arena-2 ()
(setq *test-input-flat-coords*
(alexandria:flatten (mapcar #'input-line-to-rock-coords
(uiop:read-file-lines *day14-input-file*))))
;; building empty arena
(setq *test-arena*
(let ((flat-coords
(alexandria:flatten (mapcar #'input-line-to-rock-coords (uiop:read-file-lines *day14-input-file*)))))
(destructuring-bind (leftmost rightmost bottommost)
(loop
for (x y) on flat-coords
by #'cddr
minimize x into leftmost
maximize x into rightmost
maximize y into bottommost
finally (return (list leftmost rightmost bottommost)))
(let ((new-bottommost (+ 2 bottommost))
(new-leftmost (min leftmost
(- 500 (* 2 bottommost))))
(new-rightmost (max rightmost
(+ 500 (* 2 bottommost)))))
(make-arena new-leftmost new-rightmost new-bottommost)))))
;; and put floor
(let ((floor-y (bottommost *test-arena*))
(floor-x-start (leftmost *test-arena*))
(floor-x-end (rightmost *test-arena*)))
(put-rock-line *test-arena* floor-x-start floor-x-end floor-y floor-y))
(setq *test-input-coords-chains*
(mapcar #'input-line-to-rock-coords
(uiop:read-file-lines *day14-input-file*)))
; this is second step of initialization
(put-rock-lines *test-arena* *test-input-coords-chains*))
;; rewriting previous. otherwise endless loop
(defun drop-sand-unit (arena)
(do*
((prev-coords '(500 0) sand-coords)
(sand-coords (sand-check-next-move 500 0 arena)
(sand-check-next-move
(first sand-coords) (second sand-coords) arena)))
((or (not sand-coords) ; sand rests
(out-of-bounds (first sand-coords) (second sand-coords) arena)) ; end condition - rest or out of bounds
(when (and (not sand-coords)
(not (equal prev-coords '(500 0)))) ; if sand rests
(set-place arena (first prev-coords) (second prev-coords) #\x)))
;; (format t "sc: ~a, prev: ~a~%" sand-coords prev-coords)
))
(init-arena-2)
(print (1+ (drop-sand-unit-abyss *test-arena*)))

33
day15-input.txt Normal file
View File

@@ -0,0 +1,33 @@
Sensor at x=2302110, y=2237242: closest beacon is at x=2348729, y=1239977
Sensor at x=47903, y=2473047: closest beacon is at x=-432198, y=2000000
Sensor at x=2363579, y=1547888: closest beacon is at x=2348729, y=1239977
Sensor at x=3619841, y=520506: closest beacon is at x=2348729, y=1239977
Sensor at x=3941908, y=3526118: closest beacon is at x=3772294, y=3485243
Sensor at x=3206, y=1564595: closest beacon is at x=-432198, y=2000000
Sensor at x=3123411, y=3392077: closest beacon is at x=2977835, y=3592946
Sensor at x=3279053, y=3984688: closest beacon is at x=2977835, y=3592946
Sensor at x=2968162, y=3938490: closest beacon is at x=2977835, y=3592946
Sensor at x=1772120, y=2862246: closest beacon is at x=2017966, y=3158243
Sensor at x=3283241, y=2619168: closest beacon is at x=3172577, y=2521434
Sensor at x=2471642, y=3890150: closest beacon is at x=2977835, y=3592946
Sensor at x=3163348, y=3743489: closest beacon is at x=2977835, y=3592946
Sensor at x=2933313, y=2919047: closest beacon is at x=3172577, y=2521434
Sensor at x=2780640, y=3629927: closest beacon is at x=2977835, y=3592946
Sensor at x=3986978, y=2079918: closest beacon is at x=3998497, y=2812428
Sensor at x=315464, y=370694: closest beacon is at x=-550536, y=260566
Sensor at x=3957316, y=3968366: closest beacon is at x=3772294, y=3485243
Sensor at x=2118533, y=1074658: closest beacon is at x=2348729, y=1239977
Sensor at x=3494855, y=3378533: closest beacon is at x=3772294, y=3485243
Sensor at x=2575727, y=210553: closest beacon is at x=2348729, y=1239977
Sensor at x=3999990, y=2813525: closest beacon is at x=3998497, y=2812428
Sensor at x=3658837, y=3026912: closest beacon is at x=3998497, y=2812428
Sensor at x=1551619, y=1701155: closest beacon is at x=2348729, y=1239977
Sensor at x=2625855, y=3330422: closest beacon is at x=2977835, y=3592946
Sensor at x=3476946, y=2445098: closest beacon is at x=3172577, y=2521434
Sensor at x=2915568, y=1714113: closest beacon is at x=2348729, y=1239977
Sensor at x=729668, y=3723377: closest beacon is at x=-997494, y=3617758
Sensor at x=3631681, y=3801747: closest beacon is at x=3772294, y=3485243
Sensor at x=2270816, y=3197807: closest beacon is at x=2017966, y=3158243
Sensor at x=3999999, y=2810929: closest beacon is at x=3998497, y=2812428
Sensor at x=3978805, y=3296024: closest beacon is at x=3772294, y=3485243
Sensor at x=1054910, y=811769: closest beacon is at x=2348729, y=1239977

481
day15-scratch.lisp Normal file
View File

@@ -0,0 +1,481 @@
;; https://adventofcode.com/2022/day/15
;;
;; oh, wow. i can already imagine the second part of the task
;; so. for arrangements of (sensor closest-beacon)
;; i need to figure out which points are out of rangle for all sensors?
;; where "range" is distance between sensor and the closest-beacon
;;
;; so for each sensor also store distance, and each sensor should be able to answer query for point
;; whether it disproves existence of a beacone there
;; then for ( POINTS x SENSORS ) computations i'll be able to mark all points that aren't covered.
;;
;; doesn't seem like too much
(ql:quickload 'cl-ppcre)
;; poor man's parsing
(rest (mapcar (lambda (str)
(parse-integer str :junk-allowed t))
(cl-ppcre:split "="
"Sensor at x=2, y=18: closest beacon is at x=-2, y=15")))
;; manhattan distance : https://en.wikipedia.org/wiki/Taxicab_geometry
;; sum of abs of coord-diffs
(defclass point ()
((x :initarg :x :reader x)
(y :initarg :y :reader y)))
(defmethod print-object ((obj point) stream)
(print-unreadable-object (obj stream :type t)
(with-slots (x y)
obj
(format stream "x:~a y:~a" x y))))
(defparameter *test-point-1*
(make-instance 'point :x 1 :y 19))
(defparameter *test-point-2*
(make-instance 'point :x -2 :y -20))
(defmethod manh-dist ((one point) (two point))
(+ (abs (- (x one) (x two)))
(abs (- (y one) (y two)))))
(manh-dist *test-point-1* *test-point-2*)
;; i guess this is right
(defclass sensor ()
((self-coord :initarg :self :reader self-coord)
(beacon-coord :initarg :beacon :reader beacon-coord)
(covered-dist :initarg :dist :reader covered-dist)))
(defun make-sensor (sens-x sens-y beac-x beac-y)
(let* ((sensor (make-instance 'point :x sens-x :y sens-y))
(beacon (make-instance 'point :x beac-x :y beac-y))
(dist (manh-dist sensor beacon)))
(make-instance 'sensor :self sensor :beacon beacon :dist dist)))
(defmethod print-object ((obj sensor) stream)
(print-unreadable-object (obj stream :type t)
(with-slots (self-coord beacon-coord covered-dist)
obj
(format stream "at: ~a, linked to: ~a, covering dist: ~a"
self-coord beacon-coord covered-dist))))
(defparameter *test-sensor* (make-sensor 2 18 -2 15))
(defmethod can-have-unknown-beacon-p ((p point) (s sensor))
(> (manh-dist p (self-coord s))
(covered-dist s)))
(manh-dist *test-point-1* (self-coord *test-sensor*))
(can-have-unknown-beacon-p *test-point-1* *test-sensor*)
(manh-dist *test-point-2* (self-coord *test-sensor*))
(can-have-unknown-beacon-p *test-point-2* *test-sensor*)
;; ok. now read in all sensors?
;; and then for line with specified 'y'
;; and from leftmost to rightmost S or B for each point ask each sensor if possible
;; to have an unknown beacon, if any says "no" - then no
;; otherwise - count
(defparameter *day15-input-file* "day15-test.txt")
(defun line-to-coords (line)
(rest (mapcar (lambda (str)
(parse-integer str :junk-allowed t))
(cl-ppcre:split "=" line))))
(defparameter *day15-sensors-list* nil)
(setq *day15-sensors-list*
(mapcar (lambda (coords-list)
(apply #'make-sensor coords-list))
(mapcar #'line-to-coords (uiop:read-file-lines *day15-input-file*))))
;; next - find lovest x and highest x
;; but then i guess i'd also want lovest and highest y overall
;; that's neat
(loop
for sensor in *day15-sensors-list*
minimize (x (self-coord sensor)) into xs
minimize (x (beacon-coord sensor)) into xs
maximize (x (self-coord sensor)) into xm
maximize (x (beacon-coord sensor)) into xm
minimize (y (self-coord sensor)) into ys
minimize (y (beacon-coord sensor)) into ys
maximize (y (self-coord sensor)) into ym
maximize (y (beacon-coord sensor)) into ym
finally (return (list xs xm ys ym)))
;; (-2 25 0 22)
;; now for line y=10 check all x and count how many -for-all- sensors allow new point
(defun all-sensors-allow-for-hidden-beacon (point sensors)
(macroexpand `(and ,@(mapcar (lambda (sensor) (can-have-unknown-beacon-p point sensor))
sensors))))
(defun all-sensors-allow-for-hidden-beacon (point sensors)
(not (position nil (mapcar (lambda (sensor) (can-have-unknown-beacon-p point sensor))
sensors))))
;; well, do i have to write my own function for AND ?
(when (all-sensors-allow-for-hidden-beacon *test-point-2* *day15-sensors-list*)
1)
(when (all-sensors-allow-for-hidden-beacon *test-point-1* *day15-sensors-list*)
1)
;; count how many ARE covered
(loop
for x from -2 to 25
count (not (all-sensors-allow-for-hidden-beacon
(make-instance 'point :x x :y 10)
*day15-sensors-list*)))
;; on the image it's from -2 and till 24, so should be 27, if counting 0
;; well. we're counting posistions "wher beacon can't possibly exist"
;; so removing points which _are_ beacons?
;;
;; and - range needs to be extended significantly, no?
;; what would be enough?
;; doubling into each direction?
(defmethod points-equal ((left point) (right point))
(and (= (x left) (x right))
(= (y left) (y right))))
(points-equal (make-instance 'point :x 1 :y 1)
(make-instance 'point :x 1 :y 1))
(defun possible-to-have-beacon (point sensors)
(let ((all-checks
(mapcar (lambda (sensor)
(if (points-equal point (beacon-coord sensor))
'known-sensor
(can-have-unknown-beacon-p point sensor) ; single NIL means - not possible to have unknown
))
sensors)))
(or (not (position nil all-checks)) ; nil if all sensors allow (said T) presense of unknown beacons
(position 'known-sensor all-checks) ; exists known sensor
)))
;; beacon is possible : either sensor has beacon at that point
;; or position is out of the sensor range
;; but here's the thing. if sencor-beacon is at this point - need to short-circuit T
(possible-to-have-beacon *test-point-2* *day15-sensors-list*)
(possible-to-have-beacon *test-point-1* *day15-sensors-list*)
(possible-to-have-beacon (make-instance 'point :x -2 :y 15) *day15-sensors-list*)
;; i guess that works
;; count how many ARE covered
(loop
for x from -2 to 25
count (not (possible-to-have-beacon
(make-instance 'point :x x :y 10)
*day15-sensors-list*)))
;; ok.
;;
;; new idea:
;; have class for "not intersecting intervals"
;; with method to add ( ? remove ) new interval
;; in part 2 we're looking for points which are outside of all scanners
;; where "last beacon" can be
;; start of idea - distance goes by x and y simmetrically.
;; between line Y1 and beacon (X2 Y2) we can calculate Y2 - Y1,
;; if that is > than length covered - then knowingly 0 points covered by scanners
;; if htat is < that covered length : abs(Y2 - Y1) = diff
;; that diff will be covered into both sides to the left and to the right of the X2
;; (Y1 X2) will be exactly diff distance away.
;; so (length - diff) is by how much we can go to the left and right and still be with distance to beacon upto length
;; Interval [(x2-diff, y1) .. (x2+diff, y1)] are all points where "there can't be unkown beacons"
;;
;; and my idea is to operate on the point intervals.
;; start with "total interval" from 0 to 4M, i guess
;; then - for each beacon calculate Interval where "can't be unknown beacons"
;; and subtract them from the line
;;
;; without use of "per point" is best
;; so. want to have class, that stores non-intersecting intervals ( scala SortedMap would be good here )
;;
;; but ok, can be just ((start end) (start2 end2)) sorted by #'first after every operation
;; what would be algo for "removing interval"
;;
;; go though the increasing 'interval starts', find first that's > our-start
;; then check current interval and previous interval
;;
;; previous interval could have end that clips current-interval
;; at-which-we-stopped could clip "end" of current-interval
;; should i just have class for interval? nah, just method, since no need in type checking?
(defun subtract-interval (minuend subtrahend)
(destructuring-bind ((m-left m-right) (s-left s-right)) (list minuend subtrahend)
(let ((resulting-interval
(if (< m-left s-left)
(list ; minuend starts to the left
m-left (min m-right s-left))
(list ; minuend starts to the right
s-right m-right)
)))
(when (<= (first resulting-interval) (second resulting-interval)) ; >= to allow intervals [4 4]
resulting-interval))))
(subtract-interval '(1 100) '(0 101)) ; NIL correct
(subtract-interval '(1 100) '(10 20)) ; only one return value, incorrect
;; oh, but it can be that our subrahend fully devours "to the right" and we'd need to check "next to the right"
;; ugh
;; went to search and found 'cl-interval
(ql:quickload 'cl-interval)
(interval:make-interval :start 1 :end 100 )
;; this is not what i need?
(defparameter *some-tree*
(interval:make-tree ))
(interval:insert *some-tree* (interval:make-interval :start 1 :end 100) )
(interval:delete *some-tree* (interval:make-interval :start 10 :end 20) )
*some-tree*
(interval:find-all *some-tree* 11) ; nope deletion doesn't work like i want it
;; ugh. write it on my own
(defstruct ([] (:constructor [] (low high)))
(low 0.0 :type real)
(high 0.0 :type real))
(defmethod sub ((i1 []) (i2 []))
([] (- ([]-low i1) ([]-high i2))
(- ([]-high i1) ([]-low i2))))
(sub ([] 1 100) ([] 10 20)) ; ([] -19 90) that's bs
;;; ugh. this is somethign completely different
;; so, back to my function
;; should be able to return list of intervals. either one or two if split
(defun subtract-interval (minuend subtrahend)
(destructuring-bind ((m-left m-right) (s-left s-right)) (list minuend subtrahend)
(cond
((< m-right s-left) (list m-left m-right)) ; minuend fully to the left
((> m-left s-right) (list m-left m-right)) ; minuend fully to the right
((and (< m-left s-left)
(> m-right s-right)) ; minuend is around subtrahend
(list (list m-left (1- s-left))
(list (1+ s-right) m-right))) ; part before and after subtrahend
((and (>= m-left s-left)
(<= m-right s-right)) ; subtrahend consumes minuend
nil)
((< m-left s-left) ; minuend start to the left, but not subtrahend consumes all right part
(list m-left (1- s-left)))
((> m-right s-right) ; minuend has part to the right of subtrahend
(list (1+ s-right) m-right)))))
(subtract-interval '(1 100) '(0 101)) ; NIL correct
(subtract-interval '(1 100) '(10 20)) ; two intervals, correct
(subtract-interval '(1 20) '(10 30)) ; correct, had deducted 10
(subtract-interval '(10 30) '(1 20)) ; correct, had deducted 20
(subtract-interval '(25 30) '(1 20)) ; correct, not changed
(subtract-interval '(1 20) '(25 30)) ; correct not changed
(subtract-interval '(1 20) nil) ; correct not changed
;; ok. now what. have interval
'(0 4000000) ; and deduct from it found intervals.
; it would produce list of intervals
; so for each new interval - deduct from all
; then i'll have list of intervals, where "unknown beacon is possible"
;; now. hm.
;; loop. no. first function that for LINE-Y and BEACON-CENTER calculates "no-unkown-beacons" interval
(defun get-no-unknown-beacons-x-interval (line-y scanner)
(let* ((y-dist (abs (- line-y (y (self-coord scanner)))))
(x-slack (- (covered-dist scanner) y-dist))
(x-sc (x (self-coord scanner))))
(when (>= x-slack 0)
(list (- x-sc x-slack) (+ x-sc x-slack)))))
*test-sensor* ; x: 2, y: 18, dist: 7
(y (self-coord *test-sensor*))
(get-no-unknown-beacons-x-interval 18 *test-sensor*)
(get-no-unknown-beacons-x-interval 17 *test-sensor*)
(get-no-unknown-beacons-x-interval 19 *test-sensor*)
;; should be (-5 9)
(get-no-unknown-beacons-x-interval 11 *test-sensor*)
(manh-dist (make-instance 'point :x 2 :y 11) (self-coord *test-sensor*))
;; seems right
(get-no-unknown-beacons-x-interval 4 (make-sensor 1 1 2 2))
;; seems right
(get-no-unknown-beacons-x-interval 2 *test-sensor*)
;; yup
;; now. start with interval '(0 4000000)
;; list of that interval
;; when working on a line
;; get 'no-unknowns' interval for each scanner
;; then for each interval in the lists -
;; take it oud and put results of subtraction instead
(defun subtract-from-all (intervals subtrahend)
(mapcan (lambda (interval) (subtract-interval interval subtrahend))
intervals))
(subtract-from-all '((1 4000000)) '(5 15)) ; yay
(subtract-from-all '((1 10) (12 17) (20 25)) '(5 23)) ; yay
(subtract-from-all '((3 10) (12 17) (20 25)) '(1 40)) ; yay
(subtract-from-all '((3 10) (12 17) (20 25)) nil) ; yay
;; now looping.
;; we fix line, then for each scanner we calculate interval and update our intervals
;; in the end - if not NIL - then some points can have "unknown beacond"
;; let's figure out inner loop first
(defun line-unknown-intervals (y scanners max-x)
(do*
((rest-scanners scanners (cdr rest-scanners))
(scanner (first rest-scanners) (first rest-scanners))
(known-interval (get-no-unknown-beacons-x-interval y scanner)
(when scanner (get-no-unknown-beacons-x-interval y scanner)))
(intervals (subtract-from-all `((0 ,max-x)) known-interval)
(subtract-from-all intervals known-interval)))
((not scanner) intervals)
;; (format t "step, ~a intervals, after removing ~a; from ~a ~%" intervals known-interval scanner)
))
(line-unknown-intervals 11 (get-sensors-list "day15-test.txt") 20)
(line-unknown-intervals 10 (get-sensors-list "day15-test.txt") 20)
;; 2: (SUBTRACT-FROM-ALL ((0 2) 14 4000000) (-3 3))
;; why is that intervals get polluted
;;
;; anothre problem we don't include last scanner?
;;
;; and another problem. do we remove too little?
;; step, ((-40 11) (13 40)) intervals, after removing (12 12); from #<SENSOR at: #<POINT x:12 y:14>, linked to: #<POINT x:10 y:16>, covering dist: 4>
;; for line y=10, dist 4, sensor at <POINT x:12 y:14>, no all ok
;; so, proposed answer is x=14, y=11
;; which sensor precludes that in my process?
;; step, ((-40 10) (14 40)) intervals, after removing (11 13); from #<SENSOR at: #<POINT x:12 y:14>, linked to: #<POINT x:10 y:16>, covering dist: 4>
;; <SENSOR at: #<POINT x:12 y:14>, linked to: #<POINT x:10 y:16>, covering dist: 4>
;; for y=11. dist is 3. so 12+-1 right?
(manh-dist (make-instance 'point :x 12 :y 14)
(make-instance 'point :x 14 :y 11))
;; so here distance is 5. wtf.
;; so. y=11
;; sensor at <POINT x:12 y:14>
;; we spend 3 12+-1 wtf
;; OOOH. it's (14 14) - meaning X is 14
;; and Y is 11
;; crap
(subtract-from-all '((1 4000000)) '(3 13)) ; yay
;; using (format t "step, ~a intervals, after removing ~a ~%" intervals known-interval)
;; inside of DO loop
(subtract-from-all '((0 10) (14 400000)) '(3 13)) ; whoa
(subtract-interval '(14 400000) '(3 13)) ; correct not changed
;; well that's because in the "all below" i return not list of list
;; hello type safety, man
(defparameter *day-15-2-ans* nil)
(setq *day-15-2-ans*
(let ((sensors (get-sensors-list "day15-input.txt")))
(loop
for y from 1 to 4000000
for y-unknown-intervals = (line-unknown-intervals y sensors 4000000)
when y-unknown-intervals collect (list y y-unknown-intervals)
when (= 0 (mod y 10000)) do (format t "in step ~a~%" y))))
(print *day-15-2-ans*)
;; well, there are lots of "possible solutions", ugh
(defparameter *day-15-2-test* nil)
(setq *day-15-2-test*
(let ((sensors (get-sensors-list "day15-test.txt")))
(loop
for y from 0 to 20
for y-unknown-intervals = (line-unknown-intervals y sensors 20)
when y-unknown-intervals collect (list y y-unknown-intervals)
when (= 0 (mod y 1000)) do (format t "in step ~a~%" y))))
*day-15-2-test*
;; so, i do find the answer, but also lots of NON ANSWERS:
'((11 ((14 14))) (12 ((3 3))) (13 ((2 4))) (14 ((1 5))) (15 ((0 6)))
(16 ((0 7))) (17 ((0 8))) (18 ((0 7))) (19 ((0 6))) (20 ((0 5))))
;; for example :x 3 :y 12
;; it should have been thrown out. why not? which scanner should have covered it
(line-unknown-intervals 12 (get-sensors-list "day15-test.txt") 20)
;; for example (3 12) and (-2 15 #7) nope, ok
;; for example (3 12) and (8 7 #9) nope, ok
;; i need to automate it. for all scanners, find what? closest?
(let ((p (make-instance 'point :x 3 :y 12)))
(loop
for scanner in (get-sensors-list "day15-test.txt")
collect (list (manh-dist (self-coord scanner) p) (covered-dist scanner))))
;; so for 1st scanner, dist 7 and covered-dist is 7.
;; UGH
;; and
;; - step, ((0 20)) intervals, after removing (1 3); from #<SENSOR at: #<POINT x:2 y:18>, linked to: #<POINT x:-2 y:15>, covering dist: 7>
;; here it was all along
(subtract-from-all '((0 20)) '(1 3 ))
;; maybe that's bug of first iteration of DO* or something
;; it would be in "non-covered interval"
;; maybe i don't remove enough?
;; i should remove interval where all points "covered by the sensor"
;; do i want to draw that shit?
'(((-40 -8) (28 40)) ((-40 -7) (27 40)) ((-40 -6) (26 40)) ((-40 -5) (25 40))
((-40 -4) (24 40)) ((-40 -3) (23 40)) ((-40 -2) (22 40)) ((-40 -1) (23 40))
((-40 -2) (24 40)) ((-40 -3) (25 40)) ((-40 -4) (14 14) (26 40))
((-40 -3) (3 3) (27 40)) ((-40 -2) (2 4) (28 40)) ((-40 -1) (1 5) (29 40))
((-40 6) (28 40)) ((-40 7) (27 40)) ((-40 8) (26 40)) ((-40 7) (25 40))
((-40 6) (24 40)) ((-40 5) (24 40)))
(defun draw-line-def (line-intervals)
(format t "!")
(do*
((intervals line-intervals (cdr intervals))
(prev-interval nil interval)
(interval (first intervals) (first intervals)))
((not interval) nil)
;; (format t "iteration int: ~a; prev: ~a" interval prev-interval)
(when (not prev-interval)
(dotimes (i (first interval))
(format t ".")))
(when prev-interval
(dotimes (i (- (first interval) (second prev-interval)))
(format t ".")))
(dotimes (i (- (second interval) (first interval)))
(format t "#"))
)
(format t "!") (terpri)
)
(draw-line-def '((-40 -8) (28 40)))
;; ok, i have 'draw-line'
(loop for line-def in *day-15-2-test* do
(draw-line-def line-def))
;;
;; let's yolo
(2175292 ((2335771 2335771)))
(+ (* 2335771) 2175292)
;; that didn't work

14
day15-test.txt Normal file
View File

@@ -0,0 +1,14 @@
Sensor at x=2, y=18: closest beacon is at x=-2, y=15
Sensor at x=9, y=16: closest beacon is at x=10, y=16
Sensor at x=13, y=2: closest beacon is at x=15, y=3
Sensor at x=12, y=14: closest beacon is at x=10, y=16
Sensor at x=10, y=20: closest beacon is at x=10, y=16
Sensor at x=14, y=17: closest beacon is at x=10, y=16
Sensor at x=8, y=7: closest beacon is at x=2, y=10
Sensor at x=2, y=0: closest beacon is at x=2, y=10
Sensor at x=0, y=11: closest beacon is at x=2, y=10
Sensor at x=20, y=14: closest beacon is at x=25, y=17
Sensor at x=17, y=20: closest beacon is at x=21, y=22
Sensor at x=16, y=7: closest beacon is at x=15, y=3
Sensor at x=14, y=3: closest beacon is at x=15, y=3
Sensor at x=20, y=1: closest beacon is at x=15, y=3

151
day15.lisp Normal file
View File

@@ -0,0 +1,151 @@
;; https://adventofcode.com/2022/day/15
(ql:quickload 'cl-ppcre)
(defparameter *day15-input-file* "day15-test.txt")
(defclass point ()
((x :initarg :x :reader x)
(y :initarg :y :reader y)))
(defmethod print-object ((obj point) stream)
(print-unreadable-object (obj stream :type t)
(with-slots (x y)
obj
(format stream "x:~a y:~a" x y))))
(defmethod points-equal ((left point) (right point))
(and (= (x left) (x right))
(= (y left) (y right))))
(defmethod manh-dist ((one point) (two point))
(+ (abs (- (x one) (x two)))
(abs (- (y one) (y two)))))
(defclass sensor ()
((self-coord :initarg :self :reader self-coord)
(beacon-coord :initarg :beacon :reader beacon-coord)
(covered-dist :initarg :dist :reader covered-dist)))
(defun make-sensor (sens-x sens-y beac-x beac-y)
(let* ((sensor (make-instance 'point :x sens-x :y sens-y))
(beacon (make-instance 'point :x beac-x :y beac-y))
(dist (manh-dist sensor beacon)))
(make-instance 'sensor :self sensor :beacon beacon :dist dist)))
(defmethod print-object ((obj sensor) stream)
(print-unreadable-object (obj stream :type t)
(with-slots (self-coord beacon-coord covered-dist)
obj
(format stream "at: ~a, linked to: ~a, covering dist: ~a"
self-coord beacon-coord covered-dist))))
(defmethod can-have-unknown-beacon-p ((p point) (s sensor))
(> (manh-dist p (self-coord s))
(covered-dist s)))
(defun line-to-coords (line)
(rest (mapcar (lambda (str)
(parse-integer str :junk-allowed t))
(cl-ppcre:split "=" line))))
(defun get-sensors-list (input-file-name)
(mapcar (lambda (coords-list)
(apply #'make-sensor coords-list))
(mapcar #'line-to-coords (uiop:read-file-lines input-file-name))))
(defun get-limits (sensors-list)
(loop
for sensor in sensors-list
minimize (x (self-coord sensor)) into xs
minimize (x (beacon-coord sensor)) into xs
maximize (x (self-coord sensor)) into xm
maximize (x (beacon-coord sensor)) into xm
minimize (y (self-coord sensor)) into ys
minimize (y (beacon-coord sensor)) into ys
maximize (y (self-coord sensor)) into ym
maximize (y (beacon-coord sensor)) into ym
finally (return (list xs xm ys ym))))
(defun possible-to-have-beacon (point sensors)
(let ((all-checks
(mapcar (lambda (sensor)
(if (points-equal point (beacon-coord sensor))
'known-sensor
(can-have-unknown-beacon-p point sensor) ; single NIL means - not possible to have unknown
))
sensors)))
(or (not (position nil all-checks)) ; nil if all sensors allow (said T) presense of unknown beacons
(position 'known-sensor all-checks) ; exists known sensor
)))
(defun count-certainly-not-beacons (input-file-name)
(let ((sensors (get-sensors-list input-file-name)))
(destructuring-bind (min-x max-x min-y max-y)
(get-limits sensors)
(let ((to-add-x (abs (- max-x min-x)))
;; (to-check-y 10)
(to-check-y 2000000)
)
(loop
for x from (- min-x to-add-x) to (+ max-x to-add-x)
count (not (possible-to-have-beacon
(make-instance 'point :x x :y to-check-y)
sensors))
do (format t "iterating for x:~a y:~a~%" x to-check-y))))))
(count-certainly-not-beacons "day15-test.txt")
;; (count-certainly-not-beacons "day15-input.txt")
;; well, that's just too slow
;; how do i rewrite it to make it faster?
;; i guess i could exclude the sensors which are too far away from the list?
;;
;; well, optimization here that we move by 1 point toward or away from sensor
;; so, we can kind of calculate when we'll be in it's range?
;; * in what amount of steps
;; ** whoa, org colors
;;
;; so.
;; PART 2 - just start search overnight?
;; for 0 to 4.000.000 by x and y?
;; and collect all such possible x and y?
;; nope, even if it were 5 minutes for 16mil,
;; so 2 minutes per 4 mil, then multiply by 4M - more than a day.
;; think better
(defun subtract-interval (minuend subtrahend)
(if (not subtrahend)
(list minuend) ; list of one interval
(destructuring-bind ((m-left m-right) (s-left s-right)) (list minuend subtrahend)
(cond
((< m-right s-left)
(list (list m-left m-right))) ; minuend fully to the left
((> m-left s-right)
(list (list m-left m-right))) ; minuend fully to the right
((and (< m-left s-left)
(> m-right s-right)) ; minuend is around subtrahend
(list (list m-left (1- s-left))
(list (1+ s-right) m-right))) ; part before and after subtrahend
((and (>= m-left s-left)
(<= m-right s-right)) ; subtrahend consumes minuend
nil)
((< m-left s-left) ; minuend start to the left, but not subtrahend consumes all right part
(list (list m-left (1- s-left)))) ; list of one interval
((> m-right s-right) ; minuend has part to the right of subtrahend
(list (list (1+ s-right) m-right)))))))
(defun get-no-unknown-beacons-x-interval (line-y scanner)
(let* ((y-dist (abs (- line-y (y (self-coord scanner)))))
(x-slack (- (covered-dist scanner) y-dist))
(x-sc (x (self-coord scanner))))
(when (>= x-slack 0)
(list (- x-sc x-slack) (+ x-sc x-slack)))))
(defun subtract-from-all (intervals subtrahend)
(mapcan (lambda (interval) (subtract-interval interval subtrahend))
intervals))

View File

@@ -0,0 +1,2 @@
Valve AA has flow rate=0; tunnels lead to valves BB
Valve BB has flow rate=1; tunnels lead to valves AA

51
day16-input.txt Normal file
View File

@@ -0,0 +1,51 @@
Valve NV has flow rate=5; tunnels lead to valves ZV, CG, YB, HX, OY
Valve NU has flow rate=6; tunnels lead to valves DA, MA, OA, DK
Valve VU has flow rate=0; tunnels lead to valves PS, FX
Valve JW has flow rate=0; tunnels lead to valves AA, MD
Valve RI has flow rate=0; tunnels lead to valves OY, DG
Valve DG has flow rate=9; tunnels lead to valves TG, RI, DF, EV, KW
Valve PH has flow rate=7; tunnels lead to valves KW, OW, LT, LZ
Valve KZ has flow rate=12; tunnels lead to valves ET, QV, CK, MS
Valve IX has flow rate=0; tunnels lead to valves TS, DO
Valve MS has flow rate=0; tunnels lead to valves LZ, KZ
Valve IL has flow rate=0; tunnels lead to valves DO, ET
Valve EJ has flow rate=20; tunnels lead to valves AV, JY
Valve DK has flow rate=0; tunnels lead to valves NU, CG
Valve YB has flow rate=0; tunnels lead to valves NV, PS
Valve OA has flow rate=0; tunnels lead to valves YA, NU
Valve DA has flow rate=0; tunnels lead to valves NU, RG
Valve KO has flow rate=0; tunnels lead to valves AA, TG
Valve RG has flow rate=4; tunnels lead to valves DF, DA, ZV, MD, LB
Valve MA has flow rate=0; tunnels lead to valves AA, NU
Valve OW has flow rate=0; tunnels lead to valves DO, PH
Valve KW has flow rate=0; tunnels lead to valves DG, PH
Valve DO has flow rate=14; tunnels lead to valves IX, IL, CZ, OW
Valve DF has flow rate=0; tunnels lead to valves RG, DG
Valve TG has flow rate=0; tunnels lead to valves DG, KO
Valve LB has flow rate=0; tunnels lead to valves RG, FX
Valve HX has flow rate=0; tunnels lead to valves AA, NV
Valve GB has flow rate=0; tunnels lead to valves AV, XK
Valve CG has flow rate=0; tunnels lead to valves DK, NV
Valve LT has flow rate=0; tunnels lead to valves AO, PH
Valve FX has flow rate=23; tunnels lead to valves LB, HY, VU
Valve ET has flow rate=0; tunnels lead to valves IL, KZ
Valve CK has flow rate=0; tunnels lead to valves UX, KZ
Valve LZ has flow rate=0; tunnels lead to valves PH, MS
Valve YA has flow rate=17; tunnels lead to valves JY, OA
Valve TS has flow rate=0; tunnels lead to valves NO, IX
Valve NO has flow rate=8; tunnel leads to valve TS
Valve XK has flow rate=24; tunnel leads to valve GB
Valve PS has flow rate=18; tunnels lead to valves EV, VU, YB
Valve AA has flow rate=0; tunnels lead to valves JW, HX, MA, KO
Valve MD has flow rate=0; tunnels lead to valves JW, RG
Valve JM has flow rate=19; tunnels lead to valves QV, HY, AO
Valve AV has flow rate=0; tunnels lead to valves EJ, GB
Valve AO has flow rate=0; tunnels lead to valves JM, LT
Valve JY has flow rate=0; tunnels lead to valves YA, EJ
Valve OY has flow rate=0; tunnels lead to valves NV, RI
Valve UX has flow rate=13; tunnels lead to valves CZ, CK
Valve HY has flow rate=0; tunnels lead to valves JM, FX
Valve EV has flow rate=0; tunnels lead to valves PS, DG
Valve CZ has flow rate=0; tunnels lead to valves UX, DO
Valve ZV has flow rate=0; tunnels lead to valves NV, RG
Valve QV has flow rate=0; tunnels lead to valves JM, KZ

128
day16-scratch-cl-graph.lisp Normal file
View File

@@ -0,0 +1,128 @@
;; https://adventofcode.com/2022/day/16
;; so. only idea i had is to build the graph, and then do random walk? ugh.
;; we could maybe potentially divide by 2 amount of recursion,
;;
;; since possible actions are
;; - go to next room
;; - open current valve & go to next room
;;
;; and that shared part is almost similar, but is 1 move shorter, but adds some turns of this valve being open
;; if i return info on which valves were open for how many turns from the recursion,
;; i could potentially calculate what is more - 1 less turn of all of these and + some amount of current room's valve
;; or just go to next turn.
;;
;; but this is kind of way too much, to wander aimlessly?
;; maybe I need to build closure, then could choose any desired vertice? and select only those which are not visited.
;; this seems much more sane
;;
;; maybe there's already good \ easy \ powerful graph library?
;;
;; i found two libraries for graphs.
;; https://cl-graph.common-lisp.dev/user-guide.html - this one seem to allow for calculating closures, and filtering.
;; (repo: https://github.com/gwkkwg/cl-graph )
;; so i could potentially filter the remaining graph for the walkthrough
;; https://github.com/kraison/graph-utils - this one visualization and primitives that could allow for writing algos
;;
;; i guess i'll try to install first. is it available in quicklisp?
;; (ql:quickload 'cl-graph)
(push #p"~/quicklisp/local-projects/cl-graph/" asdf:*central-registry*)
;; (ql:quickload "cl-graph")
(ql:quickload '(:cl-graph :moptilities))
(defclass my-graph (cl-graph:basic-graph)
())
(defparameter *test-graph* nil)
;; (:documentation "Stub for matrix based graph. Not implemented.")
;; OH NO
;; (cl-graph:add-vertex *test-graph* 6)
;; (cl-graph:vertex-count *test-graph*)
;; (cl-graph:graph->dot *test-graph* t)
;; (in-package #:cl-graph)
(in-package cl-user)
(make-graph 'basic-graph) ; still doesn' work
;; to allow export to DOT
;; https://github.com/gwkkwg/cl-graph/issues/12
;; (defclass* dot-graph (dot-graph-mixin graph-container)
;; ()
;; (:export-p t))
(let ((g (make-container 'dot-graph :default-edge-type :directed)))
(loop for (a b) in '((a b) (b c) (b d) (d e) (e f) (d f)) do
(add-edge-between-vertexes g a b))
(graph->dot g nil))
(setq *test-graph*
(let ((g (cl-graph:make-graph 'cl-graph:dot-graph)))
(loop for v in '(a b c d e) do
(cl-graph:add-vertex g v))
(loop for (v1 . v2) in '((a . b) (a . c) (b . d) (c . e)) do
(cl-graph:add-edge-between-vertexes g v1 v2))
g))
(setq *test-graph*
(let ((g (make-graph 'graph-container)))
(loop for v in '(a b c d e) do
(add-vertex g v))
(loop for (v1 . v2) in '((a . b) (a . c) (b . d) (c . e)) do
(add-edge-between-vertexes g v1 v2))
g))
(cl-graph:vertex-count *test-graph*)
(graph->dot *test-graph* nil)
(vertexes *test-graph*)
(make-graph-from-vertexes (vertexes *test-graph*))
(identity 1)
;; graph-container already subclass of basic-graph.
;; then why doesn't this method is dispatched?
(make-filtered-graph *test-graph* (lambda (v) t) )
;; maybe quicklisp doens't have a fresh enough version?
;; ok. how do i make quicklisp use cloned code?
;; well. too bad.
(cl-graph:make-graph-from-vertexes (cl-graph:vertexes *test-graph*))
(cl-graph:make-filtered-graph *test-graph* (lambda (v) t) )
((lambda (v) t) 1)
(ql:where-is-system :cl-graph)
;; => #P"/home/efim/quicklisp/dists/quicklisp/software/cl-graph-20171227-git/"
(ql:update-client)
(ql:update-all-dists)
;; Changes from quicklisp 2022-07-08 to quicklisp 2022-11-07:
(cl-graph:graph->dot *test-graph* nil)
;; required additional dependency
;; (ql:quickload '(:cl-graph :moptilities))
;; asdf system connections
;; https://github.com/gwkkwg/cl-graph/blob/3cb786797b24883d784b7350e7372e8b1e743508/cl-graph.asd#L84-L89
(setq *test-graph*
(let ((g (cl-graph:make-graph 'cl-graph:dot-graph)))
(loop for v in '(a b c d e) do
(cl-graph:add-vertex g v))
(loop for (v1 . v2) in '((a . b) (a . c) (b . d) (c . e)) do
(cl-graph:add-edge-between-vertexes g v1 v2))
g))
(print (cl-graph:graph->dot *test-graph* nil))
(print (cl-graph:graph->dot
(cl-graph:make-filtered-graph *test-graph*
(lambda (v) (not (eq v 'a)))
:graph-completion-method nil)
nil))
;; well, that was all for nothing?
;; or do i still rather use that library?
;; because it would allow me to add data to vertices?
;;
;; and graph-utils allows for getting hashmap of all paths and lengts?

File diff suppressed because it is too large Load Diff

5
day16-simpler-test.txt Normal file
View File

@@ -0,0 +1,5 @@
Valve AA has flow rate=0; tunnels lead to valves BB
Valve BB has flow rate=1; tunnels lead to valves CC, EE
Valve CC has flow rate=1; tunnels lead to valves DD
Valve DD has flow rate=1; tunnels lead to valves EE
Valve EE has flow rate=1; tunnels lead to valves EE

10
day16-test.txt Normal file
View File

@@ -0,0 +1,10 @@
Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
Valve BB has flow rate=13; tunnels lead to valves CC, AA
Valve CC has flow rate=2; tunnels lead to valves DD, BB
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
Valve EE has flow rate=3; tunnels lead to valves FF, DD
Valve FF has flow rate=0; tunnels lead to valves EE, GG
Valve GG has flow rate=0; tunnels lead to valves FF, HH
Valve HH has flow rate=22; tunnel leads to valve GG
Valve II has flow rate=0; tunnels lead to valves AA, JJ
Valve JJ has flow rate=21; tunnel leads to valve II

58
day16.lisp Normal file
View File

@@ -0,0 +1,58 @@
;; https://github.com/kraison/graph-utils
(ql:quickload 'graph-utils)
(ql:quickload 'alexandria)
;;; reading in data
;; graph and hashmap from node name to flow and state
(defclass verticle-data ()
((flow :reader flow :initarg :flow)
(name :reader name :initarg :name)
(is-opened-p :accessor is-opened-p :initform t)))
(defmethod print-object ((obj verticle-data) stream)
(with-slots (name flow is-opened-p) obj
(format stream "~a with flow: ~a; is opened? ~a" name flow is-opened-p)))
(defun parse-integer-or-symbol (str)
(let ((maybe-int (parse-integer str :junk-allowed t)))
(if maybe-int
maybe-int
(intern (string-upcase str)))))
(defun parse-input-line (line)
(destructuring-bind (-valve source-name -has -flow -rate flow-rate
-tunnels -lead -to -valves &rest to-valve-names)
(mapcar #'parse-integer-or-symbol
(remove-if (lambda (str) (equal "" str)) (cl-ppcre:split "(,| |=)" line)))
(format t "from ~a with ~a; to ~a~%" source-name flow-rate to-valve-names)
(list source-name flow-rate to-valve-names)))
(defun read-file-data (filename graph vertices-data-map)
(loop
for line-struct in
(mapcar #'parse-input-line (uiop:read-file-lines filename))
do (put-struct-into-storages line-struct graph vertices-data-map)))
;;; calculations for part 1
(defun get-possible-next-vs (cur-node graph vertices-data-map shortest-paths time-remaining)
(loop
for (from . to)
being the hash-keys in shortest-paths using (hash-value dist)
for from-node = (graph-utils:lookup-node graph from)
for to-node = (graph-utils:lookup-node graph to)
for to-node-data = (gethash to-node vertices-data-map)
when (and (equal cur-node from-node)
(not (equal cur-node to-node))
(not (= 0 (flow to-node-data)))
(> time-remaining dist)
(is-opened-p to-node-data))
do (format t "from ~a to ~a dist: ~a. ~a~%" from-node to-node dist to-node-data)
when (and (equal cur-node from-node)
(not (equal cur-node to-node))
(not (= 0 (flow to-node-data)))
(> time-remaining dist)
(is-opened-p to-node-data))
collect (list to-node dist)))

1
day17-input.txt Normal file

File diff suppressed because one or more lines are too long

998
day17-scratch.lisp Normal file
View File

@@ -0,0 +1,998 @@
;; https://adventofcode.com/2022/day/17
;; so. cool.
;; one thought - i'd want to learn how to specify smaller argument types for optimizations
;; another - better think of optimizing checks
;; one more - reads from array should be faster, write new figure only after it comes to rest
;; thinking of checks. i could have separate methods that check 'possible left|right|down movement'
;; so. is there a cycle datastructure?
;; yes, but not in standart library, just cycle the list on itself
(defun circular (items)
(setf (cdr (last items)) items)
items)
(circular '(2 5 8 ))
(type-of '(1 . 7))
(typep '(1 . 7) '(cons fixnum fixnum))
(declaim (ftype (function (string (cons fixnum fixnum)) string) test-types))
(defun test-types (s tup)
(format nil "~a here, sup ~a~%" tup s))
(test-types "hello" '(1 . 4))
;; cool, but i want for separate arguments, so that it could be also used in defgeneric ?
(defun test-types-2 (ss tt str)
(declare (type string ss)
(type (cons fixnum string) tt)
;; (type 'string str)
)
(format t "~a ~a ~a" ss tt str))
(test-types-2 "hello" '(1 . "yy") 13)
;; that works!
;; and will probably work with defgeneric?
(defgeneric test-types-3 (obj str)
(declare (ignore str)))
;; doesn't work.
;; http://www.lispworks.com/documentation/HyperSpec/Body/m_defgen.htm
;; only allows "optimize" declaration
;; The special, ftype, function, inline, notinline, and declaration declarations are not permitted. Individual implementations can extend the declare option to support additional declarations.
;; OK
;; so, do i want to have separate classes and generic methods for checking left | bottom | right?
;; possibly, yes. and for printing
;; how do I select "anchor point"? from which i'd do checking?
;; well, HM. it could be always lowest point, i guess
;; how'd i do the check for moving left?
;; pass in array, and coord of the anchor, compute locally coords to check and check array content at that point
(defparameter *test-grid* nil)
(defun init-test-grid (height)
(declaim (type fixnum height))
(setq *test-grid*
(let*
((grid (make-array `(,height 7) :initial-element #\.))
(rownum (1- (array-dimension grid 0)))
(rowsize (array-dimension grid 1))
(row (make-array rowsize
:displaced-to grid
:displaced-index-offset (* rownum rowsize))))
(loop for i from 0 below (array-total-size row) do
(setf (aref row i) #\_))
grid))
nil)
(init-test-grid 200)
(defun print-grid (grid )
(let ((rows (array-dimension grid 0))
(rowsize (array-dimension grid 1)))
(terpri)
(loop for rownum from 0 below rows
do (let ((row-arr
(make-array rowsize
:displaced-to grid
:displaced-index-offset (* rownum rowsize))))
(format t "|~a|~%" (coerce row-arr 'string) )))
(terpri)))
(print-grid *test-grid* )
(print-grid *test-grid* ) ; well, it will hardly be helpful without specifying slice. if we're to drop Ks and Ms of stones
*test-grid*
;; (ql:quickload 'array-operations)
;; what's displaced array? would it be easy to get rows from multidimentional that way?
;; https://lispcookbook.github.io/cl-cookbook/arrays.html
;; The reduce function operates on sequences, including vectors (1D arrays), but not on multidimensional arrays.
;; To get around this, multidimensional arrays can be displaced to create a 1D vector.
;; Displaced arrays share storage with the original array, so this is a fast operation which does not require copying data:
(setf (aref (make-array 7 :displaced-to *test-grid*) 0) #\!)
;; if i just to :displaced-to it makes linear array of size 7 from index 0
;; now let's try to take third row
(setf (aref (make-array 7 :displaced-to *test-grid* :displaced-index-offset (* 2 7)) 0) #\?)
;; so :displaced-index-offset (* row cols) would get me correct row. and i could iterate over it and write into the array i suppose
;; how do i best loop over array?
(let*
((grid *test-grid*)
(rownum 2)
(rowsize (array-dimension grid 1))
(row (make-array rowsize
:displaced-to grid
:displaced-index-offset (* rownum rowsize))))
(loop for i from 0 below (array-total-size row) do
(setf (aref row i) #\%)))
*test-grid*
;; ok. and maybe i'd have to what? wrap grid in class that would translate the BOTTOM & Y into actual ROWNUM
;; ok, next problem - it can't really be infinite height, could need to shift down sometimes?
;; maybe every 1000 check 3 lines and if there's no vertical clearings - shift all down?
;;; GENERIC CODE for figures
(defclass figure () ())
;; maybe only for debugging and printing
(defgeneric all-points-from-hook (fig hook)) ; do i need that?
(defgeneric check-down-points (fig hook))
(defgeneric check-left-points (fig hook))
(defgeneric check-right-points (fig hook))
(defgeneric get-fig-top (fig hook)) ; for updating TOP
(defun points-into-array (points array ch)
(loop for (row . col) in points
do (setf (aref array row col) ch)))
(defmethod resting-into-array ((fig figure) array hook)
(declare (type (cons fixnum fixnum) hook)) ; also would like to declare array type
(loop for (row . col) in (all-points-from-hook fig hook)
do (setf (aref array row col) #\#))) ; save figure points into array. can be common for all figures
;; the figures start with their lovest point 3 units higher than TOP
;; and leftmost point 2 units to the right of left wall
;; so that i guess a good HOOK location
;; how would common code work? 0 .. 6 array
;; - generate hook position: (2 . (top + 3 + 1))
;; - check down,
;; if move - update hook, maybe update TOP & side-turn
;; else - call finalize into arry; go into same loop for next figure
;;
;; side move - read in direction, select check, apply result of the check to the Y coord of the HOOK
;; if it's DO loop. then what are the VARS:
;; figure, hook, iterations
;; is-resting is exit check, exit Sexp is finalizing TOP and INTO-ARR
;; then next figure loop could continue
;; also DO would count the iterations? could return the iterations, i guess
;; NOPE: we're counting amount of rocks that stopped
;; so, return TOP i guess, or owerwrite TOP that's set up in external LOOP
;; which takes FIGURE from infinite figure looped list
;;
;; ok, i guess
;; let's impelement one figure first, and then generic code. and check that
;;; so, now i could write the generic looping movement down?
;;; hmmm. i could code 2000 size array, but yup. probably should code row calculation immediately
;;; and maybe add ##### flor at the -1 ?
;; oh, come on, let's just make a big array, i have 32Gb of ram, shouldn't that be enough for one time run?
(defmethod is-point-free (hook array)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (row . col)
hook
(and (>= col 0)
(>= row 0)
(< row (array-dimension array 0))
(< col (array-dimension array 1))
(equal #\. (aref array row col)))))
;; really want to declare also array type
(is-point-free '(-1 . 2) *test-grid*)
(is-point-free '(0 . 2) *test-grid*)
(is-point-free '(9 . 2) *test-grid*)
(is-point-free '(1 . 9) *test-grid*)
(is-point-free '(2 . 0) *test-grid*)
(is-point-free '(2 . 1) *test-grid*)
(is-point-free '(2 . 2) *test-grid*)
(aref *test-grid* 2 2)
(equal #\. #\#)
(defmethod check-move ((fig figure) array hook direction)
(declare (type (cons fixnum fixnum) hook)
(type symbol direction))
(let* ((points-to-check (case direction
(DOWN (check-down-points fig hook))
(LEFT (check-left-points fig hook))
(RIGHT (check-right-points fig hook))
(t nil)))
(can-move (loop for check-point in points-to-check
always (is-point-free check-point array))))
(if (not can-move)
0
(case direction
(down 1)
(left -1)
(right 1)))))
;; https://sodocumentation.net/common-lisp/topic/1369/loop--a-common-lisp-macro-for-iteration thanks
(defun -check-fig (fig)
(let ((hook '(7 . 2)))
(init-test-grid 200)
(resting-into-array fig *test-grid* hook)
(print-grid *test-grid*)
(points-into-array (check-down-points fig hook) *test-grid* #\D)
(print-grid *test-grid*)
(points-into-array (check-left-points fig hook) *test-grid* #\L)
(print-grid *test-grid*)
(points-into-array (check-right-points fig hook) *test-grid* #\R)
(print-grid *test-grid*)
(init-test-grid 200)
))
;; hook is left point
;;; First figure class Horizontal Line
(defclass h-line (figure) ())
(defparameter *test-h-line* (make-instance 'h-line))
(defmethod all-points-from-hook ((fig h-line) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (row . col)
hook
(list (cons row col) (cons row (1+ col)) (cons row (+ 2 col)) (cons row (+ 3 col)))))
(all-points-from-hook *test-h-line* '(1 . 3 ))
;; well, check-down could be a generic method over figure with 'down-check-points' being generic methods specialized for figures. ok, i guess
;; row 0 should be top. The higher row - the lower thing is.
(defmethod check-down-points ((fig h-line) hook)
(declare (type (cons fixnum fixnum) hook))
(mapcar (lambda (coord)
(cons (1+ (car coord)) (cdr coord)))
(all-points-from-hook fig hook)))
(check-down-points *test-h-line* '(1 . 2))
(resting-into-array *test-h-line* *test-grid* '(2 . 1))
;; if DOWN is from zero, then LEFT is also from zero
(defmethod check-left-points ((fig h-line) hook)
(declare (type (cons fixnum fixnum) hook))
(list (cons (car hook) (1- (cdr hook)))))
(check-left-points *test-h-line* '(1 . 2)) ; (ROW . COL) that's quite prone to errors
;; if DOWN is from zero, then RIGHT is to zero
(defmethod check-right-points ((fig h-line) hook)
(declare (type (cons fixnum fixnum) hook))
(list (cons (car hook) (+ 4 (cdr hook)))))
(check-right-points *test-h-line* '(1 . 2))
(defmethod get-fig-top ((fig h-line) hook)
(declare (type (cons fixnum fixnum) hook))
(car hook)) ; for updating TOP
*test-grid*
(resting-into-array *test-h-line* *test-grid* '(0 . 0))
(resting-into-array *test-h-line* *test-grid* '(2 . 0))
;; (resting-into-array *test-h-line* *test-grid* '(3 . 4))
;; (defgeneric get-fig-top (fig hook)) ; for updating TOP
;;; now I could try to build a generic inner loop;
;; NEXT classes
;; WHELP. figure appears +4 from lowest point and +2 from leftmost
;; that means that hook for cross would be not a part of figure, but leftbottom corner
(defclass cross (figure) ())
(defmethod all-points-from-hook ((fig cross) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,(- hook-row 2) . ,(1+ hook-col))
(,(1- hook-row) . ,hook-col) (,(1- hook-row) . ,(1+ hook-col)) (,(1- hook-row) . ,(+ 2 hook-col))
(,hook-row . ,(1+ hook-col))
)
)
) ; do i need that?
(defparameter *test-cross* (make-instance 'cross))
(init-test-grid 200)
(resting-into-array *test-cross* *test-grid* '(2 . 2))
(print-grid *test-grid*)
(defmethod check-down-points ((fig cross) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,hook-row . ,hook-col) (,hook-row . ,(+ 2 hook-col))
(,(1+ hook-row) . ,(1+ hook-col))
)
)
)
(defmethod check-left-points ((fig cross) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,(- hook-row 2) . ,hook-col)
(,(1- hook-row) . ,(1- hook-col))
(,hook-row . ,hook-col)
)
)
)
(check-left-points *test-cross* '(18 . 2))
;; hook:(18 . 2); moveLEFT -> 0
;; so why is this?
(defmethod check-right-points ((fig cross) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,(- hook-row 2) . ,(+ 2 hook-col))
(,(1- hook-row) . ,(+ 3 hook-col))
(,hook-row . ,(+ 2 hook-col))
)
)
)
(defmethod get-fig-top ((fig cross) hook)
(declare (type (cons fixnum fixnum) hook))
(- (car hook) 2) ; for updating TOP
)
(defclass bracket (figure) ())
(defparameter *test-bracket* (make-instance 'bracket))
(defmethod all-points-from-hook ((fig bracket) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,(- hook-row 2) . ,(+ 2 hook-col))
(,(- hook-row 1) . ,(+ 2 hook-col))
(,hook-row . ,hook-col)(,hook-row . ,(+ 1 hook-col))(,hook-row . ,(+ 2 hook-col))
)
)
) ; do i need that?
(defmethod check-down-points ((fig bracket) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,(+ hook-row 1) . ,hook-col)(,(+ hook-row 1) . ,(+ 1 hook-col))(,(+ hook-row 1) . ,(+ 2 hook-col))
)))
(defmethod check-left-points ((fig bracket) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,(- hook-row 2) . ,(+ 1 hook-col))
(,(- hook-row 1) . ,(+ 1 hook-col))
(,hook-row . ,(- hook-col 1))
)))
(defmethod check-right-points ((fig bracket) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,(- hook-row 2) . ,(+ 3 hook-col))
(,(- hook-row 1) . ,(+ 3 hook-col))
(,hook-row . ,(+ 3 hook-col))
)))
(defmethod get-fig-top ((fig bracket) hook)
(declare (type (cons fixnum fixnum) hook))
(- (car hook) 2) ; for updating TOP
)
(defclass v-line (figure) ())
(defparameter *test-v-line* (make-instance 'v-line))
(defmethod all-points-from-hook ((fig v-line) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,(- hook-row 3) . ,hook-col)
(,(- hook-row 2) . ,hook-col)
(,(- hook-row 1) . ,hook-col)
(,hook-row . ,hook-col)
))
) ; do i need that?
(defmethod check-down-points ((fig v-line) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,(+ hook-row 1) . ,hook-col)
))
)
(defmethod check-left-points ((fig v-line) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,(- hook-row 3) . ,(- hook-col 1))
(,(- hook-row 2) . ,(- hook-col 1))
(,(- hook-row 1) . ,(- hook-col 1))
(,hook-row . ,(- hook-col 1))
))
)
(defmethod check-right-points ((fig v-line) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,(- hook-row 3) . ,(+ hook-col 1))
(,(- hook-row 2) . ,(+ hook-col 1))
(,(- hook-row 1) . ,(+ hook-col 1))
(,hook-row . ,(+ hook-col 1))
))
)
(defmethod get-fig-top ((fig v-line) hook)
(declare (type (cons fixnum fixnum) hook))
(- (car hook) 3) ; for updating TOP
) ; for updating TOP
(defclass square (figure) ())
(defparameter *test-square* (make-instance 'square))
(defmethod all-points-from-hook ((fig square) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,(- hook-row 1) . ,hook-col) (,(- hook-row 1) . ,(+ hook-col 1))
(,hook-row . ,hook-col) (,hook-row . ,(+ hook-col 1))
))
) ; do i need that?
(defmethod check-down-points ((fig square) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,(+ hook-row 1) . ,hook-col) (,(+ hook-row 1) . ,(+ hook-col 1))
))
)
(defmethod check-left-points ((fig square) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,(- hook-row 1) . ,(- hook-col 1))
(,hook-row . ,(- hook-col 1))
))
)
(defmethod check-right-points ((fig square) hook)
(declare (type (cons fixnum fixnum) hook))
(destructuring-bind (hook-row . hook-col)
hook
`(
(,(- hook-row 1) . ,(+ hook-col 2))
(,hook-row . ,(+ hook-col 2))
))
)
(defmethod get-fig-top ((fig square) hook)
(declare (type (cons fixnum fixnum) hook))
(- (car hook) 1) ; for updating TOP
) ; for updating TOP
;; COPY from above
;; how would common code work? 0 .. 6 array
;; - generate hook position: (2 . (top + 3 + 1))
;; - check down,
;; if move - update hook, maybe update TOP & side-turn
;; else - call finalize into arry; go into same loop for next figure
;;
;; side move - read in direction, select check, apply result of the check to the Y coord of the HOOK
;; if it's DO loop. then what are the VARS:
;; figure, hook, iterations
;; is-resting is exit check, exit Sexp is finalizing TOP and INTO-ARR
;; then next figure loop could continue
;; also DO would count the iterations? could return the iterations, i guess
;; NOPE: we're counting amount of rocks that stopped
;; so, return TOP i guess, or owerwrite TOP that's set up in external LOOP
;; which takes FIGURE from infinite figure looped list
(let* ((grid *test-grid*)
(top (1- (array-dimension grid 0))) ; max row with stone, get's smaller. 0 on the TOP
(figures (circular (list *test-h-line*)))
;; (fig *test-h-line*)
;; (hook (cons (- top 4) 2))
(lateral-moves (circular '(left right))))
;; outer loop is simple dotimes for amount of figures we want to drop
(dotimes (i 19)
;; let's do simple loop? returning when no longer can move down?
;; move down
(let ((hook (cons (- top 4) 2))
(fig (pop figures)))
(loop
;; first check lateral move (just after apperaing)
(let ((lateral-change (check-move fig grid hook (pop lateral-moves))))
(setq hook (cons (car hook) (+ lateral-change (cdr hook)))))
;; then check if possible to go down
(when (= 0 (check-move fig grid hook 'down))
;; all moves down done, update TOP and exit for next FIG
(setq top (min top (get-fig-top fig hook)))
(resting-into-array fig grid hook)
(return))
;; more moves down exist
;; do move down, and loop for the lateral change and possible exit
(setq hook (cons (1+ (car hook)) (cdr hook)))))))
(init-test-grid 200)
(print-grid *test-grid*)
*test-grid*
(let ((my-list '(1 2 3 4)))
`(returning ,(pop my-list) ,my-list))
;; well it seems to work maybe ok.
(defun print-intermediate-step (fig grid hook)
(let ((fig-points (all-points-from-hook fig hook)))
(points-into-array fig-points grid #\@)
(print-grid grid)
(points-into-array fig-points grid #\.)))
;; let's generalize this?
(defun try-dropping (figures lateral-moves
times grid height)
;; (print-grid grid)
(let* ((top (1- (array-dimension grid 0))) ; max row with stone, get's smaller. 0 on the TOP
(percent-index (floor (/ times 100)))
(running-percent-index 0)
(additional-count 0))
;; outer loop is simple dotimes for amount of figures we want to drop
(dotimes (i times)
;; fuck i forgot about my inverted TOP. it goes to 0
(when (< top (/ height 20))
;; ok. let's think about this.
;; my "TOP" for 10 rows is 8, overall indices start from 0
;; but "TOP" would be what?
;; it would start on 9. on the "already occupied" line
;; (by the floor, which we don't want to count)
;; so if TOP is 2, then 2 is "already occupied"
;; and only 2 left, so it's 7 elements
;; 10 - 2 - 1 how much we're need to count
;; which row i want to copy? the TOP, right?
;; if top is 9, then
;;
;; ok. let's count TOP at the moment of TRUNCATE
;; that would leave us with 1 unnecessary - the manual "floor"
(incf additional-count
(- (array-dimension *test-grid* 0) top 1))
(format t "Truncating~%" )
(setq grid (truncate-grid grid top height))
(setq top (1- (array-dimension grid 0)))
)
(when (= percent-index running-percent-index)
(setq running-percent-index 0)
(format t "One more: ~a%, , intermediate height: ~a; the step is ~a; the times is ~a~%"
(floor (* 100 (/ i times))) (- (array-dimension grid 0) top 1) i times)
)
(incf running-percent-index)
;; let's do simple loop? returning when no longer can move down?
;; move down
(let ((hook (cons (- top 4) 2))
(fig (pop figures)))
;; (print-intermediate-step fig grid hook)
(loop
;; first check lateral move (just after apperaing)
;; (print-intermediate-step fig grid hook)
(let* ((lat-move (pop lateral-moves))
(lateral-change (check-move fig grid hook lat-move)))
(setq hook (cons (car hook) (+ lateral-change (cdr hook))))
;; (format t "Looping for ~a figure ~a~%hook:~a; move~a -> ~a~%"
;; i fig hook lat-move lateral-change)
)
;; (print-intermediate-step fig grid hook)
;; then check if possible to go down
(when (= 0 (check-move fig grid hook 'down))
;; all moves down done, update TOP and exit for next FIG
(setq top (min top (get-fig-top fig hook)))
(resting-into-array fig grid hook)
(return))
;; more moves down exist
;; do move down, and loop for the lateral change and possible exit
(setq hook (cons (1+ (car hook)) (cdr hook))))))
(+ additional-count (- (array-dimension grid 0) top 1)))
;; (print-grid grid)
)
;; (init-test-grid 200)
;; (try-dropping (circular (list *test-h-line*)) (circular '(right left)) 9 *test-grid*)
;; (try-dropping (circular (list *test-h-line*)) (circular '(right)) 9 *test-grid*)
;; (try-dropping (circular (list *test-h-line*)) (circular '(right right left)) 9 *test-grid*)
;; (try-dropping (circular (list *test-cross* *test-h-line*))
;; (circular '(right right left)) 1 *test-grid*)
;; ;; seems maybe ok.
;; (try-dropping (circular (list *test-cross* *test-h-line*))
;; (circular '(right left left left left left)) 4 *test-grid*)
;; ;; now to implement the other figures. it's not quite fun
;; (try-dropping (circular (list *test-cross* *test-h-line*))
;; (circular '(left)) 1 *test-grid*) ; this is not right. no lateral moves done
;; (init-test-grid 200)
;; (try-dropping (circular (list *test-cross* *test-h-line*))
;; (circular '(right right left right)) 5 *test-grid*) ; this is not right. no lateral moves done
;; (try-dropping (circular (list *test-cross* *test-h-line*))
;; (circular '(left left right right right right left right)) 5 *test-grid*) ; this is not right. no lateral moves done
;; this is failure
;; ugh. this is failure. i'd rather take all points and shift them down \ left \ right
;; than do this manually
;; or - have better visual testing.
;; do (put-to-array) for left and for right and for down, and for figure
(-check-fig *test-cross*)
(-check-fig *test-h-line*)
(-check-fig (make-instance 'bracket))
(-check-fig *test-v-line*)
(-check-fig *test-square*)
;; ok, with this things would have to be better
;; and with this check fig, could at least visually check 3 other figures
;; (init-test-grid 20)
;; (try-dropping (circular (list *test-cross* *test-h-line* *test-bracket*))
;; (circular '(left left right right right right left right)) 5 *test-grid*) ; this is not right. no lateral moves done
;; ;; ok, i guess
;; (init-test-grid 100)
;; (try-dropping (circular (list *test-cross* *test-h-line* *test-bracket* *test-v-line*))
;; (circular '(left left right right right right left right)) 55 *test-grid*) ; this is not right. no lateral moves done
;; ok, maybe. but overall - ugh.
;; so, run the test data? oh, i havent' yet consumed the data. but it's in few lines,
;; right
(defparameter *test-lat-chars* ">>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>")
(defparameter *test-lat-symbs*
(mapcar (lambda (ch) (case ch
(#\< 'LEFT)
(#\> 'RIGHT))) (coerce *test-lat-chars* 'list)))
(defparameter *shapes-order*
(list *test-h-line* *test-cross* *test-bracket* *test-v-line* *test-square*))
(defparameter *endless-shapes* (circular *shapes-order*))
(defparameter *endless-test-laterals* (circular *test-lat-symbs*))
;; now, i'd want to drop 2022 rocks. in example it should yield 3068 height
(typep 1 'fixnum)
(init-test-grid 10000)
(defparameter *test-run-result* 0)
;; (setq *test-run-result*
;; (try-dropping *endless-shapes*
;; *endless-test-laterals* 2022 *test-grid*)) ; this is not right. no lateral moves done
(print-grid *test-grid*)
;; ok my 7010 is to be deducted from 10000
(- (array-dimension *test-grid* 0) *test-run-result* 1)
;; well, something is wrong with the square
;; how could i test square without printing intermediate steps? well, i could add that, yeah
;;; let's add per-turn printing as well.
(init-test-grid 50)
;; (defparameter *test-run-result*
;; (try-dropping *endless-shapes*
;; *endless-test-laterals* 15 *test-grid*)) ; this is not right. no lateral moves done
;; well, let's run 2022 for my own input?
(defparameter *input-lat-chars* (uiop:read-file-string "day17-input.txt"))
(length (coerce *input-lat-chars* 'list))
(defparameter *input-lat-symbs*
(remove-if-not #'identity (mapcar (lambda (ch) (case ch
(#\< 'LEFT)
(#\> 'RIGHT))) (coerce *input-lat-chars* 'list))))
(print *input-lat-symbs*) ; cool, it has NIL in the end. why?
(defparameter *endless-input-laterals* (circular *input-lat-symbs*))
(type-of *input-lat-symbs*)
(typep *input-lat-symbs* 'list)
(length *input-lat-symbs* )
(init-test-grid 10000)
;; (defparameter *task-run-result*
;; (try-dropping *endless-shapes*
;; *endless-input-laterals* 2022 *test-grid*)) ; this is not right. no lateral moves done
(- (array-dimension *test-grid* 0) *task-run-result* 1)
;; PART 2
;; In the example above, the tower would be 1514285714288 units tall!
;; How tall will the tower be after 1000000000000 rocks have stopped?
;; so. let's print out intermediate? each 1% ?
;; 866549760 bytes available, 112800000000144 requested.
(floor (/ 112800000000144 866549760))
(floor (/ 910721024 1024 1024 1024)) ; available
(floor (/ 112800000000144 1024 1024 1024)) ; 105000 iGb requested
;; so, no
;; so, how'd i print report each 1% ?
(init-test-grid 10000)
(defparameter
*task-2-run-result* 0)
;; (setq *task-2-run-result*
;; (try-dropping *endless-shapes*
;; *endless-input-laterals* 2022 *test-grid*)) ; this is not right. no lateral moves done
(- (array-dimension *test-grid* 0) *task-2-run-result* 1)
(mod 7 4)
;; ok. i'd want to what? maybe every million size truncate?
;; when size get to 1M, get last row (height - 1?)
;; copy that last row to the first, add to the
(defun truncate-grid (grid top-row height)
(let*
((rownum (1- (array-dimension grid 0))) ; bottom row
(new-grid (make-array `(,height 7) :initial-element #\.))
(rowsize (array-dimension grid 1))
(row-bottom (make-array rowsize
:displaced-to new-grid
:displaced-index-offset (* rownum rowsize)))
(row-top (make-array rowsize
:displaced-to grid
:displaced-index-offset (* top-row rowsize))))
(gc :full t)
(loop for i from 0 below (array-total-size row-bottom) do
(setf (aref row-bottom i) (aref row-top i)))
new-grid))
;;; well, it will not work.
;; but let's try? first on test, and then maybe cancel
(/ 56000512 1024 1024) ; 54 Mb, that's WTF
(gc :full t)
(init-test-grid 100)
(defparameter *test-run-result* 0)
(setq *test-run-result* (try-dropping *endless-shapes*
*endless-test-laterals* 2022 *test-grid* 100)) ; this is not right. no lateral moves done
;; ok my 7010 is to be deducted from 10000
;; oh and one more transformation. hmmm hmmm
;; with enough grid 3068 - ok
;; when doing by 1000 - nok 3063. i'm missing rows somewhere
;;
;; i'm looking height when i'm truncating
(room t)
(init-test-grid 700)
(defparameter *test-run-result* 0)
(setq *test-run-result* (try-dropping *endless-shapes*
*endless-test-laterals* 2022 *test-grid* 700)) ; this is not right. no lateral moves done
;; but loosing 2 when do 1 truncating
;; 3087 when doing how many truncating?
;; for 500 600 700 wildly different numbers, so
;; yup. fuck if i only transfer last row - then hole in that last row is considered what?
;; yuck. i'd need to transfer serveral layers and still no guarantee
;;
;; how about i transfer 100 rows?
;; i'd init grid on my own, keep 100 rows below this is ugly as hell
;;
;; so, only good way is to actually trigger TRANSFER when there's possibility in
;; good enough floor
;;
;; and to know how to calculate correct amount of "negative space" below.
;; yuk.
;;; PART 2, again.
;; so the advice was to "find the loop"
;; loop would depend on 3 things that should match exactly: the current item, the current left-right movement, the last N (100, 200?) lines of the tower,
;; so that any falling figures would stop at same levels.
;; let's try to discover how could i compute hashes from collections and other things in CL?
;; maybe i could just use a triplet as a hash-key?
;; so, let's try with the hmmmm, i'd need to take first N of 'left and 'right, in order not to break hashmap
(defparameter *test-hashing-map* (make-hash-table :test #'equalp))
(setf (gethash '(left left right) *test-hashing-map*) 1)
(gethash '(left left right) *test-hashing-map*)
;; for lists it seems to work
;; then how about slices of the 2d array?
(defparameter *test-big-array* (make-array '(7 4) :initial-element #\.))
(defparameter *test-array-line-3* (make-array 4 :displaced-to *test-big-array* :displaced-index-offset (* 4 2)))
(defparameter *test-array-line-4* (make-array 4 :displaced-to *test-big-array* :displaced-index-offset (* 4 3)))
(setf (gethash *test-array-line-3* *test-hashing-map*) 111)
(gethash *test-array-line-4* *test-hashing-map*) ; nope, with arrays - not by contents, even when they are identical. so. i'd want a hashing funciton?
; for the contencts of the displaced array that takes 100 previous rows (including the top filled)
; so with #'equalp arrays seem to point to same thing?
; and if i change one array, then only by the new key value i retrieve the stored data.
; seems ok, i guess
(setf (aref *test-array-line-3* 3) #\?)
(sxhash *test-array-line-3*)
;; => 1193941381096739655 (61 bits, #x1091BB5C3EE91347)
(sxhash *test-array-line-4*)
(equalp *test-array-line-3* *test-array-line-4*) ; equal not good enough, with #'equalp - contents are checked
;; => 1193941381096739655 (61 bits, #x1091BB5C3EE91347)
;; ;; wait! it's the same!, but even after i changed contents?
;; so, i could do what? can i create list of left and right?
(defparameter *test-list-for-circ* '(left left right left left right right right))
(defparameter *test-circ* (copy-list '(left left right left left right right right)))
;; oh, this modifies in place, not nice
(circular *test-circ*) ; hehe, and calling it twice - it starts to look for the end. whops
(defparameter *test-0-offset-circ*
(subseq *test-circ* 0 (length *test-list-for-circ*))) ; seems ok.
(defparameter *test-2-offset-circ*
(progn
(pop *test-circ*)
(pop *test-circ*)
(subseq *test-circ* 0 (length *test-list-for-circ*))
))
*test-0-offset-circ*
*test-2-offset-circ*
;; i think that's ok.
;; so, gather these things into a list:
;; the offset 100 previous rows of the array
;; the current 'left 'right list subseq
;; and the current shape
;; could do this only on steps that start new shape
;; and check hashmap \ put into hashmap for future. for the previous line that had same structure.
;;
;; so, maybe 10M? 20M of lines to check?
;; create hashmap outside.
;; take initial slice of lateral-moves, mix with current-shape, and last 100 lines of grid (including top-filled-line-index)
;; create hashmap on the outside, with :test #'equalp
;;
;; now. if 0 is what? top. how would i calculate index from which to start TOP 100 lines?
;; if index 0, and i want 0th line - 0 * lineleng
;; so if index is 115 and i want TOP 5 it will be 111 112 113 114 115. so -5 + 1
;; so (- top-filled-line-index 4) is what should get multiplied by line len to get start of the start of TOP 100 lines
;; and if 0 is the bottom, then 1st line is 1 * 7
;;
;; now. hashtable returns second return value that signifies whether value was present in the hashtable
;;
(defun check-for-loop (top-filled-line-index lateral-moves
lateral-moves-initial-number current-shape grid states-hashmap)
(let* ((cur-moves (subseq lateral-moves 0 lateral-moves-initial-number))
(top-100-lines-lements-amount (* 7 100))
(start-index-of-top-100-lines (* 7 (- top-filled-line-index 99)))
(last-100-lines (make-array top-100-lines-lements-amount :displaced-to grid :displaced-index-offset start-index-of-top-100-lines))
(full-state (list current-shape cur-moves last-100-lines))
(hashmap-check (gethash full-state states-hashmap)))
(if (nth-value 1 hashmap-check)
;; state WAS previously saved
;; return the previous index where that was the case
(nth-value 0 hashmap-check)
;; first time seeing this state
(progn
(setf (gethash full-state states-hashmap) top-filled-line-index)
nil))))
;; now in our shitty throwing contest, let's call that function and whenever it finds a loop
;; print it out
(defparameter *found-loop-info* nil)
(defun try-dropping-search-loop (figures initial-lateral-moves
times grid)
;; (print-grid grid)
(format t "starting~%")
(let* ((top (1- (array-dimension grid 0))) ; max row with stone, get's smaller. 0 on the TOP
(percent-index (floor (/ times 100)))
(running-percent-index 0)
(additional-count 0)
(states-for-100-lines (make-hash-table :test #'equalp))
(endless-lateral-moves (circular initial-lateral-moves)))
;; outer loop is simple dotimes for amount of figures we want to drop
(dotimes (i times)
;; fuck i forgot about my inverted TOP. it goes to 0
(when (= percent-index running-percent-index)
(setq running-percent-index 0)
(format t "One more: ~a%, , intermediate height: ~a; the step is ~a; the times is ~a~%"
(floor (* 100 (/ i times))) (- (array-dimension grid 0) top 1) i times)
)
(incf running-percent-index)
(let* ((hook (cons (- top 4) 2))
(fig (pop figures))
(check-result (check-for-loop top endless-lateral-moves (length initial-lateral-moves)
fig grid states-for-100-lines)))
(when (check-result)
(setq *found-loop-info* `(found ,check-result start point at ,top check
with ,fig ))
(format t "found loop previously recorded at ~a
now it's ~a" check-result top)
)
;; (print-intermediate-step fig grid hook)
(loop
;; first check lateral move (just after apperaing)
;; (print-intermediate-step fig grid hook)
(let* ((lat-move (pop lateral-moves))
(lateral-change (check-move fig grid hook lat-move)))
(setq hook (cons (car hook) (+ lateral-change (cdr hook))))
;; (format t "Looping for ~a figure ~a~%hook:~a; move~a -> ~a~%"
;; i fig hook lat-move lateral-change)
)
;; (print-intermediate-step fig grid hook)
;; then check if possible to go down
(when (= 0 (check-move fig grid hook 'down))
;; all moves down done, update TOP and exit for next FIG
(setq top (min top (get-fig-top fig hook)))
(resting-into-array fig grid hook)
(return))
;; more moves down exist
;; do move down, and loop for the lateral change and possible exit
(setq hook (cons (1+ (car hook)) (cdr hook))))))
(+ additional-count (- (array-dimension grid 0) top 1)))
;; (print-grid grid)
)
(gc :full t)
(room t)
;; (/ (- sb-vm:dynamic-space-end sb-vm:dynamic-space-start) (expt 1024 2))
(init-test-grid 200000000)
;; 991133696 bytes available,
;; 5600000016 requested.
(sb-vm::dynamic-space-size)
;; 1073741824 (31 bits, #x40000000)
;; is that in bytes?
(sb-ext:dynamic-space-size)
;; 1073741824 (31 bits, #x40000000)
(/ 1073741824 1024 1024 1024 1024) ; 1/1024
;; so maybe in megabites
(/ 1073741824 1024 1024 1024) ; 1/1024
;; it seems that it's 1 Gb, not funny
;; (/ 981172224 1024 1024 1024 1024)
;; (* 10 1024 )
;; (* 1024 3)
;; ok, this is ridiculous
;; let's forget this
;;
;; i can't get more than 1 Gb
;; CL-USER> (sb-ext:dynamic-space-size)
;; 1073741824 (31 bits, #x40000000)
;; ok.
;;
;; Ugh. So. what? what do you do Sly. why not passing?
;;
;; so, with just inferior lisp it works. when i do it without "="
;;
;; ok. let's again, forget all that? ugh. so hard to just move on
;; yes, just move on. 1 Gb is what i get. can't figure out the configuration.
;; ugh
;;
;; UGH! I'm kind of hating it.
;; Interactively, both COMMAND and CODING-SYSTEM are nil and the
;; sly-restart-inferior-lisp didn't restart the underlying sbcl,
;; i suppose it should have asked.
;; oh, but I haven't even tried the M-x sly command
;;
;; so, maybe even just the
;; (setq inferior-lisp-program "sbcl --dynamic-space-size 10240")
;; could have been enough, if I actually killed the sbcl, not just restart
;;
;; well, this is strange
;; it does seem that it should "reastart" inferior lisp
;;
;; YUP, that's it. Thanks i hate it.
;; do i want to try to run this thing?
(defparameter *test-run-result* 0)
(setq *test-run-result* (try-dropping-search-loop *endless-shapes*
*input-lat-symbs* 10 *test-grid* )) ; this is not right. no lateral moves done
;; well, i think NOW i can let it go.
;; and return back LATER, to REWRITE THIS ANEW WITH MY UPDATED KNOWLEDGE.
;; SO HERE I GO, LEAVING THIS BEHIND

2893
day18-input.txt Normal file

File diff suppressed because it is too large Load Diff

166
day18-scratch.lisp Normal file
View File

@@ -0,0 +1,166 @@
;; ;; https://adventofcode.com/2022/day/18
;; so, 1x1x1 cubes on grid, given by x-y-z coords,
;; so each line is 1 cube.
;;
;; my guess is 1,1,1 is cube [0,1]x[0,1]x[0,1]
;; and 2,1,1 is cube [1,2]x[0,1]x[0,1]
;;
;; for cubes to have "joint" side - two dimentions should be totally same
;;
;; so, could do what? put into 3d array?
;; have 3 hash tables?
;;
;; allright, looking at discussions already.
;; i "could" consider these as graph nodes, but what would be the edges?
;;
;; the 3d array would be 'connectivity' matrix
;; then i'd want what ? go through all the nodes.
;; and for each node know how many neighbors it has.
;; that would directly transform into how many sides are open.
;; ok, i guess
(defparameter *day-18-test-input*
(mapcar
(lambda (line)
(mapcar #'parse-integer (cl-ppcre:split "," line)))
(uiop:read-file-lines "day18-test.txt")))
(setq *day-18-test-input* (coords-from-input "day18-test.txt"))
;; so. init array and fill with nodes
;; figure out maximal values?
(loop
for (x y z) in *day-18-test-input*
maximize x into xs
maximize y into ys
maximize z into zs
finally (return (list xs ys zs)))
;; => (3 3 6)
(defparameter *day-18-test-graph-connectivity*
(make-array '(4 4 7) :initial-element 0))
;; fill the array with nodes
(loop
for (x y z) in *day-18-test-input*
do (setf (aref *day-18-test-graph-connectivity* x y z) 1))
;; and now would have to do full scan? that's not very fun =/
;; well, it's not quite what a connectivity matrix is, isn't it?
;; connectivity has 1 in (i j) if from node i to node j there's edge
;; and it current case we have only 1 unit length connections.
;; here's that
(neighbors-for '(2 2 2) *day-18-test-graph-connectivity*)
(neighbors-for '(1 1 1) *day-18-test-graph-connectivity*)
(neighbors-for '(2 3 5) *day-18-test-graph-connectivity*)
;; and now to iterate over all of the array?
;; how'd i do safer aref?
;; well, i guess ok.
(apply #'aref *day-18-test-graph-connectivity* '(2 3 5))
;; this is first time i see something like this
;; how to use that correctly though?
;; so, last value must be a list, and all values are appended
;; so just numbers and nil in the end would work?
;; and more importatntly passing array as just self works.
;; and splitting points as two lists should work, right?
(apply #'aref *day-18-test-graph-connectivity* 2 3 '(5))
;; no, it doesn't, only one by one with last thing as list
;; now loop over all elements as ask amount of neighbors and sum 6-neighbors?
(loop for x from 0 to 3 sum
(loop for y from 0 to 3 sum
(loop for z from 0 to 6
when (= 1 (aref *day-18-test-graph-connectivity* x y z))
summing (- 6
(length (neighbors-for (list x y z)
*day-18-test-graph-connectivity*)))
;; into the-sum
;; collecting (list x y z)
;; into nodes
;; finally (return (list the-sum nodes))
)
))
;; => (42 ((0 0 0) (0 0 1) (0 0 2) (0 0 3) (0 0 4) (0 0 5) (0 0 6)))
(neighbors-for '(2 2 2) *day-18-test-graph-connectivity*)
;; well it's not quite so pliant to use multiple 'summing 'collecting 'max 'into
;; when working with nested loops then
;; for those cases DO macro? =C
(count-open-sides *day-18-test-graph-connectivity*)
;; now for my own input?
(defparameter *day-18-input-coords* nil)
(setq *day-18-input-coords*
(coords-from-input "day18-input.txt"))
(defparameter *day-18-input-connectivity*
(make-array (find-maxes *day-18-input-coords*) :initial-element 0))
(fill-connectivity-array *day-18-input-coords* *day-18-input-connectivity*)
(count-open-sides *day-18-input-connectivity*)
;; now. how could i only include surface area
;; did i need to model points as what?
;;
;; well, i could start with 0th layer. there's no stone there, only air
;; and start filling with 2
;; then count for all points as previously, but only neighbors which are 2
;; i guess
;; so. start at '(0 0 0)
;; then get neighbors, filter those that are 0
;; put into queue / list - actually dfs is good enough, so just recurse?
(point-at-is '(0 0 0) *day-18-test-graph-connectivity* 0)
(point-at-is '(0 0 0) *day-18-test-graph-connectivity* 2)
(fill-outside-with-2 '(0 0 0) *day-18-test-graph-connectivity*)
;; this seems to work.
;; now i want to cound only outside that contacts 2?
;; so, same cound but look for neighbors 2 and count them, not 6 - stone-neighbors
(count-open-sides-to-outside *day-18-test-graph-connectivity*)
;; well, now i need to add 1 to all sides
(setq *day-18-test-input*
(coords-from-input "day18-test.txt"))
(setq *day-18-test-graph-connectivity*
(make-array (find-maxes *day-18-test-input*) :initial-element 0))
(fill-connectivity-array *day-18-test-input* *day-18-test-graph-connectivity*)
(fill-outside-with-2 '(0 0 0) *day-18-test-graph-connectivity*)
(count-open-sides-to-outside *day-18-test-graph-connectivity*)
;; and now it's 58
;; so, let's cound for full input?
;;; part 2
(setq *day-18-input-coords*
(coords-from-input "day18-input.txt"))
(setq *day-18-input-connectivity*
(make-array (find-maxes *day-18-input-coords*) :initial-element 0))
(fill-connectivity-array *day-18-input-coords* *day-18-input-connectivity*)
(fill-outside-with-2 '(0 0 0) *day-18-input-connectivity*)
(count-open-sides-to-outside *day-18-input-connectivity*)
;; 2484 - not correct, too low
;; there's 1 at the edge of the array. whoops. so there are 0s in the input?
;; yep. so now what, shift all by 1? and add one more +1 to the find max?
;; hahaha, this is stupid.
;; but let's do it
(coords-from-input "day18-test.txt") ; yep. +1
;; 2490

13
day18-test.txt Normal file
View File

@@ -0,0 +1,13 @@
2,2,2
1,2,2
3,2,2
2,1,2
2,3,2
2,2,1
2,2,3
2,2,4
2,2,6
1,2,5
3,2,5
2,1,5
2,3,5

71
day18.lisp Normal file
View File

@@ -0,0 +1,71 @@
;; https://adventofcode.com/2022/day/18
(ql:quickload 'cl-ppcre)
(defun coords-from-input (file-name)
(mapcar
(lambda (line)
(mapcar #'parse-integer (cl-ppcre:split "," line)))
(uiop:read-file-lines file-name)))
(defun find-maxes (all-coords)
(loop
for (x y z) in all-coords
maximize (+ x 3) into xs
maximize (+ y 3) into ys
maximize (+ z 3) into zs
finally (return (list xs ys zs))) )
(defun fill-connectivity-array (all-coords connectivity-matrix)
(loop
for (x y z) in all-coords
do (setf (aref connectivity-matrix x y z) 1)))
;; 1 - rock, 0 - initial empty, 2 - outside air
(defun neighbors-for (coords connectivity-matrix &key (type 1))
(labels ((coords-fit (potential-point)
(loop for i from 0 to 2
always (and (< (nth i potential-point)
(array-dimension connectivity-matrix i))
(>= (nth i potential-point) 0)))))
(loop
for deltas in `((1 0 0) (-1 0 0)
(0 1 0) (0 -1 0)
(0 0 1) (0 0 -1))
for neighbor = (mapcar #'+ coords deltas)
when
(and (coords-fit neighbor)
(= type (apply #'aref connectivity-matrix neighbor)))
collect neighbor)))
(defun count-open-sides (connectivity-matrix)
(destructuring-bind (n m k)
(array-dimensions connectivity-matrix)
(loop for x from 0 below n sum
(loop for y from 0 below m sum
(loop for z from 0 below k
when (= 1 (aref connectivity-matrix x y z))
summing (- 6
(length (neighbors-for (list x y z) connectivity-matrix))))))))
(defun point-at-is (coords connectivity-matrix elem)
(= elem (apply #'aref connectivity-matrix coords)))
;; call with initial coord '(0 0 0)
(defun fill-outside-with-2 (coord connectivity-matrix)
(when (point-at-is coord connectivity-matrix 0)
(setf (apply #'aref connectivity-matrix coord) 2)
(mapcar (lambda (neighbor) (fill-outside-with-2 neighbor connectivity-matrix))
(neighbors-for coord connectivity-matrix :type 0))))
(defun count-open-sides-to-outside (connectivity-matrix)
(destructuring-bind (n m k)
(array-dimensions connectivity-matrix)
(loop for x from 0 below n sum
(loop for y from 0 below m sum
(loop for z from 0 below k
when (= 1 (aref connectivity-matrix x y z))
summing (length (neighbors-for
(list x y z)
connectivity-matrix
:type 2)))))))

3
day19-2-input.txt Normal file
View File

@@ -0,0 +1,3 @@
Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 12 clay. Each geode robot costs 4 ore and 19 obsidian.
Blueprint 2: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 11 clay. Each geode robot costs 4 ore and 12 obsidian.
Blueprint 3: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 2 ore and 11 obsidian.

30
day19-input.txt Normal file
View File

@@ -0,0 +1,30 @@
Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 12 clay. Each geode robot costs 4 ore and 19 obsidian.
Blueprint 2: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 11 clay. Each geode robot costs 4 ore and 12 obsidian.
Blueprint 3: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 2 ore and 11 obsidian.
Blueprint 4: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 15 clay. Each geode robot costs 4 ore and 20 obsidian.
Blueprint 5: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 16 clay. Each geode robot costs 4 ore and 17 obsidian.
Blueprint 6: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 19 clay. Each geode robot costs 2 ore and 12 obsidian.
Blueprint 7: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 9 clay. Each geode robot costs 2 ore and 10 obsidian.
Blueprint 8: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 5 clay. Each geode robot costs 3 ore and 7 obsidian.
Blueprint 9: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 11 clay. Each geode robot costs 4 ore and 8 obsidian.
Blueprint 10: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 16 clay. Each geode robot costs 2 ore and 15 obsidian.
Blueprint 11: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 20 clay. Each geode robot costs 2 ore and 19 obsidian.
Blueprint 12: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 16 clay. Each geode robot costs 3 ore and 20 obsidian.
Blueprint 13: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 3 ore and 14 obsidian.
Blueprint 14: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 2 ore and 15 obsidian.
Blueprint 15: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 15 clay. Each geode robot costs 3 ore and 12 obsidian.
Blueprint 16: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 17 clay. Each geode robot costs 3 ore and 19 obsidian.
Blueprint 17: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 4 ore and 9 obsidian.
Blueprint 18: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 6 clay. Each geode robot costs 3 ore and 16 obsidian.
Blueprint 19: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 6 clay. Each geode robot costs 2 ore and 14 obsidian.
Blueprint 20: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 11 clay. Each geode robot costs 3 ore and 15 obsidian.
Blueprint 21: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 18 clay. Each geode robot costs 4 ore and 19 obsidian.
Blueprint 22: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 15 clay. Each geode robot costs 2 ore and 20 obsidian.
Blueprint 23: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 5 clay. Each geode robot costs 2 ore and 10 obsidian.
Blueprint 24: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 10 clay. Each geode robot costs 2 ore and 14 obsidian.
Blueprint 25: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 7 clay. Each geode robot costs 4 ore and 13 obsidian.
Blueprint 26: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 20 clay. Each geode robot costs 2 ore and 20 obsidian.
Blueprint 27: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 18 clay. Each geode robot costs 2 ore and 19 obsidian.
Blueprint 28: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 10 clay. Each geode robot costs 2 ore and 7 obsidian.
Blueprint 29: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 15 clay. Each geode robot costs 3 ore and 7 obsidian.
Blueprint 30: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 4 ore and 18 obsidian.

462
day19-scratch.lisp Normal file
View File

@@ -0,0 +1,462 @@
;; https://adventofcode.com/2022/day/19
;; whelp. do i do somehow DP? generic over parameters of blueprints somehow
;; we could potentially calculate optimal step in forward time, but i'm not sure how.
;; and backward time - no easy way to know which robots will be available?
;;
;; intuitive idea, have some state of (resource1, recource2, robot1, robot2)
;; and have 2 types of steps, one - production is simple
;; then we can have different types of actions - build robot1 \ build robot2 - parallel these out
;; somehow prune ideally, but then move forward in time and get max of these. i guess it's ok plan
;; so.
;; - each robot collects 1 of it's own resource per minute
;; so function to update state with new resources is common
;; - cost of one new robot, consumed immediately, robot is produced in 1 minute
;; costs are different and listed in the bluerint
;; i suppose overall format of the blueprint is the same, only numbers change.
;; so could hardcode the translation
;;
;; and i guess i'd have one class of "blueprint" and several instances,
;; each instance does the updating of the state.
(in-package :day-19)
(defclass state ()
((geodes :initform 0 :initarg :geodes)
(ore :initform 0 :initarg :ore)
(clay :initform 0 :initarg :clay)
(obsidian :initform 0 :initarg :obsidian)
(geodes-robot :initform 0 :initarg :geodes-robot)
(ore-robot :initform 1 :initarg :ore-robot)
(clay-robot :initform 0 :initarg :clay-robot)
(obsidian-robot :initform 1 :initarg :obsidian-robot)))
(defclass blueprint ()
((ore-robot-cost :initarg :ore)
(clay-robot-cost :initarg :clay)
(obsidian-robot-cost :initarg :obsidian)
(geode-robot-cost :initarg :geode)))
;; wrote like this initially
(make-instance 'state)
;; i'd like to have code across building robots, checking whether robot can be build
;; to be shared. would i want to do it with classes?
;; state could have hashmaps from symbol to the amount
;; do i want to have plists?
(defparameter *my-plist* '(:ore 1 :clay 15))
*my-plist*
(getf *my-plist* :ore)
(getf *my-plist* :clay)
(setf (getf *my-plist* :clay) 3)
;; i guess i like that
;; then i could have robot costs as plists as well?
;; i could iterate over the plist with destructuring
;; and blueprint can just be plist of plists
;; we don't really need generic method dispatch
;; but for state - i'd kind of want to have static field
;; to share found max and pruning
(loop
for (resource cost) on '(:ore 3 :clay 14) by #'cddr
;; for (resource cost) in (getf *test-blueprint* :obsidian)
collect (list (* 2 cost) 'is 'cost resource) )
;; yes. comprehension is possible
(defparameter *test-state* (make-instance 'state))
(setf (getf (resources *test-state*) :ore 0) 5)
(setf (getf (robots *test-state*) :ore 0) 2)
(setf (getf (robots *test-state*) :obsidian 0) 5)
;; now let's check my function for can-create
(print *test-state*)
(can-create-robot *test-blueprint* :ore *test-state*)
(can-create-robot *test-blueprint* :clay *test-state*)
(can-create-robot *test-blueprint* :geode *test-state*)
(can-create-robot *test-blueprint* :obsidian *test-state*)
;; yay, i guess
;;
;; i had the error of putting quoted lists into the quoted list
;;
;; and now function to create new state with resources for a particular robot deducted?
;; and i guess with that robot already increased.
;; that function would signify passing of one turn \ minute
(setq *test-state* (make-instance 'state))
(setf (getf (resources *test-state*) :ore 0) 3)
(defparameter *another-state*
(create-robot *test-blueprint* :clay *test-state*))
;; well, that seems to work.
;; now i'd need to create blueprints from the lines.
;; then for each of the blueprint, calculate maximum of geodes.
;; multiply with the :id and sum.
;;
;; ok, i guess. i'd want a function that takes in blueprint.
;; gets initial state. and recurses searching for maximum
;; maybe even saving into blueprint as well.
;; how would that recursion look?
;; ore is added at the end of the minute.
;; resources for building is taken out at the beginning of the minute
;; built bot is added at the end of the minute
;;
;; so, i could
;; - calculate resources to be added
;; - for each possible (on old resources) bot build
;; recurse with bot cost deducted and new resources added
;; so next functions would be
;; - resources-to-be-collected :: just the plist of additional resources that would be
;; generated in 1 turn
;; and
;; - add-resources :: modifying operation that would update state
*test-state*
(calc-resources-to-be-collected *test-state*)
;; lol.
(add-resources '(:spagetty 1 :tuna 2) *test-state*)
;; and it works
;; so, now only main loop i suppose. and maybe-maybe later-later pruning
(get-possible-bot-builds *test-blueprint* *test-state*)
(defmethod find-max-geod (blueprints (s state) minute)
;; (format t "in step for ~a; with ~a~%" minute s)
(if (= 25 minute)
(getf (resources s) :geode 0)
(progn
(let* ((will-collect-this-minute (calc-resources-to-be-collected s))
(max-if-building
(loop
for bot-type in (get-possible-bot-builds blueprints s)
for state-with-new-bot = (create-robot blueprints bot-type s)
when state-with-new-bot
maximize (progn
(add-resources will-collect-this-minute state-with-new-bot)
(find-max-geod blueprints state-with-new-bot (1+ minute)))))
(if-not-building (let ((state-copy (copy-state s)))
;; (break)
(add-resources will-collect-this-minute state-copy)
(find-max-geod blueprints state-copy (1+ minute)))))
(max (or max-if-building 0) if-not-building)))))
;; Blueprint 1:
;; Each ore robot costs 4 ore.
;; Each clay robot costs 2 ore.
;; Each obsidian robot costs 3 ore and 14 clay.
;; Each geode robot costs 2 ore and 7 obsidian.
;; Blueprint 2:
;; Each ore robot costs 2 ore.
;; Each clay robot costs 3 ore.
;; Each obsidian robot costs 3 ore and 8 clay.
;; Each geode robot costs 3 ore and 12 obsidian.
;; do i just test this?
(setq *test-blueprint* '(:ore (:ore 4)
:clay (:ore 2)
:obsidian (:ore 3 :clay 14)
:geode (:ore 2 :obsidian 7)))
(setq *test-state* (make-instance 'state))
;; (print (find-max-geod *test-blueprint* *test-state* 1))
;; => 0
;; that's because i have no ability to "wait"
;; whoops
;; so. do i want, um. add one more attempted call after the loop in the iteration?
;; now. the looping is serious.
;; would it work for me to order keys geode first
;; now we seem to get geodes first, yay
;; maybe just run without printing?
;; let's check manually that when i do state copy, the plists are independent?
(setq *test-state* (make-instance 'state))
*test-state*
(setq *another-state* (copy-state *test-state*))
(incf (getf (resources *another-state*) :ore 0))
*another-state*
(add-resources '(:seeds 151) *another-state*)
(incf (getf (robots *another-state*) :obsidian 0))
;; oh, i didn't check that state returned from the "create bot" is independent
(setq *test-state* (make-instance 'state))
(add-resources '(:ore 10) *test-state*)
(setq *another-state* (create-robot *test-blueprint* :clay *test-state*))
;; ugh. resources stays shared.
;; WTF, why
;; manually create new list, i guess then then do set to the 'copied state'?
;; this is unpleasant
;; so, i guess use (copy-list
;; ok. the numbers seem ok. but this is long.
;; how do i trim this?
;; if on step 10 there's already a state with 3 obsidian machines.
;; does this state would always be ahead of
;; state on step 10 with 1 obsidian machine?
;;
;; it seems so!
;; for which reason? because if the state got 3 geode machines, it will be able to get more?
;; i suppose only when i reach case where each new step can add one more geod machine
;; only then i can guess the state is actually domeeneering?
;; but only over states with same amount of steps?
;; ok. let's commit what i have right now and try to trim?
;; how could i compare with that "cur-max" and update that cur-max?
;; no, i don't understand
(format t "some result ~a~%" (find-max-geod *test-blueprint* *test-state* 1))
;; well, yes one optimizaiton - stop building robots, when resource is to the top of
;; max daily expense
;; that would reduce a lot
;; 1)
;; would be nice to put these into (possible-robots-to-build)
;; so that it would also filtered out unnecessary new robots
;;
;; 2)
;; "keep global current max state" how would i compare and check if it's impossible to beat?
;; with "even if i could to build geod machine every day for rest N days"
*test-blueprint*
*test-state*
(add-resources '(:ore 10) *test-state*)
(incf (getf (robots *test-state*) :ore) 2)
(any-use-of-creating-robot *test-blueprint* *test-state* :ore)
(any-use-of-creating-robot *test-blueprint* *test-state* :clay)
(any-use-of-creating-robot *test-blueprint* *test-state* :obsidian)
(any-use-of-creating-robot *test-blueprint* *test-state* :geode)
(max-need *test-blueprint* *test-state* :ore)
(max-need *test-blueprint* *test-state* :clay)
(max-need *test-blueprint* *test-state* :obsidian)
(max-need *test-blueprint* *test-state* :geode)
;; and this is not good for :geode, we want as much as possible
(get-possible-bot-builds *test-blueprint* *test-state*)
;; and now let's add static "max state"?
;; i'd need comparison like "can catch up" with that found max "is dominated by"
;; and also way to update that maximal state?
;;
;; so, what will that be?
;; comparison for update, should it also be if i found a state that dominates?
;; only for satiated states?
;;
;; if day is same or more
;; but the amount of geode robots and geodes is smaller?
(is-satiated-p *test-blueprint* *test-state*)
(incf (getf (robots *test-state*) :obsidian 0) 20)
;; seems to work,
;; but i already want to utilize some test framework
;; whelp. i do want to test this
;; 4 14 7 to be satisfied
(is-satiated-p
*test-blueprint*
(make-instance 'state :robots '(:ore 4 :clay 14 :obsidian 7 :geode 2)))
(is-satiated-p
*test-blueprint*
(make-instance 'state :resources '(:ore 4 :clay 14 :obsidian 7 :geode 2))) ; not, need robots
(is-satiated-p
*test-blueprint*
(make-instance 'state :robots '(:ore 4 :clay 14 :obsidian 7 :geode 2)))
;; now for checking is-dominated. ugh.
(a-dominates-b-p
*test-blueprint*
(make-instance 'state :robots '(:ore 4 :clay 14 :obsidian 7 :geode 2))
(make-instance 'state :robots '(:ore 4 :clay 14 :obsidian 7 :geode 2)))
;; both satiated, but second bigger
(a-dominates-b-p
*test-blueprint*
(make-instance 'state :robots '(:ore 5 :clay 17 :obsidian 7 :geode 2))
(make-instance 'state :robots '(:ore 6 :clay 18 :obsidian 7 :geode 2)))
;;
;; both satiated, but second not always bigger
(a-dominates-b-p
*test-blueprint*
(make-instance 'state :robots '(:ore 5 :clay 17 :obsidian 9 :geode 2))
(make-instance 'state :robots '(:ore 6 :clay 18 :obsidian 8 :geode 2)))
;;
;; first not satiated, even though second is bigger - nil
(a-dominates-b-p
*test-blueprint*
(make-instance 'state :robots '(:ore 2 :clay 17 :obsidian 9 :geode 2))
(make-instance 'state :robots '(:ore 6 :clay 18 :obsidian 8 :geode 2)))
;; and that's not right. if we have on same amount of steps
;; reference as satiated and checking as not - wouldn't keep up
;; so big check should be whether steps are even in imagination permit
;; ugh. that would mean putting minute\step into state.
;; um, let's not do it right now?
;; for both satiated is a very weak check, but let's try it like this?
(setq *test-state* (make-instance 'state))
(setf (cur-found-max *test-state*) (make-instance 'state))
;; so whelp
;; should have committed after doing the "build makes sence list"
;;
;; my problems are because "is dominated by" is not simmetrical to "dominates"
;; and i want both
;;
;; now in the loop set first satiated as domination
;; after that compare if our set dominates that one and swap
;; and compare if it's dominated by that one and prune
;; so, only if ref earlier than checked state.
;; and then - if checked not saitated, or by all resources less than
;; but i do want tests
;; both satiated, but second bigger
(a-dominates-b-p
*test-blueprint*
(make-instance 'state :robots '(:ore 6 :clay 18 :obsidian 7 :geode 2) :minute 2)
(make-instance 'state :robots '(:ore 6 :clay 18 :obsidian 7 :geode 2) :minute 3))
;; should be NIL
;; now want to check for different amount of steps.
;; so if same resources but first is earlier - it dominates
(minute (make-instance 'state :robots '(:ore 6 :clay 18 :obsidian 7 :geode 2) :minute 2))
;; i was putting :minute 2 into :robots plist, cool, no thanks to you types
(minute (make-instance 'state :robots '(:ore 6 :clay 18 :obsidian 7 :geode 2) :minute 2))
;; ok. this also seems well.
;; then main loop? on fisrt satiated set as `cur-found-max`
;; and after that always check -
(defmethod find-max-geod-2 (blueprints (s state))
;; (declare (optimize (debug 3)))
;; (format t "in step for ~a; with ~a~%" (minute s) s)
(cond
((= 25 (minute s)) ; exit condition fully calculated
(getf (resources s) :geode 0))
((< (estimate s) (cur-found-max s))
;; (print "pruning")
0) ; pruning this branch
(t ; default check
(progn
(let* ((will-collect-this-minute (calc-resources-to-be-collected s))
(possible-bot-builds (get-possible-bot-builds blueprints s))
(max-if-building
(when possible-bot-builds
(loop
for bot-type in possible-bot-builds
for state-with-new-bot = (create-robot blueprints bot-type s)
when state-with-new-bot
maximize (progn
(add-resources will-collect-this-minute state-with-new-bot)
(incf (minute state-with-new-bot))
(find-max-geod-2 blueprints state-with-new-bot )))))
(if-not-building
(let ((state-copy (copy-state s)))
;; (break)
(add-resources will-collect-this-minute state-copy)
(incf (minute state-copy))
(find-max-geod-2 blueprints state-copy )))
(recursed-max (max (or max-if-building 0) if-not-building)))
;; (break)
;; (format t "would build ~a~%" possible-bot-builds)
(when (> recursed-max (cur-found-max s))
(setf (cur-found-max s) recursed-max))
recursed-max
)))))
(setq *test-state* (make-instance 'state))
(setf (cur-found-max *test-state*) 0)
(timing (print (find-max-geod-2 *test-blueprint* *test-state*)))
(timing (let ((a 1) (b 2)) (* a b 15)))
;; thank you CL-Cookbook: https://cl-cookbook.sourceforge.net/dates_and_times.html
(defmacro timing (&body forms)
(let ((real1 (gensym))
(real2 (gensym))
(run1 (gensym))
(run2 (gensym))
(result (gensym)))
`(let* ((,real1 (get-internal-real-time))
(,run1 (get-internal-run-time))
(,result (progn ,@forms))
(,run2 (get-internal-run-time))
(,real2 (get-internal-real-time)))
(format *debug-io* ";;; Computation took:~%")
(format *debug-io* ";;; ~f seconds of real time~%"
(/ (- ,real2 ,real1) internal-time-units-per-second))
(format t ";;; ~f seconds of run time~%"
(/ (- ,run2 ,run1) internal-time-units-per-second))
,result)))
;; so, why doesn't it ever builds obsidian?
*test-blueprint*
;; because is "has to build something if it can" whops
;; wow 20 seconds. cool
;; last things:
;; read in the line for the blueprints into plist
;; then loop over lines in file
;; for each line compute max, multiply by index
;; and sum
;; ok, i guess
(rest (remove-if-not #'identity
(mapcar (lambda (str) (parse-integer str :junk-allowed t))
(ppcre:split " "
"Blueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian."))))
(blueprint-line-to-plist "Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian.")
;; and now loop over file.
(print (with-open-file (in "day19-test.txt")
(loop
for line = (read-line in nil nil)
for n from 1
for blueprints = (when line (progn
(format t "Starting processing for ~a~%" line)
(blueprint-line-to-plist line)))
for max-geo = 0
;; for max-geo = (when blueprints
;; (progn
;; (setf (cur-found-max *test-state*) 0)
;; (timing (find-max-geod-2 blueprints (make-instance 'state)))))
while blueprints
do (format t "processed ~a : ~a. its max is ~a~%" n blueprints max-geo)
summing (* n max-geo))))
(format t "and the result is : ~a~%" (read-and-calc-part-1 "day19-test.txt"))
(format t "and the result is : ~a~%" (read-and-calc-part-1 "day19-input.txt"))
;; wtf is taking so long in between the processings?
(apply #'* (list 2 3 5))
;; but before that - change exit point
(format t "and the result is : ~a~%" (read-and-calc-part-2 "day19-2-input.txt"))
;; 261 is too low. so
;; but in previous my maxes were 0 1 2
;; and current are 3 3 29
;; but still not good
;; ugh. what about test input?
(format t "and the result is : ~a~%" (read-and-calc-part-2 "day19-test.txt"))
;; my calc : 18 and 55
;; correct : 56 and 62
;; coooool. let's move on.

2
day19-test.txt Normal file
View File

@@ -0,0 +1,2 @@
Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian.
Blueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian.

193
day19.lisp Normal file
View File

@@ -0,0 +1,193 @@
;; https://adventofcode.com/2022/day/19
(defpackage :day-19
(:use :cl))
(in-package :day-19)
(ql:quickload 'cl-ppcre)
(defparameter *all-types* '(:geode :obsidian :clay :ore))
(defclass state ()
((resources :accessor resources :initform nil :initarg :resources)
(robots :accessor robots :initform (list :ore 1) :initarg :robots)
(minute :accessor minute :initarg :minute :initform 1 )
(cur-found-max :initform nil :accessor cur-found-max :allocation :class) ; would be nice to add types
))
(defmethod print-object ((obj state) stream)
(print-unreadable-object (obj stream :type t)
(with-slots (resources robots)
obj
(format stream "collected: ~a, with robots: ~a"
resources robots))))
;; example of blueprint:
(defparameter *test-blueprint*
'(:ore (:ore 4)
:clay (:ore 2)
:obsidian (:ore 3 :clay 14)
:geode (:ore 2 :obsidian 7)))
;; thank you blambert & stackoverflow
;; https://stackoverflow.com/questions/11067899/is-there-a-generic-method-for-cloning-clos-objects
;; oh, but this is shallow copy and lists reused. crap
(defmethod copy-state ((s state))
(make-instance 'state :resources (copy-list (resources s))
:robots (copy-list (robots s))
:minute (minute s)))
(defmethod can-create-robot (blueprints type (s state))
(let ((this-robot-costs (getf blueprints type)))
(loop for (resource amount) on this-robot-costs by #'cddr
always (>= (getf (resources s) resource 0) amount))))
(defmethod create-robot (blueprints type (s state))
(when (can-create-robot blueprints type s)
(let ((this-robot-costs (getf blueprints type))
(copied-state (copy-state s)))
(loop for (resource amount) on this-robot-costs by #'cddr
do (incf (getf (resources copied-state) resource 0) (- amount)))
(incf (getf (robots copied-state) type 0))
copied-state)))
(defmethod calc-resources-to-be-collected ((s state))
(robots s))
(defmethod add-resources (new-resources (s state))
(loop for (resource amount) on new-resources by #'cddr
do (incf (getf (resources s) resource 0) amount)))
;; robot is unnecessary if resouce it brings is alreay produced
;; at amount of maximal possible per-turn expence
(defmethod max-need (blueprints (s state) resource-type)
(loop
for (la blueprint) on blueprints by #'cddr
;; do (print blueprint)
maximize (getf blueprint resource-type 0)))
(defmethod any-use-of-creating-robot (blueprints (s state) robot-type)
(if (eq :geode robot-type)
t ; always reason to build more geode robots
(let ((max-need (max-need blueprints s robot-type))
(state-production (getf (robots s) robot-type 0)))
;; (format t "comparing need ~a with prod ~a" max-need state-production)
(> max-need state-production))))
(defmethod get-possible-bot-builds (blueprints (s state))
(remove-if-not (lambda (robot-type)
(any-use-of-creating-robot blueprints s robot-type))
(remove-if-not (lambda (robot-type)
(can-create-robot blueprints robot-type s))
*all-types*)))
;; true when no longer need to build secondary robots
(defmethod is-satiated-p (blueprints (s state))
(loop for type in '(:ore :clay :obsidian)
never (any-use-of-creating-robot blueprints s type)))
(defmethod a-dominates-b-p (blueprints (a state) (b state))
;; (declare (optimize (debug 3)))
(when (is-satiated-p blueprints a) ; when not a satiated - don't know
(and
(<= (minute a) (minute b)) ; a earlier than b
(or
(not (is-satiated-p blueprints b))
(loop for resource-type in *all-types* ; for both satiated compare all resources
always (and (>= (getf (resources a) resource-type 0)
(getf (resources b) resource-type 0))
(>= (getf (robots a) resource-type 0)
(getf (robots b) resource-type 0))))))))
;; loose bound on geodes
(defmethod estimate ((s state))
(let ((time-left (- 25 (minute s))))
(+ (getf (resources s) :geode 0)
(* time-left (getf (robots s) :geode 0))
(/ (* time-left (1- time-left)) 2))))
(defmethod find-max-geod-2 (blueprints (s state))
(declare (optimize (speed 3)))
;; (declare (optimize (debug 3)))
;; (format t "in step for ~a; with ~a~%" (minute s) s)
(cond
(
(= 33 (minute s)) ; exit condition fully calculated
;; (= 25 (minute s)) ; exit condition fully calculated
(getf (resources s) :geode 0))
((< (estimate s) (cur-found-max s))
;; (print "pruning")
0) ; pruning this branch
(t ; default check
(progn
(let* ((will-collect-this-minute (calc-resources-to-be-collected s))
(possible-bot-builds (get-possible-bot-builds blueprints s))
(max-if-building
(when possible-bot-builds
(loop
for bot-type in possible-bot-builds
for state-with-new-bot = (create-robot blueprints bot-type s)
when state-with-new-bot
maximize (progn
(add-resources will-collect-this-minute state-with-new-bot)
(incf (minute state-with-new-bot))
(find-max-geod-2 blueprints state-with-new-bot )))))
(if-not-building
(let ((state-copy (copy-state s)))
;; (break)
(add-resources will-collect-this-minute state-copy)
(incf (minute state-copy))
(find-max-geod-2 blueprints state-copy )))
(recursed-max (max (or max-if-building 0) if-not-building)))
;; (break)
;; (format t "would build ~a~%" possible-bot-builds)
(when (> recursed-max (cur-found-max s))
(setf (cur-found-max s) recursed-max))
recursed-max
)))))
(defun blueprint-line-to-plist (line)
(destructuring-bind
(ore-cost-in-ore clay-cost-in-ore obs-cost-in-ore obs-cost-in-clay
geod-cost-in-ore geod-cost-in-obs)
(rest (remove-if-not #'identity
(mapcar (lambda (str) (parse-integer str :junk-allowed t))
(ppcre:split " " line))))
`(:ore (:ore ,ore-cost-in-ore)
:clay (:ore ,clay-cost-in-ore)
:obsidian (:ore ,obs-cost-in-ore :clay ,obs-cost-in-clay)
:geode (:ore ,geod-cost-in-ore :obsidian ,geod-cost-in-obs))))
(defun read-and-calc-part-1 (filename)
(with-open-file (in filename)
(loop
for line = (read-line in nil nil)
for n from 1
for blueprints = (when line (blueprint-line-to-plist line))
for max-geo = (when blueprints
(progn
(setf (cur-found-max *test-state*)
0)
(format t "Starting processing for ~a" line)
(timing (find-max-geod-2 blueprints (make-instance 'state)))))
while blueprints
do (format t "processed ~a. its max is ~a~%" n max-geo)
summing (* n max-geo))))
(defun read-and-calc-part-2 (filename)
(with-open-file (in filename)
(loop
for line = (read-line in nil nil)
for n from 1
for blueprints = (when line (progn
(format t "Starting processing for ~a~%" line)
(blueprint-line-to-plist line)))
for max-geo = (when blueprints
(progn
(setf (cur-found-max *test-state*) 0)
(timing (find-max-geod-2 blueprints (make-instance 'state)))))
while blueprints
do (format t "processed ~a. its max is ~a~%" n max-geo)
collecting max-geo into maxes
finally (return (apply #'* maxes)))))

2500
day2-input.txt Normal file

File diff suppressed because it is too large Load Diff

174
day2.lisp Normal file
View File

@@ -0,0 +1,174 @@
;;;; https://adventofcode.com/2022/day/2
;; input is lines [A B C] [X Y Z]
;; meaning a-b-c what opponent will play
;; and x y z what i should play in rock-paper-scissors
;;
;; score is calculated as:
;; 1 for Rock X
;; 2 for Paper Y
;; 3 for Scissors Z
;;
;; 0 if Lost
;; 3 if Tie
;; 6 if Win
;;
;; Win if
;; (A Y) (B Z) (C X)
(setq MY-WIN-COMBINATIONS '((A Y) (B Z) (C X)))
;;
;; Loss if
;; (X B) (Y C) (Z A)
(setq MY-LOSS-COMBINATIONS '((B X) (C Y) (A Z)))
;;
;; otherwise it's a tie
(setq TIE-COMBINATIONS '((A X) (B Y) (C Z)))
;; now i'd also like to get symbol from the string...
(equal (intern "a") (intern "A")) ; not exactly what i means, but yeah this is it
;; now i'd like to get list of two symbols from string of two symbols
(setq my-test-line "A Z")
;; https://stackoverflow.com/questions/59516459/split-string-by-delimiter-and-include-delimiter-common-lisp
(require 'cl-ppcre)
(cl-ppcre:split "(\\.)" "a.bc.def.com" :with-registers-p t)
(cl-ppcre:split "(\\.)" "a.bc.def.com" :with-registers-p nil)
(setq my-test-line-list (mapcar #'intern (cl-ppcre:split "(\\ )" my-test-line :with-registers-p nil)))
;; yay
;;; now write scoring function over the lists of chars, for tie-win-loose match and for "my-selection-match"
;; sum the scores of the two parts of scoring
;; and iterate over input
;; would be cool to use pattern matching...
;; that's something like CASE in my
(case 1
((:in :in2) :lala)
((2 3) :numBig)
((1 -1) :numOne))
(case (list 1 2)
((:in :in2) :just-sym)
((list 1 2) :a-list))
;; this doesn't work with lists.
;; COND is similar to CASE, except it is more general. It accepts arbitrary
(find my-test-line-list my-win-combinations :TEST #'equal)
(find my-test-line-list my-loss-combinations :TEST #'equal)
(cond
((find my-test-line-list my-win-combinations :TEST #'equal) :WIN)
((find my-test-line-list my-loss-combinations :TEST #'equal) :LOSS)
(t :TIE))
(defun score-result (hands)
(cond
((find hands my-win-combinations :TEST #'equal)
6)
((find hands my-loss-combinations :TEST #'equal)
0)
(t 3)))
(score-result '(A Z))
(score-result '(A Y))
;;; now let's get score of the hands, by only my hand
(defun score-my-hand (hands)
(let ((my-hand (second hands)))
(case my-hand
(X 1)
(Y 2)
(z 3))))
(score-my-hand '(A Z))
(score-my-hand '(A Y))
(score-my-hand '(A X))
(defun full-score-hands (hands)
(+ (score-my-hand hands) (score-result hands)))
(full-score-hands '(A Y))
(full-score-hands '(B X))
(full-score-hands '(C Z))
;;; and now, iterate over file, converting strings into symbols and accumulating the score...
(require 'cl-ppcre)
(setq running-sum 0)
(let ((running-sum 0))
(with-open-file (in "~/Documents/personal/advent-of-code/2022/day2-input.txt")
(loop
for line = (read-line in nil nil)
while line
;; do (format t "line ~A~%" line)
do (let* ((line-word-list (cl-ppcre:split "(\\ )" line :with-registers-p nil))
(hands (mapcar #'intern line-word-list)))
(incf running-sum (full-score-hands hands)))
finally (return running-sum)
)))
;; (setq my-test-line-list (mapcar #'intern (cl-ppcre:split "(\\ )" my-test-line :with-registers-p nil)))
;; 12156 is the right answer!
;; let's wrap this into a function
(defun count-plays-score (filename)
(require 'cl-ppcre)
(let ((running-sum 0))
(with-open-file (in filename)
(loop
for line = (read-line in nil nil)
while line
do (let* ((line-word-list (cl-ppcre:split "(\\ )" line :with-registers-p nil))
(hands (mapcar #'intern line-word-list)))
(incf running-sum (full-score-hands hands)))
finally (return running-sum)
))))
(count-plays-score "~/Documents/personal/advent-of-code/2022/day2-input.txt")
;;; now for the Second part of the game
;; second part means something else!
;; X - need to loose
;; Y - need to draw
;; Z - need to win
;;
;; so, scoring is the same, but I need to calculate what is my hand
;; C Z means they play (SCISSORS) and i need to WIN, so I need to get ROCK
;; that goes into the calculation of the score
;; i would be able to reuse the scoring function,
;; but! i need a funtion that returns my hand
;; let's put it off for a bit?
;; or no. so. this would be best with what? ugh.
;; so Z - find hand from loose-hands that starts with required hand
;; Y - find from draw, Z - find from win
;; could use #'FIND with cusom :TEST - to compare only first item
(defun get-hand-set-by-result (hands)
(case (second hands)
(X my-loss-combinations)
(Y tie-combinations)
(Z my-win-combinations)))
(get-hand-set-by-result '(A Y))
(get-hand-set-by-result '(B X))
(get-hand-set-by-result '(C Z))
;; ok, somewhat like that
(find (first '(A Y))
(get-hand-set-by-result '(A Y)) :KEY (lambda (hands) (first hands)) )
(defun count-plays-score-2 (filename)
(require 'cl-ppcre)
(let ((running-sum 0))
(with-open-file (in filename)
(loop
for line = (read-line in nil nil)
while line
do (let* ((line-word-list (cl-ppcre:split "(\\ )" line :with-registers-p nil))
(hand-and-result (mapcar #'intern line-word-list))
(handset (get-hand-set-by-result hand-and-result))
(hands (find (first hand-and-result) handset :KEY (lambda (hands) (first hands)) )))
(incf running-sum (full-score-hands hands)))
finally (return running-sum)
))))
(count-plays-score-2 "~/Documents/personal/advent-of-code/2022/day2-input.txt")
;; 10835 is the right answer!

5000
day20-input.txt Normal file

File diff suppressed because it is too large Load Diff

264
day20-scratch.lisp Normal file
View File

@@ -0,0 +1,264 @@
;; https://adventofcode.com/2022/day/20
(in-package :day-20)
;; so. how would i do moves in a list?
;; and are there duplicate numbers?
;; it's possible but not sure.
;; also in the input numbers are 4k 5k.
;; i guess on during the moving it would be best to figure out their index?
;; could i insert into list at index?
;; it could be nice to use just cycled list. but.
;; maybe use array?
'(1 2 -3 3 -2 0 4)
;; calculating index and then modifying array. is it easy to do shifts on array?
;; and i'd sometimes need to
;; and how multiple passes work with going over self?
;; let's take a break
;; i guess i could copy part of array with the offset arrays
;;
;; the stupid version seems to be 4 cases :
;; - to right inside of array
;; - to right over with overflow
;; - to left inside of array
;; - to left over with overflow
;; but when overflow - could stop to the left or to the right of self.
(defparameter *my-arr*
(aops:linspace 0 9 10))
;; imagine i'm displacing 345 by 1 to right
;; ( that would mean 6 moving 3 to the left)
(setq *my-arr* (aops:linspace 0 9 10))
(let ((to-be-moved (make-array 3 :displaced-to *my-arr* :displaced-index-offset 3))
(into-these-move (make-array 3 :displaced-to *my-arr* :displaced-index-offset 4)))
(loop
for i from 2 downto 0
do (setf (aref into-these-move i) (aref to-be-moved i))))
*my-arr*
;; now displacing 345 by 1 to left
(setq *my-arr* (aops:linspace 0 9 10))
(let ((to-be-moved (make-array 3 :displaced-to *my-arr* :displaced-index-offset 3))
(into-these-move (make-array 3 :displaced-to *my-arr* :displaced-index-offset 2)))
(loop
for i from 0 below 3
do (setf (aref into-these-move i) (aref to-be-moved i))))
*my-arr*
;; now let's also remember "moved" element and put it to the "freed up space"
;; moving 6 by 3 to the left
(setq *my-arr* (aops:linspace 0 9 10))
(let* ((index-of-moved 6)
(moved-value (aref *my-arr* index-of-moved))
(move-by -3)
(to-be-moved (make-array 3 :displaced-to *my-arr*
:displaced-index-offset (+ index-of-moved move-by)))
(into-these-move (make-array 3 :displaced-to *my-arr*
:displaced-index-offset (+ index-of-moved move-by 1))))
(loop
for i from 2 downto 0
do (setf (aref into-these-move i) (aref to-be-moved i)))
(setf (aref *my-arr* (+ index-of-moved move-by)) moved-value))
*my-arr*
;; ok. but these 2 downto 0 || 0 to 2 dependent on -3 +3 and that's ugh
;; moving 2 by 3 to the right (now displacing 345 by 1 to left)
(setq *my-arr* (aops:linspace 0 9 10))
(let* ((index-of-moved 2)
(moved-value (aref *my-arr* index-of-moved))
(move-by 3)
(to-be-moved (make-array 3 :displaced-to *my-arr*
:displaced-index-offset (+ index-of-moved 1)))
(into-these-move (make-array 3 :displaced-to *my-arr*
:displaced-index-offset index-of-moved)))
(loop
for i from 0 to 2
do (setf (aref into-these-move i) (aref to-be-moved i)))
(setf (aref *my-arr* (+ index-of-moved move-by)) moved-value))
*my-arr*
;; so also difference in displaced indexes.
;; shift to LEFT (move item left):
;;
;; shift to RIGHT (move item right):
;; well, i could just save this code as two separate functions
;; would be nice to immediately start doing the repeatable tests
(move-item-to-left (aops:linspace 0 9 10) 6 6)
;; and a separate function for swithing to the right?
(move-item-to-right (aops:linspace 0 9 10) 6 1)
(move-item-to-right (aops:linspace 0 9 10) 6 2)
(move-item-to-right (aops:linspace 0 9 10) 6 3)
;; next what? calculation of the target index through modulo
'(1 2 3 4 5 6 7 8 9)
;; if we're moving 2 by -2 how does that work?
;; we have starting index 1, we have length 9.
;; my guess is that take MOD by 9-1
;; how many swaps to the right until the element returns to its original place?
'(1 2 3 4 5 6 7 8 9)
'(2 1 3 4 5 6 7 8 9)
'(1 3 4 5 6 7 8 9 2)
'(1 3 4 5 6 7 8 2 9)
'(1 3 4 5 6 7 2 8 9)
'(1 3 4 5 6 2 7 8 9)
'(1 3 4 5 2 6 7 8 9)
'(1 3 4 2 5 6 7 8 9)
'(1 3 2 4 5 6 7 8 9)
'(1 2 3 4 5 6 7 8 9)
;; so, if moving by 9. hm
;; then moving by 12 is 9 + 3
(mod 9 3)
(mod 10 3)
(length (make-array 7))
(move-item-to-left (aops:linspace 0 9 10) 6 9)
;; ok, now join into one function that moves the element by it's value?
(find 4 '(1 4 3 2 9))
(position 4 '(1 4 3 2 9))
(defparameter *test-array* (make-array 7 :initial-contents '(1 2 -3 3 -2 0 4)))
*test-array*
(move-elem-by-itself *test-array* -2)
;; whelp. my movements are ugh.
;; so. "i'd want additional move on top of my move-left and move-right"?
(mod -1 3)
(move-item *test-array* 3 3)
(move-item *test-array* 3 4)
(defparameter *test-array* (make-array 7 :initial-contents '(1 2 -3 3 -2 0 4)))
*test-array*
(move-elem-by-itself *test-array* -2)
;; this seems to work.
;; now back to the loop?
(defparameter *test-array* (make-array 7 :initial-contents '(1 2 -3 3 -2 0 4)))
(mixing-array *test-array*)
;; after moving 2, arr: #(1 -3 2 3 -2 0 4)
;; after moving -3, arr: #(1 2 3 -2 0 -3 4)
;; -3 move wasn't correct
(loop for elem across *test-array*
do (print elem))
(defparameter *test-array* (make-array 7 :initial-contents '(1 -3 2 3 -2 0 4)))
(move-elem-by-itself *test-array* -3)
;; 0 -> 0
;; -1 -> (len - 1)
;; -2 -> (len - 2)
(mod -1 7)
;; so, just hack it? when we move to the left, we add one more?
;; so, ugh and when moving to positive, but going over the what
;; the number is not "switched" with the neighbor, it's jumping over the neighbor...
;; so, if we go to 0 or to len-1 then we jump to the other side?
(defparameter *test-array* (make-array 7 :initial-contents '(1 -3 3 -2 2 0 4)))
(move-elem-by-itself *test-array* 2)
(defparameter *test-array* (make-array 7 :initial-contents '(1 -3 3 -2 2 4 0)))
(move-elem-by-itself *test-array* 4)
(defparameter *test-array* (make-array 7 :initial-contents '(1 2 -3 0 3 4 -2)))
(move-item *test-array* 5 4)
(move-elem-by-itself *test-array* 4)
;; now this incorrect:
;; after moving 3, arr: #(1 2 -2 -3 0 3 4)
;; after moving -2, arr: #(-2 1 2 -3 0 3 4)
;; -2 should have went instead of to 0 straight to the end. so
;;
;; and now it works
;; god i also need to take 1000th value with overbound. ugh.
(defun get-ugh-nth (arr n)
(let* ((zero-ind (position 0 arr))
(unsafe-index (+ zero-ind n))
(safe-n (mod unsafe-index (length arr))))
(aref arr safe-n)))
(get-ugh-nth (mixing-array *test-array*) 1000)
(get-ugh-nth (mixing-array *test-array*) 2000)
(get-ugh-nth (mixing-array *test-array*) 3000)
;; uh. after the value 0...
;; so first find index of 0
(let* ((nums (mapcar #'parse-integer (uiop:read-file-lines "day20-input.txt")))
(input-arr (make-array (length nums) :initial-contents nums))
(mixed (mixing-array input-arr)))
(+ (get-ugh-nth (mixing-array mixed) 1000)
(get-ugh-nth (mixing-array mixed) 2000)
(get-ugh-nth (mixing-array mixed) 3000)))
;; 1797 is too low,
(defun part-1-ans (filename)
(let* ((nums (mapcar #'parse-integer (uiop:read-file-lines filename)))
(input-arr (make-array (length nums) :initial-contents nums))
(mixed (mixing-array input-arr)))
(+ (get-ugh-nth mixed 1000)
(get-ugh-nth mixed 2000)
(get-ugh-nth mixed 3000))))
;; (part-1-ans "day20-test.txt")
;; (print (part-1-ans "day20-input.txt"))
;; well, do we have duplicates?
(ql:quickload :fset)
(fset:set 1 2 3)
(fset:set '(1 2 3))
(print (let* ((nums (mapcar #'parse-integer (uiop:read-file-lines "day20-input.txt")))
(input-arr (make-array (length nums) :initial-contents nums))
(input-set (fset:convert 'fset:set nums))
)
(list 'arr (length input-arr) 'set (fset:size input-set))
))
;; (ARR 5000 SET 3613)
;; well, yupikayey
;; how should i be doint that?
;; AND i should have checked that from the start.
;; so. there are duplicates.
(fset:convert 'fset:bag '(1 2 3 2 4 5))
;; what should i do about the duplicates?
;; i'd need to store elements with their initial indexes i suppose
;; and then what? iterate not over initial collection, but just over "initial" indexes
;; yay, at least previous solution was still incorrect. yayyayay
;;; PART 2.
;; wowy.
;; 1. multiply all numbers by 811589153
;; 2. do 10 mixings
(map 'vector #'1+ (aops:linspace 0 9 10))
(defun part-2-ans (filename)
(let* ((data (map 'vector (lambda (zipped) (list (first zipped) (* 811589153 (second zipped))))
(input-arr filename)))
;; (mixed (mixing-array input-arr))
(mixed (do* ((arr data (mixing-array arr))
(iteration 0 (1+ iteration)))
((= 10 iteration) arr))))
(format t "getting part 1, mixed array: ~a~%" mixed)
(+ (get-ugh-nth mixed 1000)
(get-ugh-nth mixed 2000)
(get-ugh-nth mixed 3000))))
(print (part-2-ans "day20-test.txt"))
(print (part-2-ans "day20-input.txt"))

7
day20-test.txt Normal file
View File

@@ -0,0 +1,7 @@
1
2
-3
3
-2
0
4

136
day20.lisp Normal file
View File

@@ -0,0 +1,136 @@
;; https://adventofcode.com/2022/day/20
(defpackage :day-20
(:use :cl))
(in-package :day-20)
(ql:quickload :array-operations)
(ql:quickload "fiveam")
(ql:quickload 'alexandria)
(5am:def-suite day20-tests)
;; and shift some slice 1 to right
(defun move-item-to-left (array moved-index move-size)
(declare (optimize (debug 3)))
(let* ((move-size (mod move-size (1- (length array))))
(moved-value (aref array moved-index))
(move-by (- (mod move-size (length array))))
(moving-slice-size move-size)
(to-be-moved (make-array moving-slice-size :displaced-to array
:displaced-index-offset (+ moved-index move-by)))
(into-these-move (make-array moving-slice-size :displaced-to array
:displaced-index-offset (+ moved-index move-by 1))))
(loop
for i from (1- move-size) downto 0
do (setf (aref into-these-move i)
(aref to-be-moved i)))
(setf (aref array (+ moved-index move-by)) moved-value)
array))
(5am:def-test move-left-inside-of-array (:suite day20-tests)
(5am:is (equalp (make-array 10 :initial-contents '(0 1 2 6 3 4 5 7 8 9))
(move-item-to-left (aops:linspace 0 9 10) 6 3))))
(5am:def-test move-left-to-edge (:suite day20-tests)
(5am:is (equalp (make-array 10 :initial-contents '(6 0 1 2 3 4 5 7 8 9))
(move-item-to-left (aops:linspace 0 9 10) 6 6))))
(5am:def-test move-by-arr-size-leaves-intact (:suite day20-tests)
(5am:is (equalp (make-array 10 :initial-contents '(0 1 2 3 4 5 6 7 8 9))
(move-item-to-left (aops:linspace 0 9 10) 6 9))))
(5am:def-test move-by-more-than-arr-size (:suite day20-tests)
(5am:is (equalp (make-array 10 :initial-contents '(0 1 2 6 3 4 5 7 8 9))
(move-item-to-left (aops:linspace 0 9 10) 6 12))))
(defun move-item-to-right (array moved-index move-by)
(declare (optimize (debug 3)))
(let* ((move-by (mod move-by (1- (length array))))
(moved-value (aref array moved-index))
(moving-slice-size move-by)
(to-be-moved (make-array moving-slice-size
:displaced-to array
:displaced-index-offset (+ moved-index 1)))
(into-these-move (make-array moving-slice-size
:displaced-to array
:displaced-index-offset moved-index)))
(loop
for i from 0 below move-by
do (setf (aref into-these-move i)
(aref to-be-moved i)))
(setf (aref array (+ moved-index move-by)) moved-value)
array))
(5am:def-test move-right-inside-of-array (:suite day20-tests)
(5am:is (equalp (make-array 10 :initial-contents '(0 1 2 3 4 5 7 6 8 9))
(move-item-to-right (aops:linspace 0 9 10) 6 1))))
(5am:def-test move-right-to-edge (:suite day20-tests)
(5am:is (equalp (make-array 10 :initial-contents '(0 1 2 3 4 5 7 8 9 6))
(move-item-to-right (aops:linspace 0 9 10) 6 3))))
(5am:def-test move-right-by-arr-size-leaves-intact (:suite day20-tests)
(5am:is (equalp (make-array 10 :initial-contents '(0 1 2 3 4 5 6 7 8 9))
(move-item-to-right (aops:linspace 0 9 10) 6 9))))
(5am:def-test move-right-by-more-than-arr-size (:suite day20-tests)
(5am:is (equalp (make-array 10 :initial-contents '(0 1 2 3 4 5 7 8 9 6))
(move-item-to-right (aops:linspace 0 9 10) 6 12))))
(defun move-item (array move-index move-by)
(let* ((raw-target-index (if (>= move-by 0)
(+ move-index move-by)
(+ move-index move-by)))
(in-array-target-index (mod raw-target-index (1- (length array))))
(in-array-target-index (if (= 0 in-array-target-index)
(1- (length array))
in-array-target-index ; a hack
))
(safe-move-by (- in-array-target-index move-index)))
;; (list move-index move-by
;; 'raw-target raw-target-index
;; 'in-array-target in-array-target-index
;; 'safe-move-by safe-move-by)
(if (> safe-move-by 0)
(move-item-to-right array move-index safe-move-by)
(move-item-to-left array move-index (- safe-move-by)))
))
;; we know the element value, but not it's place
(defun move-elem-by-itself (array initial-index)
(declare (optimize (debug 3)))
(let ((i (position initial-index array :test (lambda (searched-index zipped)
(= searched-index (car zipped))))))
(move-item array i (second (aref array i)))))
(defun mixing-array (arr)
(let ((to-be-modified (alexandria:copy-array arr)))
(loop
for initial-index from 0 below (length arr)
;; for elem across arr
do (progn (move-elem-by-itself to-be-modified initial-index)
;; (format t "after moving ~a, arr: ~a~%" elem to-be-modified)
))
to-be-modified))
(defun zip-with-index (ls)
(loop for v in ls
for i from 0
collect (list i v)))
(defun input-arr (filename)
(let ((nums (mapcar #'parse-integer (uiop:read-file-lines filename))))
(make-array (length nums) :initial-contents (zip-with-index nums))))
(defun get-ugh-nth (arr n)
;; need to find 0 by value in the (index, value) array
(let* ((zero-ind (position 0 arr :test (lambda (searched-value zipped)
(= searched-value (second zipped)))))
(unsafe-index (+ zero-ind n))
(safe-n (mod unsafe-index (length arr))))
(second (aref arr safe-n))))
(defun part-1-ans (filename)
(let* ((input-arr (input-arr filename))
(mixed (mixing-array input-arr)))
(format t "getting part 1, mixed array: ~a~%" mixed)
(+ (get-ugh-nth mixed 1000)
(get-ugh-nth mixed 2000)
(get-ugh-nth mixed 3000))))
(5am:run! 'day20-tests)

2979
day21-input.txt Normal file

File diff suppressed because it is too large Load Diff

135
day21-scratch.lisp Normal file
View File

@@ -0,0 +1,135 @@
;; // https://adventofcode.com/2022/day/21
;; well, this seems like this could be done with (eval)
;; would it be possible for me to also translate
;; xxx + yyy into (call xxx) + (call yyy)
;; that would be neat
(in-package :day-21)
;; so. have mashmap from symbol name into operation
;; and have (my-eval)?
;; it will take symbol name, and either return number directly from the map
;; or will wrap the names into my-eval and run operation on them?
;; is there a way to have less code and reuse existing lisp things?
;; if there's direct number, i could just run (defparameter lfqf 4)
;; and then execute root directly, i think
;; or what, i'd need to also define all the intermediate symbols,
;; (setq a (+ c d)) ; complains that C is unbound
;; how could this be a lazy eval?
;; well. hm
;; i could define all of these as macroses?
(defmacro *test-monkey-hmdt* () 32)
(+ 3 (*test-monkey-hmdt*))
;; yup, i guess
(defparameter *test-monkey-sllz* 4)
(eval *test-monkey-sllz*)
(defparameter *test-monkey-ljgn* 2)
(defparameter *my-operation* '(+ *test-monkey-sllz* *test-monkey-ljgn*))
*my-operation*
(eval *my-operation*) ; well, that works ok
;; so, read all of these things as parameters.
;; "root: pppw + sjmn "
(mapcar #'intern (ppcre:split " " "root: pppw + sjmn "))
(mapcar #'parse-integer-or-symbol (ppcre:split " " "root: 44"))
(ppcre:regex-replace ":" "root: pppw + sjmn " "")
(line-to-quoted-operation "root: pppw + sjmn")
(eval (line-to-quoted-operation "dbpl: 5"))
;; well, i'd want to put quoted expression into parameter?
;; and now i can remove quoting of the defparameter?
;; and actually define all of the parameters?
(loop
for line in (uiop:read-file-lines "day21-test.txt")
for definition = (line-to-quoted-operation line)
do (eval definition))
(eval root)
;; (load-file-defs "day21-test.txt")
;; (eval root)
;; (load-file-defs "day21-input.txt")
;; (print (eval root))
;; now. things are different.
;; HUMN is my input
;; and ROOT is "comparison of two numbers"
;; and change in root can influence results in a significant way
;; so, how'd i do that?
;;
;; what could be done then?
;; i could potentially somehow modify the operations?
;; so that (eval humn) would return
;;
;; root: pppw + sjmn
;; so. root should mean
;; pppw == sjmn
;; don't know which has HUMN yet.
;; should i then just eval those that have HUMN into a operation?
;; and others into a number?
;; well, i suppose i'd need to do pass down somehow
;; eval both parts of the root.
;; and then what?
;;
;; let's skip for now?
;; or, alternatively. i could save HUMN num disregard
;; defparameter with HUMN to be used as HUMN =
;; and then what? root
;; but then i'd need to reverse all the other operations, hm
;; or, maybe i could join into flat expression?
;; and then what? i macroexpand?
;;
;; now. i had an idea. i could have additional symbols,
;; also pointing to quoted computations
;; but these would be `back-ptdq`
;; for line 'lgvd: ljgn * ptdq'
;; make two? for each
;;
;; ptdq: humn - dvpt
;; back-humn = ptdq + dvpt
;; but one of these wouldn't be possible to forward eval, so it would be back-ptdq + dvpt
;; and on
;; root: pppw + sjmn
;; two would be created back-pppw = - eval sjmn and vice versa
;; this should work?
;; sure, let's try?
;; so we'd do what?
;; same for forward eval?
;; and two for back-monkey
(back-symbol 'hello)
(intern (format nil "BACK-~a" 'yo))
;; and i need reverse of the operands?
(reverse-operation '+)
(line-to-quoted-operation-2 "dbpl: 5")
(line-to-quoted-operation-2 "pppw: cczh / lfqf")
(line-to-quoted-operation-2 "lgvd: ljgn * ptdq")
(line-to-quoted-operation-2 "drzm: hmdt - zczc")
(line-to-quoted-operation-2 "cczh: sllz + lgvd")
(line-to-quoted-operation-2 "root: pppw + sjmn")
;; i think it's done? let's try to eval all of this?
;; but i also need root back-computation.
;; for each operant that they are equal to forward calculation of another
;; (load-file-defs-2 "day21-test.txt")
;; (eval root)
;; (eval back-humn) ; 301. cool
;; (load-file-defs-2 "day21-input.txt")
;; (print (eval back-humn))
;; 3715799488132

15
day21-test.txt Normal file
View File

@@ -0,0 +1,15 @@
root: pppw + sjmn
dbpl: 5
cczh: sllz + lgvd
zczc: 2
ptdq: humn - dvpt
dvpt: 3
lfqf: 4
humn: 5
ljgn: 2
sjmn: drzm * dbpl
sllz: 4
pppw: cczh / lfqf
lgvd: ljgn * ptdq
drzm: hmdt - zczc
hmdt: 32

98
day21.lisp Normal file
View File

@@ -0,0 +1,98 @@
;; // https://adventofcode.com/2022/day/21
(defpackage :day-21
(:use :cl))
(in-package :day-21)
(ql:quickload 'cl-ppcre)
(defun parse-integer-or-symbol (str)
(let ((maybe-int (parse-integer str :junk-allowed t)))
(if maybe-int
maybe-int
(intern (string-upcase str)))))
(defun line-to-quoted-operation (line)
(let* ((words (ppcre:split " " (ppcre:regex-replace ":" line "")))
(symbols (mapcar #'parse-integer-or-symbol words)))
(cond
((= 4 (length symbols))
;; with operation
(destructuring-bind (name operand1 op operand2)
symbols
`(defparameter ,name '(,op (eval ,operand1) (eval ,operand2)))))
((= 2 (length symbols))
;; just number
(destructuring-bind (name value)
symbols
`(defparameter ,name ,value))))))
(defun load-file-defs (filename)
(loop
for line in (uiop:read-file-lines filename)
for definition = (line-to-quoted-operation line)
do (eval definition)))
(defun reverse-operation (op)
(case op
('* '/)
('/ '*)
('+ '-)
('- '+)))
(defun back-symbol (symb)
(intern (format nil "BACK-~a" symb)))
;; adding BACK-symbol computations.
(defun line-to-quoted-operation-2 (line)
(let* ((words (ppcre:split " " (ppcre:regex-replace ":" line "")))
(symbols (mapcar #'parse-integer-or-symbol words)))
(cond
((= 4 (length symbols))
;; with operation
(destructuring-bind (name operand1 op operand2)
symbols
(if (eq name 'ROOT)
`(progn (defparameter ,(back-symbol operand1) '(eval ,operand2))
(defparameter ,(back-symbol operand2) '(eval ,operand1)))
(let ((forward-calc
`(defparameter ,name '(,op (eval ,operand1) (eval ,operand2))))
(backward-calc
(case op
('+ `((defparameter
,(back-symbol operand1)
'(- (eval ,(back-symbol name)) (eval ,operand2)))
(defparameter
,(back-symbol operand2)
'(- (eval ,(back-symbol name)) (eval ,operand1)))))
('- `((defparameter
,(back-symbol operand1)
'(+ (eval ,(back-symbol name)) (eval ,operand2)))
(defparameter
,(back-symbol operand2)
'(- (eval ,operand1) (eval ,(back-symbol name))))))
(t `((defparameter
,(back-symbol operand1)
'(,(reverse-operation op) (eval ,(back-symbol name)) (eval ,operand2)))
(defparameter
,(back-symbol operand2)
'(,(reverse-operation op) (eval ,(back-symbol name)) (eval ,operand1)))))
)))
`(progn
,forward-calc
,@backward-calc
;; (defparameter ,(innern (format t "BACK~a" name) ))
)))))
((= 2 (length symbols))
;; just number
(destructuring-bind (name value)
symbols
`(defparameter ,name ,value))))))
(defun load-file-defs-2 (filename)
(loop
for line in (uiop:read-file-lines filename)
for definitions = (line-to-quoted-operation-2 line)
do (eval definitions)))

200
day22-map.txt Normal file
View File

@@ -0,0 +1,200 @@
......#....#.#........................................#.......##...........#.............#......#...
..............#..#........#......##........................#......#....#........................#...
.....................#.........#...#.#........#..............................#....#........#..#.....
.........#.........##................................#.....#.........#...........#...........#......
..........#.............#.....##.......#..#..........##......#.#...........#............##..........
......#.............##.........#.....#....#...............................................#.......#.
..#......#......#.........#..#.........#....#...................#...........#...#.....##.#..#...#..#
#.#.............#.............#.#......#.....#.....#.##.##.....#...#..#...............#.............
.#....#...##....#...................#..#............................................#.........#.....
....#..##....#..#....#..............#..#...#...#................#...........#..#..#............##...
..#.#....................................................................#.....##....##.....#..#....
.......#...#......#...##........#...#......................#.#.#..............#...#..#.....#........
.....#.#..#........#..............##......#........##...............#..................#.....#......
.......#...............#...#...................................#............#.......................
......#..##.....#.......#....#..................................................#.#.......#.........
................#..#..#....#.#.....................#................................................
.................#.#........#.....##...#...#.#..#....#....#.............#...#..................#..#.
.#...................#......#..#...............#.............#.........................#...#.....#..
...#.#...................#...#.........................#.......##.......................#.........#.
.#.............................#........##.........#.#.....##.....................#....#...........#
..........#.....#..............................#................##.....................#.......#....
.....................................#....##..........#...............#.......##.........#.#........
....#.###............#....#..........#..........#.......................#...............#....#.#....
.#...#...#...............#.........#........................#.................#..................#.#
.................#......#.....................#........#......#.....................#....#.##.......
##..#....................#.....................#....#....#.....#.............................#.....#
#...#.......................................................##.#...#.........#..#...................
............#......#.....#........#..#.#......#.#.............#....#......#.#...............#.......
..................................................#.#..........##.........##......#.#.#.........##..
..#..........................#.......#..#..#.......#.................###.......#...........#..#...##
..#.....#..#...#.....#.....#...#..#.................................#.....#.........#.............#.
............#.#..#..##..#.#.##....#...............#.......#........#............#........#..........
.#...........#...........................#............#.....#.#.........#.....#.......###...#.......
...#.......................#.........................#...##........#.....................#.......#..
...........#..#.............................#.................#..##...#.............................
..................#.#...#..#....#....#..........#................#..#.........#......#.......#......
...#...#....#.#................#.............#.............................#..#.....................
....................#.........#..#.#...#.#.##...#...#..............#.......#.........#.............#
...#.....#.............##.....#....#.#.......#......................................................
..........#..#...#.......................#.................##.....#........#...#......#.......#.....
........#......#...............#.#.....#...........................#.....................#.......#..
..................................#...........#......#...........#.............#....###.............
................#.......................#.#......#.##..........#......#............#................
.........................................#..........................................##...........#..
...#.......#....##.#....#...............#..#...#.............#...#....#.....#.#...........#.........
#........#...........#...........#.....................#........#..................#.....#......#...
........#.....##..#.........................#....#..........#.##..#.......#.#.................#...#.
..........................#.............................#........#............#.............#....#..
.............................#..................................................#...................
................#.............#..#..........##......#......#.........#...........##............##...
#...#.......#.............#............#..........
#................#...#....#..................#....
.................#.....#.#....#......#...#........
..................................#...............
.....#...............................#............
...............#............##..........#.......#.
#............#.....................###.#.........#
.#...............#...........#....#......#........
.#.............###.#................#........#....
....##............#..........#.#.........#.#.#....
..................#..#..............#......#......
....#.............................#...............
.#.#..........#...........#......##...............
..........#......#....#...#.#....#..#.............
................#...............#.................
..........#..#...#..............#...............#.
...#..............##..............#...............
..#...#.#....#.........#.........#.......#........
.................#..............#.........#.....#.
.......#........#......#............#......#......
..........#..............#....#..#............#...
.......#............#.............#...............
.....#.#..........#.#..........#..................
#...#...................#......#......#.....#.....
........#........##.#.......##................#...
..................#.........................##....
..#................#..............#.#....#.#.#...#
........#..........................#..........#...
..#.......#.#............#..........#.....#.......
....#....#...............................#........
..#............................................#..
....#.......#..............##.......#......##.....
.#..........#......#....#.#........#..............
................#.#.......##.............###.....#
...............#......##.#...#................#...
....#.......#....##...#..#..........#.........#...
.....#.........#...#...........#........#.........
.......#...............#..................#.......
...........#.....#.........#........#....#.......#
..#.....................................#...#.....
..................#..............#....#.#.........
........................#.......#.#......#........
...#......#..#..........#..#..#........#..........
.....#.......#.........#.............#.......#....
......#......#...............#.....#.........#....
.#.........................#.....#.............#..
...#......#.#.....##...#.#....#.#...............#.
.............#........#.#.#.....#.................
...#.........#.........#....#.................##..
.......#.......##...#....#..........#.#...........
..#......#....................#.........#........#.....................#............#.....#.........
.##...........##...................#.#..................................#...........................
....#............#..........#..........................#...#......................#....##...........
.#...........#........................#..............................#..#...................#......#
#................#.#........#...........................#....................#...........#..........
#.....................#.....#.......##....#......#..##...#...........#...................#..........
.........#..#......#....#......#....#.......#.....................................................##
..#...#......##.#..................#.......#.............#....#....#.........#..............#.....#.
...........#...#...#.#........#..................##...........#.....#...............................
.............................#....##..#..#..........#.............................#.................
...#.................#...#...#...#.................................................#..............##
......#........#........#.........##....#....#.....#.......#.............#...##.##.#................
..#.......................#....................#..#...#.................#......#..........#......#..
.........................#....#..##..............#.............#.#...#....#.......#...#....#.....#..
....#................#.#...........................#....#..#.......##.#.....#................#.#....
..#.......................#.....#...#..#..#...#...#.............................#............#......
#..............................................#.......................................##........#.#
..............#.#............##..........#.........................#..................#.#...........
.....#......................#...........#.....#.................#................#........#...#..#.#
......#.#....#......#.#..................#.#................#.#.#...........#............#.....#....
.#......#......##..............#.........#.#.#.#..................#...#..........#..................
...#...........#.............#....#.#...#....#.......................#.#.....#.....#..............#.
...#...#.#.........#...#............#....#.........#.....#......#..#...........#.....#......#.......
.#.....#..........#..............#..#........#..............#...#.............#.#.......#..#........
.....#........................#.....#......#...............##..#.#...#...#.#............#...........
.....#......#.........#....#.......##.......#.##..................#...............#......#........#.
.#..#..#..#.................................#......#.#............#..#....#...................#.....
.#..#...........................#....#............................................................#.
......#..............................#..#.......#.........##..........##...#........................
............#...............#..#..#..........#......................#...#.#............#............
...##..................#.....#.........#......#...........#.......#.....#.......................#...
..#..#..#......#......#.....#.......#.................##..#.........................................
............#...##...#..........#.................................##....#........##........#........
...##...#....#....#........................#.............##.........................##.......#......
.............##..................#...................##.......#........##.............#.#..........#
.......#.....#...##..............#..........................#..........#..........#..#.............#
............#...#........#........#...............#.....#.....#.......#..............#.....#......#.
...........#.....#..##.................#......#........#.#.....................#....................
.....#......#.........#..........#..#......................................................##.......
..........#.....#......#.#.........#.....#..................##.............................#........
##......#...#..........#...............#.............#........#..................#........#........#
..#.........#...........#.......#...........##...................#.................#.#.....#...#....
...#.........#..................................#.....#..#............#.............#.#.............
....#...........#..........#..............#..###........#..#.........#....................#.#.......
..#..........#..#...............................#...#.................#............#............#.#.
.....................#.............#....#..#....#......................#..#......#..................
........#.#.............#....#...#.#.....#..........#................#.......#........#....#.#.....#
##.........................##....#...............#..........#......................##...............
.........#..................................#........................#....#............#...#.#......
........#........................#..#...#..........................#................................
................#..#.......#..#...................
.............#........#...................#.......
..#....#.......................#..........#...#..#
..........#.....................#..............#.#
.........#...#...#..............#..#.........#....
...........#.....#................................
.......#..#..#.......#............#...............
.........................#..........#..#....#..#..
#...........#....#.....#....#.#..#.......#........
#.#.......#.....#........#....#...#...............
..............................................#...
#......#....................................#...#.
........##..#.....#.#......#.........#..##....#...
...............#.........#...#.......#......#..#..
..........#.#......#.....#........................
.....#.....#......................................
..#..#............#.......#.....#..#.......#...#..
...............##....#........#..#.............#.#
..............#..................#.....#......#...
#.......#.......#...#...............#.#....#......
#.........#........#..........#........#....#.....
.....###.#...........#...........##............#..
.........#..##.......#......................#.....
.....#.##......#.......#...#.............#........
##.................#.....#.............#....#...#.
........#..............#.#.........#.......#......
........#..#.#.....#.............#............#..#
.#.....#.#..#..#.##........#..........#.....##....
.....#....#.........#.............................
................#..#....#.....#....#........#..#..
#.#............#.....#.............#.........#....
...#....#..........#.#.................#.#..#...#.
........#................#...#......#......#...#.#
..#.............#....#.......#..............#.....
.....................................##.........#.
............#.#...................................
..#...........................#..........#........
...#.............#..............#..........#...#..
#......#...#...#...#...#..................#....#..
....#......#..#....#.#.#..........................
..#.......................#..............#..#.....
................#........#...#..........#.#.......
....#...#......#...................#.#.#...#....#.
............#..............#........#..#.....#....
..........#...............#.......#...............
#....................#.......#...........#........
.......#.........#..........#.#..#.#..............
..#.........##......................#...#.........
...#.................#.##............#........#...
....#......#..#.....................#.............

1
day22-path.txt Normal file

File diff suppressed because one or more lines are too long

229
day22-scratch.lisp Normal file
View File

@@ -0,0 +1,229 @@
;; https://adventofcode.com/2022/day/22
(in-package :day-22)
;; monkey map. so, i'd want to store the map.
;; and have functions that return "neighbors" maybe as alist?
;; neighbor is the right place to calculate wrapping around empty space
;; on top of neighbors get walkable directions
;; how to best represent coord?
;; next - moving
;; looking at the map of input. maybe somehow precompute where to jump on the map?
;; nah.
;; so, let's get map. with chars space, dot, hash
;; have line of spaces at the start, end, left and right?
;; that would shift coords by +1
;; and i'd also like what? i'd also like to store the path?
;; when exiting save that last orientation at the point?
;; and only treat space and hast as special, dot and arrows as walkable
;; or i could print "every snapshot" with setting and removing the walkout
;; i could split the input into files, that would simplify things
;; let's read the map into array?
(setq *ugh*
(let* ((lines (uiop:read-file-lines "day22-test-map.txt"))
(rows (length lines))
(cols (apply #'max (mapcar #'length lines)))
(arr (make-array (list (+ 2 rows) (+ 2 cols)) ; adding for padding row of empty space
:initial-element #\ )))
(loop for row from 0 below rows
for line = (coerce (nth row lines) 'array)
do (loop for col from 0 below cols
for char = (if (array-in-bounds-p line col) (aref line col) #\ )
do (setf (aref arr (1+ row) (1+ col)) char)))
arr))
(setq *test-arr-out-bounds* (make-array '(2 2) :initial-element #\. :adjustable t))
(print-map *ugh*)
;; yep, this is what i want
(print-map (read-map-to-array "day22-map.txt"))
(setq *ugh* (read-map-to-array "day22-test-map.txt"))
;; seems to work.
;; what are next steps?
;;
;; for some coords get neighboring to four sides
;; this should just return coords even with wrapping
;; let's first do function that returns coord or wrapped coord if value is space?
(alexandria:assoc-value *movements* 'left)
;; so from coord as list to updated coord
(move-coord-one-step '(1 1) 'right)
;; next should check the value of the moved. and if it's space -
;; calculate wrap
;; would also take the map array
;; if we're out of bounds, just skip this movement. shouldn't happen in my data
(opposite-movement 'left)
(opposite-movement 'right)
(opposite-movement 'down)
(opposite-movement 'up)
(apply #'aref *ugh* '(1 12))
;; now i need to check that. hm.
*ugh*
(print-map *ugh*)
'(4 1) ; begining of part
(move-with-possible-wrap '(5 1) 'left *ugh*)
(aref *ugh* 5 0)
(let ((coord '(5 1))
(map *ugh*)
(direction 'left))
(do
((mov-coord coord
(move-coord-one-step mov-coord (opposite-movement direction))))
((equal #\ (apply #'aref map mov-coord)) (move-coord-one-step mov-coord direction))))
;; now? um
(move-with-possible-wrap '(5 2) 'up *ugh*) ; now that seems ok
;; next is from 'move-with-possible-wrap
;; i guess i'd alreay want to display?
;; set X on that coord?
(display-coord '(5 2) *ugh*)
(display-coord (move-with-possible-wrap '(5 2) 'up *ugh*) *ugh*)
;; yeah, kind of ok.
;; what next? simulate movement?
(move 4 'right '(1 1) *ugh*)
(display-coord '(6 1) *ugh*)
(display-coord (move 4 'right '(6 1) *ugh*) *ugh*)
(display-coord '(6 8) *ugh*)
(display-coord (move-with-possible-wrap '(6 8) 'left *ugh*) *ugh*)
(display-coord (move 1 'left '(6 8) *ugh*) *ugh*)
(display-coord (move 2 'left '(6 8) *ugh*) *ugh*)
(display-coord (move 3 'left '(6 8) *ugh*) *ugh*)
(display-coord '(6 8) *ugh*)
(display-coord (move-with-possible-wrap '(6 8) 'right *ugh*) *ugh*)
(display-coord (move 1 'right '(6 8) *ugh*) *ugh*)
(display-coord (move 2 'right '(6 8) *ugh*) *ugh*)
(display-coord (move 3 'right '(6 8) *ugh*) *ugh*)
(display-coord '(6 2) *ugh*)
(display-coord (move-with-possible-wrap '(6 2) 'left *ugh*) *ugh*)
(display-coord (move 1 'left '(6 2) *ugh*) *ugh*)
(display-coord (move 2 'left '(6 2) *ugh*) *ugh*)
(display-coord (move 3 'left '(6 2) *ugh*) *ugh*)
(display-coord (move 4 'left '(6 2) *ugh*) *ugh*)
(display-coord (move 5 'left '(6 2) *ugh*) *ugh*)
(display-coord (move 6 'left '(6 2) *ugh*) *ugh*)
;; ok, i guess
;;
;; and now code the walk?
(defparameter *test-path* "10R5L5R10L4R5L5")
(ppcre:split "(L|R|U|D])" *test-path* :with-registers-p t )
;; somewhat of what i want, but also lrud into words
(mapcar #'parse-integer-or-symbol
(ppcre:split "(L|R)" *test-path* :with-registers-p t ))
;; initial number is "forward" from initial direction
;; oh, so the path is with turns Right turn or Left turn.
;; with initial Right
;; so, now i'd want a fuction that transformes direction
;; i guess i could what? make cyclic list? not quite i guess
(alexandria:circular-list 'up 'right 'down 'left)
(position 'up (alexandria:circular-list 'up 'right 'down 'left))
(nth (mod -1 4) (alexandria:circular-list 'up 'right 'down 'left))
;; yeah i guess
(new-direction 'UP 'L)
(new-direction 'LEFT 'L)
(new-direction 'down 'L)
(new-direction 'right 'L)
(new-direction 'UP 'R)
(new-direction 'LEFT 'R)
(new-direction 'down 'R)
(new-direction 'right 'R)
;; yay. that's kind of ok
;; now. ugh
;; yup, let's add that in code...
(append (read-path "day22-test-path.txt") (list 'L))
(read-path "day22-path.txt")
;; the path is "go N to your direction"
;; then L or R to change direction
;; so, now the main loop?
;; i guess i could add one more R or L to the end
;; and treat path as (n turn-direction)
;; oh, but the final direction is part of the answer
;; OK, LET'S add L to the end
(let ((padded-path (append (read-path "day22-test-path.txt") (list 'L)))
(direction 'right)
(coords '(1 1)) ; to be calculated
(map *ugh*)
)
(loop
for (n turn-direction) on padded-path by #'cddr
do (progn
(setq coords (move n direction coords map))
(setq direction (new-direction direction turn-direction)))
finally (return (list coords direction))))
;; hoho. the task requires indices starting from 1, cool
;; and i did 1 too many left turns, so let's turn right
;; UP to right, is RIGHT
;; and 0 for right, cool
;; yay! now let's clean it up.
;; one more thing. determining top leftmost point.
(get-topmost-left-coords *ugh*)
(print-map *ugh*)
(apply #'calc-password (walk-path "day22-test-path.txt" "day22-test-map.txt"))
(apply #'calc-password (walk-path "day22-path.txt" "day22-map.txt"))
;; 11464
;; and one gold star.
;;; and PART 2.
;; then neighbors is different
;; especially the wrap thing.
;; how'd i calc that? for the map? ugh
;; so, it's 6 parts. huh. ugh
;; oh, they're oblong, but they are all 4 by 4
;; XX
;; X
;; XX
;; X
;; outline of my input
;; how do i get freaking folding?
;; ugh.
;; maybe go for the next? um.
;; yeah. i'm giving up for now. let's go to rest for the new years. 19:33 of Dec 31st
;; fare well Common Lisp, I'll return to use in Q2 or Q3

12
day22-test-map.txt Normal file
View File

@@ -0,0 +1,12 @@
...#
.#..
#...
....
...#.......#
........#...
..#....#....
..........#.
...#....
.....#..
.#......
......#.

1
day22-test-path.txt Normal file
View File

@@ -0,0 +1 @@
10R5L5R10L4R5L5

141
day22.lisp Normal file
View File

@@ -0,0 +1,141 @@
;; https://adventofcode.com/2022/day/22
(defpackage :day-22
(:use :cl))
(in-package :day-22)
(ql:quickload 'alexandria)
(ql:quickload 'fiveam)
(ql:quickload 'cl-ppcre)
(5am:def-suite :day-22-test)
(defun read-map-to-array (filename)
(let* ((lines (uiop:read-file-lines filename))
(rows (length lines))
(cols (apply #'max (mapcar #'length lines)))
(arr (make-array (list (+ 2 rows) (+ 2 cols)) ; adding for padding row of empty space
:initial-element #\ )))
(loop for row from 0 below rows
for line = (coerce (nth row lines) 'array)
do (loop for col from 0 below cols
for char = (if (array-in-bounds-p line col) (aref line col) #\ )
do (setf (aref arr (1+ row) (1+ col)) char)))
arr))
(defun print-map (arr)
(loop for row from 0 below (array-dimension arr 0)
do (let ((line (make-array (array-dimension arr 1)
:displaced-to arr
:displaced-index-offset (* row (array-dimension arr 1)))))
(format t "~a~%" (coerce line 'string))
)))
(defconstant *movements*
'((left . (0 -1))
(right . (0 1))
(down . (1 0))
(up . (-1 0))))
(defun opposite-movement (movement)
(let ((alist '((left . right) (down . up))))
(or (alexandria:assoc-value alist movement)
(alexandria:rassoc-value alist movement))))
(defun move-coord-one-step (coord direction)
(mapcar #'+ coord (alexandria:assoc-value *movements* direction)))
(5am:def-test move-coord-left (:suite :day-22-test)
(5am:is (equalp (move-coord-one-step '(2 2) 'left)
'(2 1))))
(5am:def-test move-coord-right (:suite :day-22-test)
(5am:is (equalp (move-coord-one-step '(2 2) 'right)
'(2 3))))
(5am:def-test move-coord-up (:suite :day-22-test)
(5am:is (equalp (move-coord-one-step '(2 2) 'up)
'(1 2))))
(5am:def-test move-coord-down (:suite :day-22-test)
(5am:is (equalp (move-coord-one-step '(2 2) 'down)
'(3 2))))
(defun move-with-possible-wrap (coord direction map)
(let ((initial (move-coord-one-step coord direction)))
(if (not (equal #\ (apply #'aref map initial)))
;; when not wrapping
initial
;; when map on initial movement is empty - wrap
(do
((mov-coord coord
(move-coord-one-step mov-coord (opposite-movement direction))))
((equal #\ (apply #'aref map mov-coord)) (move-coord-one-step mov-coord direction))))))
(defun display-coord (coord map)
(let ((copied (alexandria:copy-array map)))
(setf (apply #'aref copied coord) #\X)
(print-map copied)))
(defun move (n direction coord map)
(do* ((prev-coord coord next-coord)
(next-coord (move-with-possible-wrap coord direction map) (move-with-possible-wrap next-coord direction map))
(count 0 (1+ count)))
((or (= count n)
(equal #\# (apply #'aref map next-coord)))
prev-coord)
;; (format t "before move, iter ~a~%" n)
;; (display-coord prev-coord map)
;; (format t "after move, iter ~a~%" n)
;; (display-coord next-coord map)
))
(defun new-direction (direction turn-to)
(let* ((directions-cycle '(UP RIGHT DOWN LEFT))
(turn-mod '((L . -1) (R . 1)))
(cur-dir-pos (position direction directions-cycle))
(new-pos (mod
(+ cur-dir-pos (alexandria:assoc-value turn-mod turn-to))
4)))
(nth new-pos directions-cycle)))
(defun parse-integer-or-symbol (str)
(let ((maybe-int (parse-integer str :junk-allowed t)))
(if maybe-int
maybe-int
(intern (string-upcase str)))))
(defun read-path (filename)
(mapcar #'parse-integer-or-symbol
(ppcre:split "(L|R)" (uiop:read-file-string filename) :with-registers-p t )))
(defun get-topmost-left-coords (map)
(loop for col from 0 below (array-dimension map 1)
do (when (equal #\. (aref map 1 col))
(return (list 1 col)))))
(defun walk-path (path-filename map-filename)
(let* ((padded-path (append (read-path path-filename)
(list 'L)))
(direction 'right)
; to be calculated
(map (read-map-to-array map-filename))
(coords (get-topmost-left-coords map))
(walk-result
(loop
for (n turn-direction)
on padded-path by #'cddr
do (progn
(setq coords (move n direction coords map))
(setq direction (new-direction direction turn-direction)))
finally (return (list coords direction)))))
(destructuring-bind ((row col) over-direction)
walk-result
(list row col (new-direction over-direction 'R)))))
(defun calc-password (row col direction)
(let* ((direction-scores '((right . 0) (down . 1) (left . 2) (up . 3)))
(direction-score (alexandria:assoc-value direction-scores direction)))
(+ (* 1000 row) (* 4 col) direction-score)))
(5am:run! ':day-22-test)

129
day25-input.txt Normal file
View File

@@ -0,0 +1,129 @@
1-012=0=2=--12
11=
1=--000111=01-0
201-12=0211--
110-=010-01--02
11021==---22-1
122001
1--0
2-=2
22=02==01=0-2-011
12-2-00-11
20=0-2102=-01
1102=
122--0-112221
11=00-2=201-22=-=
10-02==210--=0
2=220-02=1202
1=--0-
2-122==
10-=00
1=001-22==1
1=121022122-1--0
11-
2=0-1-0-1
1=-0221-==
1-==-0--1012
1--02=-01=020110=
2-0212==1--=2=
112
1=-=1=0012201
1==-
1=02-2=012-=2--=--
1=220-1=0--=1
10-=
1-=22-111=211
11--==21==202
20-
1=-1=02=0=1===0-210
1==-0=010
1=-2=-=2-01-102102=
110-==0=2=-==-2-10
12200=--21-
21-=1-=1-2-
111-==2=2
210=-0-02=-0=11
10-1
1-0=011
20=10=001-
2-0=0-=1121=---2-0
22-1=2=0202
21=2201020211=2
1-110=
21=22=0-=1==121
1==-=01
1-1=1012==1
1-01===1=--21
1==
2-=
200=202121--0122
1-02
1=21=-12-0-
2-=10
121=-20=0200=02==1
101=2-2102-0-02=
1===11
22==0
22-21==-2-1220=10
1==2120--1-=
1=11-2=-110100002200
2211=2=-=-=01-01
1==-010==-=2-=
2=0=2
11-100-21=
11=1=-1=0
2=2--1=2
1-0==1=2-211=1
1-2=-202011211
10=-==-00-1==01
1-=2122==
112=-012
12==-0=
1122-0=0
1=2=0
2===-0=-0-0
1212
202
1==1
2111=1=000221-=-2=-
210111=2=0-1==-
1===00=
22=22=-1-==2-==
102--1=-1=222
2=--=--0-2
11-02=201101=2
1=
12--112-=0=
10====0=220
100020002=-0=02-1-
101
1=1-112-=
2022-02
22201212
21221201010210-1-
1-=1=-121-0-221-10
1=212=01--10-==
12-0=2121=21-2
111-2-00
1=20=202--
2-==2=--2-2101002
111-12=00
1=0===2=
12=-2020=1=2012
2=
1-02---
221---2122212
10=-20002=20-22
2010-220
12
2=0-=221
10011=0
1-20--=1=1-=1
1=1
1=0202-2-1=20-2-
101=--0-=-010-=
1=12=--
2=2111=
1=0-2=2120002=0
10-1=0---10=-20=010
20-121===--=2-=111

96
day25-scratch.lisp Normal file
View File

@@ -0,0 +1,96 @@
;; https://adventofcode.com/2022/day/25
(in-package :day-25)
;; so. from decimal to SNAFU and back...
;; or maybe direct sum in snafu?
;;
;; at least 16 digits in my input
(parse-integer (format nil "~a" '1)) ; kek
;; would rather have hashmap then? or array, i guess
;; no? list? alist is list of cons cells, no?
;; from SNAFU should be easier
;; 1=-0-2
(defparameter *test-snafu*
'((5 . 1) (4 . -2) (3 . -1) (2 . 0) (1 . -1) (0 . 2)))
(assoc 4 *test-snafu*)
(alexandria:assoc-value *test-snafu* 4)
(loop
for (pow . mul) in *test-snafu*
sum (* mul (expt 5 pow)))
(exp 2) ; e^2
(expt 5 2) ; 5^2
;; now i want to parse snafu number, right?
;; reverse, start with power 0 yeah, i guess
;; 1-12
(mul-to-char 1)
(mul-to-char -1)
(mul-to-char -2)
(char-to-mul #\=)
(coerce )
(let ((str "1-12"))
(loop
for char across (reverse (coerce str 'array))
for pow from 0
collect (cons pow (char-to-mul char))))
(snafu-to-dec (read-snafu "1-12"))
;; but last thing i want is decimal to snafu.
;; and that's ugh.
;; i could decode into 5 base system, maybe even automatically,
;; then parse into powers of 5 written in 0 - 5
(format t "print in base/radix 5 - ~5R ~5R ~5R ~5R ~5R " 4 5 6 7 8 9)
;; i think this works.
;; now i could parse this into amounts of powers of 5.
;; but then i'd still need to go from 0..5 to -2..2
;;
;; if in pow_k we have >2
;; we can +1 to higher power pow_k+1
;; and to balance -5 in pow_k
(decimal-to-pows-5 1747) ; yeah, maybe good, yes
(- (char-code #\1) (char-code #\0))
(- (char-code #\4) (char-code #\0))
(- (char-code #\6) (char-code #\0))
(- (char-code #\7) (char-code #\0))
(- (char-code #\9) (char-code #\0))
;; and now - modify multipliers of the powers.
;; loop from 0 to (1- length) over all powers.
;;
(defparameter *test-snafu*
'((5 . 1) (4 . -2) (3 . -1) (2 . 0) (1 . -1) (0 . 2)))
(setf (cdr (assoc 4 *test-snafu*)) 6)
(setf (cdr (assoc 6 *test-snafu*)) 6)
(setf (assoc 6 *test-snafu*) '(6 . 2))
(alexandria:assoc-value *test-snafu* 4)
(print (decimal-to-pows-5 1747))
;; ((0 . 2) (1 . 4) (2 . 4) (3 . 3) (4 . 2))
(print (pows-5-to-snafu (decimal-to-pows-5 1747)))
;; ((0 . 2) (1 . -1) (2 . 0) (3 . -1) (4 . -2) (5 . 1))
;; ((0 . 2) (1 . 4) (2 . 4) (3 . 3) (4 . 2))
;; ((0 . -3) (1 . 0) (2 . 5) (3 . 3) (4 . 2))
(coerce (list #\a #\1 #\- #\e) 'string)
(snafu-to-dec (pows-5-to-snafu (decimal-to-pows-5 1747)))
(snafu-pows-print (pows-5-to-snafu (decimal-to-pows-5 1747)))
;; yeah
(loop
for line in (uiop:read-file-lines "day25-test.txt")
for dec = (snafu-to-dec (read-snafu line))
summing dec into the-sum
finally (return (snafu-pows-print (decimal-to-snafu the-sum))))
;; (part-1-calc "day25-test.txt")
;; (print (part-1-calc "day25-input.txt"))

13
day25-test.txt Normal file
View File

@@ -0,0 +1,13 @@
1=-0-2
12111
2=0=
21
2=01
111
20012
112
1=-1=
1-12
12
1=
122

68
day25.lisp Normal file
View File

@@ -0,0 +1,68 @@
;; https://adventofcode.com/2022/day/25
(defpackage :day-25
(:use :cl))
(in-package :day-25)
(ql:quickload 'alexandria)
(defun snafu-to-dec (snafu-alist)
(loop
for (pow . mul) in snafu-alist
sum (* mul (expt 5 pow))))
;; let's do that as alist as well?
(defparameter *snafu-char-to-mul*
'((#\2 . 2)
(#\1 . 1)
(#\0 . 0)
(#\- . -1)
(#\= . -2)))
(defun char-to-mul (char)
(alexandria:assoc-value *snafu-char-to-mul* char))
(defun mul-to-char (n)
(alexandria:rassoc-value *snafu-char-to-mul* n))
;; into the alist power representation
(defun read-snafu (str)
(loop
for char across (reverse (coerce str 'array))
for pow from 0
collect (cons pow (char-to-mul char))))
(defun decimal-to-pows-5 (num)
(let ((str (format nil "~5R" num)))
(loop
for char across (reverse (coerce str 'array))
for pow from 0
;; do (print char)
collect (cons pow (- (char-code char) (char-code #\0))))))
(defun pows-5-to-snafu (pows-5)
(let ((copied-list (copy-alist pows-5)))
(loop
for pow from 0 below (length pows-5)
when (> (alexandria:assoc-value copied-list pow) 2)
do (progn
(incf (cdr (assoc pow copied-list)) -5)
(when (not (assoc (1+ pow) copied-list))
(push (cons (1+ pow) 0) copied-list))
(incf (cdr (assoc (1+ pow) copied-list)))))
copied-list))
(defun snafu-pows-print (snafu-alist)
(coerce (loop
for pow from (1- (length snafu-alist)) downto 0
collect (mul-to-char (alexandria:assoc-value snafu-alist pow))
)
'string))
(defun decimal-to-snafu (num)
(pows-5-to-snafu (decimal-to-pows-5 num)))
(defun part-1-calc (filename)
(loop
for line in (uiop:read-file-lines filename)
for dec = (snafu-to-dec (read-snafu line))
summing dec into the-sum
finally (return (snafu-pows-print (decimal-to-snafu the-sum)))) )

300
day3-input.txt Normal file
View File

@@ -0,0 +1,300 @@
GwrhJPDJCZFRcwfZWV
LjnQlqNpjjmpmQlLlqNfZRvQcTWcTSTTZcSQcZ
nNqjdspspngnmjmslqmjjjCDGrHPHMGddGCMCGPPPJWC
GwmVZmPWWFFmBbVbZVwmbPsTCnlgQgnQfhlffffZnlQh
DqVDSqqSMzLLDDNSHHLdqSdSllCQjsTlClhlflnTlhjgfgfM
VHJztNLHGtcbvvPG
bjrPrNCtNrjdcCPpptfpTVspDtfTtB
JGQJMJQMmmmZMnnLpLBTpHCD
WJJqWRgWlCJZhZRCQZwdPScdrPNbvzPzwvqz
QNSQNBWQNLjZBNNhLhSNRsTcsrTTVzcwZZZsfrrbwb
tCFtHpppppMldpvpqnMFmMVGrbPcrwbzswrzcccfvTfw
pdmCpgqCdmHHdJVWgSRNJDRVVj
sNrFnvNSzrjQtQjQTj
lcPmcJDLdPDbJPVLljdGGBBThBQTGwTtBw
PDLqmJmpJQfFqfqsCM
BnhctqdnqnRcBnslCJJCMrJrsG
wNDMZpbQwMpCvCGVjlss
WfzNwZFbwZzZmFZbLzNwzzzzcdqgRMTTPdHPTTPMRdcWgRPt
grsrVSFSSdFSDFVFjZZWwpWpZWZplgZZ
mcBPPPBLBfNdLlvvWljWJC
dMcmcRdbRzdVhFthSsTShM
bzvJZMTzTZSHLCCdDzmDcc
hqBqWPFssvshWvvssNqtsHftmfpHfdcdDGHmcpfctL
WvBQgNNNhghTJbJQlJTZlT
chcdwNwdbCbQctCjnnQGHsQspMHMjG
nSSSJqJZzJgWWRfZDJSnqvTTsVvvHVPpHVfpjHMTjP
BZRDRmmrDWSrZWWzWSRNhdnCFwChclFtwbNdtr
lNgmssCtqLwqCCtfsCLHPFhhhmMhVzBDbVzMDMVz
ZnRlQTlJzFQFQFVV
npZJvRRGZSnWvSvrSLglsClfpfcLgNgpHf
tVtqcVqFVtZhcfFtqlgSpmpDSDNPzSzZmNpw
LRGTHqbrHdnGHrTCSSwNDzMDwPMzNwbp
TqWGJrGHCHnTWnhsWcFthFjtfQch
qNnTbwtctvffFcqfrHjMrFjVHRjSjZDZ
dLLzWWPmCmCzGdsLgBLGGBDRMVMHRlrrrZDDZsNMrNNS
PJQWggCzWNWJzGWfchvfTbJvfnnwtf
ghzdgzzdQsdqzzhMNqQzvhgQnRRBWTjWWGTRGWwGTZhwGnBT
fsrfJHbFfDFLVLVFHrWCWrBRZZTGCCjwWZ
HLLllcDPbLPQdPspMNgvMt
fNDJqdPNbtHpCbwpCCCp
RTMRLrzGrMRMRPWnnvSmgCHFCCFmmT
WQsWQjzGWMsGQzWclQtVBJfBftNdtqVPfP
gbTCVVmDVFdsgmgrrcfwlwfTfPlcRR
qhQZqQvnQhLQhJnvfPcSwSwlfjGcqjqj
tLNZLZZJJZthpzhMZDCdFmFsmWWmtDDgsw
bqCvLvLppzPzPPvPbFztFtttBNGdGsRggSgGSHDdggHSzNgH
rMQpWfMfrcTjWJhwWHHsSBsRBdSTTNBgSR
VwfmWjwMWwccrWcWpQQFnFtlCqmltFnFLbbZmn
cWqsMWJMzqJJMHsJcqsJqTqjSbLBdfdSbtzLbbLfbSfShfhd
gplGvQmRrCrgZSZtSGZZjhbj
CQmmmmNQRPvjgRClCvmmcVHPqMFMFsWJVqFFcnTJ
QHHqvGwjjWNqvGTQGvTFcGwJRJbszcPtDbJVbtPzVbDptp
MLdrgmSgZZdhdfbLVRpszlRDstRL
gdSgMCSfdMnrghCWGRQvHwvNHjnjvv
RDBZwvZBrMlsvnlb
WdFQqdjWWcHHPrwSPnnSWnSS
mLdqgqHmcjHHjqLHjLppmhfBfgtDtBJZJfVtBZwGZB
CCWRJQnZlHtHtNZRFDcBhrcvhDrJVVDv
dPPSqLzfsqGLSTzfLzLGdLMVVgvBcmgMVwmmDFrVgmBBBr
SFjdTGzqpjdRbNRNnjtnQR
hjNcwBDDwDFcjdFfjtFhtcRsGGgTsGRRRTsGGqZGRq
gbmrLnbzLmvQJnQVVpqZTqzWSCRpqRTsSR
MQMvVMbPQQHrQMnMPldtwNNfgHtlwBhdwj
zwzwpzMfzrBMWfCCZrwzrMJDGGGnNmGNZvgNZsDDsGsG
FbFqSbcSbSHqTjmgGFnJglllsDJm
TbhVdVjqdtqTjVHqjPdthPBBWpCnRfwRPRCfBCCnWR
hlpmbfJJpCSChmJMmrSjTjcSdjTtQQTtTtjF
gqrgsqLzgnBgZGzHBnnsQNNQtjjcNNjjtNFQNcNH
LVRzgGGzzzPCVrJMbPJb
VHrmqFnVdvlzzNrr
PMtwBJPBcPwfbwBJndplLvLdLlgMMzLL
bBZnTwbtnScfQJPJwPTjqGZFsVFjDHHGhhHhVj
cftqScHJrfVfrrRZ
DTTsDvvlBbTGrWBwwsWDBbWdVpZjjZjpVPPGhRRVjVZNRPNN
lsWdWDbrTLBsbdrmdwbMJtmHMQJccFHFnJFqFt
SWNPTPVSWChCSmQQhpppJdFJLpDpgLJmLd
NGGtNtGfHtDpdJdqLB
NcsNGNjHZsZGnzZfnGhQnhPClrVlQPhTVVhl
QDdgMBsNhhMgcWbZdzmWLzFzWH
fRqRJJqGCvrJGjCRRrSJlfPtHzzPmfFbtPtLZZLnmt
VjvwwjlwVGGqJSSqJFccshpgNhQNQTsVgBgT
wvDLDwCbFgSTfTSJJgfB
qsRhmhqchmVhPdfTHJSzpCtJpfPf
hmdhrWrddmhlqCRcwQjDLMQnMFDZnlLl
trMWtlwwMplMZMCZWltDpzBLBnflVLBbHzbBSGlVlL
ghhqJTfmjQjfqqznznnHnBRzBLmn
sQhPQsjjQcQcTsPqZWwwZcFfWrWcrZww
MRVpVCZZTHWVMCHvgNvVvbQSqgQSlg
NFmnrNDDfnjFnndfssmcStvjvQQlvzvllqvwQllj
GGPNmBrFNdcfcGrsGcdmDFhJHMMhHLZJMhpLHCMMMMPJ
DSvDGdGFlGGnDZFdVSZvfPqwnfhpnrqpPNpLPrrh
sWcTjtHCsTmsCNfgMPjpfPhqhP
BtHzBzChzBBvFSDJvVzFJJ
sfsNrsFFBTfjwwtNNWHPVCVWtSCDDCDmmS
zMdhMMZnSccMmmWVWmCPlC
cLSScJZQbcvLhZvnzBwfTjrpNwNrBFffpb
TBrCBgrTngVQBVbhrCtgJJrGssGsMGRGcjMcNjfN
LZdSLvHMFdzFRWsLjcGRWWNJ
pHpzlqPqFPvdBthgMbVPDhgh
SZlnZZvBvvMrcBnllBMZSvhGMtQwFMGztthfwQtMwwPf
HLqsDgNsDLDDDjggHDHszthzFbQGTghPGQPbTfFT
dmLqDqCmFNjJsjHdssFNHDVWZccnRllnVZvRSBZrZlCc
SccnnSGGftShfHSHHhnvbMjvVlCjzbVzzbMMTbCB
gRpppNNQLWqZgPZwNWwwBMBbDlZCTzVTjHMMbBjV
dqNQPQRqrqpPcGtchhdfhHSF
mfDzgnNMMszBtJCpHlrjnFppCdHj
LLRThGGZcbClBQpdWFGl
bSqVTbBbMVMsNmNM
BTTbbLVpfchmjbsj
JSQJHDMHqdNZTZlhFFhCFFrNhNcsrr
tMwJQlwMMlQwDDJtWGLGPpWLLGnTPn
LcVQQCPPLqTzqQTcllTzhnHHfFJRcGHcFfwRGHwJjJ
stdWDDBtVgbpWgZbsNgDNdWFGMnnwHfjHFpfwwMGMMGRjJ
ZWSDtgNdWNBdgsdsNDDsdbDlTzCVSTCqQmSqTQSvhqLVQq
dZbgdZbNtmqttFJtHHzcczMcFszHnsvH
wwpQplQQwqVVjqwPjCGCSMCMcHSHvvzHMzvcsrMc
pfjlQRpPRRLQWtmLNdWdmqqJ
CPTPPmbjmVjVGCvzbjjPrGsnnMpttdtGdncdMccDRd
lhlHzQSHwzhJLwgWgpMDMMsDdcDQMDMMns
BHZghLWwSFBJJBFvzmbfjNZvZmCvmb
PBGcvvcRwpwNcZcNPpPNcTHGdMtrCWrCCtCLWMtWgbVdMV
fmsJjnqmmfsjQJnjFzSFSqsqgWrtMttZgMWVMbbVMdbSrLtr
qQjjZFmfjZhZmwcvPhNpTNBTwN
HHlVVmmsbbqMsJmVzGSBMSrQQrRrGvvnDn
PZcphZPPZPhjcpdWgPZhRPfcDSrtDBSGNvtggrQtnvQNGNDn
dcWwFjpcPhRcCpjwdCPLzHblJbLbzmsmbTwzqH
hRfzTTfRrTGzhGWTrRrbfcQZQSttWtwddJtvdJJvWSHq
npjnDjFlpDnFFNMjljCnFMQtHHtqNHNQJwwZZqstNwJJ
DCjpLjjpVLDMDpVLDLQbbhzBhVrcVgVGQQcz
LncLBLjCSNrNrNpCLQBBBGwqQwzlzmggvqRqgllmzwtv
fMZPHhhHfthMdbRgHJzmVqlvwlwg
hfsPbZFPPDsfGLcBtSFNBSjL
MlZmszBMJBHrMBMbShwSFpbZSZfwwb
TCLCcPNGTgTPNGWtCtcWtPcSsRfRjRwjFbfpNFDjwsFspw
nVtqqsWsdHzJHqmM
RCrhSmWrmrvmrvhMvRNrRCzCJcQQbPtsMZVGJJtsZssPcQcZ
jLFBGqLFpqBLgZVbPbsLJQcbsV
HjDljGFwrRHRRTrS
GZZhnrwZBwNjRPRCbCbn
fJtJJpsVfpgNTbVNFTRP
JJcpLJfLdcWLdplwRdQMBvSqwRhvrG
wmZDPlRlCDwglgsHtsBvdBHLFLSddr
VbVMnMftfVjQWFFHdMBdBFMFHr
zfjtnGqqnjGqfjPcDPlZPlRDzccw
BRjhfhvRgnTMlFDDJfZzZFFQDZ
qLdqcNttwwcwwSPSpqLNmrwmrZsGzzDFZGZFzVssrzJGnsQG
wSNdHScScdmwHSpdNcmmtLMvChRHbvBMTBnCBBvhvlCh
JgWTPfFPgCPPlCntQSGghHvQnSdQ
BzvMZvLVQpdQpSZh
RwVVjRDVcRDNDTlJPqTv
SGHSrBBRPhPPHQcTccQTRRQjTN
vvWvspCbzWVWVrWdjj
wZpDzCDgDbCZJZzJGlrlqPqnqPllmH
FCncCrDWMLCbjMCcFpLdzZfmZzwwWzdzNRZdWB
sqsgTqHSqllNldMwlZzJ
MtHPTgQhvhhqcrDrrDpjLCQc
pPPvmPWSClqqPvqCmSwqmgGBWDjhGLHfjhDLJGjBBhNj
zrbdcdMndcRdTrsMcbTRdzRFVHjLjDjNLNHsfDhNGjhJNhDj
RdFFcnTdZcTrRRdFFbZtwQCPQglvPlwJwQPZSqqP
wlmbvwmvQvWQsvmbsSsQbswlRCNPfCTcTRVCffPtTSCPNRVP
FhJJJFgFqJGBtDpJhTTcVcVhdcCdCdTV
GDFtgLFnqqDGqGZsQvsllrjbLjbrvw
lnFSnJvmgvLlfnJpgnsjnjgfDQWqCJqZdDtDCtCtCdDrtDDQ
VTBBMPFcNNtMZDMW
VTGbzGGhTbTGHwVPvvFnfpvjgHnfjppp
JJwHqvlvDjljDwJFlZjZDwHNNsMqhNpphNpmNVzpsnsnRV
mTLgrLLcLSTTTdmPPfrrrnssNhRNWhgngzMWzgzVnM
SmTfdSBbBJbtjJvljl
bPNLwTCLLQQqtJsf
zdnnZVlWWGGRWGWdgdSStQMqJSMRptftbsMf
FWbvgvZZZZgnTmwrrhrFPCrP
HcGzzszFGllHWHbZspHbHGsHTwwrTrLLCNjSZwNjNjjCCNLj
PBJMJQJDDDnDggRhMdRSLmjTmTwwVjVQSvvwvC
RqfdhgDPDJDqJJnBdfzWWHcstslcbtStfHzl
zvRRlCqrdNdZcZpjBpVwjsmjsm
fgbTDqbhGfDnLDnLLqLhFmsHpTPHjHppppBwpwws
nhnnnDDngDtDbfSbDnGhhgRlNvQdQqNvQvtcQQNJRNJN
cZbCcbbScCbcmPGjPfSBQQSq
lnMnnVsMVvmzzGMDzPDf
LhrTsTTglrnsrrWWVvlwTnNtcpZRCmhtbCZFdttZbRCp
NWrFPZVWNVrvvrhtnNdddtpldmjm
DcBQBDsJbCwQnbtdzmjjjljbpjbz
qCDcGsDJGCcBDBcswJnBJQDfWfqgvZSvgZPfrVSWvPvZZZ
vcsdHdGtHtMHMFtVsddsWCcbppZwjScLpWhbjRWR
NTwrnzJrgTPrDwnlphRpjSpWbJJLLZWj
TlDPfPnzzlzTBzzvQFFBHMtVtqBqqw
NHnqqfZvZBNHHvgfrSlJrJCSllJRVrCn
TDTdhLMWjFcddMJPSSPJRmlCPz
bljWFdLLTDLtdFtLlwZvqfbgwwHfwqHNvw
BRRjhRQndRNVqBjRVhFLccjpwMmLmjHmgFHH
fZJfJvzPPWtWWlltZzZPpcgFMsFFwwFdpHdgwtdw
PCrdrzzfWCPdvSlqTqNSDnnQVVQQGT
DjbfBMDSfBljBsLSjSZbzrGtPtMCPtVPvvqrzqzG
mWdJWcppcNTdpppjzjRRVrPRpq
QncmnHwmdTmwQcmjNTfgfhlBShshhsffnfbB
WGDsMJsrjHCWtDMGDDVQqSvZqfSJzSnvnvvv
LgLFLFBFLVVzfBzMqZ
lgmFcwLhNcwdwwMLwhmcRDjNpCWRsWRspGGssHCp
PnPzNccnjFfvCvhbSBVcWqdhSVhV
psGMDQJDDDJgQNDHHJbwqwBsVqqZVWBBhBdd
DlDJDQGptpgpGDfTRnrTrFPnNTlf
MSSSMLLmFHcDScSq
ppZnCsbjPZpnnJcbRDmzHJqRRD
pmNmnGnQNnClZGMVMdBGrMgVWg
lsTTGcQzBcljCcQzGcGjGptttpmvSJtmggtwwswwtS
qZRnrhMbRVdhZRhhdnnVRPbmwSNwNNHtmJBvwpvtwNSvSb
VnMrqrrdqhZrnrBLLlzzlQjQjLfTcGfFDF
dJJTlHvhZqZlQTJnSgQDzgsSbScsSBzc
RRNtGjCCpRPPpRtjfrttRzmbscLsLZLgcsbmLzSGLB
wfNttfNrtWwPNNFfRtpfrdJMTTTZTMZTTVTlVwTlvM
PQTGLmdNTgPmGgNNdCPLQlrMqBrDzMCMFqDqFqjVCBCD
hhRwwvpSFmzDrmFh
vwwZfSfsmvtSspnZLLLdLGWPTGTQtTWG
pMcWzWFvWhFpPMWzvvhpdprHTZTQrHrQdZTJdfTgQTnJ
CGbjBbNjjDmRHJDgrTVVZg
NNttGlGqNLsbtlhMFMFcMLwMvvZz
CGSCBNCQBtBCQttBwCGtGtQrqrLrJqZHLHbqHvLDHLrq
nVVhPMfVdfVPbfqLLqgDDqPvgZsv
cpVncbfnhFcBltTplpmTBC
MrdcdStbMnddtRBdqMnFmbqGCwqCVHVsNHwPfGVPqsCsCs
DBLllzWWQQzlZVVVCsGWHfsH
JQphjTgBjlLgjjpTpLgvTjQnnnSJJRRFmdbRRSdMRtmdMc
QbRZMSWMblwLsgpwZzqZ
BFncBrfcdNrrnVrNjsFzFTJpJLGJsGqLTp
VjhDDBdrfdhQMllzHmPQMh
LdVVjFVFbpVGRQGllG
cNMcJNHzJWJtCWHNJHcHczWpGmmhMQmBBqrlRhBmpGpGBQ
JZzTTtCZtHCJnNnNwPfbFpnfdDdLdnvP
TpMlrWTTddjmlmDmgQgRtw
MNNVMSsVSNSnNVMFLDqwtGgRRtGbgFRwtR
CCLSCPSCZZHVCfZscBJJhPphpdpprdhjJM
gSMSHJHsMMpzRgHzsRMPPSzsPhtZtZdqdDqQDhdCdZmQldht
FCcCnrGcNTfvvtqqfvlflQ
TrTrWNWwrTJLMzJCzWLL
TpTzwMrfbrpFpMbFrrrzbPSdZmtSZRTlTZRlmdCVlCtJ
vqvWgqDJQJsQCVtZgdZdRRGd
vsvLJLchWBcqnvczwjLfzPjfrjzPrz
zqzbqCFZgmzzmNmf
vpRWSbRVbVWddVpwvwdRSwnSNgLHsnfNgMmgMLMmnrns
DwWVpJRlpdbpRDWdGJGcGlhFtPPCqCCBFqZPQttlqFBq
wQRlwtBJBDwttJdGvLfBvHLLfTLz
MMmNZcMrcMFnRHzfjjvvHfvc
FggpbFnhrNNrrMrMbMbnhQVJVhstJwqWCVCRsQJQ
DQbCGblQlpQFQlHjCbjwDQQMggNmJmgnnpRBngfZmNgJMf
zvhWccWVdWBchdssPrrWZZZfmsmmmgsnZZJRsRTf
zBdtqPccWPHFCqCCqljq
ttrbRMmgtHgfmHSfBpLfnBBZBppB
CVTJDCCNPwCPDwcqzmddQZdTQdnLBQThWp
zwFDjwDJJPzjzVNcVJwCcbRHGmbbMrFHgHvrsgbblG
gZjjwHqHCzrMZVVR
hhzcdTzPrVhVCGMb
fPcmLPNffsccJDdNDjBnpwzmHqgWjHwwvg
SJQFSvQBlzbSCgdPPddPPPSN
pcrjcWLwwcHcgPNgTPLMNTCB
pRsjsWRnrpHRmrBrHrjlbJFvvzQFnzQblQDDbJ
VjQVMQPVMfVPPbGPHHbGJD
pcqSttltsbDGddsCJG
TSchqLtTLFhgQbMMQMrr
trqzMRwNTtDzLPJQgWmjmjrf
lbBQdpZbsmhGmZhmmG
llVbpCplvvHBBHpnRDcDRRqnRRQnFRzT
SLSSFFmzLShsVSSHnLnrJdbnRdZZbrRw
qCfWBftpNWNNlqvTpwrRbGGCnwGmgRJGZn
NcTBNpvWvBWpMftNffpqWlTpmzPDQPSzFVMsFQVhHsjHszss
VtJtNBRBGDpdpNbC
QgLncnttvFcwwhLvFjSGsSbmmQCSDdpCmpdG
vLgjLhhrctMvLFFjLtMTLMgfPZqBZPZzJBBfWZZPRZZTRV
mJzDJJpJBvfsGMQnBM
CwPWCLRRWwRqwPqhPsrZrnrlhhQrMTrvZl
dCdLLSPRLSqWqVSLqLjgJDzDmtbngFVtJtzz
mtgWtMWrqjzQTTjghwwfczlNJdlcJnlc
FvRsDPPFGRBFvvslwDnTlcTTdwndlh
SGBZRBTsFGBRvLpvSCmgQWQjgggMrQjmmSmW
GcsRrQhrVVjhRcWlnDFGGmvntDWZ
TPbSgJJgBSCbCTbLHMCMTTZdFHvtZlWZDZFzmzZHZmmF
gBCMCSpbPMMPjcjqQQpqQprv
nZJcnZwvwzvTTTVtpDFnHH
DQPBqGGGdMdTRHRBpNgFNR
dCGPfhPWQdWWWCWShWPqrChWLLwLswjcvSJbvbLjJLbzJbJD
QrBQtdtrQBrdtFHPrdQBDvGhLGnPnCWnmpDmLpmD
NjlRJRlNzJJVbSSRVZwwJcmpWDGCWnbchnLCCmnWCG
llSJzsZzMMlsSZjSjZwJNQqtHHdBFsqdfTHhqFftQB
zdTJFHTdDBzrNdMnhNnNdM
ZlLZZcLtVtcWtGjtzLjLZjCrnVNrnRbrQQbQSRVrRnSNqS
lZtGtCvjZPCGCctPpsDDBzTHFmPmFszD
mQSMvdMQtQdZhQrPWCPqPQrN
RwjwnZGzJFTZgzggzJDDwJnCPPhNNqPrLhrGNcWcWNPqCq
ZTzDfnwFzTngTwJvfSlMtMMlmsHmHt
lZlmFRVZWmgQWhRsRpJsCJpJct
PTbPTGTGwwGrbdfjNNZJvcCsCZtvpTsh
bGdBBqGrdBPjDMzzVFZgqQzFFL
szvsmLvppPPtzGLGWpVdTSHTNgjHQRmHTgSH
FnBMBNZwZNcnDZMcnZlZgwgdQTTHjVJjHHVRQHJj
DnZrFCMZMNffrLPbLsfW
rJvmnBgnrCrGRSGNQR
hthjNfhwctwpjTLtVLjTGSpldSCGSPdlPSRzSqSz
TVcTfHNFcwtjMhTvgbHZsBbWmmZbnH
WsQgstQmvQJnssWsWPzhRzhBjZBSBRZSnj
qwCNqFwDrrlDrFPvRhTSPPzLRz
bppqwppCddlvfbDNVgmMmtMfVVmfmVWW

View File

@@ -0,0 +1,108 @@
;; rucksack has 2 compartments
;; items have types
;; for each type there's 1 compartment where the item must go
;; elf put exactly 1 item into wrong compartment for each rucksack
;; item type is identified by letters a .. z A .. Z case sensitive
;; first half exactly is items in first compartment, second half of chars - items in second compartment
;;; find item type that appears in both compartments for each rucksack
;; translate then item type into priority a .. z -> 1 .. 26 ; A .. Z -> 27 .. 52
;; return sum of all priorities
;;; ok. how to start solving that?
(setq test-line "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL")
;; i need to find char that appears in the first half and in the second half.
;; i could split the line in two, convert to list and use set diff function
(setq half-length (/ (length test-line) 2))
(intersection
(coerce (subseq test-line 0 half-length) 'list)
(coerce (subseq test-line half-length) 'list))
;; and now char to int,
(- (char-int #\a) (- (char-int #\a) 1))
(- (char-int #\z) (- (char-int #\a) 1))
(- (char-int #\A) (- (char-int #\A) 27))
(- (char-int #\Z) (- (char-int #\A) 27))
(lower-case-p #\z)
(lower-case-p #\A)
(defun get-char-priority (ch)
(if (lower-case-p ch) (- (char-int ch) (- (char-int #\a) 1))
(- (char-int ch) (- (char-int #\A) 27))))
(get-char-priority #\a)
(get-char-priority #\z)
(get-char-priority #\A)
(get-char-priority #\L)
(get-char-priority #\Z)
(let* ((test-line "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL")
(first-compartment (coerce (subseq test-line 0 half-length) 'list))
(second-compartment (coerce (subseq test-line half-length) 'list))
(the-misplaced-item-type (intersection first-compartment second-compartment)))
(get-char-priority (car the-misplaced-item-type))) ; in real life I'd need more defensiveness here, CAR woudn't be guaranteed
(defun get-rucksack-misplaced-item-priority (rucksack-as-string)
(let* ((test-line rucksack-as-string)
(half-length (/ (length test-line) 2))
(first-compartment (coerce (subseq test-line 0 half-length)
'list))
(second-compartment (coerce (subseq test-line half-length)
'list))
(the-misplaced-item-type (intersection first-compartment second-compartment)))
(get-char-priority (car the-misplaced-item-type)))
; in real life I'd need more defensiveness here, CAR woudn't be guaranteed
)
(get-rucksack-misplaced-item-priority "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL")
(get-rucksack-misplaced-item-priority "PmmdzqPrVvPwwTWBwg")
;; again I'm making mistakes by referring to the globally visible symbols inside of the functions. so bad.
;; maybe i'd want to use something like "make-symbol" as recommended in the part on macro?
;; now the funciton seems to work, need to iterate over input file, call it for each line and sum
(defun count-priories-in-file (filename)
(let ((running-sum 0))
(with-open-file (in filename)
(loop
for line = (read-line in nil nil)
while line
do (incf running-sum
(get-rucksack-misplaced-item-priority line))
finally (return running-sum)))))
(count-priories-in-file "day3-input.txt")
(count-priories-in-file "day3-test-input.txt")
;;; so, now different task for same input:
;; considering lines in groups of 3, what is their common char (group identification badge)
;; then map to priorities and sum
;; that should be a very similar program.
;; but how can i configure loop to give me 3 lines at a time?
(defun get-three-rucksacks-id-badge (r1 r2 r3)
(let* ((r1 (coerce r1 'list))
(r2 (coerce r2 'list))
(r3 (coerce r3 'list))
(badge-type-char (intersection (intersection r1 r2) r3)))
(get-char-priority (car badge-type-char)))
; in real life I'd need more defensiveness here, CAR woudn't be guaranteed
)
(get-three-rucksacks-id-badge "vJrwpWtwJgWrhcsFMMfFFhFp" "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL" "PmmdzqPrVvPwwTWBwg")
(defun count-id-badges-in-file (filename)
(let ((running-sum 0))
(with-open-file (in filename)
(loop
for line1 = (read-line in nil nil)
for line2 = (read-line in nil nil)
for line3 = (read-line in nil nil)
while line1
do (incf running-sum
(get-three-rucksacks-id-badge line1 line2 line3))
finally (return running-sum)))))
(count-id-badges-in-file "day3-test-input.txt")
(count-id-badges-in-file "day3-input.txt")
;; surely there's a better way to use loop?
;; or maybe a good introduction into how to use it?
;; the documentation site doesn't give examples =C

6
day3-test-input.txt Normal file
View File

@@ -0,0 +1,6 @@
vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw

71
day4-id-intervals.lisp Normal file
View File

@@ -0,0 +1,71 @@
;;; https://adventofcode.com/2022/day/4
;; so, just read two intervals.
;; intervals , separated, two numbers - separated.
;; so. ugh. have a parsing function. maybe ask how to better parse
;; then to calculate "total inclusion" - can go both ways, so 4 checks
(setq test-line "2-4,6-8")
(setq test-line "2-8,3-7")
(require 'cl-ppcre)
;; (cl-ppcre:split "(\\ )" line :with-registers-p nil)
(setq intervals (mapcar #'parse-integer (cl-ppcre:split "(,|-)" test-line)))
(defun line-to-nums (line)
(mapcar #'parse-integer (cl-ppcre:split "(,|-)" line)))
(defun first-includes-second (l1 r1 l2 r2)
(and (<= l1 l2) (>= r1 r2)))
(first-includes-second 2 8 3 7)
(first-includes-second 3 8 3 7)
(first-includes-second 4 8 3 7)
(defun first-or-last-includes-another (l1 r1 l2 r2)
(or (first-includes-second l1 r1 l2 r2)
(first-includes-second l2 r2 l1 r1)))
(with-open-file (in-file "day4-test-input.txt")
(let ((running-count 0))
(loop
for line = (read-line in-file nil nil)
while line
do (if (apply #'first-or-last-includes-another (line-to-nums line))
(incf running-count 1))
finally (return running-count))))
(defun count-full-interlaps (filename)
(with-open-file (in-file filename)
(let ((running-count 0))
(loop
for line = (read-line in-file nil nil)
while line
do (if (apply #'first-or-last-includes-another (line-to-nums line))
(incf running-count 1))
finally (return running-count)))))
(count-full-interlaps "day4-test-input.txt")
(count-full-interlaps "day4-input.txt")
;; next part - count intervals that "overlap at all", even if by single point
;; could count 'not overlapping' - should be very easy
;; and count total, and deduct
(defun count-any-overlap (filename)
(with-open-file (in-file filename)
(let ((running-count-non-overlap 0)
(total-count 0))
(loop
for line = (read-line in-file nil nil)
while line
do (let ((nums (line-to-nums line)))
(if (or (< (second nums) (third nums))
(< (fourth nums) (first nums)))
(incf running-count-non-overlap 1))
(incf total-count 1)
)
finally (return (- total-count running-count-non-overlap))))))
(count-any-overlap "day4-test-input.txt")
(count-any-overlap "day4-input.txt")

1000
day4-input.txt Normal file

File diff suppressed because it is too large Load Diff

6
day4-test-input.txt Normal file
View File

@@ -0,0 +1,6 @@
2-4,6-8
2-3,4-5
5-7,7-9
2-8,3-7
6-6,4-6
2-6,4-8

501
day5-input.txt Normal file
View File

@@ -0,0 +1,501 @@
move 4 from 9 to 6
move 7 from 2 to 5
move 3 from 5 to 2
move 2 from 2 to 1
move 2 from 8 to 4
move 1 from 6 to 9
move 1 from 9 to 4
move 7 from 1 to 2
move 5 from 2 to 3
move 5 from 7 to 4
move 5 from 6 to 3
move 1 from 7 to 6
move 2 from 6 to 9
move 3 from 2 to 4
move 4 from 5 to 6
move 2 from 7 to 3
move 2 from 9 to 3
move 1 from 5 to 2
move 11 from 4 to 3
move 1 from 2 to 9
move 1 from 9 to 3
move 2 from 1 to 6
move 5 from 8 to 5
move 7 from 5 to 4
move 2 from 5 to 6
move 6 from 6 to 4
move 17 from 3 to 4
move 1 from 8 to 3
move 11 from 4 to 7
move 1 from 6 to 4
move 3 from 4 to 2
move 2 from 2 to 6
move 8 from 3 to 1
move 8 from 3 to 9
move 3 from 9 to 6
move 3 from 1 to 3
move 11 from 7 to 5
move 1 from 6 to 4
move 4 from 9 to 6
move 3 from 1 to 4
move 1 from 2 to 3
move 1 from 6 to 9
move 24 from 4 to 9
move 2 from 6 to 5
move 1 from 1 to 2
move 1 from 1 to 3
move 12 from 9 to 6
move 5 from 4 to 2
move 4 from 2 to 3
move 5 from 6 to 3
move 13 from 6 to 7
move 1 from 5 to 6
move 9 from 5 to 3
move 4 from 7 to 5
move 1 from 6 to 1
move 3 from 5 to 1
move 14 from 9 to 4
move 2 from 7 to 9
move 13 from 4 to 9
move 1 from 4 to 7
move 4 from 7 to 9
move 3 from 5 to 1
move 8 from 3 to 9
move 4 from 1 to 4
move 8 from 3 to 7
move 3 from 7 to 6
move 4 from 4 to 2
move 3 from 1 to 9
move 6 from 2 to 6
move 3 from 3 to 1
move 7 from 9 to 7
move 2 from 6 to 5
move 1 from 5 to 3
move 3 from 7 to 5
move 5 from 7 to 4
move 2 from 1 to 4
move 5 from 5 to 9
move 6 from 4 to 1
move 6 from 7 to 8
move 22 from 9 to 3
move 7 from 1 to 8
move 4 from 9 to 6
move 1 from 4 to 5
move 8 from 6 to 4
move 7 from 8 to 1
move 1 from 6 to 4
move 1 from 9 to 4
move 1 from 1 to 2
move 1 from 2 to 5
move 1 from 9 to 8
move 11 from 3 to 7
move 1 from 6 to 2
move 2 from 1 to 5
move 1 from 8 to 2
move 1 from 7 to 8
move 4 from 5 to 7
move 1 from 6 to 9
move 6 from 3 to 1
move 6 from 3 to 1
move 15 from 7 to 5
move 1 from 3 to 1
move 1 from 3 to 6
move 1 from 6 to 8
move 14 from 5 to 1
move 16 from 1 to 3
move 2 from 8 to 9
move 1 from 7 to 4
move 3 from 9 to 8
move 3 from 8 to 7
move 2 from 3 to 5
move 1 from 7 to 1
move 6 from 8 to 5
move 2 from 2 to 9
move 1 from 7 to 2
move 2 from 9 to 2
move 5 from 4 to 7
move 3 from 2 to 7
move 14 from 1 to 5
move 2 from 4 to 7
move 8 from 7 to 6
move 1 from 1 to 5
move 1 from 7 to 4
move 1 from 7 to 5
move 1 from 1 to 8
move 12 from 3 to 4
move 1 from 8 to 7
move 3 from 4 to 1
move 1 from 6 to 2
move 8 from 5 to 2
move 1 from 7 to 6
move 1 from 1 to 7
move 6 from 6 to 2
move 1 from 1 to 2
move 14 from 5 to 7
move 1 from 6 to 4
move 4 from 4 to 7
move 1 from 1 to 6
move 1 from 5 to 6
move 2 from 3 to 1
move 14 from 7 to 5
move 10 from 4 to 7
move 1 from 1 to 9
move 1 from 5 to 9
move 11 from 5 to 1
move 6 from 7 to 6
move 1 from 4 to 6
move 1 from 3 to 7
move 2 from 1 to 5
move 13 from 2 to 1
move 10 from 6 to 7
move 4 from 5 to 2
move 1 from 9 to 1
move 1 from 3 to 6
move 2 from 5 to 2
move 1 from 9 to 3
move 1 from 3 to 1
move 21 from 7 to 5
move 1 from 6 to 4
move 4 from 5 to 1
move 1 from 4 to 1
move 6 from 2 to 3
move 1 from 3 to 6
move 1 from 3 to 8
move 1 from 8 to 7
move 1 from 7 to 3
move 9 from 5 to 3
move 24 from 1 to 4
move 1 from 3 to 7
move 11 from 3 to 8
move 1 from 7 to 3
move 1 from 2 to 4
move 2 from 2 to 1
move 2 from 3 to 5
move 1 from 6 to 5
move 10 from 4 to 6
move 2 from 6 to 4
move 5 from 1 to 2
move 1 from 6 to 7
move 8 from 8 to 6
move 4 from 2 to 7
move 8 from 6 to 7
move 1 from 2 to 8
move 1 from 8 to 3
move 1 from 7 to 4
move 3 from 4 to 1
move 2 from 6 to 7
move 4 from 1 to 9
move 3 from 6 to 7
move 10 from 7 to 4
move 2 from 3 to 9
move 2 from 6 to 9
move 2 from 1 to 8
move 2 from 9 to 5
move 4 from 5 to 6
move 3 from 8 to 1
move 4 from 4 to 8
move 5 from 8 to 4
move 1 from 8 to 2
move 5 from 5 to 9
move 1 from 6 to 1
move 2 from 1 to 7
move 22 from 4 to 8
move 4 from 8 to 7
move 2 from 6 to 7
move 1 from 2 to 6
move 16 from 8 to 9
move 3 from 7 to 4
move 1 from 5 to 9
move 2 from 6 to 7
move 1 from 8 to 2
move 1 from 2 to 3
move 24 from 9 to 3
move 1 from 1 to 7
move 3 from 5 to 1
move 4 from 4 to 6
move 15 from 3 to 6
move 18 from 6 to 2
move 3 from 3 to 2
move 4 from 1 to 6
move 4 from 7 to 3
move 1 from 3 to 9
move 4 from 2 to 1
move 1 from 8 to 7
move 3 from 9 to 6
move 1 from 9 to 3
move 4 from 7 to 3
move 2 from 4 to 2
move 1 from 1 to 2
move 7 from 3 to 5
move 8 from 6 to 1
move 1 from 9 to 2
move 3 from 7 to 5
move 1 from 4 to 8
move 3 from 1 to 7
move 5 from 7 to 6
move 3 from 5 to 2
move 3 from 7 to 3
move 5 from 5 to 9
move 5 from 3 to 6
move 1 from 8 to 3
move 5 from 9 to 7
move 7 from 2 to 4
move 11 from 2 to 7
move 7 from 1 to 6
move 1 from 1 to 9
move 5 from 3 to 6
move 5 from 2 to 1
move 1 from 3 to 9
move 1 from 3 to 7
move 6 from 6 to 2
move 10 from 6 to 7
move 5 from 6 to 7
move 28 from 7 to 8
move 2 from 9 to 1
move 1 from 6 to 3
move 4 from 7 to 5
move 1 from 3 to 6
move 7 from 2 to 7
move 6 from 7 to 3
move 1 from 5 to 9
move 1 from 6 to 2
move 1 from 7 to 3
move 1 from 9 to 1
move 4 from 5 to 2
move 5 from 3 to 5
move 2 from 2 to 8
move 4 from 4 to 7
move 1 from 4 to 7
move 2 from 3 to 6
move 5 from 7 to 1
move 2 from 5 to 8
move 2 from 5 to 8
move 2 from 5 to 3
move 2 from 3 to 1
move 2 from 6 to 7
move 31 from 8 to 3
move 2 from 8 to 5
move 2 from 7 to 4
move 7 from 1 to 4
move 2 from 5 to 1
move 3 from 2 to 8
move 2 from 4 to 6
move 3 from 1 to 2
move 6 from 4 to 8
move 1 from 1 to 8
move 1 from 6 to 5
move 11 from 8 to 9
move 1 from 6 to 8
move 1 from 4 to 1
move 1 from 8 to 7
move 1 from 5 to 8
move 3 from 2 to 1
move 2 from 4 to 3
move 1 from 8 to 1
move 7 from 3 to 6
move 12 from 3 to 2
move 1 from 7 to 9
move 4 from 6 to 1
move 1 from 6 to 3
move 12 from 9 to 3
move 1 from 6 to 4
move 1 from 1 to 7
move 1 from 4 to 1
move 1 from 7 to 2
move 1 from 6 to 5
move 1 from 5 to 6
move 5 from 3 to 1
move 1 from 6 to 4
move 7 from 2 to 1
move 3 from 2 to 6
move 1 from 4 to 5
move 3 from 3 to 2
move 4 from 2 to 8
move 1 from 6 to 4
move 1 from 4 to 9
move 1 from 5 to 1
move 11 from 1 to 5
move 10 from 1 to 8
move 2 from 6 to 4
move 1 from 2 to 9
move 1 from 2 to 4
move 18 from 3 to 5
move 4 from 1 to 4
move 3 from 1 to 2
move 14 from 8 to 5
move 2 from 2 to 6
move 1 from 3 to 2
move 2 from 2 to 7
move 3 from 4 to 1
move 2 from 4 to 3
move 2 from 3 to 4
move 2 from 6 to 9
move 1 from 7 to 1
move 3 from 1 to 4
move 4 from 9 to 7
move 31 from 5 to 2
move 25 from 2 to 4
move 13 from 4 to 2
move 10 from 2 to 3
move 2 from 5 to 7
move 5 from 2 to 9
move 7 from 5 to 7
move 5 from 7 to 4
move 1 from 5 to 8
move 2 from 7 to 3
move 11 from 4 to 8
move 1 from 7 to 3
move 1 from 1 to 4
move 2 from 5 to 3
move 3 from 2 to 9
move 8 from 9 to 6
move 10 from 8 to 2
move 5 from 3 to 2
move 1 from 7 to 3
move 3 from 7 to 3
move 15 from 2 to 1
move 11 from 1 to 3
move 1 from 8 to 2
move 8 from 6 to 5
move 1 from 2 to 6
move 1 from 6 to 1
move 12 from 3 to 7
move 1 from 2 to 9
move 2 from 4 to 1
move 3 from 1 to 8
move 1 from 8 to 7
move 3 from 3 to 4
move 1 from 4 to 7
move 15 from 7 to 9
move 1 from 7 to 5
move 4 from 1 to 8
move 6 from 8 to 6
move 1 from 6 to 2
move 5 from 5 to 1
move 2 from 6 to 8
move 1 from 2 to 7
move 1 from 8 to 2
move 1 from 7 to 1
move 1 from 5 to 8
move 6 from 3 to 1
move 4 from 3 to 8
move 7 from 8 to 5
move 1 from 2 to 4
move 2 from 4 to 2
move 3 from 6 to 4
move 5 from 9 to 3
move 4 from 1 to 4
move 10 from 5 to 9
move 8 from 1 to 7
move 1 from 2 to 1
move 1 from 1 to 9
move 20 from 9 to 2
move 12 from 2 to 3
move 17 from 4 to 3
move 6 from 7 to 2
move 5 from 3 to 8
move 20 from 3 to 5
move 2 from 9 to 4
move 3 from 3 to 1
move 1 from 7 to 1
move 6 from 3 to 6
move 4 from 2 to 3
move 4 from 5 to 3
move 1 from 1 to 9
move 6 from 6 to 1
move 3 from 8 to 4
move 1 from 9 to 8
move 2 from 2 to 1
move 3 from 3 to 2
move 1 from 3 to 6
move 1 from 7 to 4
move 3 from 3 to 6
move 6 from 1 to 5
move 9 from 2 to 4
move 3 from 2 to 5
move 2 from 6 to 5
move 16 from 4 to 8
move 18 from 8 to 6
move 1 from 4 to 5
move 2 from 6 to 7
move 4 from 1 to 7
move 22 from 5 to 6
move 1 from 4 to 9
move 4 from 7 to 6
move 11 from 6 to 5
move 9 from 5 to 2
move 2 from 2 to 3
move 2 from 7 to 2
move 1 from 1 to 7
move 9 from 6 to 2
move 1 from 5 to 1
move 1 from 8 to 9
move 18 from 6 to 8
move 1 from 7 to 4
move 4 from 5 to 1
move 2 from 5 to 2
move 2 from 2 to 5
move 1 from 9 to 5
move 1 from 5 to 9
move 1 from 9 to 1
move 1 from 9 to 2
move 1 from 4 to 8
move 4 from 1 to 4
move 2 from 6 to 5
move 1 from 1 to 9
move 3 from 6 to 7
move 1 from 6 to 9
move 1 from 9 to 8
move 2 from 5 to 9
move 3 from 3 to 5
move 7 from 2 to 3
move 1 from 1 to 3
move 2 from 5 to 9
move 1 from 5 to 7
move 10 from 8 to 3
move 10 from 8 to 9
move 3 from 4 to 3
move 9 from 2 to 1
move 4 from 9 to 6
move 5 from 1 to 9
move 2 from 5 to 9
move 1 from 6 to 4
move 4 from 7 to 2
move 7 from 2 to 9
move 3 from 6 to 8
move 1 from 1 to 3
move 2 from 8 to 5
move 1 from 8 to 1
move 18 from 3 to 6
move 15 from 9 to 2
move 8 from 9 to 1
move 2 from 9 to 2
move 2 from 4 to 9
move 2 from 9 to 7
move 12 from 6 to 3
move 7 from 1 to 7
move 12 from 2 to 5
move 7 from 3 to 2
move 4 from 3 to 4
move 2 from 7 to 6
move 7 from 7 to 8
move 1 from 4 to 2
move 4 from 1 to 8
move 5 from 3 to 1
move 9 from 8 to 3
move 1 from 8 to 7
move 2 from 1 to 2
move 4 from 6 to 7
move 11 from 2 to 5
move 2 from 4 to 6
move 1 from 8 to 2
move 7 from 3 to 2
move 1 from 2 to 4
move 4 from 6 to 1
move 7 from 5 to 8
move 2 from 3 to 1
move 7 from 2 to 3
move 6 from 5 to 1
move 1 from 4 to 2
move 8 from 1 to 6
move 3 from 2 to 9

4
day5-test-input.txt Normal file
View File

@@ -0,0 +1,4 @@
move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2

210
day5.lisp Normal file
View File

@@ -0,0 +1,210 @@
;;; wow, now this is complicated.
;; first read in until the empty line
;; and somehow construct internal representation
;; i want Stack data structure. cool. where is that?
;; use list with PUSH and REMOVE ?
(defparameter *some-stack* (list 1 2 3))
(push 1 *some-stack*)
(pop *some-stack*)
*some-stack*
;; well, yea. list is a stack. ok
;; so I need to have addressable from 1 to n
;; lists
;; and after i read them - reverse
;; i guess i could read in the string. and calculate index of the list
(defparameter *test-string-0* " [D]")
(defparameter *test-string* "[Z] [M] [P]")
;; [Z] [M] [P]
;; 1 2 3
;; 01234567890
;; so. first letter is at 1 (after 0) and next letter is at i+4
;; let's write function that translates that string into '((1 Z) (2 M) (3 P))
;; and would translate *test-string* into '((2 D))
;; i guess i could just iterate by i+4 from i=1 until the end of the string, and that's it
(defun parse-crate-string (str)
(do
((str-index 1 (+ 4 str-index))
(index 1 (1+ index))
(accum (list)))
((> str-index (1- (length str))) accum)
(let ((box-label (aref str str-index)))
(if (not (eq box-label #\ ))
(setq accum (push (list index (aref str str-index)) accum))))))
(defparameter *test-line-parsed* (parse-crate-string *test-string*))
(do
( (index 1 (+ 4 index)))
((> index 15) "hello")
(format t "lala ~D~%" index)
)
(do ((temp-one 1 (1+ temp-one))
(temp-two 0 (1- temp-two)))
((> (- temp-one temp-two) 5) temp-one))
(aref "hello-world" 1)
(aref " hello-world" 0)
(aref "hello-world" 11)
(length "hello-world")
;;; now. for each string I want to take index, take list on that index and put the label on top
;; now, i want "common lisp MAP", and ideally with default
(defparameter *test-table* (make-hash-table))
(gethash 1 *test-table*)
(setf (gethash 2 *test-table*) "hello")
(gethash 2 *test-table*)
(gethash 3 *test-table* (list)) ; so anyway by default it returns NIL
*test-line-parsed*
(mapcar (lambda (box-descr)
(let* ((index (first box-descr))
(label (second box-descr))
(cur-list (gethash index *test-table*)))
(setf (gethash index *test-table*) (push label cur-list))))
*test-line-parsed*)
*test-table*
(defun apply-parsed-line-to-lists (parsed-line table)
(mapcar (lambda (box-descr)
(let* ((index (first box-descr))
(label (second box-descr))
(cur-list (gethash index table)))
(setf (gethash index table) (push label cur-list))))
parsed-line))
(apply-parsed-line-to-lists *test-line-parsed* *test-table*)
(defparameter *full-test-boxes* " [D]
[N] [C]
[Z] [M] [P] ")
(require 'cl-ppcre)
(cl-ppcre:split (cl-ppcre:create-scanner :end-anchor) *full-test-boxes*)
(cl-ppcre:split (cl-ppcre:create-scanner "\n") *full-test-boxes*)
;; all of this didn't fucking work. can't split the line by the newline, what a joke
;;; god. i'm ready to create these lists manually.
;;; ugh.
(defparameter *all-test-boxes-lines* (list
" [D]"
"[N] [C]"
"[Z] [M] [P]"))
(defparameter *all-input-boxes-lines* (list
" [C] [N] [R]"
"[J] [T] [H] [P] [L]"
"[F] [S] [T] [B] [M] [D]"
"[C] [L] [J] [Z] [S] [L] [B]"
"[N] [Q] [G] [J] [J] [F] [F] [R]"
"[D] [V] [B] [L] [B] [Q] [D] [M] [T]"
"[B] [Z] [Z] [T] [V] [S] [V] [S] [D]"
"[W] [P] [P] [D] [G] [P] [B] [P] [V]"))
(defun get-boxes-lists-hashtable (boxes-lines)
(let ((hash-table (make-hash-table))
(parsed-lines (mapcar #'parse-crate-string boxes-lines)))
(mapcar (lambda (parsed-line) (apply-parsed-line-to-lists parsed-line hash-table)) parsed-lines)
(maphash (lambda (key list) (setf (gethash key hash-table) (reverse list))) hash-table)
hash-table))
(defparameter *test-boxes* (get-boxes-lists-hashtable *all-test-boxes-lines*))
(gethash 2 (get-boxes-lists-hashtable *all-test-boxes-lines*))
;; yay. ok. good enough.
;; now i need a function that would modify that hash table for each line
;; "move 1 from 2 to 1"
;; if i just to intern, would i get numbers?
(cddr (mapcar #'intern (cl-ppcre:split " " "move 1 from 2 to 1")))
;; nope that would be a symbol
;; allright, let's just emit list of numbers
(let ((string "move 1 from 2 to 3"))
(do*
((words (cl-ppcre:split " " string) (cddr words))
(number (parse-integer (second words)) (parse-integer (second words)))
(nums (list number) (push number nums)))
((not (cddr words)) (reverse nums))))
(defun command-string-to-indices (str)
(do*
((words (cl-ppcre:split " " str) (cddr words))
(number (parse-integer (second words)) (parse-integer (second words)))
(nums (list number) (push number nums)))
((not (cddr words)) (reverse nums))))
(command-string-to-indices "move 1 from 2 to 1")
(defun run-command (hashtable amount from to)
(loop
for i from 1 to amount
do (push (pop (gethash from hashtable)) (gethash to hashtable))))
(run-command *test-boxes* 3 2 1)
(gethash 2 *test-boxes*)
(gethash 1 *test-boxes*)
(with-open-file (in "day5-test-input.txt")
(loop
for line = (read-line in nil nil)
while line
do (apply #'run-command (cons *test-boxes* (command-string-to-indices line)))))
;; https://riptutorial.com/common-lisp/example/4463/looping-over-hash-tables
(print (coerce (loop
for v from 1 to 3
collect (first (gethash v *test-boxes*))) 'string))
(defparameter *day-5-boxes* (get-boxes-lists-hashtable *all-input-boxes-lines*))
(gethash 1 *day-5-boxes*)
(with-open-file (in "day5-input.txt")
(loop
for line = (read-line in nil nil)
while line
do (apply #'run-command (cons *day-5-boxes* (command-string-to-indices line)))))
;; printing things as a string
(print (coerce (loop
for v from 1 to (hash-table-count *day-5-boxes*)
collect (first (gethash v *day-5-boxes*))) 'string))
(getf :count *day-5-boxes*)
(hash-table-count *day-5-boxes*)
;; oh, wow. now i need to implement moving "with retaining order".
;; cool
(defun run-command-9001 (hashtable amount from to)
(let ((moving-part (subseq (gethash from hashtable) 0 amount))
(remaining-part (subseq (gethash from hashtable) amount)))
(setf (gethash from hashtable) remaining-part)
(setf (gethash to hashtable) (concatenate 'list moving-part (gethash to hashtable)))))
;; so, taking is subseq, but wound need to drop these elements
;; but how to prepend list to another list? concat?
(concatenate 'list (list 1 2 3) (list 5 6 7))
(subseq (list 1 2 3 4 5) 0 2) ; so "until end"
(subseq (list 1 2 3 4 5) 2)
;; nullify hash with boxes before running
(with-open-file (in "day5-test-input.txt")
(loop
for line = (read-line in nil nil)
while line
do (apply #'run-command-9001 (cons *test-boxes* (command-string-to-indices line)))))
(with-open-file (in "day5-input.txt")
(loop
for line = (read-line in nil nil)
while line
do (apply #'run-command-9001 (cons *day-5-boxes* (command-string-to-indices line)))))

1
day6-input.txt Normal file
View File

@@ -0,0 +1 @@
llqnqffqsqttfffbcfcbcbdcczccfssvwswrwddzlddpdhdwwlvlffjllnjjwjqwjjttwbwcwfccdmmnddgvvpwvvgsshnshsgglljfjzjpjfpfjpplddjcchdhvhlhvllvflfbllsdllgppwjjprjpjrrdwrdrggjvjppgbgttdppwhhcshsvvgpvggsllstsggdjdmjjrvjjszjsjbbsffjwjnwwzjjjvqvfftbffbpffndfdzfdfvdfdggmpmbbwgbgnnbtnnnhggdmdffrqrlrhrzzrmzzmbzzcdcwwzffsrrnfnvfnnvppwjjndjnndtdppgcppsmppljlpjjmlldlsltlglwgwcwnwvwddzrrllwjjnvjvwvppjssncnfcnfcfcczfccpjphjphjjjsgszzhthghjhrjrbrtrjrhrsrfftfzftfmmwmpmgghbggjrrsdswddtjjvnnrwrzrpzzlglwggrnrgrfftnffwwgllrqqzbqbbtltbbgdgpgphggspggplggmcmscsffzcfzzbggdrgrqgrrnlrnrbnnzsnnzcctvvnvwvnwnhhwpwtptllpflfcfttwtjjhwjhhbwhbbtppwhwvhvghvhphpwwcgwwhbbfvbffzpzlllrzlrrbnnrngrnrpnnsszbbqffpsffhfshfhzzqhhcgcgfggzmmdllthhrhnrrwggdqdsstccqllflmflfddjwjzjffvjjfgjgdgbdgdngnpgpnpffsnsjnnbbjdbjbtbmmbrrlbbqmqpqrprjjrbbvnbbzvvcwwlfwfggmhhdhsdhsdhshhqfhfrhhqlqttffpmmjzjqjggqzzdfzflfsllshhvjvfvbfvbbjljhhzrzqqszqzsqqswswbsbzszgzdgzzhjzhhvffhthvtthltthghzhvvjttczttlssvvgjjmsjstjjrfjjhbjbnjbjddqrddnbdnbnwbnbqbmqqgtgqtttcmmqbqrrgrrsrszssvpsvvjqjttjpjwwmwfwttczttgccwhcwwrzwzbwwqbqmqnmqqnfnmmmzdmzmpmssdpsslbbmgmbmlmnlldlccvzzlrzzqbqfqlflwlvlhhtrtcttgnnqhnqqtjjphjhwjhwhpwwvdvfddmndncnppcffhllfvfdfllhgslvtsqhtlfdflcjfmqbnctnfnwqrlqbzrcbvldrffcptsgslqcszqcfdvtpggvdqblwcgmdjqrpjdhtrmvrfrzznspqlfhnjsppbpjdggcwjwprpnlnntgfgmflctqphdmzfvpzzmbzmvrqdgchzmdvjdzmfsslpqvhpgznmpspjpdmlfwwjbbwqbfthghclldpmnsbcwlzswrsnfzbdzpcnrrpspdpfqhvmtfjlppqtphvzzqrwhzccnrgrtgfbfgtwvlwsmcvzmqmhsvztmmvpjzfwzgfwntbrsfthdgrcmgtdsvzcllmcshrlqldrvrnmdgbwttmhczvscrdvfgdvrhfvlghhsfbmrptbwmpnvtsrjlpjlbmmjzwwzbdtjlqqdczqgpzfjslccrcrblhplndblghchczbjjfzlsvvrqhvgdsncgpjhjlprhfhswwbmrnszqzhhlrbqpphvgtfsgmdpjwgcmqnvfdhrqmbspjpdrtdbqnbmbpgqwgmltqwrjprvsfjsmpldcqqbvmfhgzltzfvhlnfdqrphzzjrbdvnnjspvnlnnsdzvgqsqztndjpmnbqtwnpzmmfhsswwnnwwlbnpgbrhzchbnsrwwpprhntngsjzvssttqwfvjrdddtfpgtqqzcwljzmdjtgzdqjjvbqgdttdgvqvlfdsgcjhsmdmwrwdcqdflpfjbfzsvjrzrhhcnvcjblwcdvtbgfhfgcwrcjsrzcdrfwtvdqrghdtrjgdmhrfcsnwwwdpvjtpzdqfgrlmrqscjbfgdbgvflhvdjmnmslvsbcbgwplgqljmlzpgrfjwmvqfwmwrhnmdjhdwgjrngvccrbzmhcqthvvtdtmfqvfczhqbfgzgrmdtprznfzjtrcwqgztchtdmzmnwbfbnbttbvzsflcpsjshgphfdlvhdrcpsqnhjjggbnsqrfpwsdznzcwjbcswwndzbpdnfcbdrfgrmqzvtjttltbntznmqfsmqlgqvlqnrvgrnggslqhbplmgpzwlfzbvwdvrchsnhrnvgmzjdprvvspltcdzmdnlgtmrwnwpdndpdqjltcnmsggrvbprslqhfgmzqtppdpsjcmmbvfgmbpdnwdcgnssfgjhzhrjljdwhrzznscndgbscdmbbtbrnzbqzvcjgjgljbjlrrvdhjdllsnjzhwlmjslghrqplwjwssbzzpdzdfhhsqctlcddnfnnvbcwpdvzdcsgcqpctsjtdtnzpggpzsrrhfjtthqcqhtvwzltbdvdnbgwlppblwzjsqqbcpcrthhrhdnzhdnflqlvbzmcjfcrbmgdgqptfqfbmlfbblqdfmnwgvbdhmcmtmvtggqstjpwhvzjhbgpblmdrnggvrvphbglqgfcphmrgfmrwcdchtwfllqwsnbqttwdcvrwgzjfztmcffppqtmnwpgcrgwtjbdtjlmnpmvlzndljglzblwdrggqvbbfvqcbcbpqttrmqlcqnqvrfqsnlpmwlcgfwfcqpgmszfccbqtcqfwlwqrjjhrdbjqvdmfzjgncjqgqbthpgjgbfdvltbhpnbjqqwrsczrthfhmlzjjjgsjtsvgmwfsjngzfqdqzfhvwjrswvnqvsvvsjdbwlwdcsszdngmmhnnqsgvsrvpnndghrwgzztqczvhcrzdpqtrmrnfsfrlpdnbbtshfhplzqvdvzdvwhwsbpnbzlvcbgptdszjlcgfdzchjcsvhzdljvgpwstzwnssvhztcptnhslggnrschvfnmhcnjvldthtfpqzdvltfgnmtgvlrljhwqdzqfmfblstvfnpfcdsqslrqbztrbfzmsfjtjwhlzfnhrvpfqfqvtdllrvchmqphgljwcspgpwsdwqfdhsqhsflpbcbjjmjrfjrqrqfqcqzqsqcnqhfgsclfnfzblfdhphrvqdpvcqmllrcdnrlwqbrgqsbfqqllcvmglntjwcsjljgntmmldscndfdjcqpwbqpbmfjsgwfwcqbqbbhhgprlbzmvdfjcsmsqvhfhmgrhnwpslztmwbhdgrfzfcmwjswpbpzwstfbfmgwtprmptzjwtrqthrqwgslnmtlfgnvgpwvsfwthtrgwfbnnnwmdcfrpqqztplscvfnfpfwwdnfnzjccnhswwlcrrdqfhvsrnvcdrwmjswzggscplggbwgndsbntqvtrjbmbzrnbbmdjvwrmmtrmfjjhnvrcjcbqlhlthbvtjjczddblbbttmmzgdqmtdqswjdwbjhsrjbvdtqzqdbhhgbttgmgwfgfpczpqpfsddgslltwsvngwbwfbfcdzlqghwdbfzzldjpwpmpjmslwnwbrjjvwcsjgdzjwrrwnvgvrqlgjhwvrgnczspfplhfbtdpbpfqmhbvmcqdgrrjfslzgsqfpwrrrmjdtgbslddwvddrbmrdsdhhnlwsncrmnglrrpvtbrfvjbdmcpgphcdfwnfcglvmlbslttpmjnspqhnmbcqgmncfjjpdfjqhggnswbgppjhllscrvtmtmmbwbpgddtzblscntrmccdpzdnllqpvfdpfpwwvnnbjlzphvqwffwsjmbtllctrjmllwscmldcdrpfrzrqlpwbjwfgmnshzqzgdjqhcwtsqlsjffvzcpnrzmvtlzlgwvrrjtdbcnddbhjgqqzrvhplrbsrwgscjnfmhbcnpdcjqrltgdzzzzbqtsspbcdssbjrzfqdgvhmgdzsjdsqcfwbgrnhrlzgpjmhctqdccmvqzddmcptsjgtfshprqmslvtmtrprfsngrnnpnrccrvnrvcwzrbbnbghlwvcncgzglnqthchhsnzlfrcggdptvwlrbnfwgjpflgrcfzhhgffwcbhwlsdmvmsvvzvdcrlvlnstgz

97
day6.lisp Normal file
View File

@@ -0,0 +1,97 @@
(defparameter *test-input-1* "mjqjpqmgbljsphdztnvjfqwrcgsmlb")
(defparameter *test-input-2* "bvwbjplbgvbhsrlpgdmjqwftvncz")
(defparameter *test-input-3* "nppdvjthqldpwncqszvftbrmjlhg")
(defparameter *test-input-4* "nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg")
(defparameter *test-input-5* "zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw")
(defun all-char-different-p (str)
)
;; (set-difference (list 1 2 3 1 1) (list 3))
(ql:quickload "fset")
(defparameter *test-set* (fset:empty-set))
(fset:with *test-set* 4)
(fset:set 'a 'ab 'c)
(fset:set '(a b c ))
(apply #'fset:set '(a b c))
(eval (macroexpand `(fset:set ,@'(1 2 3))))
(fset:size (coerce "hello" 'list))
(subseq (coerce *test-input-1* 'list) 0 4)
(let
((str *test-input-5*))
(do*
((line (coerce str 'list) (cdr line))
(checked-suf (subseq line 0 4) (subseq line 0 4))
(suf-set (eval (macroexpand `(fset:set ,@(coerce checked-suf 'list)))) (eval (macroexpand `(fset:set ,@(coerce checked-suf 'list)))))
(ind 4 (1+ ind)))
((= 4 (fset:size suf-set)) ind)
(format t "another step with ~A~%" checked-suf)))
(subseq '(a b c d s e t d) 0 5)
(defun get-index-after-first-quad-unique (str)
(do*
((line (coerce str 'list)
(cdr line))
(checked-suf (subseq line 0 4)
(subseq line 0 4))
(suf-set (eval (macroexpand `(fset:set ,@(coerce checked-suf 'list))))
(eval (macroexpand `(fset:set ,@(coerce checked-suf 'list)))))
(ind 4 (1+ ind)))
((= 4 (fset:size suf-set))
ind)))
(with-open-file (in "day6-input.txt")
(let ((line (read-line in)))
(get-index-after-first-quad-unique line)))
(defun get-index-after-first-14-unique (str)
(do*
((line (coerce str 'list)
(cdr line))
(checked-suf (subseq line 0 14)
(subseq line 0 14))
(suf-set (eval (macroexpand `(fset:set ,@(coerce checked-suf 'list))))
(eval (macroexpand `(fset:set ,@(coerce checked-suf 'list)))))
(ind 14 (1+ ind)))
((= 14 (fset:size suf-set))
ind)))
(get-index-after-first-14-unique *test-input-1*)
(get-index-after-first-14-unique *test-input-2*)
(get-index-after-first-14-unique *test-input-3*)
(get-index-after-first-14-unique *test-input-4*)
(get-index-after-first-14-unique *test-input-5*)
(with-open-file (in "day6-input.txt")
(let ((line (read-line in)))
(get-index-after-first-14-unique line)))
;;; but in Scala it would be something like this:
;; "mjqjpqmgbljsphdztnvjfqwrcgsmlb".toList
;; .sliding(4)
;; .map(_.toSet)
;; .zipWithIndex
;; .find(_._1.size == 4)
;; .map(_._2 + 4)
;; def findIndexAfterNUnique(str: String, n: Int): Option[Int] = {
;; str.toList
;; .sliding(n)
;; .map(_.toSet)
;; .zipWithIndex
;; .find(_._1.size == n)
;; .map(_._2 + n)
;; }
;; findIndexAfterNUnique("mjqjpqmgbljsphdztnvjfqwrcgsmlb", 4)
;; findIndexAfterNUnique("bvwbjplbgvbhsrlpgdmjqwftvncz", 4)
;; findIndexAfterNUnique("nppdvjthqldpwncqszvftbrmjlhg", 4)
;; findIndexAfterNUnique("nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg", 4)
;; findIndexAfterNUnique("zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw", 4)

View File

@@ -0,0 +1,284 @@
;; https://adventofcode.com/2022/day/7
;; so, right now if i need to calculate sum of the size of files.
;; but, there could be duplicates.
;; so, i suppose i'll need to maintain the full filename?
;; so, track the current directory? and on $ ls read lines until next $
;; and put them into hashtable, under full name. ok. ugh
;;
;; so types of commands:
;; cd / - drop current path
;; cd <name> - add <name> to current path
;; cd .. - drop head of current path
;; ls - read in filenames, and add them with current path and size into hashmap
;;
;; then what? go through the hashmap and do calculation
;; with current task, i don't really need to process
;; dir d - names of the directories after $ ls
;; but, how to do pleasant parsing of the lines?
;; and how to store the state, if I'm reading things one line at a time?
;; possibly with DO macro again
;; i guess is could be one function that takes in line and returns new state
;; so state would be
;; - list of directories
;; - hashtable of (filename -> size)
;; i could split string, and try to do case pattern match
(ql:quickload 'alexandria)
(require 'cl-ppcre)
(let* ((line "dir a")
(line-list (cl-ppcre:split " " line)))
(cond ((equal '("$" "cd" "/") line-list) 'ROOT)
((equal '("$" "cd") (subseq line-list 0 2)) 'CD)
((equal '("$" "ls") (subseq line-list 0 2)) 'LS)
((equal '("dir") (subseq line-list 0 1)) 'DIR)
((integerp (parse-integer (first line-list))) 'FILE)
(t 'OTHER)))
;; CASE or COND
(subseq '(1 2 3) 0 2)
(integerp (parse-integer (first (cl-ppcre:split " " "14848514 b.txt"))))
(integerp "1")
(parse-integer "1")
(parse-integer "r")
(defun what (n)
(format t "~S~%" n))
(defun my-parse-line (line)
(let ((line-list (cl-ppcre:split " " line)))
(cond ((equal '("$" "cd" "/") line-list) 'ROOT)
((equal '("$" "cd") (subseq line-list 0 2)) 'CD)
((equal '("$" "ls") (subseq line-list 0 2)) 'LS)
((equal '("dir") (subseq line-list 0 1)) 'DIR)
((integerp (parse-integer (first line-list))) 'FILE)
(t 'OTHER))))
;; (integerp (parse-integer (first (cl-ppcre:split " " "$ cd /"))))
(mapcar #'my-parse-line '(
"$ cd /"
"$ ls"
"dir a"
"14848514 b.txt"
"8504156 c.dat"
"dir d"
"$ cd a"
))
;; next step is to utilize parse line to change state, i guess
(ql:quickload 'fset)
(defparameter *test-dir-list* ())
(defparameter *test-dir-set* (fset:empty-set))
(defparameter *test-file-sizes* (make-hash-table))
(let ((current-path-dirs '())
(file-sizes (make-hash-table))
(dirset (fset:empty-set)))
(labels ((my-full-file-name (dirs lastName)
(let* ((all-dirs (reverse (concatenate 'list (list lastName)
dirs))))
(format nil "~{~a~^/~}" all-dirs)))
(ingest-line (line)
(let ((line-list (cl-ppcre:split " " line)))
(cond ((equal '("$" "cd" "/")
line-list)
(setf current-path-dirs '()))
((equal '("$" "cd" "..")
line-list)
(pop current-path-dirs))
((equal '("$" "cd")
(subseq line-list 0 2))
(push (third line-list) current-path-dirs))
((equal '("$" "ls")
(subseq line-list 0 2))
;; do i need to do anything if just act on the file?
)
((equal '("dir")
(subseq line-list 0 1))
(setf dirset (fset:with dirset (my-full-file-name current-path-dirs (second line-list)))))
((integerp (parse-integer (first line-list)))
(let ((file-name (my-full-file-name current-path-dirs (second line-list)))
(file-size (parse-integer (first line-list))))
(setf (gethash file-name file-sizes) file-size)))))))
(with-open-file (in "day7-input.txt")
;; with-open-file (in "day7-test-input.txt")
(loop
for line = (read-line in nil nil)
while line
do (ingest-line line))))
(setf *test-dir-list* current-path-dirs)
(setf *test-file-sizes* file-sizes)
(setf *test-dir-set* dirset))
*test-dir-list*
*test-dir-set*
*test-file-sizes*
;; now let's iterate over keys in the sizes
(print (loop
for k being each hash-key of *test-file-sizes* using (hash-value v)
do (format t "~a => ~a~%" k v)))
;; ok, popping doesn't happen i think
;; fixed
;; now i want / in the beginning
;; now let's loop over dirs in set. and loop over keys in the hashtable
;; and sum values, and collect sum if it's < 100000
;;
;; well. it's for sure! should be different value
;; hmw/tsrqvpbq/dqbnbl/mbc/nqrdmvjm
;; is also a file
;; hmw/tsrqvpbq/dqbnbl/mbc/nqrdmvjm.vtq => 137158
;; but if all such directories are above 100k then they wouldn't matter.
;; ugh. let's sort lines
(fset:do-set (dirname *test-dir-set*)
(print dirname))
;; but I guess i'll need to just map with fset:image
;; and put sum of all files there
;; let's first return all files for which dir is prefix
(fset:image (lambda (dir) `(,dir imagined)) *test-dir-set*)
(print (fset:reduce #'+
(fset:filter (lambda (sumed)
(>= 100000 sumed))
(fset:image (lambda (dir)
(loop
for filename being each hash-key of *test-file-sizes* using (hash-value filesize)
when (alexandria:starts-with-subseq (concatenate 'string dir "/") filename )
summing filesize)) *test-dir-set*))))
;; oh, shit. it's set, so duplicates of the freaking same sizes get dropped.
;; so, i need to calculate differently
(print (let ((total-sum 0))
(fset:do-set (dirname *test-dir-set*)
(let ((dir-size (loop
for filename being each hash-key of *test-file-sizes* using (hash-value filesize)
when (alexandria:starts-with-subseq (concatenate 'string dirname "/")
filename )
summing filesize)))
(if (> 100000 dir-size)
(incf total-sum dir-size))))
total-sum))
;; crap
;; with / 159935456
;; without / 160367201
;; but if i'm not filtering, then they should be same? wtf
;; or like i'm not counting top level?
;; wow. summing instead of collect
;; now filter those that less than 10000 and sum again
;; ok, i guess.
;; now with a different file?
;;
;; wrong answer 1265478
;;
;; oh, you tricky people
;; there's dir.file that matches as prefix. ugh
;; but then my value should be more that required? ugh twice
(fset:image (lambda (dir)
(loop
for filename being each hash-key of *test-file-sizes* using (hash-value filesize)
when (alexandria:starts-with-subseq (concatenate 'string dir "/")
filename )
collect (list filename filesize)))
*test-dir-set*)
(string-prefix-p "a" "aab")
(alexandria:starts-with "a" "aab")
(alexandria:starts-with-subseq "a/" "a/ab")
(alexandria:starts-with-subseq "" "aab")
;; ok. hello
;; error - tried to use FLET* for allowing recursion, again went to stackoverflow.
;; oh. i need to sum over dirs, ugh.
;; now that's more complicated now.
;; so. then maybe i'd want to register DIRs in another hashtable?
;; and then for each dir collect all files that start with that prefix and sum?
;; would be O(n^2) but ok, i guess
(defparameter *test-set* (fset:empty-set))
(fset:with *test-set* "hello") ; already uses #'EQUAL , cool
(concatenate 'string "hello" "another" "yay")
;; yay!
;; thank you https://stackoverflow.com/questions/5457346/lisp-function-to-concatenate-a-list-of-strings
(format nil "~{~a~^/~}" '("hello" "this" "one"))
(concatenate 'list '("name") '("efim" "home"))
(defun my-full-file-name (dirs lastName)
(let* ((all-dirs (reverse (concatenate 'list (list lastName) dirs))))
(format nil "/~{~a~^/~}" all-dirs)))
(my-full-file-name '("eifm" "home") "Documents")
;; well. ok. now what? maybe i don't need to count root anyway?
;; ugh. can i build a tree then?
;; have pointer? ugh/
;;; so, just start anew? ugh
;;; TO THE PART 2
;; need to find /smallest/ directory to delete, so that free space would be 30000000 our of 70000000
;; so I need "total sum of all"
;; copying over code to calculate sum
;; oh, shit. it's set, so duplicates of the freaking same sizes get dropped.
;; so, i need to calculate differently
(print (let ((total-sum 0))
(fset:do-set (dirname *test-dir-set*)
(let ((dir-size (loop
for filename being each hash-key of *test-file-sizes* using (hash-value filesize)
when (alexandria:starts-with-subseq (concatenate 'string dirname "/")
filename )
summing filesize)))
(incf total-sum dir-size)))
total-sum))
;; 166378694 ; oh that's sum with the duplicates. ugh
;; (- 70000000 166378694)
;; i need direct sum, just over the lines.
;; luckily this should be easier? or no? well, sum over the file-hashtable, there are all unique
(print (loop
for filename being each hash-key of *test-file-sizes* using (hash-value filesize)
summing filesize))
(print (- 70000000 44795677))
;; wait, no. I need 30000000
;; so, that's my free memory right now: 25204323
;; to free is
(print (- 30000000 25204323))
;; to free 4795677
;; now i need for all dir sizes find one that is more than than, but the smallest
(fset:filter (lambda (item)
(< 4795677 (first item))) (fset:image (lambda (dir)
(list (loop
for filename being each hash-key of *test-file-sizes* using (hash-value filesize)
when (alexandria:starts-with-subseq (concatenate 'string dir "/")
filename )
summing filesize) dir))
*test-dir-set*))
;; and it shows sorted, and the first one - is the dir to be deleted.
;; cooooool. it was very hard.
;;
;; what are lessons:
;; image (mapping) on set discards duplicates. lot's of time spent debugging this
;; also - i need to learn threading.
;; maybe that's the way to make code simpler.
;; but then i won't be able to call it iteratevly? i really still should.
;;
;; so, go to Alexandria for threading, and for string things.
;; and maybe read about functions for hashmaps and such. ugh.

1008
day7-input.txt Normal file

File diff suppressed because it is too large Load Diff

23
day7-test-input.txt Normal file
View File

@@ -0,0 +1,23 @@
$ cd /
$ ls
dir a
1 b.txt
1 c.dat
dir d
$ cd a
$ ls
dir e
1 f
1 g
1 h.lst
$ cd e
$ ls
1 i
$ cd ..
$ cd ..
$ cd d
$ ls
1 j
1 d.log
1 d.ext
1 k

99
day8-input.txt Normal file
View File

@@ -0,0 +1,99 @@
011201001000123232122300403211332202122424332111151523152310403222120311202224013311113203311122001
102201211220103202323002411123324024134251423232343141424431144431022143443131141222323122010012220
002022232232102013311311301321044421352134513235443522243113311323213013301030440423203311103101020
002212021110130112400112141310424411421435324412235335534245212325313312413434430114302030310200000
202000312203303110042324124431114212153432535412115323131323541522511253002131401212012131031321110
120203002030304244102444143021314124552253521343321513511124144454343454102412220143321013220111212
012133330030200444414333325255125142322121412245551424242135123513411533153323130432231002121211210
012300220003100211444401144353345522135453435223464636451554321531323513234331131114224102232333310
000201310302031301344341134512444312432566266533252332656654251123535525135213300040211242011230031
121002133124022203240512452433331223524622643252532325346635555552514352434233454024134201432001111
112213110140442401434531255323512525265655352543623565556265545555235551143135124203142220020302000
033001202421424143555311243322416262636322654432542644633525453666655354514351121150231101002002310
133303044321221102531154151541224245536464535622566355532543644552554644312231415325142303020031312
112333344411024045335422225146442243536464622553556234523445362524655623435243115242532313102020021
123023422310204444121415255225254435644446326664473564435422565325224635623542352154120001224144312
102303024142131515433355242322223363453633455657436436574636544336652564626641215232314243234004001
021344140434455245134415553542352643537665534644574553367446664254532523624521243554252411433032112
100140101131444142414254644644434663647646555637737475474473636562243265243536422253531252202124322
111043301134142345422324342454235374733474673456744577746755765343355535622342432251442244140231224
232120141224122324244532255543256467566454337465647735433663734756446566663442525425254525142212311
102310340244433433553362546534535757453376643763344566566557634664535744445254533545223521213213014
330111232252114431226334564636467643777466445537346735563633337744734474466254662225321443542401243
344311321253412213666443354643647347656735478884748547564466577774737677363226422622515344334010341
222340105234132533423442424376674757757675647476557547564445666676437755355626455436313331225343402
334241221121414455435265324646757456774784864846746867457546648735456677555624445353555434433340341
333430021343121666326363537633737767788775478777445558858444854755434544735362564626265444342330020
332224425333452333556456745375454657668644877658744844547774765844454475434765533256545152435214410
411322431421116436336347456774356844455867864644844878664785864444475567664473365652253123453220003
130345455115155526426437663665665668576686587847778476557678655576775553535745643522532344433523042
241333521455132466523664543556384776587787745658797755565556576546847447434775733626365325451531301
202135433134452323646546565545646885747548679876767658578565476458486465755545465664435422532454541
344025243154435524235475655536845545775797795959686975588855546544875685664377465455353661444452422
120511445324333353265334766654858656857755669695597899959957757545465687447345336332322634434414522
041425252513666643357433333888555778459755889566967799659865567757457567576463765323236366123221323
142343534134652443554434768544658774587669979986775985989879787975445856456554364645323653454511323
443155144123223566654765746758688875856899955996667659755976778586644774777456744653322566354532232
013242522162435447764573774877757879868788876799896979576555597985885468586473474464455426633333452
101431333345553353553337548577478656967866886877887889699999856979976485874455544477534422463331314
422325541533664573334736464857446675995799977868697688998787757585668584775766563477536636621514142
313315332565562573637376866486547776557979868979996867779966955885566785455767644565336236452541411
231122455364326235655644685888786685587796897688777698977986787596655865857448333576665523356143332
314415154446535337443754887576795586569678967879977696896667866768856785586774365336636426455324541
251324556334435537567468544665859588888869687767876697967887867856679658788866355353346553442543353
134353225423362456734666455757877769577678987866887877799886886885859796767664444665534363236114533
251241346545626367667578575687955957988796678987999979977897978877579787844755554533763646262143315
353543555544353753474346565789555799696999667888997899777669899867697878476845756644734243432245123
221521465632632737777766744748678869769669668898887888987898666789869785645678734643552655525624335
351552456455622567337644647486678857766866879798779999878779869885869788874885873744772665326352324
153242153665224557353455465857685566797887699998988788877767696668668675666664465757646436665554315
321113152666424547657348876876678597898779877779998999978978777885976658558676664444674243656333212
421511245364456777655754476646885699898678788797778788778778999795687589454774563737333365434325525
213532265252653474345766566877669898969767779777879797899977669868595997784466766655547455234435452
125232235356525353764645486577668857868788699799787978898988669878688867586564457353673236664223343
441242562562223643773466848558599657669669968987979987787969676777796877655876456745562442232541525
135122156635652746574578664849659556998698797778797889988788869797687977855447474475546334662522444
144315413442434666777478887855885568968799966889978797797867786966685589646488554737453225335213325
511213234443636433646678657654587788667696879878989799867699988765895758788675765445656425425334544
052145146243336363474565857687976889776768867898889967686967668565998666768575534675445244546424155
235513424332444756467574556745997958679678999799789777998968876679956958746554677637762355253554335
331155256654246447545776676487485655676699678967897779688898989999768655488874564764434223445132152
152152253254255234473347878744485766678897879689897888667968795675655864748584644653323363464154251
245154344235223346354765457746867586969968687876867899766986679689585778787473555663424264553541344
235253541263666477544377746867785766579566868896689699876766695956667455774677646576554255521144355
033522343456423455634354575764856898657669957896677776766596688857787474488436433455326554242331222
321532413246333226435563556578864759978657759897896799958558598588975755858856537673332523244522141
101422552442534324467345475684574877989759655788785857697957976679848768474665346435664653421242444
103425135453353666736674677847548667967885667765576995797857589796866646565443377775564436443333543
041131245522253556554636537878457787468577768876778599999689667978487755747676763666266652435545351
424232344536333364556466767555646468677996965895798968676966868665587584664535544755645232211324114
334034423343366322247357747635787857555667756956768657779596877655676555367754633345545442422145333
424344345121532564223643563774744574746844686888885779565686455664565643634566756543362551431252401
232123114442152332546734767375678475664877645798695799654765488755876545334345452455463633534433233
414423121145222454332477456654436757485685646546884446667744645744675377357654436554353221451345404
234130223314353235262655676637577858558554556467788664555466588778677546456334642623666524333250443
414001252524152463224524734765775677644765886656877578666575855788653533364773455446565352432424320
024323134311552535243564667476365737764685474446876486685546667685363735646643655435355533243440034
331141044111451522226436327536773637654887585478885586588745847444466365767232265352211455413531431
241321311312323233252665352455436545735388846445565487667644555744667753556266645332452431541341044
234030032312154414563442653244476576544654676884777445766434443476675746365245632242515342521301442
202112004552434344564624422526757574735736566643654737673776743354737744242533546523434111443034202
323422334452422412134566522262537334374446646774476534347655656336555632626663364214333341322443300
031243421344143515452456444553266345437737337675574563437533573575456463665443432215213541123241240
002114441013421154331235436253442576764555535635775735635377573353666526333623554524421352131443020
111342301013125124521245222663363363467436357434736773473777464564655622533254352444544553311114233
222323000331131531351433363334345533653474663466435557365553376535246564324662454422135233103003200
002103300342403311123432563445263435443255635353333564444573456633466424623313351545133022013122320
300304042333200223123432352234525626625234236453763536563235242224645265643515312312520000242200000
210121244033001141551213125554433445222532265463624234562324443435344362451243522525243002401410013
303323342040431313415255233251226626334264553655346266323665655652522363324341123235410333230402230
300112203021311400115231251543524354554262365526643622264625434236554412121342322522123434120120203
011001023222004142422445443143212526654365444643442536365453622222634154551441553400220414300301332
230032020342121242113341435444543253355352433246243543645634456552525315313143243431133302112320020
232132202131312144424224413332214322543242664652323324456222615212244414145113442320023403200012111
112222030320432400004224215552515412325221525356363643351335211141344255554442403013303120331312202
110321230332323212301432002424211134155124241552254334221154111545254253122214132321141212032221001
021020121321302320401011302153145251455114411155452245422422135453412153112033343412340101230302010
122203012232330222213342133012334131225335225325343355122151154444535354414423434423220001330003020
221120213213221333210131242440001425551432522221141211124544343151315104244333311124033221102312011
202201033331203122413021242022211002455531321354252412214332215513311231404032244320020330332301120

5
day8-test-input.txt Normal file
View File

@@ -0,0 +1,5 @@
30373
25512
65332
33549
35390

507
day8-tree-heights.lisp Normal file
View File

@@ -0,0 +1,507 @@
;;; https://www.youtube.com/watch?v=aGedUxTAfBk
;; tree is visible if from one of 4 directions there are only trees that are "strictly lower"
;; the computation reuse - if we checked the tree on the top before, and it's visible from top and lower - then currnt is visible
;; but if it's not visible from top, then we need to know which tree covered it up, to calculate whether current tree is taller than that.
;;
;; so. i'd want to i think this time actually use classes. to store visibility from the directions.
;; or rather for each tree store the highest tree towards the enge in the direction.
;; and would be possible to calculate visibility into a direction then
;;
;; so. have a class with hash-table of DIRECTION -> tallest-in-that-direction
;; i suppose can be done without storing this data. just go through the line against the checking direction, and store last tallest tree in var
;; could store visibility in the shared 2d array
(loop
:for i :across (vector 1 2 3 4)
:do (print (* 5 i)))
(coerce (list 1 2 3 4) 'vector)
(require 'cl-ppcre)
(cl-ppcre:split "" "hello")
(coerce (mapcar #'parse-integer (cl-ppcre:split "" "30373" )) 'vector)
;; (defparameter *file-name* "day8-test-input.txt")
(defparameter *file-name* "day8-input.txt")
(progn
(defparameter *trees-2d-vector*
(let ((rows-accumulation ()))
(with-open-file (in *file-name*)
(loop
for line = (read-line in nil nil)
while line
do (push
(coerce (mapcar #'parse-integer (cl-ppcre:split "" line)) 'vector)
rows-accumulation)
)
(coerce (reverse rows-accumulation) 'vector))))
(defparameter *trees-rownum* (length *trees-2d-vector*))
(defparameter *trees-colnum* (length (aref *trees-2d-vector* 0))))
*trees-2d-vector*
;; (aref *trees-2d-vector* 3 0) ; error
(let ((arr (make-array '(2 3))))
(setf (aref arr 1 1) "hello")
arr) ; but can't access row at a time.
; ugh.
;; now. i'd want visibility matrix. with true on edges and false inside
;; then loop over lines / rows against the direction
;; store previous max height, if current is bigger - store it as previous max visible and
;; put visible into the shared matrix
;;
;; then do iteration against all directions, only updating table to true
(ql:quickload "iterate")
(use-package 'iterate)
(defparameter *tree-vis-matr*
(let* ((rows-count (length *trees-2d-vector*))
(cols-count (length (aref *trees-2d-vector* 0)))
(visibility-matrix (make-array (list rows-count cols-count) :initial-element nil)))
(iterate:iter (for rownum from 0 to (1- rows-count))
(iterate:iter (for colnum from 0 to (1- cols-count))
(if (or (= rownum 0)
(= rownum (1- rows-count))
(= colnum 0)
(= colnum (1- cols-count)))
(setf (aref visibility-matrix rownum colnum) 'T))))
;; cool
;; (loop
;; for rownum from 0 to (1- rows-count)
;; for colnum from 0 to (1- cols-count)
;; when (or (= rownum 0)
;; (= rownum (1- rows-count))
;; (= colnum 0)
;; (= colnum (1- cols-count)))
;; do (progn
;; (setf (aref visibility-matrix rownum colnum) "hello")
;; ))
;; (setf (aref visibility-matrix 1 1) "hello")
visibility-matrix))
;; now for i j if
(loop
for rownum from 0 to 3
for colnum from 0 to 4
;; when (or (= rownum 0)
;; (= rownum (1- rows-count))
;; (= colnum 0)
;; (= colnum (1- cols-count)))
collect rownum)
(iterate:iter (for i from 1 to 5)
(print i))
(iterate:iter (for i from 5 downto 1)
(print i))
(iterate:iter (for item in '(1 2 3))
(print item))
;; so. now i have visibility matrix wihch is 2d,
;; to store which trees are "visible"
;; and also i have Vector(Vectors) for tree sizes, for iteration.
;;
;; now ideally I'd be able to code these iterations in a compact way.
;; but i'm just ugh
;; no, just no. let's of iterations which i'm not sure how to generalize
;; and need to share state, upleasant
;; (defun nextPoint (row col direction)
;; (case direction
;; ('UP (list row (1- col)))
;; ('DOWN (list row (1+ col)))
;; ('LEFT (list (1- row) col))
;; ('RIGHT (list (1+ row) col))))
;; (nextpoint 1 1 'up)
;; (nextpoint 1 1 'left)
;; (nextpoint 1 1 'right)
;; (nextpoint 1 1 'down)
;; (apply #'nextpoint '(1 1 down))
;; (apply #'+ '(1 2 3))
(defun gen-line-coords (startRow startCol rowNum colNum direction)
(flet ((row-col-valid (row col)
(and (>= row 0) (>= col 0) (< row rowNum) (< col colNum)))
(nextPoint (row col)
(case direction
('LEFT (list row (1- col)))
('RIGHT (list row (1+ col)))
('UP (list (1- row) col))
('DOWN (list (1+ row) col)))))
(let ((coords-collected ()))
(do
((coords (list startRow startCol) (apply #'nextpoint coords)))
((not (apply #'row-col-valid coords)) (reverse coords-collected))
(push coords coords-collected)))))
(gen-line-coords 0 0 4 5 'down)
(gen-line-coords 0 0 4 5 'right)
(gen-line-coords 3 4 4 5 'up)
(gen-line-coords 2 4 4 5 'left)
(apply #'gen-line-coords '(0 0 4 5 down))
;; well, looks like this works
;; and then generic iteration on these coordinates?
;; store previous max tree.
;; if current is bigger than previous max - store it as previous max and put T into vix.matrix
;; i really dislike this task so far.
(defparameter *test-line-coords* (gen-line-coords 1 0 4 5 'right))
(let ((biggest-tree-so-far -1))
(loop
for coords in *test-line-coords*
do (let* ((rownum (first coords))
(colnum (second coords))
(row (aref *trees-2d-vector* rownum))
(tree-size (aref row colnum)))
(if (< biggest-tree-so-far tree-size)
(progn (setq biggest-tree-so-far tree-size)
(setf (aref *tree-vis-matr* rownum colnum) 't))))))
*test-line-coords*
*trees-2d-vector*
*tree-vis-matr*
(aref *tree-vis-matr* 1 1)
;; well it kinda worked.
;; now i need to get all possible line-coords, with desired directions
;; and then run for each of these
;; and then - count amount of T in the resulting matr
;; getting all possible direction line-coords
;;
(progn
(defparameter *trees-right-line-coords*
(loop
for startRow from 0 below *trees-rownum*
collect (gen-line-coords startRow 0 *trees-rownum* *trees-colnum* 'right)))
(defparameter *trees-left-line-coords*
(loop
for startRow from 0 below *trees-rownum*
collect (gen-line-coords startRow (1- *trees-colnum*) *trees-rownum* *trees-colnum* 'left)))
(defparameter *trees-right-down-coords*
(loop
for startCol from 0 below *trees-colnum*
collect (gen-line-coords 0 startCol *trees-rownum* *trees-colnum* 'down)))
(defparameter *trees-right-up-coords*
(loop
for startCol from 0 below *trees-colnum*
collect (gen-line-coords (1- *trees-rownum*) startCol *trees-rownum* *trees-colnum* 'up)))
(defparameter *trees-all-line-coords*
(concatenate 'list
*trees-right-line-coords*
*trees-left-line-coords*
*trees-right-down-coords*
*trees-right-up-coords*))
;;; iterate over all col-lines
(loop
for coord-line in *trees-all-line-coords*
do (let ((biggest-tree-so-far -1))
(loop
for coords in coord-line
do (let* ((rownum (first coords))
(colnum (second coords))
(row (aref *trees-2d-vector* rownum))
(tree-size (aref row colnum)))
(if (< biggest-tree-so-far tree-size)
(progn (setq biggest-tree-so-far tree-size)
(setf (aref *tree-vis-matr* rownum colnum) 't)))))))
*tree-vis-matr*
;; counting amount of 'T in the visibility matrix
(let ((running-sum 0))
(iterate:iter (for rownum from 0 to (1- *trees-rownum*))
(iterate:iter (for colnum from 0 to (1- *trees-colnum*))
(if (aref *tree-vis-matr* rownum colnum)
(incf running-sum 1))))
running-sum))
;;; wow, 1845 was the right answer. urrgh
;;; now to the second part
;; and that's totally different thing now.
;; i guess i could use my "col-line" to get coords to check from the tree
;; for each tree take tail of coord line into each direction
;; and count how long to the first tree of at least same height.
*trees-2d-vector*
(defparameter *test-tree-coords* '(2 2))
(defparameter *test-line-coords* (gen-line-coords 3 3 4 5 'right))
(cdr *test-line-coords*)
(eval `(gen-line-coords ,@*test-tree-coords* *trees-rownum* *trees-colnum* 'right))
(defparameter *test-tree-direction-cols*
(mapcar #'cdr
(mapcar #'eval
(mapcar
(lambda (direction)
`(gen-line-coords ,@*test-tree-coords* *trees-rownum* *trees-colnum* ,direction)
)
'('right 'down 'left 'up)))))
(defun tree-size-by-coords (coords)
(aref (aref *trees-2d-vector* (first coords)) (second coords)))
(tree-size-by-coords '(1 1) )
(print (mapcar (lambda (coord-line)
(mapcar #'tree-size-by-coords coord-line)) *test-tree-direction-cols*))
(defun take-while (list pred)
(loop for elt in list while (funcall pred elt) collect elt))
(take-while '(1 2 3 3 3 4 5 6) (lambda (n) (>= 3 n)))
;; it's not it. ugh. why it's so hard.
;; how can i find index of first inclusion of element in list.
;; i guess i could do strict less than and add 1? no.
(take-while '(1 2 3 3 3 4 5 6) (lambda (n) (> 3 n)))
;; and then if list i got not equal to initial list - add 1 because we dropped something?
;; UGH!
;; should be a better way.
(do*
((start-tree-size (tree-size-by-coords '(3 3)))
(coords-direction (car *test-tree-direction-cols*) (cdr coords-direction))
(coord (car coords-direction) (car coords-direction))
(coord-tree-size (tree-size-by-coords coord) (tree-size-by-coords coord))
(count 0 (1+ count)))
((or (not coords-direction)
(> coord-tree-size start-tree-size))
(if ((= coord-tree-size start-tree-size)
(1+ count)
count))))
;; i'm incredibly frustrated
;; more that an hour on trying to get initial part of list until first inclusion of target element.
;; horrible
;; ok. this monstrocity
(let ((self 3)
(found-self nil))
(loop for elt in '(1 2 2 3 1 5 1)
while (and (not found-self)
(>= self elt)) collect elt
if (= elt self) do (setq found-self 't)))
(defun my-get-prefix (trees-heights self-height)
(let ((self self-height)
(found-self nil))
(loop for elt in trees-heights
while (not found-self) collect elt
if (>= elt self) do (setq found-self 't))))
(my-get-prefix '(3 3 1 5 1 2) 4)
(my-get-prefix '() 6)
;; ok. let's map that on top of other shit
(print (mapcar (lambda (height-list)
(length (my-get-prefix height-list 3)))
(mapcar (lambda (coord-line)
(mapcar #'tree-size-by-coords coord-line)) *test-tree-direction-cols*)))
;; and this was all inconsequential because for 3 seeing 3 and seing 5 is same end
;; so i could have used take-while with strict condition.
;; in any way would have needed to add 1?
;; will modify my ugly function, making it uglier, cool
;;
;; now need to multiply them and call that with correct coords for all inner trees.
;; this is pain.
;;; returning to calculating the directions from each tree
*trees-2d-vector*
(defparameter *test-tree-coords* '(4 2))
(defparameter *test-line-coords* (gen-line-coords 3 3 4 5 'right))
(defparameter *test-tree-direction-cols*
(mapcar #'cdr
(mapcar #'eval
(mapcar
(lambda (direction)
`(gen-line-coords ,@*test-tree-coords* *trees-rownum* *trees-colnum* ,direction)
)
'('right 'down 'left 'up)))))
(defun get-tree-direction-cols (tree-coords)
(mapcar #'cdr
(mapcar #'eval
(mapcar
(lambda (direction)
`(gen-line-coords ,@tree-coords *trees-rownum* *trees-colnum* ,direction)
)
'('right 'down 'left 'up))))
)
(defun tree-size-by-coords (coords)
(aref (aref *trees-2d-vector* (first coords)) (second coords)))
(tree-size-by-coords '(1 1) )
(print (mapcar (lambda (coord-line)
(mapcar #'tree-size-by-coords coord-line)) *test-tree-direction-cols*))
(print (mapcar (lambda (height-list)
(length (my-get-prefix height-list 3)))
(mapcar (lambda (coord-line)
(mapcar #'tree-size-by-coords coord-line)) *test-tree-direction-cols*)))
(apply #'* '(1 2 2 0))
(let ((cur-max -1))
(iterate:iter (for row from 1 to (1- *trees-rownum*))
(iterate:iter (for col from 1 to (1- *trees-colnum*))
(let* ((cur-tree-height (tree-size-by-coords (list row col)))
(cur-tree-lines (get-tree-direction-cols (list row col)))
(cur-tree-lines-tree-heights
(mapcar (lambda (coord-line)
(mapcar #'tree-size-by-coords coord-line)) cur-tree-lines))
(cur-tree-visibilities
(mapcar (lambda (height-list)
(length (my-get-prefix height-list cur-tree-height))) cur-tree-lines-tree-heights))
(cur-tree-score (apply #'* cur-tree-visibilities)))
(if (> cur-tree-score cur-max)
(setq cur-max cur-tree-score)))))
cur-max)
;; 230112 is the correct answer
;; wow. i got an aswer 8
;; now try to recalculate this horrible thing with actual input.
;;; let's CLEAN UP THE CODE, at least set it all together
;;; PART 1: Count visible trees
(defparameter *file-name* "day8-input.txt")
(progn
(defparameter *trees-2d-vector*
(let ((rows-accumulation ()))
(with-open-file (in *file-name*)
(loop
for line = (read-line in nil nil)
while line
do (push
(coerce (mapcar #'parse-integer (cl-ppcre:split "" line)) 'vector)
rows-accumulation)
)
(coerce (reverse rows-accumulation) 'vector))))
(defparameter *trees-rownum* (length *trees-2d-vector*))
(defparameter *trees-colnum* (length (aref *trees-2d-vector* 0))))
;; generate Visibility matrix for trees
(defparameter *tree-vis-matr*
(let* ((rows-count (length *trees-2d-vector*))
(cols-count (length (aref *trees-2d-vector* 0)))
(visibility-matrix (make-array (list rows-count cols-count) :initial-element nil)))
(iterate:iter (for rownum from 0 to (1- rows-count)) ; trying iter to avoid nested LOOP
(iterate:iter (for colnum from 0 to (1- cols-count))
(if (or (= rownum 0)
(= rownum (1- rows-count))
(= colnum 0)
(= colnum (1- cols-count)))
(setf (aref visibility-matrix rownum colnum) 'T))))
visibility-matrix))
;; get list of coordinates towards DIRECTION, starting from startRow & startCol
;; for generalizing LOOP'ing into different directions
(defun gen-line-coords (startRow startCol rowNum colNum direction)
(flet ((row-col-valid (row col)
(and (>= row 0) (>= col 0) (< row rowNum) (< col colNum)))
(nextPoint (row col)
(case direction
('LEFT (list row (1- col)))
('RIGHT (list row (1+ col)))
('UP (list (1- row) col))
('DOWN (list (1+ row) col)))))
(let ((coords-collected ()))
(do
((coords (list startRow startCol) (apply #'nextpoint coords)))
((not (apply #'row-col-valid coords)) (reverse coords-collected))
(push coords coords-collected)))))
(progn
;; this is with unfortunate amount of manual tinkering
(defparameter *trees-right-line-coords*
(loop
for startRow from 0 below *trees-rownum*
collect (gen-line-coords startRow 0 *trees-rownum* *trees-colnum* 'right)))
(defparameter *trees-left-line-coords*
(loop
for startRow from 0 below *trees-rownum*
collect (gen-line-coords startRow (1- *trees-colnum*) *trees-rownum* *trees-colnum* 'left)))
(defparameter *trees-right-down-coords*
(loop
for startCol from 0 below *trees-colnum*
collect (gen-line-coords 0 startCol *trees-rownum* *trees-colnum* 'down)))
(defparameter *trees-right-up-coords*
(loop
for startCol from 0 below *trees-colnum*
collect (gen-line-coords (1- *trees-rownum*) startCol *trees-rownum* *trees-colnum* 'up)))
(defparameter *trees-all-line-coords*
(concatenate 'list
*trees-right-line-coords*
*trees-left-line-coords*
*trees-right-down-coords*
*trees-right-up-coords*))
;;; iterate over all col-lines
(loop
for coord-line in *trees-all-line-coords*
do (let ((biggest-tree-so-far -1))
(loop
for coords in coord-line
do (let* ((rownum (first coords))
(colnum (second coords))
(row (aref *trees-2d-vector* rownum))
(tree-size (aref row colnum)))
(if (< biggest-tree-so-far tree-size)
(progn (setq biggest-tree-so-far tree-size)
(setf (aref *tree-vis-matr* rownum colnum) 't)))))))
*tree-vis-matr*
;; counting amount of 'T in the visibility matrix
(let ((running-sum 0))
(iterate:iter (for rownum from 0 to (1- *trees-rownum*))
(iterate:iter (for colnum from 0 to (1- *trees-colnum*))
(if (aref *tree-vis-matr* rownum colnum)
(incf running-sum 1))))
running-sum))
;;; PART 2. find tree with highest view-score
;; from list of tree-heights take trees that lover than current, until first tree of same height or higher
(defun my-get-prefix (trees-heights self-height)
(let ((self self-height)
(found-self nil))
(loop for elt in trees-heights
while (not found-self) collect elt
if (>= elt self) do (setq found-self 't))))
;; use same trees 2d array. O(n^2) - for each tree construct lines into 4 directions,
;; get prefix of these lines for trees that of not exceeding height, calculate score
;; instead of CUR-MAX could possibly use MAXIMIZING of LOOP, or something
(let ((cur-max -1))
(iterate:iter (for row from 1 to (1- *trees-rownum*))
(iterate:iter (for col from 1 to (1- *trees-colnum*))
(let* ((cur-tree-height (tree-size-by-coords (list row col)))
(cur-tree-lines (get-tree-direction-cols (list row col)))
(cur-tree-lines-tree-heights
(mapcar (lambda (coord-line)
(mapcar #'tree-size-by-coords coord-line)) cur-tree-lines))
(cur-tree-visibilities
(mapcar (lambda (height-list)
(length (my-get-prefix height-list cur-tree-height))) cur-tree-lines-tree-heights))
(cur-tree-score (apply #'* cur-tree-visibilities)))
(if (> cur-tree-score cur-max)
(setq cur-max cur-tree-score)))))
cur-max)

2000
day9-input.txt Normal file

File diff suppressed because it is too large Load Diff

209
day9-rope-bridge.lisp Normal file
View File

@@ -0,0 +1,209 @@
;; https://adventofcode.com/2022/day/9
;; i have been thinking about this in a car on a way home.
;; first check - if any movement of Tail is needed - if any coord is more than 2 away
;;
;; then - if movement is needed - it's always done in 1 step into direction of Head.
;; - if difference is 0, no movement, otherwise (HeadX - TailX) / Abs(HeadX - TailX)
;;
;; and what's left is reading in changes to Head position, update of head position,
;; and calling generation of new Tail position from newHead and prevTail
;;
;; no need to worry about the borders, as Head is always closer to border?
;; so, the field should be considered unbounded. and no coordinates for the starting point are given.
;; we are also to consider that in the beginning Head is on top of Tail.
;; ok. would my math work with negative coordinates? it really should
;; so, let's consider starting coordinates as (0,0) and also keep a set of all preivously visited coordinates by the Tail
;; and return its size
(defmacro get-x (pointCoords)
`(car ,pointCoords))
(defmacro get-y (pointCoords)
`(cadr ,pointCoords))
(setf (get-x '(1 2)) 3)
(defparameter *test-list* (list 1 2))
(setf (get-x *test-list*) 2)
(setf (get-y *test-list*) 7)
(setf (first *test-list*) 3)
(get-y '(1 2))
(abs -1)
(defun tail-move-needed (headCoords tailCoords)
(flet ((diff-more-than-two (num1 num2)
(>= (abs (- num1 num2)) 2)))
(or (diff-more-than-two (get-x headcoords) (get-x tailcoords))
(diff-more-than-two (get-y headcoords) (get-y tailcoords)))))
(>= 2 2)
(tail-move-needed '(1 1) '(1 1))
(tail-move-needed '(1 1) '(1 2))
(tail-move-needed '(1 1) '(1 3))
(tail-move-needed '(1 1) '(2 3))
(tail-move-needed '(1 1) '(0 0))
(defun update-big-distance-coord (headcoord tailcoord)
(let* ((diff (- headcoord tailcoord))
(change (if (eq diff 0) 0 (/ diff (abs diff)))))
(+ tailcoord change)))
(defun update-big-distance-coords (headcoords tailcoords)
(let ((new-x (update-big-distance-coord (get-x headcoords) (get-x tailcoords)))
(new-y (update-big-distance-coord (get-y headcoords) (get-y tailcoords))))
(list new-x new-y)))
(update-big-distance-coords '(2 1) '(0 0))
(update-big-distance-coords '(-2 0) '(0 0))
(update-big-distance-coords '(0 -2) '(0 0))
(defun get-new-tail-coords (headcoords tailcoords)
(if (tail-move-needed headcoords tailcoords)
(update-big-distance-coords headcoords tailcoords)
tailcoords))
(get-new-tail-coords '(1 1) '(0 0))
(get-new-tail-coords '(-1 0) '(0 0))
(get-new-tail-coords '(1 -1) '(0 0))
;; ok, now i need to translate commands of type
;; R 4
(defparameter *test-line* "R 4")
(require 'cl-ppcre)
(let ((split (cl-ppcre:split " " *test-line*)))
(setf (first split) (intern (first split)))
(setf (second split) (parse-integer (second split)))
split)
(defun read-comman (line)
(let ((split (cl-ppcre:split " " line)))
(setf (first split)
(intern (first split)))
(setf (second split)
(parse-integer (second split)))
split))
(read-comman "U 5")
(defun modify-head-coords (headcoords direction)
(case direction
(R (incf (get-x headcoords) 1))
(L (incf (get-x headcoords) -1))
(U (incf (get-y headcoords) 1))
(D (incf (get-y headcoords) -1))))
(defparameter *test-coords* (list 0 0))
(modify-head-coords *test-coords* 'L)
(modify-head-coords *test-coords* 'R)
(modify-head-coords *test-coords* 'U)
(modify-head-coords *test-coords* 'D)
;; seems to work.
;; now loop and addint tail coords into set
(ql:quickload 'fset)
(defparameter *test-set* (fset:set '(0 0) '(1 1)))
(fset:with *test-set* '(3 1))
(fset:with *test-set* '(1 1))
;; yes, with equal, that's cool
(loop
for i from 1 to 4
do (print i))
;; got I forgot most of what there is about input attribute
;; modification, when will that modification become visible on top?
;; when I've defined the value as parameter, so it's dynamic binding,
;; instead of lexical binding?
;; ((tail-coords-set (fset:empty-set))
;; (headcoords (list 0 0))
;; (tailcoords (list 0 0)))
(progn
(defvar tail-coords-set )
(setq tail-coords-set (fset:empty-set))
(defvar headcoords )
(setq headcoords (list 0 0))
(defvar tailcoords )
(setq tailcoords (list 0 0)))
(defun run-step (direction)
(modify-head-coords headcoords direction)
(setf tailcoords (get-new-tail-coords headcoords tailcoords))
(setf tail-coords-set (fset:with tail-coords-set tailcoords))
;; (print (format t "~S ~S ~S~%" headcoords tailcoords direction))
)
(defun run-command (repetitions direction)
(loop for i from 1 to repetitions
do (progn (run-step direction)
;; (format t "~S ~S ~S ~S~%" headcoords tailcoords direction tail-coords-set)
)))
(progn
(defvar tail-coords-set )
(setq tail-coords-set (fset:empty-set))
(defvar headcoords )
(setq headcoords (list 0 0))
(defvar tailcoords )
(setq tailcoords (list 0 0))
(with-open-file (in "day9-input.txt")
(loop
for line = (read-line in nil nil)
while line
do (let*
((command (read-comman line))
(direction (first command))
(repetition (second command)))
(run-command repetition direction)))
(fset:size tail-coords-set)))
;;; PART 2
;; i kind of predicted that they'd want to generalize to longer rope.
;; ugh. but it still kind of works?
;; just have list of rope points?
;; and each step would be applying same step to some particular point
;; - logging is not much less useful
;; the points are H1234..9
;; so, array of length 10
(progn
(defvar *string-joints*)
;; (setq *string-joints* (make-array 10 :initial-element '(0 0)))
;; wow, here's example of code being AST directly from text
;; now, it's problem with "initial-element" cool
(defvar *9-tail-coords-set*)
(loop
for i from 0 to 9
do (setf (aref *string-joints* i) (list 0 0)))
(setq *9-tail-coords-set* (fset:empty-set)))
(defun run-step-2 (direction)
(modify-head-coords (aref *string-joints* 0) direction)
(loop
for cur-joint-step from 1 to 9
do (setf (aref *string-joints* cur-joint-step)
(get-new-tail-coords
(aref *string-joints* (1- cur-joint-step))
(aref *string-joints* cur-joint-step))))
(setf *9-tail-coords-set*
(fset:with *9-tail-coords-set* (aref *string-joints* 9))))
(defun run-command-2 (repetitions direction)
(loop for i from 1 to repetitions
do (progn (run-step-2 direction)
;; (format t "~S ~S ~S ~S~%" headcoords tailcoords direction tail-coords-set)
)))
(progn
(loop
for i from 0 to 9
do (setf (aref *string-joints* i) (list 0 0)))
(setq *9-tail-coords-set* (fset:empty-set))
(with-open-file (in "day9-input.txt")
(loop
for line = (read-line in nil nil)
while line
do (let*
((command (read-comman line))
(direction (first command))
(repetition (second command)))
(run-command-2 repetition direction)))
(fset:size *9-tail-coords-set*)))

8
day9-test-bigger.txt Normal file
View File

@@ -0,0 +1,8 @@
R 5
U 8
L 8
D 3
R 17
D 10
L 25
U 20

8
day9-test.txt Normal file
View File

@@ -0,0 +1,8 @@
R 4
U 4
L 3
D 1
R 4
D 1
L 5
R 2