Spyke
advent_of_codeΒ·Advent Of Codebyhades

πŸ¦† Everybody.Codes 2025 Quest 4 Solutions πŸ¦†

Quest 4: Teeth of the Wind

  • 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

Link to participate: https://everybody.codes/

View original on programming.dev

Uiua

Fortunately the ratios for the common gears all proved to be rational in part 3.

βŒŠΓ—2025/÷⊏¯1_0[128 64 32 16 8]              # ->32400
βŒˆΓ—βŠ™Γ·Β°βŠŸβŠΒ―1_0βŠ™10000000000000[128 64 32 16 8] # -> 625000000000
βŠœβ–‘βŠΈβ‰ @\s "5 5|10 10|20 5"
βŒŠΓ—100Γ—βŠƒ(Γ·βˆ©β‹•βŠƒβŠ£βŠ’|/×≑◇(/Γ·βŠœβ‹•βŠΈβ‰ @|)β†˜1β†˜Β―1) # -> 400
3

Nim

For part 3 I parse gears as tuples, with regular gears having same value on both ends e.g.

3|5 -> (3, 5)
3   -> (3, 3)
proc parseGears(input: string): seq[int] =
  for line in input.splitLines():
    result.add parseInt(line)

proc parseNestedGears(input: string): seq[(int, int)] =
  for line in input.splitLines():
    let nested = line.split('|').mapIt(it.parseInt)
    result.add:
      if nested.len == 1: (nested[0], nested[0])
      else: (nested[0], nested[1])

proc solve_part1*(input: string): Solution =
  let gears = parseGears(input)
  result := 2025 * gears[0] div gears[^1]

proc solve_part2*(input: string): Solution =
  let gears = parseGears(input)
  result := ceil(10000000000000'f64 / (gears[0] / gears[^1])).int

proc solve_part3*(input: string): Solution =
  let gears = parseNestedGears(input)
  let ratios = (0..gears.high-1).mapIt(gears[it][1] / gears[it+1][0])
  result := int(100 * ratios.prod)

Full solution at Codeberg: solution.nim

2

I liked this one!

import Control.Arrow  
import Control.Monad  
import Data.List  
import Data.Ratio  

simpleTrain = uncurry (%) . (head &&& last) . map read  

compoundTrain input =  
  let a = read $ head input  
      z = read $ last input  
      gs =  
        map  
          ( uncurry (%)  
              . (read *** read . tail)  
              . break (== '|')  
          )  
          $ (tail . init) input  
   in foldl' (/) (a % z) gs  

part1, part2, part3 :: [String] -> Integer  
part1 = floor . (2025 *) . simpleTrain  
part2 = ceiling . (10000000000000 /) . simpleTrain  
part3 = floor . (100 *) . compoundTrain  

main =  
  forM_  
    [ ("everybody_codes_e2025_q04_p1.txt", part1),  
      ("everybody_codes_e2025_q04_p2.txt", part2),  
      ("everybody_codes_e2025_q04_p3.txt", part3)  
    ]  
    $ \(input, solve) -> readFile input >>= print . solve . lines  
2
Pyro
programming.dev

Python

# snipped read_input implementation
data = read_input("input_p3.txt")

# part 1 and 2 can be solved using a calculator 
# with only the first and last gears

def part3(data):
    shafts = data.splitlines()

    rotations = 100 * int(shafts[0])
    for shaft in shafts[1:-1]:
        gear1, gear2 = [int(g) for g in shaft.split('|')]
        rotations *= gear2 / gear1
    rotations /= int(shafts[-1])
    
    return int(rotations)

assert part3("""5
7|21
18|36
27|27
10|50
10|50
11""") == 6818

print(part3(data))
2
reboot6675reply
sopuli.xyz

Ohh so it was possible to use floats for this! I was "worried" that it would lead to precision errors haha so I ended up "cheating" with BigInt (Golang) to make all the multiplications first and one division at the end

2

Yeah, it may be possible for precision errors to accumulate in my solution but for EC the inputs are few enough that it doesn't really matter. Maybe I got a little lucky with my input too.

2

maaath

Scheme/Guile

(import (rnrs io ports (6)))

(define (parse-file file-name)
       (map string->number (string-split (call-with-input-file file-name get-string-all) #\newline)))

(let* ((gears (parse-file "notes/everybody_codes_e2025_q04_p1.txt")))
  (format #t "P1 Answer: ~a\n\n" (* 2025 (/ (car gears) (car (last-pair gears))))))


(let* ((gears (parse-file "notes/everybody_codes_e2025_q04_p2.txt")))
  (format #t "P2 Answer: ~a\n\n" (ceiling (* 10000000000000 (/ (car (last-pair gears)) (car gears))))))


(define (parse-file-p3 file-name)
       (map
              (lambda (line) (map string->number(string-split line #\|)))
              (string-split (call-with-input-file file-name get-string-all) #\newline)))
(let* ((gears (parse-file-p3 "notes/everybody_codes_e2025_q04_p3.txt")))
  (format #t "P2 Answer: ~a\n\n"
          (floor (* 100
             (apply * (map (lambda (gear) (if (= 1 (length gear)) 1 (/ (cadr gear) (car gear)))) gears))
             (/ (caar gears) (caar (last-pair gears)))))))
2

Rust

use num::{BigInt, Integer};

pub fn solve_part_1(input: &str) -> String {
    let gears: Vec<i64> = input.trim().lines().map(|g| g.parse().unwrap()).collect();
    (2025 * gears[0] / gears.last().unwrap()).to_string()
}

pub fn solve_part_2(input: &str) -> String {
    let gears: Vec<i64> = input.trim().lines().map(|g| g.parse().unwrap()).collect();
    let res = (BigInt::parse_bytes(b"10000000000000", 10).unwrap() * gears.last().unwrap())
        .div_ceil(&(BigInt::ZERO + gears[0]));
    res.to_string()
}

pub fn solve_part_3(input: &str) -> String {
    let mut lines = input.trim().lines();
    let first_gear = BigInt::parse_bytes(lines.next().unwrap().as_bytes(), 10).unwrap();
    let mut nominator: BigInt = first_gear * 100;
    let mut denominator: BigInt = BigInt::ZERO + 1;
    for line in lines {
        let mut split = line.split("|");
        denominator *= BigInt::parse_bytes(split.next().unwrap().as_bytes(), 10).unwrap();
        match split.next() {
            Some(size) => {
                nominator *= BigInt::parse_bytes(size.as_bytes(), 10).unwrap();
            }
            None => {
                break;
            }
        }
    }
    (nominator / denominator).to_string()
}
2

You reached the end

πŸ¦† Everybody.Codes 2025 Quest 4 Solutions πŸ¦† | Spyke