;; 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)))