Day 25: Code Chronicle

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

  • mykl@lemmy.world
    link
    fedilink
    arrow-up
    2
    ·
    2 hours ago

    Uiua

    A Christmas Day treat: a one-liner for you all to decipher!

    "#####\n.####\n.####\n.####\n.#.#.\n.#...\n.....\n\n#####\n##.##\n.#.##\n...##\n...#.\n...#.\n.....\n\n.....\n#....\n#....\n#...#\n#.#.#\n#.###\n#####\n\n.....\n.....\n#.#..\n###..\n###.#\n###.#\n#####\n\n.....\n.....\n.....\n#....\n#.#..\n#.#.#\n#####"
    /+♭⊞(/×<8+)∩°□°⊟ (□≡≡/+⌕@#)@#(⊢⊢). (⍉⊜∘⊸≠@\n)¬±⦷"\n\n". 
    
  • GiantTree@feddit.org
    link
    fedilink
    arrow-up
    2
    ·
    5 hours ago

    Kotlin

    A fun and small challenge. First read all locks, transpose their profile and count the #s (-1 for the full row). Then do the same for the keys.

    Lastly find all keys for all locks that do not sum to more than 5 with their teeth:

    Code
    
    val lockRegex = Regex("""#{5}(\r?\n[.#]{5}){6}""")
    val keyRegex = Regex("""([.#]{5}\r?\n){6}#{5}""")
    
    fun parseLocksAndKeys(inputFile: String): Pair<List<IntArray>, List<IntArray>> {
        val input = readResource(inputFile)
        val locks = lockRegex
            .findAll(input)
            .map {
                it
                    .value
                    .lines()
                    .map { line -> line.toList() }
                    .transpose()
                    .map { line -> line.count { c -> c == '#' } - 1 }
                    .toIntArray()
            }
            .toList()
    
        val keys = keyRegex
            .findAll(input)
            .map {
                it
                    .value
                    .lines()
                    .map { line -> line.toList() }
                    .transpose()
                    .map { line -> line.count { c -> c == '#' } - 1 }
                    .toIntArray()
            }
            .toList()
    
        return locks to keys
    }
    
    fun part1(inputFile: String): String {
        val (locks, keys) = parseLocksAndKeys(inputFile)
    
        val matches = locks.map { lock ->
            keys.filter { key ->
                for (i in lock.indices) {
                    // Make sure the length of the key and lock do not exceed 5
                    if (lock[i] + key[i] > 5) {
                        return@filter false
                    }
                }
                true
            }
        }
            .flatten()
            .count()
    
        return matches.toString()
    }
    

    Also on GitHub

  • LeixB@lemmy.world
    link
    fedilink
    arrow-up
    2
    ·
    5 hours ago

    Haskell

    Merry Christmas!

    {-# LANGUAGE OverloadedStrings #-}
    
    module Main where
    
    import Data.Either
    import Data.Text hiding (all, head, zipWith)
    import Data.Text qualified as T
    import Data.Text.IO as TIO
    
    type Pins = [Int]
    
    toKeyLock :: [Text] -> Either Pins Pins
    toKeyLock v = (if T.head (head v) == '#' then Left else Right) $ fmap (pred . count "#") v
    
    solve keys locks = sum [1 | k <- keys, l <- locks, fit k l]
      where
        fit a b = all (<= 5) $ zipWith (+) a b
    
    main = TIO.getContents >>= print . uncurry solve . partitionEithers . fmap (toKeyLock . transpose . T.lines) . splitOn "\n\n"
    
  • mykl@lemmy.world
    link
    fedilink
    arrow-up
    3
    ·
    edit-2
    5 hours ago

    Dart

    Quick and dirty, and slightly tipsy, code.

    Happy Christmas everyone!

    Thanks to Eric and the team at Advent of Code, to @[email protected] and @[email protected] for giving us somewhere to share and discuss our solutions, and to everyone here for the friendly and supportive community.

    See you all next year!

    import 'dart:math';
    import 'package:collection/collection.dart';
    import 'package:more/more.dart';
    
    late int w, h;
    List<num> maxY(List<Point> ps) =>
        [for (var x in 0.to(w)) ps.where((p) => p.x == x).map((p) => p.y).max];
    List<num> minY(List<Point> ps) =>
        [for (var x in 0.to(w)) ps.where((p) => p.x == x).map((p) => p.y).min];
    
    part1(List<String> lines) {
      w = lines.first.length;
      h = lines.indexOf('');
      var gs = (lines..insert(0, ''))
          .splitBefore((l) => l.isEmpty)
          .map((g) => [
                for (var y in g.indexed())
                  for (var x
                      in y.value.split('').indexed().where((e) => e.value == '#'))
                    Point<num>(x.index, y.index - 1)
              ])
          .toList();
      var locks = gs.where((g) => g.count((g) => g.y == 0) == w).map(maxY);
      var keys = gs.where((g) => g.count((g) => g.y == h - 1) == w).map(minY);
      return locks
          .map((l) => keys.count((k) => 0.to(w).every((x) => k[x] > l[x])))
          .sum;
    }
    
  • Gobbel2000
    link
    fedilink
    arrow-up
    2
    ·
    7 hours ago

    Rust

    Nice ending for this year. Lock and key arrays are just added together and all elements must be <= 5. Merry Christmas!

    Solution
    fn flatten_block(block: Vec<Vec<bool>>) -> [u8; 5] {
        let mut flat = [0; 5];
        for row in &block[1..=5] {
            for x in 0..5 {
                if row[x] {
                    flat[x] += 1;
                }
            }
        }
        flat
    }
    
    fn parse(input: &str) -> (Vec<[u8; 5]>, Vec<[u8; 5]>) {
        let mut locks = Vec::new();
        let mut keys = Vec::new();
        for block_s in input.split("\n\n") {
            let block: Vec<Vec<bool>> = block_s
                .lines()
                .map(|l| l.bytes().map(|b| b == b'#').collect::<Vec<bool>>())
                .collect();
            assert_eq!(block.len(), 7);
            // Lock
            if block[0].iter().all(|e| *e) {
                locks.push(flatten_block(block));
            } else {
                keys.push(flatten_block(block));
            }
        }
        (locks, keys)
    }
    
    fn part1(input: String) {
        let (locks, keys) = parse(&input);
        let mut count = 0u32;
        for l in locks {
            for k in &keys {
                if l.iter().zip(k).map(|(li, ki)| li + ki).all(|sum| sum <= 5) {
                    count += 1;
                }
            }
        }
        println!("{count}");
    }
    
    fn part2(_input: String) {
        println!("⭐");
    }
    
    util::aoc_main!();
    

    Also on github

  • lwhjp@lemmy.sdf.org
    link
    fedilink
    arrow-up
    5
    ·
    11 hours ago

    Haskell

    A total inability to write code correctly today slowed me down a bit, but I got there in the end. Merry Christmas, everyone <3

    import Data.Either
    import Data.List
    import Data.List.Split
    
    readInput = partitionEithers . map readEntry . splitOn [""] . lines
      where
        readEntry ls =
          (if head (head ls) == '#' then Left else Right)
            . map (length . head . group)
            $ transpose ls
    
    main = do
      (locks, keys) <- readInput <$> readFile "input25"
      print . length $ filter (and . uncurry (zipWith (<=))) ((,) <$> locks <*> keys)
    
  • VegOwOtenks@lemmy.world
    link
    fedilink
    English
    arrow-up
    3
    ·
    edit-2
    10 hours ago

    Haskell

    Have a nice christmas if you’re still celebrating today, otherwise hope you had a nice evening yesterday.

    import Control.Arrow
    import Control.Monad (join)
    import Data.Bifunctor (bimap)
    import qualified Data.List as List
    
    heights = List.transpose
            >>> List.map (pred . List.length . List.takeWhile (== '#'))
    
    parse = lines
            >>> init
            >>> List.groupBy (curry (snd >>> (/= "")))
            >>> List.map (List.filter (/= ""))
            >>> List.partition ((== "#####") . head)
            >>> second (List.map List.reverse)
            >>> join bimap (List.map heights)
    
    cartesianProduct xs ys = [(x, y) | x <- xs, y <- ys]
    
    part1 = uncurry cartesianProduct
            >>> List.map (uncurry (List.zipWith (+)))
            >>> List.filter (List.all (<6))
            >>> List.length
    part2 = const 0
    
    main = getContents
            >>= print
            . (part1 &&& part2)
            . parse
    
  • sjmulder@lemmy.sdf.org
    link
    fedilink
    arrow-up
    4
    ·
    11 hours ago

    C

    Merry Christmas everyone!

    Code
    #include "common.h"
    
    int
    main(int argc, char **argv)
    {
    	static char buf[7];
    	static short h[500][5];	/* heights */
    	static short iskey[500];
    	int p1=0, nh=0, i,j,k;
    
    	if (argc > 1)
    		DISCARD(freopen(argv[1], "r", stdin));
    	
    	for (nh=0; !feof(stdin) && !ferror(stdin); nh++) {
    		assert(nh < (int)LEN(h));
    
    		for (i=0; i<7; i++) {
    			fgets(buf, 7, stdin);
    			if (i==0)
    				iskey[nh] = buf[0] == '#';
    			for (j=0; j<5; j++)
    				h[nh][j] += buf[j] == '#';
    		}
    
    		/* skip empty line */
    		fgets(buf, 7, stdin);
    	}
    
    	for (i=0; i<nh; i++)
    	for (j=0; j<nh; j++)
    		if (iskey[i] && !iskey[j]) {
    			for (k=0; k<5 && h[i][k] + h[j][k] <= 7; k++) ;
    			p1 += k == 5;
    		}
    
    	printf("25: %d\n", p1);
    	return 0;
    }
    

    https://codeberg.org/sjmulder/aoc/src/branch/master/2024/c/day25.c

    Made the 1 second challenge with most of it to spare! 😎

    $ time bmake bench                                                                                                      
    day01  0:00.00  1912 Kb  0+88 faults                                                                                            
    day02  0:00.00  1992 Kb  0+91 faults 
    day03  0:00.00  1920 Kb  0+93 faults
    day04  0:00.00  1912 Kb  0+90 faults 
    day05  0:00.00  2156 Kb  0+91 faults
    day06  0:00.03  1972 Kb  0+100 faults
    day07  0:00.06  1892 Kb  0+89 faults
    day08  0:00.00  1772 Kb  0+87 faults 
    day09  0:00.02  2024 Kb  0+137 faults
    day10  0:00.00  1876 Kb  0+87 faults 
    day11  0:00.00  6924 Kb  0+3412 faults
    day12  0:00.00  1952 Kb  0+103 faults
    day13  0:00.00  1908 Kb  0+88 faults
    day14  0:00.05  1944 Kb  0+92 faults                                                                                            
    day15  0:00.00  2040 Kb  0+89 faults
    day16  0:00.03  2020 Kb  0+250 faults
    day17  0:00.00  1896 Kb  0+88 faults
    day18  0:00.00  1952 Kb  0+107 faults
    day19  0:00.01  1904 Kb  0+91 faults
    day20  0:00.01  2672 Kb  0+325 faults
    day21  0:00.00  1804 Kb  0+86 faults
    day22  0:00.03  2528 Kb  0+371 faults
    day23  0:00.02  2064 Kb  0+152 faults
    day24  0:00.00  1844 Kb  0+89 faults
    day25  0:00.00  1788 Kb  0+89 faults  
                                                                    
    real    0m0,359s
    
  • Zikeji
    link
    fedilink
    English
    arrow-up
    2
    ·
    10 hours ago

    Javascript

    Spent 10 minutes debugging my solution until I reread and found out they wanted the number of keys that fit, not the ones that overlapped. Reading comprehension is not it tonight.

    const [locks, keys] = require('fs').readFileSync(0, 'utf-8').split(/\r?\n\r?\n/g).filter(v => v.length > 0).map(s => s.split(/\r?\n/g).filter(v => v.length > 0)).reduce((acc, s) => {
        const lock = s[0].split('').every(v => v === '#');
        const schema = s.slice(1, -1);
        let rotated = [];
        for (let i = 0; i < schema[0].length; i += 1) {
            for (let j = 0; j < schema.length; j += 1) {
                if (!rotated[i]) rotated[i] = [];
                rotated[i].push(schema[j][i]);
            }
        }
        if (!lock) {
            rotated = rotated.map(v => v.reverse());
        }
        const pinHeights = [];
        for (const row of rotated) {
            const height = row.indexOf('.');
            pinHeights.push(height !== -1 ? height : 5);
        }
        if (lock) {
            acc[0].push(pinHeights);
        } else {
            acc[1].push(pinHeights);
        }
        return acc;
    }, [[],[]]);
    
    let fits = 0;
    for (const lock of locks) {
        for (const key of keys) {
            let overlapped = false;
            for (let i = 0; i < lock.length; i += 1) {
                if ((lock[i] + key[i]) > 5) {
                    overlapped = true;
                }
            }
            if (!overlapped) {
                fits += 1;
            }
        }
    }
    
    console.log('Part One', fits);