Advent of Code 2024: Day 01


The Advent of Code 2024 just started! A little heads-up for those of you with a real CS diploma tired of doing dreadful code monkey crap at work.

Decided to do it in all the languages I'm decent at, for the first day only:

Common Lisp

For CL, and only for the first day, I have two versions:

Idiomatic
(load "~/.local/lib/quicklisp/setup.lisp")
(ql:quickload "iterate" :silent t)
(use-package :iterate)

(defparameter *input-path* (car uiop:*command-line-arguments*))

(let (keys vals)
  (iter (for (k v) on (uiop:read-file-forms *input-path*) by #'cddr)
    (push k keys)
    (push v vals))
  (setf keys (sort keys #'<)
        vals (sort vals #'<))
  (format t "Part 1: ~A~%"
          (reduce #'+ (mapcar (lambda (k v) (abs (- k v))) keys vals)))
  (format t "Part 2: ~A~%"
          (iter
            (with vtally = (iter (with ret = (make-hash-table))
                             (for v in vals)
                             (incf (gethash v ret 0))
                             (finally (return ret))))
            (for k in keys)
            (sum (* k (gethash k vtally 0))))))
Full-featured
(load (make-pathname :defaults *load-truename* :name "../rc"))
(in-package #:q3cpma-user)

(destructuring-bind (keys vals) (plist:separate (read:all-from-file *input-path*))
  (sortf keys #'<)
  (sortf vals #'<)
  (format t "Part 1: ~A~%"
          (reduce #'+ (mapcar (lambda (k v) (abs (- k v))) keys vals)))
  (format t "Part 2: ~A~%"
          (iter
            (with vtally = (tally vals))
            (for k in keys)
            (sum (* k (gethash k vtally 0))))))
Tcl 8.6
#!/usr/bin/env tclsh
namespace path {::tcl::mathop ::tcl::mathfunc}

try {
    set chan [open [lindex $argv 0]]
    set data [read $chan]
} finally {
    close $chan
}
set keys [lsort -int [lmap {1 2} $data {set 1}]]
set vals [lsort -int [lmap {1 2} $data {set 2}]]

set p1 [+ {*}[lmap k $keys v $vals {abs [- $k $v]}]]
puts "Part 1: $p1"

foreach v $vals {dict incr vtally $v}
set p2 [+ {*}[lmap k $keys { # Tcl 9: use [dict getwidthdefault $vtally $k 0]
    if {![dict exists $vtally $k]} continue
    * $k [dict get $vtally $k]
}]]
puts "Part 2: $p2"
Python
#!/usr/bin/env python
import sys

with open(sys.argv[1]) as f:
    data = [int(x) for x in f.read().rstrip().split()]
keys = sorted(data[0::2])
vals = sorted(data[1::2])

p1 = sum(abs(k - v) for (k, v) in zip(keys, vals))
print(f"Part 1: {p1}")

vtally = {}
for v in vals:
    vtally[v] = vtally.get(v, 0) + 1
p2 = sum(k * vtally.get(k, 0) for k in keys)
print(f"Part 2: {p2}")
POSIX-2024 sh
#!/bin/sh
set -eu

# Poor man's mktemp -d
i=$$; until mkdir -m 700 /tmp/temp$i; do i=$((i + 1)); done; d=/tmp/temp$i
trap 'exit 1' HUP INT QUIT ABRT TERM
trap 'rm -r "$d"' EXIT
in=$(realpath -- "$1")
cd "$d"

awk '{print $1}' "$in" | sort -g >k
awk '{print $2}' "$in" | sort -g >v

printf '%s' "Part 1: "$(paste -d - k v | bc | tr -d '-' | paste -sd+ - | bc)
printf '%s' "Part 2: "$(uniq -c v | join -22 k - | tr ' ' '*' | paste -sd+ - | bc)
C99
#if 0 // POSIX script mode: run with `sh file.c ARGS...`
set -eu
bin=$(echo "mkstemp(/tmp/tmp.XXXXXX)" | m4)
trap 'exit 1' HUP INT QUIT ABRT TERM
trap 'rm "$bin"' EXIT
if   command -v gcc   >/dev/null; then cc='gcc   -Wall -Wextra -std=c99 -pedantic'
elif command -v clang >/dev/null; then cc='clang -Wall -Wextra -std=c99 -pedantic'
else cc=c99; fi
$cc -O "$0" -o "$bin" && exec "$bin" "$@"
#endif

#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

static int int_cmp(const void *a, const void *b) {return *(int *)a - *(int *)b;}
#define VEC(T) struct {size_t l, c; T *d;}
#define VEC_PUSH(V, EL)                                                 \
    {                                                                   \
        if ((V).l == (V).c)                                             \
            (V).d = realloc((V).d, sizeof(*(V).d) * ((V).c = (V).c ? (V).c * 2 : 8)); \
        (V).d[(V).l++] = EL;                                            \
    }
#define VEC_SORT(V, CMPFUN) qsort((V).d, (V).l, sizeof(*(V).d), CMPFUN)


int main(int argc, char **argv)
{
    assert(argc == 2);
    FILE *f = fopen(argv[1], "r");
    assert(f);

    VEC(int) keys = {0};
    VEC(int) vals = {0};
    for (int k, v; fscanf(f, "%d %d", &k, &v) != EOF; )
    {
        VEC_PUSH(keys, k);
        VEC_PUSH(vals, v);
    }
    VEC_SORT(keys, int_cmp);
    VEC_SORT(vals, int_cmp);
    int dsum = 0;
    for (size_t i = 0; i < keys.l; ++i)
        dsum += abs(keys.d[i] - vals.d[i]);
    printf("Part 1: %d\n", dsum);

    struct kvpair {int k; size_t v;};
    VEC(struct kvpair) vtally = {0};
    for (size_t vi = 0; vi < vals.l; ++vi)
    {
        const int val = vals.d[vi];
        bool found = false;
        for (size_t ti = 0; ti < vtally.l; ++ti)
        {
            if (vtally.d[ti].k == val)
            {
                ++vtally.d[ti].v;
                found = true;
                break;
            }
        }
        if (!found)
            VEC_PUSH(vtally, ((struct kvpair){val, 1}));
    }
    int scoresum = 0;
    for (size_t ki = 0; ki < keys.l; ++ki)
    {
        const int key = keys.d[ki];
        for (size_t ti = 0; ti < vtally.l; ++ti)
        {
            if (vtally.d[ti].k == key)
            {
                scoresum += key * vtally.d[ti].v;
                break;
            }
        }
    }
    printf("Part 2: %d\n", scoresum);
}

My repo for the event: aoc2024