lainchan / λ

Advent of Code thread

Terzibashjian · 2021-12-01 14:59
Anyone doing AoC this year? I'll be using Guile Scheme this year, what about you guys? https://adventofcode.com/
Naomi Nascimento · 2021-12-01 15:00
And the solution for today (use-modules (ice-9 rdelim) (ice-9 match) (srfi srfi-1)) (define (get-lines port trans) (let loop [(line (read-line port)) (lines '())] (if (eof-object? line) (reverse lines) (loop (read-line port) (cons (trans line) lines))))) (define (count-increases nums) (let [(diffs (map - nums (cdr nums)))] (fold (lambda (el acc) (if (negative? el) (1+ acc) acc)) 0 diffs))) (define (count-increases-windowed nums) (let* [(windowed (map + nums (cdr nums) (cddr nums))) (diffs (map - windowed (cdr windowed)))] (fold (lambda (el acc) (if (negative? el) (1+ acc) acc)) 0 diffs))) (count-increases (call-with-input-file "input" (lambda (port) (get-lines port string->number)))) (count-increases-windowed (call-with-input-file "input" (lambda (port) (get-lines port string->number))))
Liet Kynes · 2021-12-01 16:11
This is my first time participating, used C++ for today. Thinking to try redoing today's code in C and keep using C for every day from now on.
Ender · 2021-12-01 17:37
Did today's first part in pure sh, then had to focus on other stuff. Not really interested in competing, so maybe I could try to catch up when I have more time.
Stallman · 2021-12-01 19:38
I'll try to participate, hopefully it works without logging in using one of those cancer services. Probably not going to stick around to the end, but it would be fun. Solved the first one in Perl and Python, but I'm planning to do Lua too to get a good feeling for their differences.
Trinity · 2021-12-01 20:16
>>28722 >>28724 >>28729 post your solutions, it's always interesting to see how other people do it
if · 2021-12-01 20:27
was there not an alt website that offered data and solution without the need to login?
Yamaoto Toshi · 2021-12-01 20:34
my solution in haskell incr :: [Int] -> Int incr xs = length . filter (< 0) $ zipWith (-) xs (tail xs) threeWindow :: [Int] -> [Int] threeWindow xs = zipWith3 (\x y z -> x + y + z) xs (tail xs) (drop 2 xs) main :: IO() main = do filecontent <- readFile "input" let m = map (\x -> read x :: Int) (lines filecontent) print $ incr m print . incr . threeWindow $ m
Dr. X · 2021-12-01 22:56
I made a leaderboard, for anyone interested: 388839-baef610d Day 1 in Common Lisp: ;; Omitting parse-lines from my utils file from last year. It does what you probably think it does (defparameter +input+ (parse-lines #'parse-integer)) (defun solve-part-1 () ;; CL loop's `:for ... :on` is a perfect contender for this problem! (loop :for (a b) :on +input+ :while b :count (> b a))) ;; I wanted to iterate over 3/4 items at a time as a "better" solution, but I've found making a throwaway list to be plainly easier for myself. (defun sliding-sums () (loop :for (a b c) :on +input+ :while c :collect (+ a b c))) (defun solve-part-2 () (loop :for (a b) :on (sliding-sums) :while b :count (> b a)))
SHODAN · 2021-12-01 23:47
Finished day 1 https://github.com/williamblair/adventofcode2021 Last year I did up to day 18, we'll see how far I do this year. >>28743 Joined!
hash table · 2021-12-02 01:36
I'm taking this as an opportunity to learn APL; here's my solution for today: ⍝ our dataset ex←⍎⎕FIO[49]'input-1.txt' ⍝ first problem sl←{+/∊</¯1 1↓¨2/⊂⍵} an←sl ex ⍝ second problem e∆←{∊+/(-⍺-1)↓¨(1-⍨⍳⍺)⌽¨⍺/⊂⍵} a∆←sl 3e∆ ex Would appreciate comments, it's my first time writing APL outside textbook exercises; it is quite fun.
McCarthy · 2021-12-02 08:14
>>28729 okay, here they are for day 1: #!/usr/bin/python3 import sys increases = 0 old_value = None for line in sys.stdin: value = int(line.rstrip('\n')) if old_value: increases += 1 if value > old_value else 0 print(value, '({})'.format('increased' if value > old_value else 'decreased' if value < old_value else 'same')) else: print(value, '(N/A no previous value)') old_value = value print('total of {} increases'.format(increases)) #!/usr/bin/perl use strict; use warnings; my $increased = 0; my $old = undef; sub compare { my $arg = $_[0]; if (!defined $old) { printf "%d (N/A no previous value)\n", $arg; return $arg; } printf "%d (%s)\n", $arg, $arg > $old ? 'increased' : $arg < $old ? 'decreased' : 'same'; $increased += $arg > $old; return $arg; } foreach (<STDIN>) { chomp($_); $old = compare($_ + 0); } printf "total of %d increases\n", $increased; Keep in mind I don't really know perl, I'm trying to learn. Here is day 2: #!/usr/bin/python3 import sys class Submarine: def __init__(self): self.position = 0 self.depth = 0 self.direction_lookup = { 'forward': (0, 1, 1), 'up': (1, 0, -1), 'down': (1, 0, 1) } print('position', self.position, self.depth) def encode_position(self): return self.position * self.depth def move(self, direction, units): try: vertical, horizontal, multiplier = self.direction_lookup[direction] self.position += horizontal * multiplier * units self.depth += vertical * multiplier * units print('new position', self.position, self.depth) except KeyError: print('invalid command') sub = Submarine() for line in sys.stdin: assert ' ' in line direction, units = line.rstrip('\n').split() print(direction, units) sub.move(direction, int(units)) print('distance {}'.format(sub.encode_position()))
Nameless · 2021-12-02 09:06
here is my day 2 solution: (use-modules (ice-9 rdelim) (ice-9 match) (srfi srfi-1)) (define (get-lines port trans) (let loop [(line (read-line port)) (lines '())] (if (eof-object? line) (reverse lines) (loop (read-line port) (cons (trans line) lines))))) (define in (call-with-input-file "input" (lambda (p) (get-lines p (lambda (l) (match-let [((cmd val) (string-split l #\space))] (cons (string->symbol cmd) (string->number val)))))))) (define (problem-1 cmds) (apply * (fold (lambda (curr-cmd state) (match-let [((cmd . val) curr-cmd) ((pos depth) state)] (cond [(eq? 'forward cmd) `(,(+ pos val) ,depth)] [(eq? 'down cmd) `(,pos ,(+ depth val))] [(eq? 'up cmd) `(,pos ,(- depth val))]))) '(0 0) cmds))) (define (problem-2 cmds) (apply * (list-head (fold (lambda (curr-cmd state) (match-let [((cmd . val) curr-cmd) ((pos depth aim) state)] (cond [(eq? 'forward cmd) `(,(+ pos val) ,(+ depth (* aim val)) ,aim)] [(eq? 'down cmd) `(,pos ,depth ,(+ aim val))] [(eq? 'up cmd) `(,pos ,depth ,(- aim val))]))) '(0 0 0) cmds) 2))) (format #t "~a~%~a~%" (problem-1 in) (problem-2 in)) t. your friendly schemer
setq · 2021-12-02 09:12
>>28750 I've also done lua this time, it's an interesting language #!/usr/bin/lua --https://www.lua.org/pil/16.html Submarine = { position = 0, depth = 0, direction_lookup = { ['forward'] = {0, 1, 1}, ['up'] = {1, 0, -1}, ['down'] = {1, 0, 1} } } function Submarine:new (o) o = o or {} setmetatable(o, self) self.__index = self print('position', self.position, self.depth) return o end function Submarine:move (direction, units) a = self.direction_lookup[direction] self.position = self.position + a[2] * a[3] * units self.depth = self.depth + a[1] * a[3] * units print('new position', self.position, self.depth) end function Submarine:encode_position () return self.position * self.depth end sub = Submarine:new() while true do local line = io.read() if line == nil then break end _, _, direction, units = string.find(line, "(%a+)%s(%d+)") print(direction, units) if not pcall(sub.move, sub, direction, tonumber(units)) then print('invalid command') end end print('distance', sub:encode_position())
The Phantom Phreak · 2021-12-02 09:40
Interestingly, the format used is compatible with Tcl lists, so no parsing needed. First problem: #!/usr/bin/env tclsh set data [read [open [lindex $argv 0]]] foreach cur $data next [lrange $data 1 end] { if {$next > $cur} { incr count } } puts "Increase count: $count" Second: #!/usr/bin/env tclsh namespace path {::tcl::mathop ::tcl::mathfunc} foreach {dir dist} [read [open [lindex $argv 0]]] { switch $dir { forward {incr hor $dist} down {incr depth $dist} up {incr depth -$dist} } } puts "Horizontal position: $hor, depth: $depth, total: [* $hor $depth]"
Armitage · 2021-12-02 09:44
>>28756 did you just repost the same post after deleting it with no changes? still, your solution is pretty genius and makes want to learn tcl
nil · 2021-12-02 09:47
>>28757 I did, fuarrrked up my post by trying to use the code tag.
J.C. Denton · 2021-12-02 10:09
>>28732 >>28724 View discretion advised #!/bin/sh while IFS= read -r num; do count=$((num > ${prev-num} ? count+1 : count)) prev=$num done < "input.txt" echo $count
John Titor · 2021-12-02 10:18
>>28756 I actually failed the first one, here's the fixed version: #!/usr/bin/env tclsh set data [read [open [lindex $argv 0]]] foreach cur [lrange $data 0 end-1] next [lrange $data 1 end] { if {$next > $cur} { incr count } } puts "Increase count: $count" but it's inefficient and ugly, this one is better: #!/usr/bin/env tclsh foreach cur [lassign [read [open [lindex $argv 0]]] prev] { if {$cur > $prev} { incr count } set prev $cur } puts "Increase count: $count"
nibble · 2021-12-02 11:37
I'm using this AoC as an excuse to learn Ocaml which I started looking at a few months ago before quickly becoming too busy with school. I'd appreciate if someone more experienced could point out if these questions could be better written. (* eliding some helper functions to read input into a list of strings *) (* q1 *) let rec diffs = function | a::b::c -> b - a :: (diffs (b :: c)) | _ -> [];; let rec window_diffs = function | a1::a2::a3::b1::xs -> b1 - a1 :: window_diffs (a2::a3::b1::xs) | _ -> [];; let q1 l = diffs l |> List.filter (fun x -> x > 0) |> List.length let q2 l = window_diffs l |> List.filter (fun x -> x > 0) |> List.length (* q2 *) type command = | Forward of int | Down of int | Up of int;; type position = int * int;; let command_of_str str = try Scanf.sscanf str "%s %d" (fun c i -> match c.[0] with | 'f' -> Some(Forward i) | 'd' -> Some(Down i) | 'u' -> Some(Up i) | _ -> None) with End_of_file -> None;; let process_com_1 (h, d) = function | Forward i -> (h +i, d) | Down i -> (h, d+i) | Up i -> (h, d-i) type bearing = int * int * int;; let process_com_2 (h, d, a) = function | Forward i -> (h +i, d + (a * i), a) | Down i -> (h, d, a+i) | Up i -> (h, d, a-i) let q1 l = let (h, d) = List.fold_left process_com_1 (0, 0) l in h * d;; let q2 l = let (h, d, _) = List.fold_left process_com_2 (0, 0, 0) l in h * d;;
Naomi Nascimento · 2021-12-02 14:47
hope you will pull through my fellow lains
swap · 2021-12-02 14:56
>>28759 The (()) forms are a bashism, your /bin/sh is probably symlinked to /bin/bash if this code runs. Might wanna change that if you want to write "pure sh".
overriding · 2021-12-02 15:05
>>28768 https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/V3_chap02.html#tag_18_06_04 Now you can drown in shame.
Iverson · 2021-12-02 15:19
>>28768 panik >>28769 kalm Thank you anon <3
Demeere · 2021-12-02 15:30
day 2 position [] h v = (h,v) position (x:xs) h v | fst x == "up" = position xs h (v-snd x) | fst x == "down" = position xs h (v+snd x) | otherwise = position xs (h+snd x) v aim [] _ h v = (h,v) aim (x:xs) a h v | fst x == "up" = aim xs (a-snd x) h v | fst x == "down" = aim xs (a+snd x) h v | otherwise = aim xs a (h+snd x) (v+(snd x * a)) main :: IO() main = do filecontent <- readFile "input" let movement = map ((\[x,y] -> (x,read y :: Int)) . words) (lines filecontent) print $ uncurry (*) $ position movement 0 0 print $ uncurry (*) $ aim movement 0 0 0
Unsigned · 2021-12-02 15:31
I'm just using plain C++. A little programming keeps me from losing my mind at my IT monkey job. >>28756 >>28761 Neat! The only time I've heard about anyone using Tcl is on the sqlite website because the Tcl bindings seem to be the author's favorite.
Incognito · 2021-12-02 15:40
>>28769 Oh, interesting! Seems I was wrong '^^ Is it a new feature in the 2018 standard?
BloodCat · 2021-12-02 16:13
2nd day, in APL: ⍝ x y forward←{⍵ 0}◊down←{0 ⍵}◊up←{0 (-⍵)} ⍝ first problem in←⍎⎕FIO[49]'input-2.txt' an←×/∊+/in ⍝ second problem h∆←∊1↑¨in ⍝ horz. variation i∆←∊+\1↓¨in ⍝ aim variation a∆←×/+/¨h∆ (h∆×i∆) I was having trouble with the second part since I thought of it in terms of a left fold over the input list, accumulating the x, y and aim; which is quite natural, but turns out to be rather awkward to express in APL (at least from what I've tried). Eventually I realized I could "scan" (like fold, but returns the intermediate values) over the vertical variation to get the aim values, then just multiply with the horizontal variation and fold as expected. What functional programming does to your brain...
Splicer · 2021-12-02 16:27
>>28773 It has always been here (cf 2008 edition: https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/) . You may confuse it with [[]] which is indeed not portable. A bit unrelated, here's a nice sh portability enhancer: if ! sh -c 'fun() { local a=1; }; fun' then if sh -c 'fun() { typeset a=1; }; fun' then alias local=typeset else echo "local/typeset not supported by sh, aborting" exit 1 fi fi I also have a pure POSIX sh readlink -f implementation, which is a massive pain to have in every script (cause you can't even source another file without it).
array · 2021-12-02 22:48
I'm seeing how far I can get with C. Day1_Task1 #include <stdio.h> #include <stdlib.h> int main(void) { FILE *fp; char *line = NULL; size_t len = 0; ssize_t read; fp = fopen("input.txt", "r"); if (fp == NULL) exit(EXIT_FAILURE); int prev_num = 0; int increase_count = 0; read = getline(&line, &len, fp); prev_num = atoi(line); while ((read = getline(&line, &len, fp)) != -1) { if (atoi(line) > prev_num) increase_count++; prev_num = atoi(line); } printf("%d\n", increase_count); fclose(fp); return 0; } Day1_Task2 #include <stdio.h> #include <stdlib.h> #define BUFFER_SIZE 3 int main(void) { FILE *fp; char *line = NULL; size_t len = 0; ssize_t read; fp = fopen("input.txt", "r"); if (fp == NULL) exit(EXIT_FAILURE); int increase_count = 0; int buffer[BUFFER_SIZE] = {0, 0, 0}; for (int i = 0; i < BUFFER_SIZE; i++) { read = getline(&line, &len, fp); buffer[i] = atoi(line); } /* 199 A * 200 A B * 208 A B C * 210 B C D * 200 E C D * 207 E F D * 240 E F G * 269 F G H * 260 I G H * 263 I J H * * Sum the As, Bs, Cs etc. then compare sumA and sumB, * then sumB and sumC, sumC and sumD, etc. * * Because they're sums, only need to compare the numbers * that aren't shared. So in the first example, instead of * comparing 199+200+208 against 200+208+210, we can compare * 199 against 210. * * buffer has 3 spaces. As file is read, buffer will store * the numbers to compare. * buffer[0]: First value of current sum * buffer[1]: First value of next sum * buffer[2]: First value of the sum after next * * Each iteration, get last value of next sum, compare * first value of current sum against last value of * next sum, then move everthing down in the buffer by 1. * */ while ((read = getline(&line, &len, fp)) != -1) { if (atoi(line) > buffer[0]) increase_count++; buffer[0] = buffer[1]; buffer[1] = buffer[2]; buffer[2] = atoi(line); } printf("%d\n", increase_count); fclose(fp); return 0; } Day2_Task1 #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { FILE *fp; char *line = NULL; size_t len = 0; ssize_t read; /* for spltting string */ char *action; fp = fopen("input.txt", "r"); if (fp == NULL) exit(EXIT_FAILURE); int h_pos = 0; int depth = 0; while ((read = getline(&line, &len, fp)) != -1) { action = strsep(&line, " "); if (strcmp("forward", action) == 0) h_pos += atoi(strsep(&line, " ")); else if (strcmp("down", action) == 0) depth += atoi(strsep(&line, " ")); else if (strcmp("up", action) == 0) depth -= atoi(strsep(&line, " ")); } printf("%d\n", h_pos*depth); fclose(fp); return 0; } Day2_Task2 #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { FILE *fp; char *line = NULL; size_t len = 0; ssize_t read; /* for spltting string */ char *action; int amount; fp = fopen("input.txt", "r"); if (fp == NULL) exit(EXIT_FAILURE); int h_pos = 0; int depth = 0; int aim = 0; while ((read = getline(&line, &len, fp)) != -1) { action = strsep(&line, " "); if (strcmp("forward", action) == 0) { amount = atoi(strsep(&line, " ")); h_pos += amount; depth += aim*amount; } else if (strcmp("down", action) == 0) aim += atoi(strsep(&line, " ")); else if (strcmp("up", action) == 0) aim -= atoi(strsep(&line, " ")); } printf("%d\n", h_pos*depth); fclose(fp); return 0; }
Just another Random Lainon · 2021-12-02 22:49
>>28778 Sorry about the formatting, lain seems to have eaten my tabs.
Case · 2021-12-02 22:52
Day 2 is still straightforward: (defparameter +input+ (parse-lines (lambda (line) (destructuring-bind (cmd arg) (split-sequence #\Space line) (cons (intern (string-upcase cmd) :keyword) (parse-integer arg)))))) (defun solve-part-1 () (loop :with breadth := 0 :with depth := 0 :for (cmd . mag) :in +input+ :do (ecase cmd (:down (incf depth mag)) (:up (decf depth mag)) (:forward (incf breadth mag))) :finally (return (* depth breadth)))) (defun solve-part-2 () (loop :with aim := 0 :with breadth := 0 :with depth := 0 :for (cmd . mag) :in +input+ :do (ecase cmd (:down (incf aim mag)) (:up (decf aim mag)) (:forward (incf breadth mag) (incf depth (* aim mag)))) :finally (return (* depth breadth)))) All hail Moloch, eater of tab indentation
Tequila · 2021-12-03 08:51
Day 3 starting to become a little more convoluted. What happens if there is no dominant 1 or 0 at some position? I hope the elfs don't use this in production. #!/usr/bin/python3 import sys class Decoder: def __init__(self, width): self.width = width self.ones = [0] * width self.zeroes = [0] * width self.gamma_rate = 0 self.epsilon_rate = 0 def decode_line(self, line): assert len(line) == self.width for i in range(len(line)): self.zeroes[i] += 1 - int(line[i]) self.ones[i] += int(line[i]) def finalize(self): assert len(self.ones) == len(self.zeroes) length = len(self.ones) for i in range(length): self.gamma_rate += (1 if self.ones[i] > self.zeroes[i] else 0) * 2 ** (length - i - 1) self.epsilon_rate += (1 if self.zeroes[i] > self.ones[i] else 0) * 2 ** (length - i - 1) # annoying first pass to init list line = input() dec = Decoder(len(line)) dec.decode_line(line) for line in sys.stdin: line = line.rstrip('\n') dec.decode_line(line) dec.finalize() print(dec.gamma_rate, dec.epsilon_rate, dec.gamma_rate * dec.epsilon_rate)
Unsigned · 2021-12-03 09:31
Is it me or you can't get the second part without logging into their gay soykafe? Anyway, 3rd in Tcl, I noticed that Tcl is retarded on multiple fronts: * binary format pads with 0 AT THE fuarrrkING END, completely retarded. tclsh <<< 'chan configure stdout -translation binary; puts -nonewline [binary format B5 "10110"]' | xxd -b 00000000: 10110000 * No support for unsigned integers, so I can't use bitwise negation, and no bit vectors like CL, so I use map like a peasant. #!/usr/bin/env tclsh namespace path ::tcl::mathop proc bin2num {binstr} { binary scan [binary format B64 [format %064s $binstr]] W dec return $dec } set data [read [open [lindex $argv 0]]] set sum [lmap i {0 1 2 3 4} { + {*}[lmap s $data {string index $s $i}] }] set Y_bin_digits [lmap x $sum {> $x [/ [llength $data] 2]}] set E_bin_digits [lmap b $Y_bin_digits {! $b}] set Y_bin [join $Y_bin_digits ""] set E_bin [join $E_bin_digits ""] set Y [bin2num $Y_bin] set E [bin2num $E_bin] puts "γ: $Y, ε: $E, power consumption: [* $Y $E]" PS: who the fuarrrk on Lainchan's admin team thought discarding tabulations in code tags was a good idea?
Hopper · 2021-12-03 10:19
So here is mine for Day 3. It took me longer than I expected. (use-modules (ice-9 rdelim) (ice-9 match) (srfi srfi-1)) (define (get-lines filename trans) (call-with-input-file filename (lambda (port) (let loop [(line (read-line port)) (lines '())] (if (eof-object? line) (reverse lines) (loop (read-line port) (cons (trans line) lines))))))) (define in (get-lines "input" (lambda (s) (map (lambda (c) (- (char->integer c) 48)) (string->list s))))) (define (count-bits bin) (fold (lambda (num cnt) (map + num cnt)) (iota (length (car bin)) 0 0) bin)) (define (problem-1 bin) (let* [(len-half (/ (length bin) 2)) (counts (count-bits bin)) (counts->number (lambda (compare) (string->number (list->string (map (lambda (cnt) (if (compare cnt len-half) #\1 #\0)) counts)) 2))) (gamma (counts->number >=)) (epsilon (counts->number <))] (* gamma epsilon))) (define (num-search bin compare bit) (if (= 1 (length bin)) (string->number (list->string (map (lambda (b) (if (= b 1) #\1 #\0)) (car bin))) 2) (let* [(len-half (/ (length bin) 2)) (bit-count (list-ref (count-bits bin) bit)) (keep-1s (compare bit-count len-half)) (candidates (filter (lambda (num) (eq? (= 1 (list-ref num bit)) keep-1s)) bin))] (num-search candidates compare (1+ bit))))) (define (problem-2 bin) (let [(oxygen (num-search bin >= 0)) (co2 (num-search bin < 0))] (* oxygen co2))) (format #t "~a~%~a~%" (problem-1 in) (problem-2 in))
Nguoi La · 2021-12-03 12:54
>>28785 It's not you, I'm not logged in either and before >>28778, I didn't even notice there was supposed to be a part 2. Don't care either way, not going to log in, less work per day I suppose. Anyways, it's surprising to see tcl lack unsigned integers and bit vectors. >discarding tabulations just use spaces lmao
hash table · 2021-12-03 14:27
day 3 in crystal, I feel so dirty for not managing to compress it into 30 lines max like other people can :(
Zuse · 2021-12-03 16:23
>>28789 I would say lines of code aren't the most important metric in the world. There are other things such as algorithmic design decisions. For example, iterating a list multiple times or requiring all input data to be loaded into memory. Thank you for your crystal contribution.
McCarthy · 2021-12-03 16:52
>>28790 Sure. During work, that's much more important. But when it comes to pieces like this where speed is not that important and maintainability is moot, I can't help but admire those densely packed solutions the guys who mastered the language put together. I like to watch what the crystal core team puts out, it makes me feel like a failure but I also learn a bunch every time
Technician · 2021-12-04 02:23
Hello, friend. We are tied right now. Let's be rivals!
vector · 2021-12-04 12:29
It got harder suddenly. With all this soykaf to mutate, I realize pure functional scripting (without creating a data type) may get hard: #!/usr/bin/env tclsh namespace path ::tcl::mathop package require textutil::split set BW 5; # Board width set BH 5; # Board height proc lincr {_list index {increment 1}} { upvar $_list list lset list $index [+ [lindex $list $index] $increment] } # Boards are of the form {nums row_tally col_tally unmarked_sum winner} proc parse_data {path} { global BW BH set chan [open $path] set draws [split [gets $chan] ,] foreach board [textutil::split::splitx [read $chan] {\n\n}] { lappend boards [list $board [lrepeat $BH 0] [lrepeat $BW 0] [+ {*}$board] 0] } close $chan return [list $draws $boards] } proc update_board {draw board} { global BW BH lassign $board nums rowtally coltally remsum set i [lsearch -exact $nums $draw] if {$i == -1} { return $board } set row [/ $i $BW] set col [% $i $BW] lincr rowtally $row lincr coltally $col incr remsum -[lindex $nums $i] set win [expr {[lindex $rowtally $row] == $BW || [lindex $coltally $col] == $BH}] return [list $nums $rowtally $coltally $remsum $win] } proc play_turn {_boards draw} { upvar 1 $_boards boards set winner {} for {set i 0} {$i < [llength $boards]} {incr i} { if {[lindex $boards $i 4] == 1} { continue } lset boards $i [update_board $draw [lindex $boards $i]] if {[lindex $boards $i 4] == 1} { set winner $i } } return $winner } lassign [parse_data [lindex $argv 0]] draws boards foreach draw $draws { set winner [play_turn boards $draw] if {$winner ne ""} { incr wincount set score [* [lindex $boards $winner 3] $draw] set lastwinner $winner if {$wincount == 1} { puts "First winner: $winner, score: $score" } elseif {$wincount == [llength $boards]} { break } } } puts "Last winner: $lastwinner, score: $score"
H.R. Giger · 2021-12-04 14:15
pub fn solve(input: &str) -> (u32, u32) { let mut iter = input.split("\n\n"); let numbers = iter.next().unwrap().split(',').map(|s| s.parse().unwrap()); let mut boards: Vec<Vec<_>> = iter .map(|s| { s.lines() .flat_map(|s| s.split_whitespace().map(|s| (s.parse::<u32>().unwrap() << 1) | 1)) .collect() }) .collect(); let size = (boards[0].len() as f64).sqrt() as usize; let check = |board: &mut [u32], drawn| { board.iter_mut().for_each(|n| *n = if *n >> 1 == drawn { 0 } else { *n }); let drawn = |y, x| board[y * size + x] & 1 == 0; (0..size).any(|y| (0..size).all(|x| drawn(y, x)) || (0..size).all(|x| drawn(x, y))) }; let mut first = 0; let mut last = 0; for drawn in numbers { let mut i = 0; while i < boards.len() { if check(&mut boards[i], drawn) { let score = boards.swap_remove(i).iter().map(|&n| n >> 1).sum::<u32>() * drawn; first += u32::from(first == 0) * score; last = score; } else { i += 1; } } } (first, last) }
Roger Pollack · 2021-12-04 14:22
Not much time today, but I'm not stopping. Here is my poorly crafted and rushed solution for today: #!/usr/bin/python3 import sys class Board: def __init__(self): self.matrix = [] self.marks = [] self.columns = 0 self.winner = False self.last_draw = 0 def __str__(self): return '\n'.join([ '\t'.join(str(e) for e in row) for row in self.matrix ]) def decode(self, line): elements = ' '.join(line.split()).split(' ') self.columns = len(elements) self.matrix.append([ [int(e), False] for e in elements ]) def mark(self, draw): self.last_draw = draw for row in self.matrix: for element in row: if draw == element[0]: element[1] = True def row_check(self, i): for j in range(self.columns): if not self.matrix[j][i][1]: return False return True def column_check(self, i): for j in range(self.columns): if not self.matrix[i][j][1]: return False return True def check_win(self): possible_wins = [ True for e in range(self.columns) ] for i in range(self.columns): horizontal = self.row_check(i) vertical = self.column_check(i) if (not horizontal) and (not vertical): possible_wins[i] = False continue for i in range(self.columns): if possible_wins[i]: self.winner = True def final_score(self): score = 0 for row in self.matrix: for element in row: if not element[1]: score += element[0] return score * self.last_draw def someone_wins(draws, boards): for draw in draws: print('drawing', draw) # three passes, because there can be multiple winners for board in boards: board.mark(draw) for board in boards: board.check_win() for board in boards: if board.winner: return True return False draws = [ int(e) for e in input().split(',') ] boards = [] for line in sys.stdin: if line == '\n': boards.append(Board()) continue boards[-1].decode(line.rstrip('\n')) if someone_wins(draws, boards): for board in boards: if board.winner: print('board has won:\n', board) print('final score:', board.final_score())
Judge Fang · 2021-12-04 17:45
Here is my todays stuff. Difficulty is slowly but surely increasing. (use-modules (ice-9 rdelim) (ice-9 match) (srfi srfi-1) (srfi srfi-8)) (define (get-input filename) (call-with-input-file filename (lambda (port) (let [(bingo-nums (map string->number (string-split (read-line port) #\,)))] (read-line port) (let loop [(line (read-line port)) (board '()) (boards '())] ;;(when (string? line) (format #t "len ~a, ~a~%" (string-length line) line)) (cond [(eof-object? line) (cons bingo-nums (reverse (cons (reverse board) boards)))] [(= 0 (string-length line)) (loop (read-line port) '() (cons (reverse board) boards))] [else (loop (read-line port) (cons (map string->number (remove string-null? (string-split line #\space))) board) boards)])))))) (define in (get-input "input")) (define (and-f a . b) (fold (lambda (a b) (and a b)) a b)) (define (or-f a b) (or a b)) (define (is-winner? marks) (or ;;rows (fold (lambda (row prev) (or prev (fold and-f #t row))) #f marks) ;;cols (fold or-f #f (apply map and-f marks)))) (define (get-winner num boards boards-marks) (let loop [(boards boards) (boards-marks boards-marks)] (cond [(null? boards-marks) #f] [(is-winner? (car boards-marks)) (list num (car boards) (car boards-marks))] [else (loop (cdr boards) (cdr boards-marks))]))) (define (play-board num board marks) (map (lambda (b-line m-line) (map (lambda (b-spot m-spot) (or (= b-spot num) m-spot)) b-line m-line)) board marks)) (define (play-number num boards boards-marks) (map (lambda (board marks) (play-board num board marks)) boards boards-marks)) (define (compute-result num board marks) (* num (apply + (map (lambda (marks-row board-row) (apply + (map (lambda (marked? val) (if marked? 0 val)) marks-row board-row))) marks board)))) (define (problem-1 nums boards) (match-let* [(board-n (length boards)) (boards-marks (make-list board-n (make-list 5 (make-list 5 #f)))) ((num board marks) (let loop [(num-prev -1) (nums nums) (boards-marks boards-marks)] (cond [(get-winner num-prev boards boards-marks)] [(null? nums) #f] [else (loop (car nums) (cdr nums) (play-number (car nums) boards boards-marks))])))] (compute-result num board marks))) (define (problem-2 nums boards) (match-let* [(board-n (length boards)) (boards-marks (make-list board-n (make-list 5 (make-list 5 #f))))] (let loop-1 [(nums nums) (boards boards) (boards-marks boards-marks)] (let loop-2 [(boards-next '()) (marks-next '()) (boards boards) (boards-marks boards-marks)] (match-let* [((board . boards-remain) boards) ((marks . marks-remain) boards-marks) (num (car nums)) (played-marks (play-board num board marks)) (winner? (is-winner? played-marks)) ;;has current board just won? (boards-next (if winner? boards-next (cons board boards-next))) ;;it doesn't go to next round (marks-next (if winner? marks-next (cons played-marks marks-next)))] (cond [(and (null? boards-next) (null? boards-remain) winner?) (compute-result num board played-marks)] ;;only board left and won [(null? boards-remain) ;;no board remain for this number (loop-1 (cdr nums) boards-next marks-next)] [else ;;test next remaining boards for this number (loop-2 boards-next marks-next boards-remain marks-remain)])))))) (format #t "~a~%~a~%" (problem-1 (car in) (cdr in)) (problem-2 (car in) (cdr in)))
Motoko Kusanagi · 2021-12-05 00:16
I ended up skipping yesterday yesterday, have it today instead: ⍝ binary → decimal dec←{+/⍵×⌽2*(⍳⍴⍵)-1} ⍝ first problem in←⎕FIO[49]'input-3.txt' i∆←⊃⍎¨¨in cb←{0≤×+⌿(¯1 1)[⍵+1]} an←{(dec ⍵)×(dec ~⍵)}cb i∆ ⍝ second problem ⍝ c∆←⊃(↑⍴i∆)/⊂cb i∆ ⍝ fn←{({⍵=cb ⍵}⍵[;⍺])⌿⍵} ⍝ the initial plan was \ with something like {({⍵=cb ⍵}⍵[;⍺])⌿⍵} and picking the ⍝ 1st with length 1, but it refuses (i'm not sure i properly understand scan yet) ⍝ also, gnu apl doesn't support guards, and i would also need a way to ⍝ specify the most or least common, so expanding on that strategy ⍝ wouldn't end up much different from this. ⍝ still can't think of a much better solution than a recursive function ⍝ with explicit control flow... ∇ z←n solve[x] m; ⍝ axis is a gnu extension →(1<↑⍴m)/3 z←m◊→end z←∊(1+n) solve[x] ((~⍣x) {⍵=cb ⍵}m[;n])⌿m end: ∇ a∆←{(dec 1 solve[0] ⍵)×(dec 1 solve[1] ⍵)}i∆ The solution to the 2nd problem doesn't feel to me like something I should be writing in APL, but I'm also not sure if I have much of a framework to judge what I should and should not be writing yet. Probably should find somebody else doing APL to peek at their answers later or something, could be enlightening. I've came to realize that I had somehow read and conveniently forgotten that APL, a language about manipulating arrays, happens to have multidimensional arrays that behave helpfully; who would have thought! This makes my solution to day 2 slightly more concise: ⍝ x y forward←{⍵ 0}◊down←{0 ⍵}◊up←{0 (-⍵)} ⍝ first problem in←⊃⍎⎕FIO[49]'input-2.txt' an←×/+⌿in ⍝ second problem h∆←in[;1]◊i∆←+\in[;2] a∆←×/+/⊃h∆ (h∆×i∆) Makes me wonder what else I could be missing. It isn't early now so I'm likely to do today tomorrow, hope with that I'm not dooming myself to being ever a day behind. Might do some of the harder problems in a language I can think about better if that becomes the case; kind of defeats the purpose, though.
Frank Garza · 2021-12-05 10:29
Day 5 ended up being pretty fun #!/usr/bin/env python3 import sys import re class Plot: def __init__(self): self.width = 0 self.height = 0 self.pixels = [] def __str__(self): return '\n'.join([ str(row) for row in self.pixels ]) def higher(self, y1, y2): return y1 > self.height or y2 > self.height def wider(self, x1, x2): return x1 > self.width or x2 > self.width def resize(self, x1, y1, x2, y2): if self.higher(y1, y2): m = max(y1, y2) + 1 for i in range(m - self.height): self.pixels.append([0] * self.width) self.height = m if self.wider(x1, x2): m = max(x1, x2) + 1 for row in self.pixels: for i in range(m - self.width): row.append(0) self.width = m def line(self, x1, y1, x2, y2): print('({}, {}) -> ({}, {})'.format(x1, y1, x2, y2)) if (x1 != x2) and (y1 != y2): print('not a straight line') return # if necessary add to grid self.resize(x1, y1, x2, y2) # vertical line if x1 == x2: for i in range(min(y1, y2), max(y1, y2) + 1): self.pixels[i][x1] += 1 # horizontal line elif y1 == y2: for i in range(min(x1, x2), max(x1, x2) + 1): self.pixels[y1][i] += 1 print(self) def get_danger_points(self): return sum([ sum(1 if pixel > 1 else 0 for pixel in row) for row in self.pixels]) plot = Plot() pattern = re.compile(r"^([0-9]+),([0-9]+) -> ([0-9]+),([0-9]+)$") for line in sys.stdin: line = line.rstrip('\n') match = re.search(pattern, line) if match: plot.line(int(match.group(1)), int(match.group(2)), int(match.group(3)), int(match.group(4))) print(plot.get_danger_points())
protected · 2021-12-05 11:18
Strangely easy compared to yesterday. #!/usr/bin/env tclsh namespace path {::tcl::mathop ::tcl::mathfunc} proc lincr {_list args} { upvar $_list list lset list {*}$args [+ [lindex $list {*}$args] 1] } set grid [lrepeat 10 [lrepeat 10 0]] set chan [open [lindex $argv 0]] while {[gets $chan line] >= 0} { regexp {^(\d+),(\d+) -> (\d+),(\d+)$} $line -> sx sy ex ey if {$sx == $ex} { for {set i [min $sy $ey]} {$i <= [max $sy $ey]} {incr i} { lincr grid $i $sx } } elseif {$sy == $ey} { for {set i [min $sx $ex]} {$i <= [max $sx $ex]} {incr i} { lincr grid $sy $i } } } puts [+ {*}[lmap x [concat {*}$grid] {> $x 1}]]
Trinity · 2021-12-05 12:04
Today was a fast one. (use-modules (ice-9 rdelim) (ice-9 match) (srfi srfi-1) (srfi srfi-43)) (define (get-lines filename trans) (call-with-input-file filename (lambda (port) (let loop [(line (read-line port)) (lines '())] (if (eof-object? line) (reverse lines) (loop (read-line port) (cons (trans line) lines))))))) (define in (get-lines "input" (lambda (line) (match-let* [((x1s mid y2s) (string-split line #\,)) (x1 (string->number x1s)) (y2 (string->number y2s)) ((y1s _ x2s) (string-split mid #\space)) (y1 (string->number y1s)) (x2 (string->number x2s))] `((,x1 ,y1) (,x2 ,y2)))))) (define vert-horizont (filter (match-lambda [((x1 y1) (x2 y2)) (or (= x1 x2) (= y1 y2))]) in)) (define boundaries (fold (lambda (line p-max) (match-let* [(((x1 y1) (x2 y2)) line) ((xm ym) p-max)] `(,(max xm x1 x2) ,(max ym y1 y2)))) '(0 0) in)) (define (d a2 a1) (if (= a2 a1) 0 (/ (- a2 a1) (abs (- a2 a1))))) (define (solution lines boundaries) (match-let* [((xmax ymax) boundaries) (diagram (make-vector (* (1+ xmax) (1+ ymax)) 0))] (for-each (match-lambda [((x1 y1) (x2 y2)) (let [(dx (d x2 x1)) (dy (d y2 y1))] (do [(xi x1 (+ xi dx)) (yi y1 (+ yi dy))] ((and (= xi (+ x2 dx)) (= yi (+ y2 dy)))) ;;(format #t "(~a ~a)->(~a ~a)->(~a ~a)~%" x1 y1 xi yi x2 y2) (let* [(i (+ xi (* yi xmax))) (val (vector-ref diagram i))] (vector-set! diagram i (1+ val)))))]) lines) (vector-count (lambda (i el) (>= el 2)) diagram))) (format #t "~a~%~a~%" (solution vert-horizont boundaries) (solution in boundaries))
Trinity · 2021-12-05 12:06
>>28808 Only fast because I didn't resize... man, Tcl lacking matrix (and the module in Tcllib is garbage) doesn't make it fun. #!/usr/bin/env tclsh namespace path {::tcl::mathop ::tcl::mathfunc} proc lincr {_list args} { upvar $_list list lset list {*}$args [+ [lindex $list {*}$args] 1] } set grid [lrepeat 10 [lrepeat 10 0]] lassign {0 0} w h set chan [open [lindex $argv 0]] while {[gets $chan line] >= 0} { regexp {^(\d+),(\d+) -> (\d+),(\d+)$} $line -> sx sy ex ey # Resize if needed set nw [+ [max $sx $ex] 1] set nh [+ [max $sy $ey] 1] if {$nw > $w} { for {set i 0} {$i < $h} {incr i} { lset grid $i [concat [lindex $grid $i] [lrepeat [- $nw $w] 0]] } set w $nw } if {$nh > $h} { lappend grid [lrepeat [- $nh $h] [lrepeat $w 0]] set h $nh } if {$sx == $ex} { for {set i [min $sy $ey]} {$i <= [max $sy $ey]} {incr i} { lincr grid $i $sx } } elseif {$sy == $ey} { for {set i [min $sx $ex]} {$i <= [max $sx $ex]} {incr i} { lincr grid $sy $i } } } puts [+ {*}[lmap x [concat {*}$grid] {> $x 1}]]
↑ · 2021-12-05 15:00
day2, just started @AllArgsConstructor public class SubmarineStrategy { private Submarine submarine = new Submarine(); public void followStrategy(FileReaderAOC fileReaderAOC) throws IOException { fileReaderAOC.eatUpAllLines(); List<String> directions = fileReaderAOC.getAllElements(); for(String directive : directions) { String direction = directive.split(" ")[0]; int howMuch = Integer.parseInt(directive.split(" ")[1]); if("up".equals(direction)) { submarine.up(howMuch); } if("down".equals(direction)) { submarine.down(howMuch); } if("forward".equals(direction)) { submarine.forward(howMuch); } } } public void followStrategyPart2(FileReaderAOC fileReaderAOC) throws IOException { fileReaderAOC.eatUpAllLines(); List<String> directions = fileReaderAOC.getAllElements(); for(String directive : directions) { String direction = directive.split(" ")[0]; int howMuch = Integer.parseInt(directive.split(" ")[1]); if("up".equals(direction)) { submarine.up2(howMuch); } if("down".equals(direction)) { submarine.down2(howMuch); } if("forward".equals(direction)) { submarine.forward2(howMuch); } } } public int getWay() { return submarine.getDepth() * submarine.getHorizontal(); } } @NoArgsConstructor @Getter public class Submarine { private int horizontal; private int depth; private int aim; public void up(int howMuch) { depth-=howMuch; } public void up2(int howMuch) { aim-=howMuch; } public void down(int howMuch) { depth+=howMuch; } public void down2(int howMuch) { aim+=howMuch; } public void forward(int howMuch) { horizontal += howMuch; } public void forward2(int howMuch) { horizontal += howMuch; depth += (aim*howMuch); } } @NoArgsConstructor public class FileReaderAOC { private String relFileName; private File testFile; @Getter private List<String> allElements = new ArrayList<>(); @Setter private BufferedReader bufferedReader; public FileReaderAOC(String relFileName) { this.relFileName = relFileName; } public static FileReaderAOC getFromFileName(String relFileName) throws FileNotFoundException { FileReaderAOC fileReaderAOC = new FileReaderAOC(relFileName); File file = new File(relFileName); FileInputStream fstream = new FileInputStream(file); fileReaderAOC.setBufferedReader(new BufferedReader(new InputStreamReader(fstream))); return fileReaderAOC; } public static FileReaderAOC getFromFileName(InputStream relFileName) throws FileNotFoundException { FileReaderAOC fileReaderAOC = new FileReaderAOC(); fileReaderAOC.setBufferedReader(new BufferedReader(new InputStreamReader(relFileName))); return fileReaderAOC; } public String getNextLine() throws IOException { return bufferedReader.readLine(); } public List<String> eatUpAllLines() throws IOException { String line; while ((line = bufferedReader.readLine()) != null) { allElements.add(line); } return allElements; } }
Cat Mother · 2021-12-05 18:09
>>28762 OCaml lain, come back. I liked your code and am in dire need to sharpen up my ML-fu.
Trinity · 2021-12-05 19:44
I really struggled with the second part of day 3 in C. I've fallen behind quite a bit but either way here's day 3: Part 1: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #define BITSIZE 12 int main(void) { FILE *fp; char *line = NULL; size_t len = 0; ssize_t read; fp = fopen("input.txt", "r"); if (fp == NULL) exit(EXIT_FAILURE); /* Keep a "card counting" count of bits. * positive means more 1s * negative means more 0s * */ int bitcounts[BITSIZE]; for (int i = 0; i < BITSIZE; i++) bitcounts[i] = 0; while ((read = getline(&line, &len, fp)) != -1) { for (int i = 0; i < BITSIZE; i++) { if (line[i] == '1') bitcounts[i]++; else bitcounts[i]--; } } /* set each bit of gamma and epsilon */ unsigned long gamma = 0; unsigned long epsilon = 0; for (int i = 0; i < BITSIZE; i++) { if (bitcounts[i] > 0) gamma |= 1 << (BITSIZE-1-i); else epsilon |= 1 << (BITSIZE-1-i); } printf("%ld\n", gamma*epsilon); fclose(fp); return 0; } Part 2: #include <stdio.h> #include <stdlib.h> #include <string.h> #define BITSIZE 12 #define FILESIZE 1000 int main(void) { FILE *fp; char *line = NULL; size_t len = 0; ssize_t read; fp = fopen("input.txt", "r"); if (fp == NULL) exit(EXIT_FAILURE); /* Read in the input file and count the bits in the first column*/ long inputs[FILESIZE]; int i = 0; int bitcount = 0; /* +ve: more 1s, -ve: more 0s */ while ((read = getline(&line, &len, fp)) != -1) { inputs[i] = strtol(line, NULL, 2); i++; if (line[0] == '1') bitcount++; else bitcount--; } fclose(fp); /* Move the inputs with the least and most common bits * as per the puzzle*/ int least_count = 0; int most_count = 0; long least[FILESIZE]; long most[FILESIZE]; int most_common_bit; if (bitcount >= 0) most_common_bit = 1; else most_common_bit = 0; /* Current bit position */ int bitpos = BITSIZE-1; int bit = 1 << bitpos; for (int i = 0; i < FILESIZE; i++) { /* Compares the current bit with the most common bit */ if (((inputs[i] & bit) >> bitpos) == most_common_bit) { most[most_count] = inputs[i]; most_count++; } else { least[least_count] = inputs[i]; least_count++; } } /* O2 rating */ int most_size = most_count; while (most_size > 1) { bitpos--; bit = 1 << bitpos; /* copy to inputs * count most common bit*/ bitcount = 0; for (int i = 0; i < most_size; i++) { inputs[i] = most[i]; if (((inputs[i] & bit) >> bitpos) == 1) bitcount++; else bitcount--; } if (bitcount >= 0) most_common_bit = 1; else most_common_bit = 0; /* filter inputs to most*/ most_count = 0; for (int i = 0; i < most_size; i++) { if (((inputs[i] & bit) >> bitpos) == most_common_bit) { most[most_count] = inputs[i]; most_count++; } } most_size = most_count; } /* CO2 rating */ int least_size = least_count; bitpos = BITSIZE-1; int least_common_bit; while (least_size > 1) { bitpos--; bit = 1 << bitpos; /* copy to inputs * count least common bit*/ bitcount = 0; for (int i = 0; i < least_size; i++) { inputs[i] = least[i]; if (((inputs[i] & bit) >> bitpos) == 1) bitcount++; else bitcount--; } if (bitcount >= 0) least_common_bit = 0; else least_common_bit = 1; /* filter inputs to most*/ least_count = 0; for (int i = 0; i < least_size; i++) { if (((inputs[i] & bit) >> bitpos) == least_common_bit) { least[least_count] = inputs[i]; least_count++; } } least_size = least_count; } printf("%ld\n", most[0]*least[0]); return 0; }
Eldon Tyrell · 2021-12-05 20:32
>>28812 I want to see more of ocaml as well
Me, myself and I · 2021-12-05 21:18
>>28719 Another solution in crystal. I didn't have much time today, but I still thinks it turned out okay. Paste: http://ix.io/3GQu
Me, myself and I · 2021-12-05 21:19
>>28817 For some reason the site refused to attach my image
Sabo Engle · 2021-12-05 21:22
>>28818 maybe if i shrink it a bit?
Unidentified · 2021-12-06 09:06
Day 6 was a nice one as well. #!/usr/bin/env python3 import sys import time def consume(countdown): value = countdown[0] countdown[0] = 0 return value countdown = [0] * 9 for element in input().split(','): countdown[int(element)] += 1 for day in range(128 if len(sys.argv) < 2 else int(sys.argv[1])): print(countdown) print(sum(countdown), 'fishies after', day, 'days') # extract respawns spawns = consume(countdown) # shift for i in range(8): countdown[i] += countdown[i + 1] countdown[i + 1] = 0 # apply previously extracted respawns countdown[6] += spawns countdown[8] += spawns #time.sleep(.01)
Jane Doe · 2021-12-06 09:44
yeah, day six was nice. It even did the bigboy in okay time. I might solve this with actual matrices if I feel like it later today
Mitnick · 2021-12-06 11:30
And easy one. #!/usr/bin/env tclsh namespace path ::tcl::mathop lassign $argv path days set fishes [split [read [open $path]] ,] for {set d 0} {$d < $days} {incr d} { set newcount [+ {*}[lmap f $fishes {== $f 0}]] set fishes [lmap f $fishes {expr {$f ? $f - 1 : 6}}] lappend fishes {*}[lrepeat $newcount 8] } puts [llength $fishes]
Hitomi · 2021-12-06 17:59
I'm still behind on days 4 and 5 but at least day 6 was easier. Part 1: #include <stdio.h> #include <stdlib.h> #include <string.h> #define DAYS 80 #define MAX_INTERNAL_TIME 8 int main(void) { FILE *fp; char *line = NULL; size_t len = 0; ssize_t read; fp = fopen("input.txt", "r"); if (fp == NULL) exit(EXIT_FAILURE); read = getline(&line, &len, fp); fclose(fp); /* The array keeps track of the internal timers of the fish. * The index is the timer and the value is the number of fish * */ int lanternfish[MAX_INTERNAL_TIME+1] = {0}; char *token; while ((token = strsep(&line, ",")) != NULL) { lanternfish[atoi(token)]++; } int day = DAYS; int created = 0; while(day) { created = lanternfish[0]; for (int i = 0; i < MAX_INTERNAL_TIME; i++) lanternfish[i] = lanternfish[i+1]; lanternfish[6] += created; lanternfish[8] = created; day--; } int total_fish = 0; for (int i = 0; i < MAX_INTERNAL_TIME+1; i++) total_fish += lanternfish[i]; printf("%ld\n", total_fish); return 0; } Part 2: #include <stdio.h> #include <stdlib.h> #include <string.h> #define DAYS 256 #define MAX_INTERNAL_TIME 8 int main(void) { FILE *fp; char *line = NULL; size_t len = 0; ssize_t read; fp = fopen("input.txt", "r"); if (fp == NULL) exit(EXIT_FAILURE); read = getline(&line, &len, fp); fclose(fp); /* The array keeps track of the internal timers of the fish. * The index is the timer and the value is the number of fish * */ long lanternfish[MAX_INTERNAL_TIME+1] = {0}; char *token; while ((token = strsep(&line, ",")) != NULL) { lanternfish[strtol(token, NULL, 10)]++; } int day = DAYS; long created = 0; while(day) { created = lanternfish[0]; for (int i = 0; i < MAX_INTERNAL_TIME; i++) lanternfish[i] = lanternfish[i+1]; lanternfish[6] += created; lanternfish[8] = created; day--; } long total_fish = 0; for (int i = 0; i < MAX_INTERNAL_TIME+1; i++) total_fish += lanternfish[i]; printf("%ld\n", total_fish); return 0; }
setq · 2021-12-06 22:20
that was an easy one. I was worried I would have to look for some patterns in part 2. (use-modules (ice-9 rdelim) (ice-9 match) (srfi srfi-1) (srfi srfi-43)) (define (get-init-state) (call-with-input-file "input" (lambda (port) (let [(fishes (map string->number (string-split (read-line port) #\,))) (state (make-vector 9 0))] (for-each (lambda (fish) (let [(val (vector-ref state fish))] (vector-set! state fish (1+ val)))) fishes) state)))) (define (simulate-day! state) (let [(d6 (vector-ref state 6)) (d8 (vector-ref state 8))] (vector-for-each (lambda (day fishes) (let* [(new-day (modulo (1- day) 9)) (fishes-new-old (vector-ref state new-day))] (cond [(= day 0) (vector-set! state 6 (+ fishes d6)) (vector-set! state 8 (+ fishes d8)) (vector-set! state day 0)] [(= day 6) (vector-set! state new-day (+ fishes-new-old d6)) (vector-set! state day (- fishes d6))] [(= day 8) (vector-set! state new-day (+ fishes-new-old d8)) (vector-set! state day (- fishes d8))] [else (vector-set! state new-day (+ fishes-new-old fishes)) (vector-set! state day 0)]))) state))) (define (solution state days) (do [(day 0 (1+ day))] ((= days day)) (simulate-day! state)) (vector-fold (lambda (_ sum fishes) (+ sum fishes)) 0 state)) (let* [(init-state (get-init-state)) (init-state2 (vector-copy init-state))] (format #t "~a~%~a~%" (solution init-state 80) (solution init-state 256)))
Splicer · 2021-12-06 23:59
Sadly I have been doing everything in Python for time reasons, I'll have more time to try other languages after day 14 or so. with open('input.txt', 'r') as in_f: start = [int(x) for x in in_f.readline().split(',')] lanternfish = [0] * 9 for s in start: lanternfish[s] += 1 for _ in range(256): spawners = lanternfish[0] for j in range(len(lanternfish) - 1): lanternfish[j] = lanternfish[j + 1] lanternfish[6] += spawners lanternfish[8] = spawners print(sum(lanternfish))
overriding · 2021-12-07 09:01
Not sure why today was so easy, the naive approach works good enough too. #!/usr/bin/env python3 import sys positions = list(map(int, input().split(','))) print(positions) min_dist = sys.maxsize index = -1 # quadratic is good enough for i, crab in enumerate(positions): dist = sum([ abs(crab - other_crab) for other_crab in positions ]) if dist < min_dist: min_dist = dist index = i print('for crab', crab, 'at', positions[i], 'dist of others is', dist) print('optimal position is that of crab', index, 'at', positions[index], 'with an expenditure of', min_dist)
Lain Iwakura · 2021-12-07 11:38
It's actually getting easier. I was thinking about getting correct answer for part 2 analytically but then I just brute forced it with reasonable bounds. (use-modules (ice-9 rdelim) (ice-9 match) (srfi srfi-1) (srfi srfi-43)) (define (get-input) (call-with-input-file "input" (lambda (port) (let [(positions (map string->number (string-split (read-line port) #\,)))] positions)))) (define (compute-cost positions point) (fold + 0 (map (lambda (p) (abs (- p point))) positions))) (define (compute-cost-2 positions point) (fold + 0 (map (lambda (p) (let [(dist (abs (- p point)))] (/ (* dist (1+ dist)) 2))) positions))) (define (find-median positions) (list-ref (sort positions <) (/ (length positions) 2))) (define (find-mean positions) (round (/ (apply + positions) (length positions)))) (define (problem-1 positions) (compute-cost positions (find-median positions))) (define (problem-2 positions) (let [(median (find-median positions)) (mean (find-mean positions)) (cost (lambda (p) (compute-cost-2 positions p)))] (apply min (unfold (lambda (p) (> p mean)) cost 1+ median)))) (let [(input (get-input))] (format #t "~a~%~a~%" (problem-1 input) (problem-2 input)))
Technician · 2021-12-07 14:34
one-liner (after file I/O and imports) in Python for part 1: import numpy as np with open('inputs.txt', 'r') as in_f: crabs = [int(x) for x in in_f.readline().split(',')] print(sum([abs(x - np.median(crabs)) for x in crabs]))
Terzibashjian · 2021-12-07 23:04
Still haven't caught up on days 4 and 5 but day 7 was straight forward. Part 1: #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_H_POS 10000 int main(void) { FILE *fp; char *line = NULL; size_t len = 0; ssize_t read; fp = fopen("exampleinput.txt", "r"); if (fp == NULL) exit(EXIT_FAILURE); read = getline(&line, &len, fp); fclose(fp); int h_positions[MAX_H_POS] = {0}; char *token; int max_value = 0; while ((token = strsep(&line, ",")) != NULL) { h_positions[atoi(token)]++; if (atoi(token) > max_value) max_value = atoi(token); } int least_fuel = 0; for (int i = 0; i < max_value+1; i++) { int cost = 0; for (int j = 0; j < max_value+1; j++) { cost += abs(i-j)*h_positions[j]; } if (i == 0) least_fuel = cost; else if (cost < least_fuel) least_fuel = cost; } printf("%d\n", least_fuel); return 0; } Part 2: #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_H_POS 10000 int main(void) { FILE *fp; char *line = NULL; size_t len = 0; ssize_t read; fp = fopen("input.txt", "r"); if (fp == NULL) exit(EXIT_FAILURE); read = getline(&line, &len, fp); fclose(fp); int h_positions[MAX_H_POS] = {0}; char *token; int max_value = 0; while ((token = strsep(&line, ",")) != NULL) { h_positions[atoi(token)]++; if (atoi(token) > max_value) max_value = atoi(token); } int least_fuel = 0; for (int i = 0; i < max_value+1; i++) { int cost = 0; for (int j = 0; j < max_value+1; j++) { /* sum(n) = n(n+1)/2 */ cost += (abs(i-j)*(abs(i-j)+1)/2)*h_positions[j]; } if (i == 0) least_fuel = cost; else if (cost < least_fuel) least_fuel = cost; } printf("%d\n", least_fuel); return 0; }
Lukasiewicz · 2021-12-08 09:49
Day 8. Anyone know if there is a mirror that includes the part 2 prompts that doesn't need logging in? #!/usr/bin/env python3 import sys lengths = { 2: 1, 4: 4, 3: 7, 7: 8 } unique = 0 for line in sys.stdin: if '|' not in line: continue for token in line.split('|')[1].split(): if len(token) in lengths.keys(): unique += 1 print(f'token {token}, length {len(token)}, segment {lengths[len(token)]}') print(f'{unique} unique digits')
Koos van der Merwe · 2021-12-08 10:10
Day 7, day 8 will come soon
Meddler · 2021-12-08 11:36
>>28719 Here's day 8 in crystal: crystal record Input, flicker : Set(Set(Char)), data : Array(Set(Char)) module Aoc08 abstract class Solver def initialize(@data : Array(Input)) end abstract def run end class Part1 < Solver def run @data.map { |l| l.data } .flatten .select { |f| [2, 3, 4, 7].includes? f.size } .size end end class Part2 < Solver def self.prime_digits(input) [{2, 1}, {3, 7}, {4, 4}, {7, 8}].reduce(Hash(Int8, (Set(Char))).new) do |hash, hardcode| if (n = input.select { |e| e.size == hardcode[0] }.shift?) hash[hardcode[1].to_i8] = n end hash end end def self.solve_digits(input, wanted_codes, solved) return solved if wanted_codes.empty? code = wanted_codes.first case code.size when 5 case when solved[7].subset_of?(code) then solved[3] = code when (solved[4] - solved[1]).subset_of?(code) then solved[5] = code else solved[2] = code end when 6 case when (solved[7] + solved[4]).subset_of?(code) then solved[9] = code when solved[7].subset_of? code then solved[0] = code else solved[6] = code end end wanted_codes.delete(code) return solve_digits(input, wanted_codes, solved) end def run @data.map do |input| to_solve = input.flicker + input.data.to_set digit_to_code_dict = Part2.solve_digits(to_solve, input.data.dup, Part2.prime_digits(to_solve)) input.data .map { |coded_digit| digit_to_code_dict.key_for(coded_digit).to_s } .join("") .to_i end .sum end end end data = File.read_lines("./../08.txt") .compact .map do |l| l = l.split(" | ") Input.new( l.shift.split.map(&.chars.to_set).to_set, l.shift.split.map(&.chars.to_set)) end puts "Part one: #{Aoc08::Part1.new(data.dup).run}" puts "Part two: #{Aoc08::Part2.new(data.dup).run}" I'm not sure if theres a trick to this one that goes beyond figuring out what digits have to be decoded in order to get the lines data number, but I doubt it makes much difference. I'll try to get it to run on multiple fibers and throw it at a bigboy next
Dr. X · 2021-12-08 14:50
Ugly ay 8 part 2, ended up sorting all strings right = [] left = [] with open('inputs/15.txt', 'r') as in_f: for line in in_f: split = line.split('|') left.append([''.join(sorted(x)) for x in split[0].split()]) right.append([''.join(sorted(x)) for x in split[1].split()]) class Display: def __init__(self, left, right): self.decoder = self.create_decoder(left) self.num = self.decode(right) def intersect(self, s0, s1): return len(set(s0).intersection(set(s1))) def create_decoder(self, l): decoder = [''] * 10 # Easy numbers first for s in l: if len(s) == 2: decoder[1] = s elif len(s) == 4: decoder[4] = s elif len(s) == 3: decoder[7] = s elif len(s) == 7: decoder[8] = s # Harder numbers now for s in l: shared = self.intersect(s, decoder[1]) # 2, 3, or 5 if len(s) == 5: if shared == 2: decoder[3] = s else: shared = self.intersect(s, decoder[4]) if shared == 2: decoder[2] = s else: decoder[5] = s # 0, 5, or 9 elif len(s) == 6: if shared == 1: decoder[6] = s else: shared = self.intersect(s, decoder[4]) if shared == 4: decoder[9] = s else: decoder[0] = s return decoder def decode(self, r): tens = 1000 ret = 0 for s in r: ret += tens * self.decoder.index(s) tens //= 10 return ret def get_num(self): return self.num final_sum = 0 for l, r in zip(left, right): final_sum += Display(l, r).get_num() print(final_sum)
Hagbard Celine · 2021-12-09 00:54
took me way too much time, but alas.... (use-modules (ice-9 rdelim) (ice-9 match) (ice-9 hash-table) (srfi srfi-1) (srfi srfi-43)) (define (get-lines filename trans) (call-with-input-file filename (lambda (port) (let loop [(line (read-line port)) (lines '())] (if (eof-object? line) (reverse lines) (loop (read-line port) (cons (trans line) lines))))))) (define in (get-lines "input" (lambda (line) (let* [(parts (string-split line #\space)) (input (list-head parts 10)) (output (list-tail parts 11))] (list input output))))) ;;1,4,7,8 appear? ;;2,4,3,7 lengths (define (problem-1 input) (fold + 0 (map (lambda (entry) (count (lambda (out) (member out '(2 3 4 7))) (map string-length (list-ref entry 1)))) input))) (define (construct-decoder entry-input) (define decoded (make-hash-table)) (define (has? num) (hash-ref decoded num)) (define (insert! num segment) (hash-set! decoded num segment)) (define (in? num segment) (lset<= eq? (hash-ref decoded num '(#\x)) segment)) (let loop [(segments (map string->list entry-input))] (if (null? segments) decoded (match-let* [((segment . remain) segments) (len (length segment))] ;;(format #t "~a ~a~%" segment (hash-map->list cons decoded)) (cond [(= len 2) (insert! 1 segment) (loop remain)] [(= len 3) (insert! 7 segment) (loop remain)] [(= len 4) (insert! 4 segment) (loop remain)] [(= len 7) (insert! 8 segment) (loop remain)] [(and (= len 6) (in? 4 segment)) (insert! 9 segment) (loop remain)] [(and (= len 6) (in? 1 segment) (has? 4) (not (in? 4 segment))) (insert! 0 segment) (loop remain)] [(and (= len 6) (has? 1) (has? 4)) (insert! 6 segment) (loop remain)] [(and (= len 5) (in? 1 segment)) (insert! 3 segment) (loop remain)] [(and (= len 5) (has? 1) (not (in? 1 segment)) (= 3 (length (lset-intersection eq? (hash-ref decoded 4 '(#\x)) segment)))) (insert! 5 segment) (loop remain)] [(and (= len 5) (has? 3) (has? 5)) (insert! 2 segment) (loop remain)] [else (loop (append remain (list segment)))]))))) (define (decode decoder out-segments) (let* [(key-vals (hash-map->list cons decoder)) (inv-decoder (lambda (code-in) (number->string (car (find (match-lambda [(num . code) ;;(format #t "~a ~a ~a~%" code-in num code) (lset= eq? code code-in)]) key-vals))))) (decoded (map inv-decoder (map string->list out-segments)))] (string->number (string-join decoded "")))) (define (problem-2 input) (fold + 0 (map (match-lambda [(in-coded out-coded) (let* [(decoder (construct-decoder in-coded)) (result-num (decode decoder out-coded))] ;;(format #t "~a ~a ~a~%" in-coded out-coded result-num) result-num )]) input))) (format #t "~a~%~a~%" (problem-1 in) (problem-2 in))
Netrunner · 2021-12-09 06:14
This is the first day that is geared towards recursivity right? import bisect with open('test.txt', 'r') as in_f: lines = [x.strip() for x in in_f.readlines()] map = [] for line in lines: map.append([int(x) for x in line]) def color_basin(map, x, y): if map[x][y] == 9: return 0 map[x][y] = 9 left = color_basin(map, x - 1, y) if x != 0 else 0 right = color_basin(map, x + 1, y) if x != len(map) - 1 else 0 up = color_basin(map, x, y - 1) if y != 0 else 0 down = color_basin(map, x, y + 1) if y != len(map[0]) - 1 else 0 return 1 + left + right + up + down sizes = [] for x in range(len(map)): for y in range(len(map[0])): if map[x][y] != 9: bisect.insort(sizes, color_basin(map, x, y)) prod = 1 for x in sizes[len(sizes) - 3:]: prod *= x print(prod)
Koos van der Merwe · 2021-12-09 09:28
Day 9. Wanted to try a sliding window approach, but it ended up quite ugly. #!/usr/bin/env python3 import sys # sliding window of input line elements class Window: def __init__(self): self.window = [ None, None, None ] def slide(self): for i in range(len(self.window) - 1): self.window[i] = self.window[i + 1] print(self.window) def analyze(self): if not self.window[1]: return for i in range(len(self.window[1])): up = self.window[0][i] if self.window[0] else sys.maxsize left = sys.maxsize if i == 0 else self.window[1][i - 1] middle = self.window[1][i] right = sys.maxsize if i == len(self.window[1]) - 1 else self.window[1][i + 1] down = self.window[2][i] if smaller(middle, [up, left, right, down]): yield middle + 1 def process(self, elements): self.window[len(self.window) - 1] = elements def smaller(a, elements): for b in elements: if b <= a: return False return True def collect(generator): return sum([ e for e in generator ]) total = 0 window = Window() for line in sys.stdin: window.slide() window.process(list(map(int, line.rstrip('\n')))) #for e in window.analyze(): print(e) total += collect(window.analyze()) # very ugly to have to repeat loop body window.slide() window.process([ 1 + e for e in window.window[2]]) total += collect(window.analyze()) print(f'sum of risk levels of all low points is {total}')
Ein · 2021-12-09 10:50
I'm quiet happy with my code for todays challenge (use-modules (ice-9 rdelim) (ice-9 match) (ice-9 hash-table) (srfi srfi-1) (srfi srfi-43)) (define (get-lines filename trans) (call-with-input-file filename (lambda (port) (let loop [(line (read-line port)) (lines '())] (if (eof-object? line) (reverse lines) (loop (read-line port) (cons (trans line) lines))))))) (define in (let* [(data (get-lines "input" (lambda (line) (map (lambda (chr-num) (- (char->integer chr-num) 48)) (string->list line))))) (rows (length data)) (cols (length (car data))) (matrix (make-vector (* rows cols) 0))] (for-each (lambda (row i) (for-each (lambda (n j) (vector-set! matrix (+ j (* i cols)) n)) row (iota cols))) data (iota rows)) (list rows cols matrix (lambda (row col . dflt) (let [(fail (if (null? dflt) #f (car dflt)))] (cond [(< row 0) fail] [(>= row rows) fail] [(< col 0) fail] [(>= col cols) fail] [else (vector-ref matrix (+ col (* row cols)))])))))) (define (get-basins rows cols matrix-raw mat) (do [(i 0 (1+ i)) (basins '())] [(= i rows) basins] (do [(j 0 (1+ j))] [(= j cols)] (when (and (< (mat i j) (mat (1+ i) j (inf))) (< (mat i j) (mat (1- i) j (inf))) (< (mat i j) (mat i (1+ j) (inf))) (< (mat i j) (mat i (1- j) (inf)))) (set! basins (cons (list i j) basins)))))) (define (problem-1 rows cols matrix-raw mat) (fold + 0 (map (lambda (basin) (1+ (apply mat basin))) (get-basins rows cols matrix-raw mat)))) (define (basin-surface mat row col) (define visited (make-hash-table)) (let dfs [(i row) (j col)] (cond [(= 9 (mat i j 9)) 0] [(hash-ref visited (cons i j)) 0] [else (hash-set! visited (cons i j) #t) (+ 1 (dfs (1+ i) j) (dfs (1- i) j) (dfs i (1+ j)) (dfs i (1- j)))]))) (define (problem-2 rows cols matrix-raw mat) (apply * (list-head (sort (map (lambda (basin) (apply basin-surface mat basin)) (get-basins rows cols matrix-raw mat)) >) 3))) (format #t "~a~%~a~%" (apply problem-1 in) (apply problem-2 in))
Unidentified · 2021-12-09 14:08
>>28874 I did it using a queue, but yes, it's essentially recursive require "bit_array" record Point, x : Int32, y : Int32 do def ==(other) return x == other.x && y == other.y end end module Aoc09 extend self abstract class Solver def initialize(@data : Array(Array(UInt8))) end abstract def run def find_lowest lows = [] of Array(Int32) @data.each_with_index do |line, y| line.map_with_index do |n, x| if [-1, 1].map do |mod| res = [] of UInt8 if 0 <= (l = y + mod) < @data.size res << @data[l][x] end if 0 <= (r = x + mod) < @data[0].size res << line[r] end res end .flatten .compact .min >(n) lows << [x, y] end end end return lows end end class Part1 < Solver def run lows = find_lowest return lows.map{|pp| @data[pp[1]][pp[0]]}.sum(lows.size) end end class Part2 < Solver def run visited = (Array(BitArray).new(@data.size) { BitArray.new(@data[0].size) }) queue = [] of Point result = find_lowest.map do |root| queue << Point.new(root[0], root[1]) basin_size = 0 while queue.any? point = queue.shift visited[point.y].toggle(point.x) basin_size += 1 queue += [{0, 1}, {0, -1}, {1, 0}, {-1, 0}] .map do |mod| pending = Point.new(point.x + mod[0], point.y + mod[1]) if 0<= pending.x < @data.[0].size && 0 <= pending.y < @data.size && @data[pending.y][pending.x] < 9 && !visited[pending.y][pending.x] pending else nil end end .compact queue.uniq! end basin_size end .sort .last(3) .product return result end end end include Aoc09 input = File.read_lines("./../09.txt") .map(&.chars.map(&.to_u8)) puts "Silver: #{Part1.new(input.clone).run}" puts "Gold: #{Part2.new(input.clone).run}" ...technically 100loc, please no bully
BloodCat · 2021-12-10 05:30
I feel weird using Python's list as a stack import bisect with open('test.txt', 'r') as in_f: lines = [x.strip() for x in in_f.readlines()] closers = {'(': ')', '[': ']', '{': '}', '<': '>'} points = {')': 3, ']': 57, '}': 1197, '>': 25137} points2 = {')': 1, ']': 2, '}': 3, '>': 4} illegals = [] scores = [] for line in lines: next_closers = [] illegal_flag = False # PART 1 for c in line: if c in ['(', '[', '{', '<']: next_closers.append(closers[c]) elif c != next_closers.pop(): illegals.append(c) illegal_flag = True break if illegal_flag: continue # PART 2 score = 0 while next_closers: curr = next_closers.pop() score *= 5 score += points2[curr] bisect.insort(scores, score) print(sum([points[x] for x in illegals])) print(scores[len(scores) // 2])
Ein · 2021-12-10 08:44
Day 10. Very fun example today. #!/usr/bin/env python3 import sys lookup = { '(': 1, '[': 1, '{': 1, '<': 1, ')': -1, ']': -1, '}': -1, '>': -1, } expected = { ')': '(', ']': '[', '}': '{', '>': '<', '(': ')', '[': ']', '{': '}', '<': '>' } score = { ')': 3, ']': 57, '}': 1197, '>': 25137 } balance = 0 for line in sys.stdin: line = line.rstrip('\n') print(line) # find balance and score of line brackets = 0 stack = [] for c in line: closing = lookup[c] < 0 brackets += lookup[c] # print with indentation print(' ' * (brackets + (1 if closing else 0)), c, brackets, lookup[c]) # manipulate stack to check for correctness and score if not closing: stack.append(c) else: bracket = stack.pop() if bracket != expected[c]: print(f'closure incorrect: {bracket} == {expected[c]} = {bracket == expected[c]}') balance += score[c] print(f'final bracket balance {brackets}') # find closure to line print('a closure look like') for _ in range(len(stack)): b = expected[stack.pop()] closing = lookup[b] < 0 brackets += lookup[b] print(' ' * (brackets + (1 if closing else 0)), b, brackets, lookup[b]) print(f'file gets a score of {balance}')
Turing · 2021-12-10 10:05
here is mine (use-modules (ice-9 rdelim) (ice-9 match) (ice-9 q) (ice-9 hash-table) (srfi srfi-1) (srfi srfi-43)) (define (get-lines filename trans) (call-with-input-file filename (lambda (port) (let loop [(line (read-line port)) (lines '())] (if (eof-object? line) (reverse lines) (loop (read-line port) (cons (trans line) lines))))))) (define in (get-lines "input" string->list)) (define score-table (alist->hash-table '((#\) . 3) (#\] . 57) (#\} . 1197) (#\> . 25137)))) (define complete-score-table (alist->hash-table '((#\) . 1) (#\] . 2) (#\} . 3) (#\> . 4)))) (define closing '(#\) #\] #\} #\>)) (define (match? open close) (or (and (eq? #\( open) (eq? #\) close)) (and (eq? #\[ open) (eq? #\] close)) (and (eq? #\{ open) (eq? #\} close)) (and (eq? #\< open) (eq? #\> close)))) (define (find-closing open) (find (lambda (close) (match? open close)) closing)) (define (corruption-score line) (define stack (make-q)) (let loop [(els line)] (if (null? els) 0 (let* [(el (car els)) (close? (member el closing eq?)) (els (cdr els))] (cond [(and close? (match? (q-front stack) el)) (q-pop! stack) (loop els)] [close? ;;(format #t "~a x ~a : ~a~%" (q-front stack) el els) (hash-ref score-table el)] [else (q-push! stack el) (loop els)]))))) (define (complete stack) (let loop [(open (q-pop! stack)) (score 0)] (let [(new-score (+ (* 5 score) (hash-ref complete-score-table (find-closing open))))] (if (q-empty? stack) new-score (loop (q-pop! stack) new-score))))) (define (autocomplete-score line) (define stack (make-q)) (let loop [(els line)] (if (null? els) (complete stack) (let* [(el (car els)) (close? (member el closing eq?)) (els (cdr els))] (cond [(and close? (match? (q-front stack) el)) (q-pop! stack) (loop els)] [close? 0];;corrupted [else (q-push! stack el) (loop els)]))))) (define (problem-1 input) (fold + 0 (map corruption-score input))) (define (problem-2 input) (let [(scores (filter positive? (map autocomplete-score input)))] (list-ref (sort scores <) (floor (/ (length scores) 2))))) (format #t "~a~%~a~%" (problem-1 in) (problem-2 in))
push · 2021-12-10 13:00
cr module Aoc10 extend Aoc10 abstract class Solver def initialize(@data : Array(Array(Char))) end def matching(c) c.to_s.tr("([{<>}])", ")]}><{[{")[0] end abstract def run def check_lines stack = [] of Char @data.map do |line| stack.clear res = line.find do |c| if "([{<".includes? c stack.push(c) && false else matching(stack.pop?) != c end end res || stack.dup end end end class Part1 < Solver Scores = {')' => 3, ']' => 57, '}' => 1197, '>' => 25137} def run check_lines .sum { |e| e.is_a?(Char) ? Scores[e] : 0 } end end class Part2 < Solver def run check_lines .map do |line| line.is_a?(Char) ? nil : line.map { |c| matching(c).not_nil! } end .compact .map(&.reverse) .map do |line| line.reduce(0_u64) do |m, c| m *= 5 m += ".)]}>".index(c).not_nil! end end .sort .mid end end end class Array def mid return self[(self.size / 2).to_i] end end input = File.read_lines("./../10.txt").map(&.chars) puts "Silver: #{Aoc10::Part1.new(input).run}" puts "Gold: #{Aoc10::Part2.new(input).run}" for some reason much cleaner than the previous days.
swap · 2021-12-10 13:44
>>28888 Any special reason why you're reversing the input lines?
Delilah · 2021-12-10 14:05
>>28891 that is a general function that I copy paste across most AoC challenges. I need to reverse because I am appending to the begging of result list so you need to reverse it in the end to get the original ordering....maybe I should just string-split the input on \n now that I think about it.
Project 2501 · 2021-12-10 16:25
>>28889 what is this language?
let · 2021-12-10 18:36
>>28896 There are only a handful of lains posting solutions, and the languages they're using all look different from each other and have been named several times. You really can crack this one on your own, I think. Actually, it's pretty much down to three right now, as even Tcl lain hasn't posted these past few days it seems. Consider yourselves cheered on, everyone!
Cereal Killer · 2021-12-10 23:32
>>28896 The other lain has a point, but I'll still gladly tell you that it's crystal-lang.org. The people at manas basically wondered what would happen if you where to recreate ruby as frontend for clang. Tooling is still kind of sparse, I use two vim plugins along with the scry lsp client. I find unit tests to be very helpful for the aoc, i always define the parts as tests and work the to completion.
Junichi Fujiwara · 2021-12-11 08:26
numpy MVP as usual import numpy as np def invalid(o, x, y): return x < 0 or x >= len(o) or y < 0 or y >= len(o[0]) def flash(o, x, y, f): for i in range(-1, 2): for j in range(-1, 2): if i == j == 0 or invalid(o, x + i, y + j) or o[x + i, y + j] == 10: continue o[x + i, y + j] += 1 if o[x + i, y + j] == 10: f.append([x + i, y + j]) flashes = 0 octopi = np.genfromtxt('input.txt', delimiter=1, dtype=int) gold = 0 while True: octopi += 1 gold += 1 flashers = np.argwhere(octopi == 10).tolist() delta_flashes = 0 while flashers: curr = flashers.pop() flash(octopi, curr[0], curr[1], flashers) delta_flashes += 1 octopi %= 10 if gold <= 100: flashes += delta_flashes if delta_flashes == 100: break print(flashes) print(gold)
Linda Lee · 2021-12-11 12:08
here is mine (use-modules (ice-9 rdelim) (ice-9 match) (ice-9 hash-table) (srfi srfi-1) (srfi srfi-43)) (define (get-lines filename trans) (call-with-input-file filename (lambda (port) (let loop [(line (read-line port)) (lines '())] (if (eof-object? line) (reverse lines) (loop (read-line port) (cons (trans line) lines))))))) (define (make-objects rows cols matrix) (list (lambda (row col . dflt) ;;getter (let [(fail (if (null? dflt) #f (car dflt)))] (cond [(< row 0) fail] [(>= row rows) fail] [(< col 0) fail] [(>= col cols) fail] [else (vector-ref matrix (+ col (* row cols)))]))) (lambda (row col val) ;;setter (when (and (>= row 0) (< row rows) (>= col 0) (< col cols)) (let [(index (+ col (* row cols)))] (if (procedure? val) (vector-set! matrix index (val (vector-ref matrix index))) (vector-set! matrix index val))))))) (define (in) (let* [(data (get-lines "input" (lambda (line) (map (lambda (chr-num) (- (char->integer chr-num) 48)) (string->list line))))) (rows (length data)) (cols (length (car data))) (matrix (make-vector (* rows cols) 0))] (for-each (lambda (row i) (for-each (lambda (n j) (vector-set! matrix (+ j (* i cols)) n)) row (iota cols))) data (iota rows)) (append (list rows cols matrix) (make-objects rows cols matrix)))) (define (step rows cols m-get m-set!) (match-let [((flash-get flash-set!) (make-objects rows cols (make-vector (* rows cols) #f)))] (letrec [(propagate (lambda (i j) (when (and (< 9 (m-get i j -1)) (not (flash-get i j))) (flash-set! i j #t);;mark as already flashed in this step (m-set! (1+ i) j 1+) (propagate (1+ i) j) (m-set! (1- i) j 1+) (propagate (1- i) j) (m-set! (1+ i) (1+ j) 1+) (propagate (1+ i) (1+ j)) (m-set! (1- i) (1- j) 1+) (propagate (1- i) (1- j)) (m-set! (1+ i) (1- j) 1+) (propagate (1+ i) (1- j)) (m-set! (1- i) (1+ j) 1+) (propagate (1- i) (1+ j)) (m-set! i (1+ j) 1+) (propagate i (1+ j)) (m-set! i (1- j) 1+) (propagate i (1- j)))))] (do [(i 0 (1+ i))] [(= i rows)] (do [(j 0 (1+ j))] [(= j cols)] (m-set! i j 1+) (when (< 9 (m-get i j)) (propagate i j)))) (do [(i 0 (1+ i)) (flashed 0)] [(= i rows) flashed] (do [(j 0 (1+ j))] [(= j cols)] (when (< 9 (m-get i j)) (set! flashed (1+ flashed)) (m-set! i j 0))))))) (define (problem-1 rows cols matrix m-get m-set!) (fold + 0 (map (lambda (_) (step rows cols m-get m-set!)) (iota 100)))) (define (problem-2 rows cols matrix m-get m-set!) (do [(counter 1 (1+ counter)) (flashed (step rows cols m-get m-set!) (step rows cols m-get m-set!))] [(= flashed (* rows cols)) counter])) (format #t "~a~%~a~%" (apply problem-1 (in)) (apply problem-2 (in)))
Arisu Mizuki · 2021-12-12 00:41
Didn't have time today, but I hope to publish my crystal tomorrow
Pulse · 2021-12-12 07:34
Had some extra time today so I wrote it out in cpp, I just brute-forced the gold star so I'm curious to see what you guys came up with #include <fstream> #include <iostream> #include <string> #include <vector> #include <set> #include <map> #include <algorithm> using std::cout; using std::ifstream; using std::set; using std::map; using std::string; using std::vector; vector<string> read_input(const char* filepath) { ifstream in_f(filepath); string line; vector<string> ret; while(std::getline(in_f, line)) ret.push_back(line); return ret; } // Just store the Node's id, neighbord, and if it's big or not class node { public: string id; bool is_big; vector<string> neighbors; node(const string &id) : id(id) { is_big = std::all_of(id.begin(), id.end(), [](unsigned char c){ return std::isupper(c); }); } node() : node("") {} void add_neighbor(const string &s) { neighbors.push_back(s); } bool can_repeat() const { return !is_big and id != "start" and id != "end"; } bool operator <(const node &rhs) const { return id < rhs.id; } }; void find_paths(const node &curr, string path, map<string, node> nodes, set<string> &paths, map<string, size_t> &visited, const string& repeat) { auto updated_path = path + curr.id + ","; if(curr.id == "end") { paths.emplace(updated_path); return; } ++visited[curr.id]; for(const auto &s : curr.neighbors) { auto n = nodes[s]; if((!n.is_big && visited[s] > 0 && s != repeat) || (s == repeat && visited[s] > 1)) continue; find_paths(n, updated_path, nodes, paths, visited, repeat); } --visited[curr.id]; } int main() { vector<string> input = read_input("input.txt"); // Build "graph" map<string, node> nodes; map<string, size_t> visited; for(const auto &s : input) { auto dash = s.find("-"); auto s0 = s.substr(0, dash); auto s1 = s.substr(dash + 1, s.length()); if(nodes.find(s0) == nodes.end()) nodes[s0] = node(s0); if(nodes.find(s1) == nodes.end()) nodes[s1] = node(s1); nodes[s0].add_neighbor(s1); nodes[s1].add_neighbor(s0); visited[s0] = 0; visited[s1] = 0; } // Output silver set<string> paths; find_paths(nodes["start"], "", nodes, paths, visited, ""); cout << paths.size() << "\n"; // Output gold set<string> gold_paths; for(const auto &p : nodes) { if(!p.second.can_repeat()) continue; find_paths(nodes["start"], "", nodes, gold_paths, visited, p.first); } cout << gold_paths.size() << "\n"; return 0; }
Dujour · 2021-12-12 10:43
DFS worked out nicely for me today. (use-modules (ice-9 rdelim) (ice-9 match) (ice-9 hash-table) (srfi srfi-1)) (define (get-lines filename trans) (call-with-input-file filename (lambda (port) (let loop [(line (read-line port)) (lines '())] (if (eof-object? line) (reverse lines) (loop (read-line port) (cons (trans line) lines))))))) (define paths (let [(path-table (make-hash-table))] (get-lines "input" (lambda (line) (match-let* [((src dest) (string-split line #\-)) (src-paths (hash-ref path-table src '())) (dest-paths (hash-ref path-table dest '()))] (hash-set! path-table src (cons dest src-paths)) (unless (or (string= src "start") (string= dest "end")) (hash-set! path-table dest (cons src dest-paths)))))) path-table)) (define (dfs-count node path) (cond [(string= node "end") 1] [(and (char-lower-case? (string-ref node 0)) (find (lambda (p) (string= p node)) path)) 0] [else (fold + 0 (map (lambda (new-node) (dfs-count new-node (cons node path))) (hash-ref paths node)))])) (define (dfs-count2 node path small-2nd?) (cond [(string= node "end") 1] [(and small-2nd? (char-lower-case? (string-ref node 0)) (find (lambda (p) (string= p node)) path)) 0] [(and (not small-2nd?) (char-lower-case? (string-ref node 0)) (find (lambda (p) (string= p node)) path)) (fold + 0 (map (lambda (new-node) (dfs-count2 new-node (cons node path) #t)) (hash-ref paths node)))] [else (fold + 0 (map (lambda (new-node) (dfs-count2 new-node (cons node path) small-2nd?)) (hash-ref paths node)))])) (format #t "~a~%~a~%" (dfs-count "start" '()) (dfs-count2 "start" '() #f))
if · 2021-12-13 06:50
This one was fun, I had forgotten about the story prompt so the gold star was a nice surprise. #include <fstream> #include <iostream> #include <string> #include <vector> #include <set> using std::cout; using std::ifstream; using std::stoi; using std::set; using std::string; using std::vector; using std::pair; using std::array; vector<string> read_input(const char* filepath) { ifstream in_f(filepath); string line; vector<string> ret; while(std::getline(in_f, line)) ret.push_back(line); return ret; } pair<int,int> fold(pair<int,int> const &p, int line, bool along_x) { pair<int,int> ret; if(along_x && p.first > line) { ret.first = line - (p.first - line); ret.second = p.second; } else if(!along_x && p.second > line) { ret.second = line - (p.second - line); ret.first = p.first; } else { ret.first = p.first; ret.second = p.second; } return ret; } int main() { vector<string> input = read_input("input.txt"); // Parse input set<pair<int,int>> dots; vector<string> instructions; for(auto const &s : input) { auto comma = s.find(","); if(comma != string::npos) dots.emplace(pair(stoi(s.substr(0, comma)), stoi(s.substr(comma + 1, s.length())))); else if(s.length()) instructions.push_back(s); } // Do the folds size_t inst_count = 0; for(auto const &inst : instructions) { bool along_x = inst.find("x") != string::npos; int val = stoi(inst.substr(inst.find("=") + 1, inst.length())); set<pair<int,int>> new_dots; for(auto const &d : dots) new_dots.emplace(fold(d, val, along_x)); dots = new_dots; // Silver star if(!inst_count) cout << dots.size() << "\n"; ++inst_count; } // Gold star array<array<int, 40>, 6> arr{}; for(auto const &d : dots) arr[d.second][d.first] = 1; for(auto const &r : arr) { for(auto const &c : r) cout << c; cout << "\n"; } return 0; }
Lunch · 2021-12-13 11:32
I had some fold problems that didn't show up in first star so debugging was fun. (use-modules (ice-9 rdelim) (ice-9 match) (ice-9 hash-table) (srfi srfi-1) (srfi srfi-43) (ice-9 receive)) (define (get-lines filename trans) (call-with-input-file filename (lambda (port) (let loop [(line (read-line port)) (lines '())] (if (eof-object? line) (reverse lines) (loop (read-line port) (cons (trans line) lines))))))) (define in (let loop [(lines (get-lines "input" identity)) (dots '()) (instructions '())] (cond [(null? lines) (cons (reverse instructions) (reverse dots))] [(= 0 (string-length (car lines))) (loop (cdr lines) dots instructions)] [(eq? #\f (string-ref (car lines) 0)) (match-let* [((fold over cmd) (string-split (car lines) #\space)) ((axis value) (string-split cmd #\=)) (axis-sym (string->symbol axis)) (value-n (string->number value))] (loop (cdr lines) dots (cons (list axis-sym value-n) instructions)))] [else (loop (cdr lines) (cons (map string->number (string-split (car lines) #\,)) dots) instructions)]))) (define (bounds dots) (apply map max dots)) (define (split dots cmd) (match-let [((axis value) cmd)] (receive (smaller bigger) (partition (match-lambda [(x-val y-val) (if (eq? axis 'x) (< x-val value) (< y-val value))]) dots) (cons smaller bigger)))) (define (dot-eq? dot1 dot2) (and (= (list-ref dot1 0) (list-ref dot2 0)) (= (list-ref dot1 1) (list-ref dot2 1)))) (define (fold-once instruction dots) (match-let* [((x-max y-max) (bounds dots)) ((axis value) instruction) ((keep-dots . fold-dots) (split dots instruction)) (folded-dots (map (match-lambda [(x-val y-val) (if (eq? axis 'x) `(,(- (* 2 value) x-val) ,y-val) `(,x-val ,(- (* 2 value) y-val)))]) fold-dots))] (lset-union dot-eq? keep-dots folded-dots))) (define (dot-print dots) (match-let* [((x-max y-max) (bounds dots)) (x-size (1+ x-max)) (y-size (1+ y-max)) (vec (make-vector (* x-size y-size) " "))] (for-each (match-lambda [(x y) (vector-set! vec (+ x (* y x-size)) "#")]) dots) (vector-for-each (lambda (i v) (when (zero? (modulo i x-size)) (newline)) (display v)) vec) (newline))) (define (problem-1 instructions dots) (length (fold-once (car instructions) dots))) (define (problem-2 instructions dots) (dot-print (fold fold-once dots instructions))) (format #t "~a~%" (problem-1 (car in) (cdr in))) (problem-2 (car in) (cdr in))
Neo · 2021-12-13 13:15
>get behind in AoC >want to do it because I have a lot of free time at work >spend 2 hours trying to figure out why my program isn't working >it was, I just entered the solution incorrectly 2 times AHHHHHHHHHHHHHHHHHHHHHHHHHHH!!!!!!!!!!!! I'm just using C++ with the STL and it makes me realize why boost bloat is so popular. it's kinda soykaf for text input, somehow even more of a pain to use than plain C.
The Oracle · 2021-12-13 14:39
Day 13. I've missed the previous 2 because of real life, tried to rush them after the fact but only got incomplete solutions. Solution doesn't pay attention to resulting matrix sizes after splitting the matrix by the folding line. #!/usr/bin/env python3 import sys import re import collections def print_bool_matrix(matrix): print(f'{width} by {height} matrix') print('\n'.join([ ' '.join([ '#' if e else '.' for e in row ]) for row in matrix ])) matrix = [] width = 0 height = 0 folding = False for line in sys.stdin: if line == '\n': folding = True continue # first part if not folding: # get points x, y = [ int(group) for group in re.match(r'(\d+),(\d+)', line).groups() ] # resize if needed if y + 1 > height: for i in range(y + 1 - height): matrix.append([False] * width) height = y + 1 if x + 1 > width: for row in matrix: for i in range(x + 1 - width): row.append(False) width = x + 1 matrix[y][x] = True # second part else: axis, stop = [ group for group in re.match(r'fold along ([xy])=(\d)', line).groups() ] horizontal = 'y' in axis stop = int(stop) print(f'fold by {axis}={stop}') if horizontal: # make horizontal fold up = matrix[0:stop] bottom = matrix[stop + 1:] bottom = bottom[::-1] # save fold matrix = [ [ u or b for u, b in zip(up_rows, bottom_rows) ] for up_rows, bottom_rows in zip(up, bottom) ] height = stop else: # make vertical fold left = [ row[0:stop] for row in matrix ] right = [ row[stop + 1:] for row in matrix ] right = [ row[::-1] for row in right ] # save fold matrix = [ [ l or r for l, r in zip(left_rows, right_rows) ] for left_rows, right_rows in zip(left, right) ] width = stop visible = sum([ len([ e for e in row if e ]) for row in matrix ]) print(f'there are {visible} visible dots') print_bool_matrix(matrix)
cond · 2021-12-13 14:50
>>28903 thank you lain! consider yourself heartily thanked
bit · 2021-12-14 06:08
Maps go brrr #include <fstream> #include <iostream> #include <string> #include <vector> #include <map> using std::cout; using std::ifstream; using std::stoi; using std::string; using std::vector; using std::map; vector<string> read_input(const char* filepath) { ifstream in_f(filepath); string line; vector<string> ret; while(std::getline(in_f, line)) ret.push_back(line); return ret; } void apply_rules(map<string,size_t> &b, const map<string,string> &r) { map<string,size_t> delta_map; for(auto const& p : r) { if(b.find(p.first) == b.end()) continue; delta_map[p.first[0] + p.second] += b[p.first]; delta_map[p.second + p.first[1]] += b[p.first]; b[p.first] = 0; } for(auto const &p : delta_map) b[p.first] += p.second; } int main() { vector<string> input = read_input("input.txt"); // Parse input auto formula = input[0]; map<string,size_t> bigrams; map<string,string> rules; for(auto const &s : input) { if(s.find("-") == string::npos) continue; rules[s.substr(0, 2)] = s.substr(6, 7); } for(size_t i = 0; i != formula.length() - 1; ++i) ++bigrams[formula.substr(i, 2)]; ++bigrams[formula.substr(formula.length() - 1, 1)]; // Do 40 steps of the formula for(size_t i = 0; i != 40; ++i) apply_rules(bigrams, rules); // Get counts map<char,size_t> counts; for(auto const &p : bigrams) counts[p.first[0]] += p.second; size_t max = 0; size_t min = (size_t) - 1; for(auto const &p : counts) { max = p.second > max ? p.second : max; min = p.second < min ? p.second : min; } cout << max - min << "\n"; return 0; }
swap · 2021-12-14 06:11
>>28943 I agree that parsing text with C++ feels awful, making it not feel fragile takes way too much work, but at least I don't have to use strtok.
setq · 2021-12-14 06:34
(anonymous user #388839) reporting in, maps are fun: (defpackage #:advent2021.day14 (:use #:cl #:alexandria #:cl-ppcre #:advent2021.util) (:export #:solve-part-1 #:solve-part-2)) (in-package #:advent2021.day14) (with-puzzle-file (stream) (defparameter +template+ (read-line stream)) (read-line stream) (defparameter +rules+ (loop :with table := (make-hash-table :test 'equal) :for line := (read-line stream nil) :while line :for (pair result) := (split " -> " line) :do (setf (gethash (cons (char pair 0) (char pair 1)) table) (char result 0)) :finally (return table)))) (defun template-table (template) "Encode the template as a table of the count of element pairs." (loop :with pair-table := (make-hash-table :test 'equal) ;; Iterate across each pair of characters in the template (e.g. for the ;; template "NNCB", (a b) is bound to (#\N #\N), (#\N #\C), then (#\C ;; #\B). ;; By encoding the table as a count of all pairs, subsequent ;; generations only need to apply a rule twice for each unique pair, ;; instead of applying them once for each pair that exists. :for (a b) :on (coerce template 'list) :while b :do (incf (gethash (cons a b) pair-table 0)) :finally (return pair-table))) (defun apply-rules (pair-table) "Return a fresh pair table generated by applying the problem-set rules on each pair." (loop :with next-generation := (make-hash-table :test 'equal) :for (a . b) :being :the :hash-keys :of pair-table :using (hash-value count) :for c := (gethash (cons a b) +rules+) :do (incf (gethash (cons a c) next-generation 0) count) (incf (gethash (cons c b) next-generation 0) count) :finally (return next-generation))) (defun count-elements (pair-table) "Return a table of the count of all elements." (loop :with freq-table := (make-hash-table) :with template := (coerce +template+ 'list) :for (a . b) :being :the :hash-keys :of pair-table :using (hash-value count) ;; "Count" each element in each pair only half as often, as they appear ;; encoded as pairs twice as much than encoded as a string. :do (incf (gethash a freq-table 0) (/ count 2)) (incf (gethash b freq-table 0) (/ count 2)) :finally (progn ;; Bump up the first and last elements, as they're only ;; counted once. (incf (gethash (first template) freq-table) 1/2) (incf (gethash (car (last template)) freq-table) 1/2) (return freq-table)))) (defun element-range (freq-table) "Return the difference of the frequencies of the most common and least common elements." (loop :for elem :being :the :hash-keys :of freq-table :using (hash-value count) :maximize count :into highest :minimize count :into lowest :finally (return (- highest lowest)))) (defun solve (n-generations) (loop :with polymer := (template-table +template+) :repeat n-generations :do (setf polymer (apply-rules polymer)) :finally (return (element-range (count-elements polymer))))) (defun solve-part-1 () (solve 10)) (defun solve-part-2 () (solve 40)) Lainchan leaderboard 388839-baef610d
The Phantom Phreak · 2021-12-14 09:31
Day 14. (map max part 2) #!/usr/bin/env python3 import sys import re def inc(dictionary, key): try: dictionary[key] += 1 except KeyError: dictionary[key] = 1 polymer = {} template = input() for p in template: inc(polymer, p) rules = {} for line in sys.stdin: if line == '\n': continue source, target = [ group for group in re.match(r'([a-zA-Z]{2}) -> ([a-zA-Z])', line).groups() ] rules[source] = target for i in range(int(sys.argv[1]) if len(sys.argv) > 1 else 16): template_new = [] prev = template[0] template_new.append(prev) for c in template[1:]: insertion = rules[prev + c] inc(polymer, insertion) template_new.append(insertion) template_new.append(c) prev = c print(f'at step {i}: {template} -> {"".join(template_new)} {polymer}') template = ''.join(template_new) l = min([polymer[p] for p in polymer.keys()]) m = max([polymer[p] for p in polymer.keys()]) print(f'the most common element ({m}) minus the least common element ({l}) yields a difference of {m - l}')
J.C. Denton · 2021-12-14 09:36
I'm digging the lispers, the code always looks so clean. Thanks >>28961 in particular for keeping it so readable.
Koos van der Merwe · 2021-12-14 14:58
>>28961 Guile can into maps as well...but without your fancy loops, recursion serves well enough :) Now I see how should I have done the counting, I didn't really think that trough it seems. (use-modules (ice-9 rdelim) (ice-9 match) (ice-9 hash-table) (srfi srfi-1) (srfi srfi-43) (ice-9 receive)) (define (get-input filename) (call-with-input-file filename (lambda (port) (let [(init (string->list (read-line port))) (trans (lambda (line) (match-let* [((pair _ mid) (string-split line #\space)) (key (string->list pair)) (val (string-ref mid 0))] (cons key (list (list (first key) val) (list val (last key)))))))] (read-line port) ;;skip empty line (let loop [(line (read-line port)) (lines '())] (if (eof-object? line) (cons init (reverse lines)) (loop (read-line port) (cons (trans line) lines)))))))) (define (in) (let* [(input (get-input "input")) (polymer-lst (car input)) (extensions (alist->hash-table (cdr input))) (polymer (make-hash-table)) (increment (lambda (el) (hash-set! polymer el (1+ (hash-ref polymer el 0)))))] (for-each (lambda (a b) (increment (list a b))) polymer-lst (cdr polymer-lst)) (list polymer extensions))) (define (extend-polymer polymer extensions) (let* [(new-polymer (alist->hash-table (hash-map->list cons polymer))) (increment (lambda (val el) (hash-set! new-polymer el (max 0 (+ val (hash-ref new-polymer el 0))))))] (hash-for-each-handle (match-lambda [(pair . count) (when (hash-ref extensions pair) (increment (* -1 count) pair)) (for-each (lambda (key) (increment count key)) (hash-ref extensions pair))]) polymer) new-polymer)) (define (score polymer) (let* [(counted (make-hash-table)) (increment (lambda (el val) (hash-set! counted el (+ val (hash-ref counted el 0)))))] (hash-for-each-handle (lambda (el) (increment (caar el) (cdr el))) polymer) (let [(sorted (sort (hash-map->list cons counted) (lambda (a b) (> (cdr a) (cdr b)))))] (- (cdr (car sorted)) (cdr (last sorted)))))) (define (strength step-limit polymer extensions) (do [(step 0 (1+ step)) (polymer polymer (extend-polymer polymer extensions))] [(= step-limit step) (1+ (score polymer))])) ;; +1 because the last character is the most common one and it gets ignored during count (format #t "~a~%~a~%" (apply strength 10 (in)) (apply strength 40 (in)))
Jet Black · 2021-12-15 07:24
Gotta admit it took me a while to realize I didn't have to update priorities in an already full queue, and could just start with an empty one. #include <fstream> #include <iostream> #include <string> #include <vector> #include <limits> #include <queue> using std::cout; using std::ifstream; using std::priority_queue; using std::string; using std::vector; using std::pair; vector<string> read_input(const char* filepath) { ifstream in_f(filepath); string line; vector<string> ret; while(std::getline(in_f, line)) ret.push_back(line); return ret; } class node { public: size_t x, y; int d; node(size_t x, size_t y, int d) : x(x), y(y), d(d) {} node() : node(0, 0, 0) {} bool operator <(const node& rhs) const { return d > rhs.d; } }; void extend_map(vector<vector<int>> &d) { vector<vector<int>> big; for(size_t i = 0; i != d.size() * 5; ++i) big.push_back(vector<int>(d[0].size() * 5, std::numeric_limits<int>::max())); d = big; } int smart_get(const vector<vector<int>> &r, size_t x, size_t y) { auto ret = r[x % (r.size())][y % (r[0].size())]; ret += x / r.size() + y / r[0].size(); if(ret > 9) ret = (ret % 10) + 1; return ret; } vector<pair<size_t,size_t>> get_neighbors(size_t x, size_t y, size_t lim_x, size_t lim_y) { vector<pair<size_t,size_t>> ret; if(x != 0) { ret.push_back(pair(x - 1, y)); } if(x != lim_x - 1) { ret.push_back(pair(x + 1, y)); } if(y != 0) { ret.push_back(pair(x, y - 1)); } if(y != lim_y - 1) { ret.push_back(pair(x, y + 1)); } return ret; } int dijkstra(vector<vector<int>> &d, const vector<vector<int>> &r) { priority_queue<node> q; q.push(node(0, 0, 0)); d[0][0] = 0; while(!q.empty()) { auto n = q.top(); auto curr_d = d[n.x][n.y]; q.pop(); for(auto const &p : get_neighbors(n.x, n.y, d.size(), d[0].size())) { auto risk = smart_get(r, p.first, p.second); auto new_d = curr_d + risk; if(new_d < d[p.first][p.second]) { d[p.first][p.second] = new_d; q.push(node(p.first, p.second, new_d)); } } } return d[d.size() - 1][d[0].size() - 1]; } int main() { vector<string> input = read_input("input.txt"); // Parse input vector<vector<int>> dist; vector<vector<int>> risk; for(auto const &s : input) { vector<int> new_r; for(size_t j = 0; j != s.length(); ++j) new_r.push_back(s[j] - '0'); risk.push_back(new_r); dist.push_back(vector<int>(s.length(), std::numeric_limits<int>::max())); } // Silver cout << dijkstra(dist, risk) << "\n"; // Gold extend_map(dist); cout << dijkstra(dist, risk) << "\n"; return 0; }
Bob Arctor · 2021-12-15 10:30
Day 15. very classic problem today #!/usr/bin/env python3 import sys from queue import PriorityQueue from dataclasses import dataclass class Bounds: width = 0 height = 0 @dataclass(order=True) class Pos: x: int y: int def bound(pos): return pos.x >= 0 and pos.y >= 0 and pos.x < Bounds.width and pos.y < Bounds.height def adjacent(pos): adjacents = [] for i in range(-1, 2): for j in range(-1, 2): if i == j or i == -j: continue if bound(Pos(pos.x + j, pos.y + i)): adjacents.append(Pos(pos.x + j, pos.y + i)) return adjacents risks = [] costs = [] visited = [] for line in sys.stdin: risks.append([int(r) for r in line.rstrip('\n')]) costs.append([sys.maxsize for r in line.rstrip('\n')]) visited.append([False for r in line.rstrip('\n')]) l = len(line.rstrip('\n')) if l > Bounds.width: Bounds.width = l h = len(risks) if h > Bounds.height: Bounds.height = h q = PriorityQueue() costs[0][0] = 0 risks[0][0] = 0 q.put((risks[0][0], Pos(0, 0))) while not q.empty(): cost, pos = q.get() visited[pos.y][pos.x] = True for a in adjacent(pos): new_cost = cost + risks[a.y][a.x] if new_cost < costs[a.y][a.x]: costs[a.y][a.x] = new_cost if not visited[a.y][a.x]: q.put((new_cost, a)) # results print(f'risk (cost so far)') print('\n'.join(['\t'.join([f'{c}({risks[y][x]})' for x, c in enumerate(row)]) for y, row in enumerate(costs)])) print(f'{costs[Bounds.height - 1][Bounds.width - 1]} is the lowest total risk of any path from top left (0, 0) to bottom right ({Bounds.height - 1}, {Bounds.width - 1})')
Fred Nurk · 2021-12-15 10:59
A* was fun, matrix wrangling not so much. (use-modules (ice-9 rdelim) (ice-9 match) (ice-9 hash-table) (srfi srfi-1) (srfi srfi-43) (ice-9 receive)) (define (get-lines filename trans) (call-with-input-file filename (lambda (port) (let loop [(line (read-line port)) (lines '())] (if (eof-object? line) (reverse lines) (loop (read-line port) (cons (trans line) lines))))))) (define (make-objects rows cols matrix) (list (lambda (row col . dflt) ;;getter (let [(fail (if (null? dflt) #f (car dflt)))] (cond [(< row 0) fail] [(>= row rows) fail] [(< col 0) fail] [(>= col cols) fail] [else (vector-ref matrix (+ col (* row cols)))]))) (lambda (row col val) ;;setter (when (and (>= row 0) (< row rows) (>= col 0) (< col cols)) (let [(index (+ col (* row cols)))] (if (procedure? val) (vector-set! matrix index (val (vector-ref matrix index))) (vector-set! matrix index val))))))) (define (in) (match-let* [(data (get-lines "input" (lambda (line) (map (lambda (chr-num) (- (char->integer chr-num) 48)) (string->list line))))) (rows (length data)) (cols (length (car data))) (matrix (make-vector (* rows cols) 0)) ((matrix-get matrix-set!) (make-objects rows cols matrix)) (not-visited (make-vector (* rows cols) #t)) ((not-visited-get not-visited-set!) (make-objects rows cols not-visited))] ;;set matrix values (for-each (lambda (row i) (for-each (lambda (n j) (matrix-set! i j n)) row (iota cols))) data (iota rows)) (list rows cols matrix-get not-visited-set! not-visited-get))) (define (for-each-matrix rows cols proc) (for-each (lambda (row) (for-each (lambda (col) (proc row col)) (iota cols))) (iota rows))) (define (new-val old add) (fold (lambda (add old) (if (= 10 (+ add old)) 1 (+ add old))) old (make-list add 1))) (define (in2 rows cols oldmatrix-get) (define (compute-new row col add) (new-val (oldmatrix-get row col) add)) (match-let* [(new-rows (* 5 rows)) (new-cols (* 5 cols)) (matrix (make-vector (* new-rows new-cols) 0)) (not-visited (make-vector (* new-rows new-cols) #t)) ((matrix-get matrix-set!) (make-objects new-rows new-cols matrix)) ((not-visited-get not-visited-set!) (make-objects new-rows new-cols not-visited))] (for-each-matrix rows cols (lambda (row col) (for-each-matrix 5 5 (lambda (i j) (matrix-set! (+ row (* i rows)) (+ col (* j cols)) (compute-new row col (+ i j))))))) (list new-rows new-cols matrix-get not-visited-set! not-visited-get))) (define (A*-search rows cols matrix visit! not-visited?) (define goal `(,(1- rows) ,(1- cols))) (define (heuristic pos) ;;Manhattan distance as heuristic (+ (- (first goal) (first pos)) (- (second goal) (second pos)))) (define (insert-front pos path cost front) (let* [(h (heuristic pos)) (f (+ cost h)) ;;(new-path (cons pos path)) ;;remeber path (new-path (list pos)) ;;don't track path (new-node (list f cost new-path))] (let loop [(front front)] (match front ['() (cons new-node '())] [((fi costi pathi) . remain) (if (<= fi f) (cons (car front) (loop remain)) (cons new-node front))])))) (let A* [(front (insert-front '(0 0) '() 0 '()))] (match-let* [(((f cost path) . remain) front) (pos (car path)) ((row col) pos)] (if (zero? (heuristic pos)) (cons cost path) (A* (fold (lambda (pos front) (if (and (apply matrix pos) (apply not-visited? pos)) (begin (visit! (first pos) (second pos) #f) (insert-front pos path (+ cost (apply matrix pos)) front)) front)) remain (list `(,(1+ row) ,col) `(,(1- row) ,col) `(,row ,(1+ col)) `(,row ,(1- col))))))))) (let* [(input (in)) (input2 (apply in2 (list-head input 3)))] (format #t "~a~%~a~%" (car (apply A*-search input)) (car (apply A*-search input2))))
Drifter · 2021-12-15 11:53
>>28981 Now I see I should have just wrapped the calls to matrix instead of generating the huge one. It still wasn't that slow despite this blunder.
Jane Doe · 2021-12-15 13:41
>>28983 I've redid my code (>>28981) to use smart_get like from >>28976 expecting speed up but it actually made things slower for 1s. (define (in2 rows cols oldmatrix-get) (match-let* [(new-rows (* 5 rows)) (new-cols (* 5 cols)) ((not-visited-get not-visited-set!) (make-objects new-rows new-cols (make-vector (* new-rows new-cols) #t))) (new-matrix-get (lambda (row col) (if (or (>= row new-rows) (>= col new-cols) (negative? row) (negative? col)) #f (let* [(val (oldmatrix-get (modulo row rows) (modulo col cols))) (new-val (+ val (floor (/ row rows)) (floor (/ col cols))))] (if (> new-val 9) (1+ (modulo new-val 10)) new-val)))))] (list new-rows new-cols new-matrix-get not-visited-set! not-visited-get)))
Dozer · 2021-12-16 06:46
Hello lains, parsing is probably my favorite type of puzzple. Here's my Day 16: (defpackage #:advent2021.day16 (:use #:cl #:alexandria #:cl-ppcre #:queues #:advent2021.util) (:export #:solve-part-1 #:solve-part-2)) (in-package #:advent2021.day16) (defun hex2val (c) (if (<= (char-code #\0) (char-code c) (char-code #\9)) (- (char-code c) (char-code #\0)) ;; 0..9 (- (char-code (char-upcase c)) (char-code #\A) -10))) ;; A..F (defparameter +input+ ;; Flatten the hex puzzle input into a bit-array. (loop :with line := (with-puzzle-file (stream) (read-line stream)) :with array := (make-array (* 4 (length line)) :element-type 'bit) :for c :across line :for nybble := (hex2val c) :for i :upfrom 0 :by 4 :do (setf (aref array i) (logand 1 (ash nybble -3))) :do (setf (aref array (+ 1 i)) (logand 1 (ash nybble -2))) :do (setf (aref array (+ 2 i)) (logand 1 (ash nybble -1))) :do (setf (aref array (+ 3 i)) (logand 1 (ash nybble -0))) :finally (return array))) (defconstant +literal-type+ 4) (defmacro defgetf-accessor (name indicator) "Define an inline-desirable wrapper function around getf." `(progn (declaim (inline ,name)) ;; XXX this macro leaks symbols NEW-VALUE and PLACE to the INDICATOR ;; param. I'd rather not change it to use gensyms though, because I want ;; those symbol names to be present in the function documentation, and the ;; indicators are only keywords in practice anyways. (defun ,name (place) (getf place ,indicator)) (defun (setf ,name) (new-value place) (setf (getf place ,indicator) new-value)))) (defun make-reader () (list :pos 0)) (defgetf-accessor pos :pos) (defun make-packet (version type payload) (list :version version :type type (if (= type +literal-type+) :value :subpackets) payload)) (defgetf-accessor ptype :type) (defgetf-accessor version :version) (defgetf-accessor value :value) (defgetf-accessor subpackets :subpackets) (defun read-bits (reader size) (loop :with start := (pos reader) :with result := 0 :for i :from start :below (+ start size) :do (setf result (logior (ash result 1) (aref +input+ i))) :finally (incf (pos reader) size) (return result))) (defun read-literal (reader) (loop :with result := 0 :for group := (read-bits reader 5) :do (setf result (logior (ash result 4) (logand group #b1111))) :while (= (logand #b10000 group) #b10000) :finally (return result))) (defun read-packet (reader) (let ((version (read-bits reader 3)) (type (read-bits reader 3))) (cond ;; simple (literal-value) packet: ((= type 4) (make-packet version type (read-literal reader))) ;; sized compound packet: ((= 0 (read-bits reader 1)) (make-packet version type (loop :with end := (+ (read-bits reader 15) (pos reader)) :collect (read-packet reader) :until (= (pos reader) end) :do (assert (not (> (pos reader) end)))))) ;; sizeless compound packet: (t (make-packet version type (loop :repeat (read-bits reader 11) :collect (read-packet reader))))))) (defun sum-versions (packet) (+ (version packet) (reduce #'+ (mapcar #'sum-versions (subpackets packet))))) (defun solve-part-1 () (sum-versions (read-packet (make-reader)))) (defun eval-packet (packet) (etypecase (ptype packet) ;; n-ary arithmetic compound packet: ((integer 0 3) (reduce (nth (ptype packet) (list #'+ #'* #'min #'max)) (mapcar #'eval-packet (subpackets packet)))) ;; simple (literal-value) packet: ((eql 4) (value packet)) ;; binary test compound packet: ((integer 5 7) (if (funcall (nth (- (ptype packet) 5) (list #'> #'< #'=)) (eval-packet (first (subpackets packet))) (eval-packet (second (subpackets packet)))) 1 0)))) (defun solve-part-2 () (eval-packet (read-packet (make-reader))))
Unknown · 2021-12-16 07:45
>>28984 Interesting, I wonder if inlining the smart_get in C++ would make it as fast as constructing the big table. >>29019 For me it was the opposite, get ready for some real soykaf code lads: #include <fstream> #include <iostream> #include <string> #include <vector> #include <algorithm> #include <sstream> using std::cout; using std::ifstream; using std::vector; using std::pair; using std::string; vector<string> read_input(const char* filepath) { ifstream in_f(filepath); string line; vector<string> ret; while(std::getline(in_f, line)) ret.push_back(line); return ret; } struct packet { unsigned long version, id, lit, l_id, l_sub; vector<packet> subs; }; unsigned long bit_to_int(const vector<bool> &b, size_t i, size_t l) { unsigned long ret = 0; for(size_t j = 0, s = l - 1; j != l; ++j, --s) ret += b[i + j] << s; return ret; } // Returns how many bits were parsed for the packet at b[i], // packet gets pushed into r, v is running version sum size_t parse_packet(const vector<bool>& b, size_t i, vector<packet> &r, unsigned long &v) { size_t parsed = 0; packet p; p.version = bit_to_int(b, i, 3); p.id = bit_to_int(b, i + 3, 3); parsed += 6; switch(p.id) { // Literal case 4: { size_t counter = i + 6; unsigned long val = 0; while(b[counter]) { val += bit_to_int(b, counter + 1, 4); val <<= 4; counter += 5; parsed += 5; } val += bit_to_int(b, counter + 1, 4); parsed += 5; p.lit = val; break; } // Operator default: p.l_id = bit_to_int(b, i + 6, 1); parsed += 1; // Change how many bits we read based on length id if(p.l_id) { p.l_sub = bit_to_int(b, i + 7, 11); parsed += 11; } else { p.l_sub = bit_to_int(b, i + 7, 15); parsed += 15; } // Keep reading until we have read n packages or n bits, // insert into current packages subs vector size_t sub_parsed = 0; if(p.l_id) { for(size_t c = 0; c != p.l_sub; ++c) sub_parsed += parse_packet(b, i + 18 + sub_parsed, p.subs, v); } else { auto idx = r.size() - 1; while(sub_parsed < p.l_sub) sub_parsed += parse_packet(b, i + 22 + sub_parsed, p.subs, v); } parsed += sub_parsed; } r.push_back(p); v += p.version; return parsed; } packet parse_bitstring(const vector<bool> &b, unsigned long &v) { vector<packet> ret; parse_packet(b, 0, ret, v); return ret[0]; } unsigned long calculate(const packet &packet) { unsigned long ret = 0; switch(packet.id) { // Lit case 4: ret = packet.lit; break; // Sum case 0: for(auto const &p : packet.subs) ret += calculate(p); break; // Prod case 1: ret = 1; for(auto const &p : packet.subs) ret *= calculate(p); break; // Min case 2: ret -= 1; for(auto const &p : packet.subs) { auto val = calculate(p); if(val < ret) ret = val; } break; // Max case 3: for(auto const &p : packet.subs) { auto val = calculate(p); if(val > ret) ret = val; } break; // GT case 5: ret = calculate(packet.subs[0]) > calculate(packet.subs[1]); break; // LT case 6: ret = calculate(packet.subs[0]) < calculate(packet.subs[1]); break; // EQ case 7: ret = calculate(packet.subs[0]) == calculate(packet.subs[1]); } return ret; } int main() { vector<string> input = read_input("input.txt"); // Parse input into bitstring vector<bool> bitstring; for(auto it = input[0].crbegin(); it != input[0].crend(); ++it) { string hexed = "0x"; hexed.push_back(*it); std::stringstream ss; ss << std::hex << hexed; unsigned long num; ss >> num; for(size_t i = 0; i != 4; ++i) { bitstring.push_back(num & 1); num >>= 1; } } std::reverse(bitstring.begin(), bitstring.end()); // Parse the bitstring unsigned long v_sum = 0; auto packet = parse_bitstring(bitstring, v_sum); // Silver cout << v_sum << "\n"; // Gold cout << calculate(packet) << "\n"; return 0; }
Knuth · 2021-12-16 08:28
I hate this type of puzzles, I'll force myself to do it in the evening
⍕ · 2021-12-16 10:43
>>29019 Thas a nise pazzle in a nise lang
Judge Fang · 2021-12-16 21:55
That was much more fun than I expected (use-modules (ice-9 rdelim) (ice-9 match) (srfi srfi-1)) (define (hex->bin hex) (let* [(bin (number->string (string->number (list->string `(,hex)) 16) 2)) (len (string-length bin))] (if (= 4 len) bin (string-join (append (make-list (- 4 len) "0") `(,bin)) "")))) (define (get-lines filename trans) (call-with-input-file filename (lambda (port) (let loop [(line (read-line port)) (lines '())] (if (eof-object? line) (reverse lines) (loop (read-line port) (cons (trans line) lines))))))) (define (convert line) (string->list (string-join (map hex->bin (string->list line)) ""))) (define in (convert (car (get-lines "input" identity)))) ;;helpers (define (bits->number bits) (string->number (list->string bits) 2)) (define (1? bit) (char=? #\1 bit)) (define (0? bit) (not (1? bit))) (define (packet->V-T-B packet) (let* [(V-bits (list-head packet 3)) (T-bits (list-head (list-tail packet 3) 3)) (B-bits (list-tail packet 6)) (read-bits 6)] (cons* read-bits (bits->number V-bits) (bits->number T-bits) B-bits))) (define (type-4->num payload) "Parse type 4 number and return it with remain and read bits" (let loop [(payload payload) (bin-num '()) (read-bits 0)] (let* [(mark (car payload)) (part (list-head (cdr payload) 4)) (num (append bin-num part)) (remain (list-tail payload 5))] (if (0? mark) (cons* (+ 5 read-bits) (string->number (list->string num) 2) remain) (loop remain num (+ 5 read-bits)))))) (define (sub-type payload) "Return number of bits/packets, type and remain" (let* [(I-bit (car payload)) (offset (if (1? I-bit) 11 15)) (type (if (1? I-bit) 'packet-count 'bit-count)) (read-bits (1+ offset))] (cons* read-bits type (bits->number (list-head (cdr payload) offset)) (list-tail (cdr payload) offset)))) (define (parse-packet bits) "Format (bits-read version type decoded-content remaining-bits)" (match-let* [((r0 ver typ . payload) (packet->V-T-B bits)) ((r1 num . payload) (if (= 4 typ) (type-4->num payload) (cons* 0 -1 payload))) ((r2 pck-typ pck-len . payload) (if (not (= 4 typ)) (sub-type payload) (cons* 0 'none -1 payload)))] (define (sub-parser stop?) (let loop [(count 0) (read-bits 0) (sub-packets '()) (payload payload)] (if (stop? count read-bits) (cons* (+ r0 r2 read-bits) ver typ (reverse sub-packets) payload) (let* [(sub-packet (parse-packet payload)) (sub-pck-strip (list-head sub-packet 4)) (r3 (car sub-packet)) (payload (list-tail sub-packet 4))] (loop (1+ count) (+ read-bits r3) (cons sub-pck-strip sub-packets) payload))))) (cond [(= 4 typ) (cons* (+ r0 r1) ver typ num payload)] [(eq? pck-typ 'packet-count) (sub-parser (lambda (pck-count bit-count) (= pck-count pck-len)))] [(eq? pck-typ 'bit-count) (sub-parser (lambda (pck-count bit-count) (= bit-count pck-len)))] [else (format #t "Error decoding!~%") #f]))) (define (problem-1 bits) (match-let dfs [((_ ver _ content . _) (parse-packet bits))] (if (list? content) (apply + ver (map dfs content)) ver))) (define (problem-2 bits) (match-let dfs [((_ _ typ content . _) (parse-packet bits))] (let [(unwrapped (if (number? content) `(,content) (map dfs content))) (b2n (lambda (bool?) (if bool? 1 0)))] (case typ [(4) content] [(0) (apply + 0 unwrapped)] [(1) (apply * 1 unwrapped)] [(2) (apply min unwrapped)] [(3) (apply max unwrapped)] [(5) (b2n (apply > unwrapped))] [(6) (b2n (apply < unwrapped))] [(7) (b2n (apply = unwrapped))])))) (format #t "~a~%~a~%" (problem-1 in) (problem-2 in))
word · 2021-12-17 08:35
I tried to be smart about day 17 but fuarrrk it, loops and maps it is: #include <fstream> #include <iostream> #include <string> #include <vector> #include <map> using std::cout; using std::ifstream; using std::map; using std::string; using std::vector; using std::pair; vector<string> read_input(const char* filepath) { ifstream in_f(filepath); string line; vector<string> ret; while(std::getline(in_f, line)) ret.push_back(line); return ret; } vector<int> valid_x_at_time(int t, const pair<int,int> &x) { vector<int> ret; if(t == 1) { for(int i = x.first; i != x.second + 1; ++i) ret.push_back(i); return ret; } for(int start_x = 0; start_x != x.first; ++start_x) { int pos = t >= start_x ? start_x * (start_x + 1) / 2 : t * ((start_x - t + 1) + start_x) / 2; if(pos >= x.first && pos <= x.second) ret.push_back(start_x); } return ret; } int y_pos(int start, int t) { int ret = 0; for(size_t i = 0; i != t; ++i) { ret += start; --start; } return ret; } pair<int,int> solve(const pair<int,int> &x, const pair<int,int> &y) { int high = 0; map<pair<int,int>,int> valid; for(int i = -200; i != 200; ++i) { for(int t = 0; true; ++t) { int pos = y_pos(i, t); if(pos >= y.first && pos <= y.second) { for(const auto &v : valid_x_at_time(t, x)) ++valid[pair<int,int>(v, i)]; high = i > high ? i : high; } else if(pos < y.first) { break; } } } return pair<int,int>(high * (high + 1) / 2, valid.size()); } int main() { vector<string> input = read_input("input.txt"); // Parse input pair<int,int> x_lims, y_lims; auto s = input[0]; auto comma_pos = s.find(","); auto x_string = s.substr(s.find("=") + 1, comma_pos); auto y_string = s.substr(s.find("=", comma_pos) + 1, s.length() - 1); x_lims.first = std::stoi(x_string.substr(0, x_string.find(".."))); x_lims.second = std::stoi(x_string.substr(x_string.find("..") + 2, x_string.length() - 1)); y_lims.first = std::stoi(y_string.substr(0, y_string.find(".."))); y_lims.second = std::stoi(y_string.substr(y_string.find("..") + 2, y_string.length() - 1)); // Get results auto p = solve(x_lims, y_lims); // Silver cout << p.first << "\n"; // Gold cout << p.second << "\n"; return 0; }
Linda Lee · 2021-12-17 11:42
Shitcode for today...I worked with so many wrong assumptions but still came out with correct answer. How did you limit the search space? For me the overshoot? function does it and a limit of 10,000 steps beyond last found max. (use-modules (ice-9 rdelim) (ice-9 regex) (ice-9 q) (ice-9 match) (srfi srfi-1)) (define in (let [(line (call-with-input-file "input" read-line))] (map (lambda (match) (string->number (match:substring match))) (list-matches "-?[0-9]+" line)))) (define (simulate vel-x vel-y box) (match-let* [((x-min x-max y-min y-max) box) (overshoot? (lambda (x2 y2 x1 y1) (cond [(= x2 x1) ;;vertical falling (not (and (>= x1 x-min) (<= x1 x-max)))] [(= y2 y1) ;;horizontal falling (not (and (>= y1 y-min) (<= y1 y-max)))] [else (let* [(k (/ (- y2 y1) (- x2 x1))) (n (- y2 (* k x2))) (fy (lambda (x) (+ n (* k x)))) (fx (lambda (y) (/ (- y n) k))) (yi (fy x-max)) (xi (fx y-min))] ;;(format #t "over xi:~a yi:~a~%" (exact->inexact xi) (exact->inexact yi)) (not (or (and (>= yi y-min) (<= yi y-max)) (and (>= xi x-min) (<= xi x-max)))))]))) (hit? (lambda (x y xp yp) (cond [(and (or (> x x-max) (< y y-min)) (and (not (zero? xp)) (not (zero? yp))) (overshoot? x y xp yp)) 'miss] [(or (> x x-max) (< y y-min)) 'flyby] [(and (>= x x-min) (<= x x-max) (>= y y-min) (<= y y-max)) 'hit] [else 'early])))] (let step [(x 0) (y 0) (xp 0) (yp 0) (max-h 0) (vel-x vel-x) (vel-y vel-y)] ;;(format #t "(~a ~a)~%" x y) (let [(hit (hit? x y xp yp))] (cond [(eq? hit 'miss) (cons 'miss -1)] [(eq? hit 'flyby) (cons 'flyby 0)] [(eq? hit 'hit) (cons 'hit max-h)] [(eq? 'early) (step (+ x vel-x) (+ y vel-y) x y (max y max-h) (max 0 (1- vel-x)) (1- vel-y))]))))) (define (greedy-search max-limit box) "Start velocity at (0,0) go only up or right" (define visited (make-hash-table)) (define (visit! vel-x vel-y) (hash-set! visited (cons vel-x vel-y) #t)) (define (visited? vel-x vel-y) (hash-ref visited (cons vel-x vel-y) #f)) (let greed-bfs [(limit max-limit) (front (enq! (make-q) '(0 0))) (best 0) (hits 0)] (if (or (zero? limit) (q-empty? front)) (cons hits best) (match-let* [((x y) (deq! front)) ((status . res) (simulate x y box))] (cond [(and (negative? res) (positive? best)) (greed-bfs (1- limit) front best hits)] [else (for-each (lambda (pos) (unless (apply visited? pos) (apply visit! pos) (enq! front pos))) (list `(,x ,(1+ y)) `(,(1+ x) ,(1+ y)) `(,(1+ x) ,y) `(,x ,(1- y)) `(,(1+ x) ,(1- y)))) (greed-bfs (if (> res best) max-limit (1- limit)) front (max res best) (if (eq? 'hit status) (1+ hits) hits))]))))) (let [(res (greedy-search 10000 in))] (format #t "~a~%~a~%" (cdr res) (car res)))
Ender · 2021-12-17 11:47
Day 17. Lot of room for optimization, but I don't have infinite time, none of the mechanisms I've tried (or tried coming up with) really usefully restricted the search space, so I just try within some silly bounds. #!/usr/bin/env python3 import sys import re from dataclasses import dataclass @dataclass(order=True) class Vec: x: int y: int def __str__(self): return f'({self.x}, {self.y})' x1, x2, y1, y2 = [int(group) for group in re.match(r'^target area: x=(-?[0-9]+)..(-?[0-9]+), y=(-?[0-9]+)..(-?[0-9]+)$', input()).groups()] print(x1, x2, y1, y2) def within(p, a, b): return p >= min(a, b) and p <= max(a, b) n = -1 y_global_max = -sys.maxsize v0_global_max = None for k in range(-x2 if x2 >= 0 else x2, x2 if x2 >= 0 else -x2): for l in range(-500, 500): n += 1 p0 = Vec(0, 0) p = Vec(p0.x, p0.y) v0 = Vec(k, l) v = Vec(v0.x, v0.y) y_local_max = -sys.maxsize if p0.y + v0.y < p0.y and y_global_max > 0: continue #print(f'attempt #{n} (v0 = {v0})') while not (within(p.x, x1, x2) and within(p.y, y1, y2)) and p.y > y2: if p.y > y_local_max: y_local_max = p.y p.x = p.x + v.x v.x += 1 if v.x < 0 else -1 if v.x > 0 else 0 p.y = p.y + v.y v.y -= 1 if p.x > x2 and v.x >= 0: break if p.x < x1 and v.x <= 0: break #print(f'throw #{n} p = {p} (v = {v})') if within(p.x, x1, x2) and within(p.y, y1, y2): print(f'success @ attempt #{n} with v0 = {v0}, probe at p = {p} ([{x1}, {x2}], [{y1}, {y2}], local y max = {y_local_max})') if y_local_max > y_global_max: print(f'new local best {y_local_max} with v0 = {v0} (previous {y_global_max})') y_global_max = y_local_max v0_global_max = Vec(v0.x, v0.y) print(f'global max of {y_global_max} with initial velocity v0 = {v0_global_max}') Tried to do day 16 too now, but it was too horrible, dealing with binary data in python. Didn't bother with string manipulation afterwards.
Miho Iwakura · 2021-12-18 10:08
Didn't have much time today so I went back to python instead of cpp. Please ignore the brute force gold star: import math import copy import itertools with open('input.txt', 'r') as in_f: lines = [x.strip() for x in in_f.readlines()] class Snail: # Constructor def __init__(self, val, left=None, right=None): if val is not None: self.is_lit = True self.lit = val else: self.is_lit = False self.lit = val self.l = left self.r = right self.p = None if self.l: self.l.p = self if self.r: self.r.p = self # Sum definition def __add_neighbor(snail, val, left): curr_s = snail curr_p = curr_s.p while curr_p and (curr_s == curr_p.l) == left: curr_s = curr_p curr_p = curr_p.p if not curr_p: return curr_s = curr_p.l if left else curr_p.r while not curr_s.is_lit: curr_s = curr_s.r if left else curr_s.l curr_s.lit += val def __explode_aux(snail): left_v = snail.l.lit right_v = snail.r.lit Snail.__add_neighbor(snail, left_v, True) Snail.__add_neighbor(snail, right_v, False) snail.is_lit = True snail.lit = 0 snail.l = None snail.r = None def explode(self, l): if self.is_lit: return False if l == 4: Snail.__explode_aux(self) return True return self.l.explode(l + 1) or self.r.explode(l + 1) def split(self): if self.is_lit and self.lit > 9: new_l = math.floor(self.lit / 2) new_r = math.ceil(self.lit / 2) self.is_lit = False self.lit = None self.l = Snail(new_l) self.r = Snail(new_r) self.l.p = self self.r.p = self return True elif self.is_lit: return False return self.l.split() or self.r.split() def __add__(self, o): new_snail = Snail(None, self, o) check = True while check: check = new_snail.explode(0) check = check or new_snail.split() return new_snail # Magnitude def __lt__(self, o): return self.magnitude() < o.magnitude() def magnitude(self): if self.is_lit: return self.lit return 3 * self.l.magnitude() + 2 * self.r.magnitude() # I/O def from_string(line, i): curr = line[i] i += 1 if(curr == '['): left, i = Snail.from_string(line, i) i += 1 right, i = Snail.from_string(line, i) i += 1 return (Snail(None, left, right), i) else: return (Snail(int(curr)), i) def __str__(self): if self.is_lit: return str(self.lit) return '[' + str(self.l) + ', ' + str(self.r) + ']' snails = [Snail.from_string(line, 0)[0] for line in lines] c_snails = copy.deepcopy(snails) sum_snail = snails[0] for snail in snails[1:]: sum_snail += snail # Silver print(sum_snail.magnitude()) # Gold max_sum = 0 for x, y in itertools.product(c_snails, repeat=2): x0 = copy.deepcopy(x) y0 = copy.deepcopy(y) x1 = copy.deepcopy(x) y1 = copy.deepcopy(y) s0 = (x0 + y0).magnitude() s1 = (x1 + y1).magnitude() max_sum = s0 if s0 > max_sum else max_sum max_sum = s1 if s1 > max_sum else max_sum print(max_sum)
Nobody important · 2021-12-18 22:08
worst day for me by far....I was stuck on some simple condition edge case :( (use-modules (ice-9 rdelim) (ice-9 match) (ice-9 eval-string) (ice-9 string-fun) (srfi srfi-1)) (define (get-lines filename trans) (call-with-input-file filename (lambda (port) (let loop [(line (read-line port)) (lines '())] (if (eof-object? line) (reverse lines) (loop (read-line port) (cons (trans line) lines))))))) (define (line->tree line) (eval-string (string-concatenate `("'" ,(string-replace-substring line "," " . "))))) (define in (get-lines "input" line->tree)) (define (explode snailfish) (define (propagate snailfish direction value) (match-let [((sub-l . sub-r) snailfish)] (cond [(and (eq? direction 'left) (number? sub-l)) (cons (+ value sub-l) sub-r)] [(and (eq? direction 'right) (number? sub-r)) (cons sub-l (+ value sub-r))] [(eq? direction 'left) (cons (propagate sub-l direction value) sub-r)] [(eq? direction 'right) (cons sub-l (propagate sub-r direction value))]))) (let dfs [(snailfish snailfish) (lvl 0)] "Returns (node . (exploded-l exploded-r exploded?)" (cond [(and (number? (car snailfish)) (number? (cdr snailfish)) (< lvl 4)) `(,snailfish . (-1 -1 #f))] ;;end nothing to explode [(and (number? (car snailfish)) (number? (cdr snailfish)) (= lvl 4)) (cons 0 (list (car snailfish) (cdr snailfish) #t))] ;;exploded [(number? (car snailfish)) ;;(num (...)) (match-let* [((num . sub) snailfish) ((sub . exploded) (dfs sub (1+ lvl))) ((l-explode r-explode exploded?) exploded)] (if (= -1 l-explode) (cons (cons num sub) exploded) (cons (cons (+ num l-explode) sub) (list -1 r-explode #t))))] [(number? (cdr snailfish)) ;;((...) num) (match-let* [((sub-snailfish . num) snailfish) ((sub-snailfish . exploded) (dfs sub-snailfish (1+ lvl))) ((l-explode r-explode exploded?) exploded)] (if (= -1 r-explode) (cons (cons sub-snailfish num) exploded) (cons (cons sub-snailfish (+ num r-explode)) (list l-explode -1 #t))))] [else (match-let* [((sub-l . sub-r) snailfish) ((sub-l . exploded-l) (dfs sub-l (1+ lvl))) ((l-explode r-explode exploded?) exploded-l)] (cond [(and exploded? (< -1 r-explode)) (cons (cons sub-l (propagate sub-r 'left r-explode)) (list l-explode -1 #t))] [exploded? (cons (cons sub-l sub-r) exploded-l)] [else (match-let* [((sub-r . exploded-r) (dfs sub-r (1+ lvl))) ((l-explode r-explode exploded?) exploded-r)] (if (and exploded? (< -1 l-explode)) (cons (cons (propagate sub-l 'right l-explode) sub-r) (list -1 r-explode #t)) (cons (cons sub-l sub-r) exploded-r)))]))]))) (define (split snailfish) (define (split-num num) (cons (floor (/ num 2)) (ceiling (/ num 2)))) (match-let [((sub-l . sub-r) snailfish)] ;;(format #t "~a | ~a~%" sub-l sub-r) (cond [(and (number? sub-l) (<= 10 sub-l)) (cons (cons (split-num sub-l) sub-r) #t)] [(and (number? sub-r) (<= 10 sub-r)) (if (pair? sub-l) (match-let [((sub-l . splitted?) (split sub-l))] (if splitted? (cons (cons sub-l sub-r) #t) (cons (cons sub-l (split-num sub-r)) #t))) (cons (cons sub-l (split-num sub-r)) #t))] [(and (pair? sub-l) (pair? sub-r)) (match-let [((sub-l . splitted?) (split sub-l))] (if splitted? (cons (cons sub-l sub-r) #t) (match-let [((sub-r . splitted?) (split sub-r))] (cons (cons sub-l sub-r) splitted?))))] [(pair? sub-l) (match-let [((sub-l . splitted?) (split sub-l))] (cons (cons sub-l sub-r) splitted?))] [(pair? sub-r) (match-let [((sub-r . splitted?) (split sub-r))] (cons (cons sub-l sub-r) splitted?))] [else (cons snailfish #f)]))) (define (printer snailfish) (match-let dfs [((sub-l . sub-r) snailfish)] (display "[") (if (pair? sub-l) (dfs sub-l) (display sub-l)) (display ",") (if (pair? sub-r) (dfs sub-r) (display sub-r)) (display "]")) (newline)) (define (magnitude snailfish) (match-let dfs [((sub-l . sub-r) snailfish)] (+ (* 3 (if (pair? sub-l) (dfs sub-l) sub-l)) (* 2 (if (pair? sub-r) (dfs sub-r) sub-r))))) (define (add snailfish2 snailfish1) (define (exploding snailfish) ;;(printer snailfish) (match-let [((snailfish . (l r exploded?)) (explode snailfish))] ;;(when exploded? (display "ex ")) (if exploded? (exploding snailfish) (match-let [((snailfish . splitted?) (split snailfish))] ;;(when splitted? (display "sp ")) (if splitted? (exploding snailfish) snailfish))))) (exploding (cons snailfish1 snailfish2))) (define (find-max fishes) (let loop [(fishes fishes) (max-mag 0)] (if (null? fishes) max-mag (let loop2 [(fishes2 (cdr fishes)) (max-mag2 max-mag)] (if (null? fishes2) (loop (cdr fishes) max-mag2) (loop2 (cdr fishes2) (max max-mag2 (magnitude (add (car fishes) (car fishes2))) (magnitude (add (car fishes2) (car fishes)))))))))) (when (string= "d18.scm" (car (command-line))) (let [(fishes (get-lines (second (command-line)) line->tree))] (format #t "~a~%~a~%" (magnitude (reduce add '() fishes)) (find-max fishes))))
Nobody special · 2021-12-19 23:25
I guess that's it from me boys. My soykaf doesn't work.
Turing · 2021-12-20 04:51
Once again python and the naive solution (20 min on real input lol) for time reasons. Hopefully after the 25th I can come back to this one to implement solving for the correct rotation between two scanners in a single step import itertools with open('input.txt', 'r') as in_f: lines = [x.strip() for x in in_f.readlines()] class Scanner: class Point: def __init__(self, x, y, z, s=None): if s: toks = [int(t) for t in s.split(',')] self.x = toks[0] self.y = toks[1] self.z = toks[2] else: self.x = x self.y = y self.z = z def distance(self, o): return abs(self.x - o.x) + abs(self.y - o.y) + abs(self.z - o.z) def __str__(self): return f'({self.x}, {self.y}, {self.z})' def __eq__(self, o): return self.x == o.x and self.y == o.y and self.z == o.z def __hash__(self): return hash(self.x) ^ hash(self.y) ^ hash(self.z) def __init__(self, idx): self.id = idx self.loc = self.Point(0, 0, 0) self.points = [] self.aligned = True if idx == 0 else False self.no_align = [] def add_point(self, s): self.points.append(self.Point(None, None, None, s)) def get_rotations(self, x, y, z): return [ self.Point(x,y,z),self.Point(x,z,-y),self.Point(x,-y,-z),self.Point(x,-z,y), self.Point(-x,-y,z),self.Point(-x,z,y),self.Point(-x,y,-z),self.Point(-x,-z,-y), self.Point(y,-x,z),self.Point(y,z,x),self.Point(y,x,-z),self.Point(y,-z,-x), self.Point(-y,x,z),self.Point(-y,z,-x),self.Point(-y,-x,-z),self.Point(-y,-z,x), self.Point(z,y,-x),self.Point(z,-x,-y),self.Point(z,-y,x),self.Point(z,x,y), self.Point(-z,-y,-x),self.Point(-z,-x,y),self.Point(-z,y,x),self.Point(-z,x,-y) ] def build_rotations(self): self.rotations = [[] for _ in range(24)] for p in self.points: rots = self.get_rotations(p.x, p.y, p.z) for i, r in enumerate(rots): self.rotations[i].append(r) def get_absolute_points(self): ret = [] for p in self.points: ret.append(self.Point(p.x + self.loc.x, p.y + self.loc.y, p.z + self.loc.z)) return ret def align(self, o): if self.id in o.no_align or o.id in self.no_align or o.aligned: return False found_align = False for rot in o.rotations: for p_ref, p_o in itertools.product(self.points, rot): shift = [p_ref.x - p_o.x, p_ref.y - p_o.y, p_ref.z - p_o.z] hits = 0 for p in rot: shifted = self.Point(p.x + shift[0], p.y + shift[1], p.z + shift[2]) if shifted in self.points: hits += 1 if hits == 12: found_align = True correct_shift = shift break if found_align: break if found_align: break if found_align: o.loc.x = self.loc.x + correct_shift[0] o.loc.y = self.loc.y + correct_shift[1] o.loc.z = self.loc.z + correct_shift[2] o.points = rot o.aligned = True return found_align # Parse input scanners = [] for line in lines: if not line: continue elif 'scanner' in line: scanners.append(Scanner(int(line.split()[2]))) else: scanners[-1].add_point(line) for s in scanners: s.build_rotations() aligned = [scanners[0]] unaligned = scanners[1:] while len(aligned) != len(scanners): new_aligned = aligned for s0, s1 in itertools.product(aligned, unaligned): if s0.align(s1): new_aligned.append(s1) aligned = new_aligned # Puzzle outputs silver = set() for s in aligned: for p in s.get_absolute_points(): silver.add(p) gold = 0 for s0, s1 in itertools.product(scanners, scanners): dist = s0.loc.distance(s1.loc) if dist > gold: gold = dist print(len(silver)) print(gold)
if · 2021-12-20 05:44
The damn trick got me, I might've made top 100 if I had caught it. Once again with Python: with open('input.txt', 'r') as in_f: lines = [x.strip() for x in in_f.readlines()] class Image: mapper = {'#': '1', '.': '0'} def __init__(self, lines): self.im = [] for i, l in enumerate(lines): if not l: continue elif i == 0: self.algo = ''.join(l) else: row = [x for x in l] self.im.append(row) def smart_get(self, x, y, flip): if x < 0 or x >= len(self.im[0]) or y < 0 or y >= len(self.im): if flip and self.algo[0] == '#': return '#' else: return '.' return self.im[y][x] def get_surrounding(self, x, y, flip): ret = [] for i in range(-1, 2): for j in range(-1, 2): ret.append(self.smart_get(x + j, y + i, flip)) return int(''.join([Image.mapper[x] for x in ret]), 2) def apply(self, n): for a in range(n): new_image = [] for i in range(-1, len(self.im) + 1): new_row = [] for j in range(-1, len(self.im[0]) + 1): algo_coord = self.get_surrounding(j, i, a % 2 == 1) algo_char = self.algo[algo_coord] new_row.append(algo_char) new_image.append(new_row) self.im = new_image def count(self): ret = 0 for l in self.im: ret += l.count('#') return ret def print_image(self): for l in self.im: print(''.join(l)) print('') image = Image(lines) # Silver image.apply(2) print(image.count()) # Gold image.apply(48) print(image.count())
Agent Jones · 2021-12-21 06:14
@cache is straight up magic import itertools from functools import cache with open('input.txt', 'r') as in_f: lines = [x.strip() for x in in_f.readlines()] in_0 = int(lines[0].split()[-1]) in_1 = int(lines[1].split()[-1]) p0_p = in_0 p1_p = in_1 p0_s = 0 p1_s = 0 winner = -1 rolls = 0 for i in range(1, 1000, 6): p0_p += i + (i + 1) + (i + 2) rolls += 3 if p0_p > 10: if p0_p % 10 == 0: p0_p = 10 else: p0_p %= 10 p0_s += p0_p if p0_s >= 1000: winner = 0 break p1_p += (i + 3) + (i + 4) + (i + 5) rolls += 3 if p1_p > 10: if p1_p % 10 == 0: p1_p = 10 else: p1_p %= 10 p1_s += p1_p if p1_s >= 1000: winner = 1 break # Silver if winner == 0: print(p1_s * rolls) elif winner == 1: print(p0_s * rolls) # Gold @cache def dirac(turn, p0_score, p1_score, p0_pos, p1_pos): if p0_score >= 21: return 1 if p1_score >= 21: return 0 ret = 0 for x, y, z in itertools.product([1, 2, 3], repeat=3): new_pos = p0_pos + x + y + z if turn == 0 else p1_pos + x + y + z if new_pos > 10: new_pos = 10 if new_pos % 10 == 0 else new_pos % 10 new_score = p0_score + new_pos if turn == 0 else p1_score + new_pos if turn == 0: ret += dirac(1, new_score, p1_score, new_pos, p1_pos) else: ret += dirac(0, p0_score, new_score, p0_pos, new_pos) return ret print(dirac(0, 0, 0, in_0, in_1))
Tank · 2021-12-21 12:39
Life has been too busy, but I managed to find some time today to do some of the past exercises. Doing day 20 made me want to visualize the procedure, so I present to you lains what the image enhancer does in vid related, I think it's pretty neat.
Hitomi · 2021-12-21 14:56
>>29098 That looks great, it was a nice problem after day 19
Spike Spiegel · 2021-12-22 07:48
Day 22 once again in Python, I wanna get off Eric's geometry ride: with open('input.txt', 'r') as in_f: lines = [x.strip() for x in in_f.readlines()] class Cube: def __init__(self, on, x_min, x_max, y_min, y_max, z_min, z_max, l=None): if l is not None: self.on = l.split()[0] == 'on' toks = l.split()[1].split(',') self.x_min = int(toks[0].split('=')[1].split('..')[0]) self.x_max = int(toks[0].split('=')[1].split('..')[1]) self.y_min = int(toks[1].split('=')[1].split('..')[0]) self.y_max = int(toks[1].split('=')[1].split('..')[1]) self.z_min = int(toks[2].split('=')[1].split('..')[0]) self.z_max = int(toks[2].split('=')[1].split('..')[1]) else: self.on = on self.x_min = x_min self.x_max = x_max self.y_min = y_min self.y_max = y_max self.z_min = z_min self.z_max = z_max self.e_x = (self.x_max - self.x_min) / 2 self.e_y = (self.y_max - self.y_min) / 2 self.e_z = (self.z_max - self.z_min) / 2 self.c_x = self.x_min + self.e_x self.c_y = self.y_min + self.e_y self.c_z = self.z_min + self.e_z def is_big(self): return (self.x_min < -50 or self.x_max > 50 or self.y_min < -50 or self.y_max > 50 or self.z_min < -50 or self.z_max > 50) def volume(self): x_len = self.x_max - self.x_min + 1 y_len = self.y_max - self.y_min + 1 z_len = self.z_max - self.z_min + 1 return x_len * y_len * z_len def intersects(self, o): if (abs(self.c_x - o.c_x)-(self.e_x+o.e_x) <= 0 and abs(self.c_y - o.c_y)-(self.e_y+o.e_y) <= 0 and abs(self.c_z - o.c_z)-(self.e_z+o.e_z) <= 0): return True return False def contains(self, c1): if (self.x_min >= c1.x_min and self.x_max <= c1.x_max and self.y_min >= c1.y_min and self.y_max <= c1.y_max and self.z_min >= c1.z_min and self.z_max <= c1.z_max): return self elif (c1.x_min >= self.x_min and c1.x_max <= self.x_max and c1.y_min >= self.y_min and c1.y_max <= self.y_max and c1.z_min >= self.z_min and c1.z_max <= self.z_max): return c1 return None def split(self, o): splits = [] i_x_min = max(self.x_min, o.x_min) i_x_max = min(self.x_max, o.x_max) i_y_min = max(self.y_min, o.y_min) i_y_max = min(self.y_max, o.y_max) i_z_min = max(self.z_min, o.z_min) i_z_max = min(self.z_max, o.z_max) # X from left if self.x_min < i_x_min: splits.append(Cube(self.on, self.x_min, i_x_min - 1, self.y_min, self.y_max, self.z_min, self.z_max)) self.x_min = i_x_min # And right if i_x_max < self.x_max: splits.append(Cube(self.on, i_x_max + 1, self.x_max, self.y_min, self.y_max, self.z_min, self.z_max)) self.x_max = i_x_max # Y from below if self.y_min < i_y_min: splits.append(Cube(self.on, self.x_min, self.x_max, self.y_min, i_y_min - 1, self.z_min, self.z_max)) self.y_min = i_y_min # And above if i_y_max < self.y_max: splits.append(Cube(self.on, self.x_min, self.x_max, i_y_max + 1, self.y_max, self.z_min, self.z_max)) self.y_max = i_y_max # Z from behind if self.z_min < i_z_min: splits.append(Cube(self.on, self.x_min, self.x_max, self.y_min, self.y_max, self.z_min, i_z_min - 1)) self.z_min = i_z_min # And front if i_z_max < self.z_max: splits.append(Cube(self.on, self.x_min, self.x_max, self.y_min, self.y_max, i_z_max + 1, self.z_max)) self.z_max = i_z_max return splits # Solve as we parse silver_flag = True cubes = [Cube(None, None, None, None, None, None, None, lines[0])] for line in lines[1:]: new_cube = Cube(None, None, None, None, None, None, None, line) # Output silver when we start reading bigger cubes if silver_flag and new_cube.is_big(): print(sum([x.volume() for x in cubes])) silver_flag = False new_cubes = [] add_flag = new_cube.on for i, cube in enumerate(cubes): # No intersection if not cube.intersects(new_cube): new_cubes.append(cube) continue contained = cube.contains(new_cube) # Old cube in list is contained, do not add to new cubes if contained and contained == cube: continue # New cube is contained, add the container and rest of list unchanged if contained and contained == new_cube: if new_cube.on: new_cubes += cubes[i:] add_flag = False break # Else, we have to split (also if contained and off) splits = cube.split(new_cube) new_cubes += splits if add_flag: new_cubes.append(new_cube) cubes = new_cubes # Gold print(sum([x.volume() for x in cubes]))
Yu-ichi · 2021-12-22 08:26
Day 22 (only part1): #!/usr/bin/env python3 import sys import re def process_command(command, cube): print(f'processing {command}') for z in range(command[1][4], command[1][5] + 1): for y in range(command[1][2], command[1][3] + 1): for x in range(command[1][0], command[1][1] + 1): cube.add((x, y, z)) if command[0] else cube.discard((x, y, z)) initialization_size = 50 commands = [] cube = set() for line in sys.stdin: match = re.match(r'(on|off) x=(-?[0-9]+)..(-?[0-9]+),y=(-?[0-9]+)..(-?[0-9]+),z=(-?[0-9]+)..(-?[0-9]+)', line.rstrip('\n')) if not match or len([group for group in match.groups()[1:] if abs(int(group)) > 50]) > 0: continue commands.append((match.groups()[0] == 'on', [int(group) for group in match.groups()[1:]])) while len(commands) > 0: command = commands.pop(0) process_command(command, cube) print(f'{len(cube)} cubes are turned on') # TODO: try calculating intersections instead >>29110 Not going to lie, that seems slightly convoluted. Like all 3D geometry code typically ends up I imagine.
⍕ · 2021-12-23 18:00
No code from me today, solved it by hand
Naomi Nascimento · 2021-12-24 08:56
Code for today is only a formality really, again solved by hand and checked with the script: class ALU: def __init__(self, n): self.digits = [int(x) for x in n] def smart_z(self): s_z = self.digits[0] + 15 s_z = s_z * 26 + self.digits[1] + 8 s_z = s_z * 26 + self.digits[2] + 2 # d2 - 7 = d3 if (s_z % 26) - 9 == self.digits[3]: s_z = s_z // 26 else: s_z = s_z // 26 s_z = s_z * 26 + self.digits[3] + 6 s_z = s_z * 26 + self.digits[4] + 13 s_z = s_z * 26 + self.digits[5] + 4 s_z = s_z * 26 + self.digits[6] + 1 # d6 - 4 = d7 if (s_z % 26) - 5 == self.digits[7]: s_z = s_z // 26 else: s_z = s_z // 26 s_z = s_z * 26 + self.digits[7] + 9 s_z = s_z * 26 + self.digits[8] + 5 # d8 - 2 = d9 if (s_z % 26) - 7 == self.digits[9]: s_z = s_z // 26 else: s_z = s_z // 26 s_z = s_z * 26 + self.digits[9] + 13 # d5 - 8 = d10 if (s_z % 26) - 12 == self.digits[10]: s_z = s_z // 26 else: s_z = s_z // 26 s_z = s_z * 26 + self.digits[10] + 9 # d4 + 3 = d11 if (s_z % 26) - 10 == self.digits[11]: s_z = s_z // 26 else: s_z = s_z // 26 s_z = s_z * 26 + self.digits[11] + 6 # d1 + 7 = d12 if (s_z % 26) - 1 == self.digits[12]: s_z = s_z // 26 else: s_z = s_z // 26 s_z = s_z * 26 + self.digits[12] + 2 # d0 + 4 = d13 if (s_z % 26) - 11 == self.digits[13]: s_z = s_z // 26 else: s_z = s_z // 26 s_z = s_z * 26 + self.digits[13] + 2 return s_z print(ALU(str(52926995971999)).smart_z()) print(ALU(str(11811951311485)).smart_z())
Unnamed · 2021-12-24 09:23
That's it for me lains, I don't even see what's to be done probably because I'm not logged in. But I came here to wish every participant a nice and merry christmas. It was a nice ride! No matter what you managed and didn't manage, at least something was learned by trying!
Trinity · 2021-12-24 19:51
>>29151 In case you come back to this one, the assembly that is the puzzle input can be broken up into 14 blocks, one for each digit. There are two kinds of blocks, the ones that increase z by a factor of about 26, and the ones that conditionally decrease it by a factor of 26. You have 7 increasing blocks and 7 decreasing blocks, so you have to hit all conditions for z to be 0 at the end. The conditions are the digit constraints. In any case, merry christmas everyone, it was fun seeing people's solutions.
Unnamed · 2021-12-25 05:58
And just posting today's solution for the sake of completeness, hope everyone had a nice dinner. import numpy as np with open('input.txt', 'r') as in_f: lines = [x.strip() for x in in_f.readlines()] mapper = {'.': 0, '>': 1, 'v': 2} width = len(lines[0]) height = len(lines) cucumbers = np.zeros((height, width), dtype=int) right_coords = [] down_coords = [] for i, line in enumerate(lines): for j, c in enumerate(line): to_add = mapper[c] if to_add == 1: right_coords.append([i, j]) elif to_add == 2: down_coords.append([i, j]) cucumbers[i, j] = to_add moved_flag = True iter_counter = 0 while moved_flag: moved_flag = False # Right cucumbers right_neighbors_coords = [[x[0], (x[1] + 1) % width] for x in right_coords] right_neighbors = np.array([cucumbers[x[0], x[1]] for x in right_neighbors_coords]) zero_neighbors = np.nonzero(right_neighbors == 0)[0] for idx in zero_neighbors: cucumbers[right_coords[idx][0], right_coords[idx][1]] = 0 cucumbers[right_neighbors_coords[idx][0], right_neighbors_coords[idx][1]] = 1 right_coords[idx] = right_neighbors_coords[idx] if len(zero_neighbors) > 0: moved_flag = True # Down cucumbers down_neighbors_coords = [[(x[0] + 1) % height, x[1]] for x in down_coords] down_neighbors = np.array([cucumbers[x[0], x[1]] for x in down_neighbors_coords]) zero_neighbors = np.nonzero(down_neighbors == 0)[0] for idx in zero_neighbors: cucumbers[down_coords[idx][0], down_coords[idx][1]] = 0 cucumbers[down_neighbors_coords[idx][0], down_neighbors_coords[idx][1]] = 2 down_coords[idx] = down_neighbors_coords[idx] if len(zero_neighbors) > 0: moved_flag = True iter_counter += 1 print(iter_counter)