my solutions to advent of code
aoc advent-of-code

Compare changes

Choose any two refs to compare.

+4
.gitattributes
···
···
+
template/** -linguist-detectable
+
build.zig -linguist-detectable
+
template/** linguist-vendored
+
build.zig linguist-vendored
+11
.gitignore
···
input_example.txt
_build
target
···
input_example.txt
_build
target
+
zig-out
+
.zig-cache
+
out
+
*.ppm
+
*.pgm
+
*.pbm
+
*.bmp
+
*.png
+
*.gif
+
*.qoi
+
*.txt
-10
2015/16/sue.txt
···
-
children: 3
-
cats: 7
-
samoyeds: 2
-
pomeranians: 3
-
akitas: 0
-
vizslas: 0
-
goldfish: 5
-
trees: 3
-
cars: 2
-
perfumes: 1
···
+7
2015/18/rust/Cargo.lock
···
···
+
# This file is automatically @generated by Cargo.
+
# It is not intended for manual editing.
+
version = 4
+
+
[[package]]
+
name = "rust"
+
version = "0.1.0"
+6
2015/18/rust/Cargo.toml
···
···
+
[package]
+
name = "rust"
+
version = "0.1.0"
+
edition = "2024"
+
+
[dependencies]
+90
2015/18/rust/src/main.rs
···
···
+
use std::mem::swap;
+
+
fn generations(
+
times: u32,
+
mut world: Vec<u8>,
+
size: usize,
+
stuck: bool,
+
) -> Vec<u8> {
+
let pos = |x, y| y * (size + 2) + x;
+
+
let sizep = size + 1;
+
+
let mut new_world = vec![0_u8; (size + 2).pow(2)];
+
+
unsafe {
+
if stuck {
+
*world.get_unchecked_mut(pos(1, 1)) = 1;
+
*world.get_unchecked_mut(pos(size, 1)) = 1;
+
*world.get_unchecked_mut(pos(1, size)) = 1;
+
*world.get_unchecked_mut(pos(size, size)) = 1;
+
}
+
}
+
+
for _ in 0..times {
+
for yo in 1..sizep {
+
let ym = yo - 1;
+
let yp = yo + 1;
+
for xo in 1..sizep {
+
let xm = xo - 1;
+
let xp = xo + 1;
+
+
unsafe {
+
let was = *world.get_unchecked(pos(xo, yo)) == 1_u8;
+
let neighbours = world.get_unchecked(pos(xm, ym))
+
+ world.get_unchecked(pos(xo, ym))
+
+ world.get_unchecked(pos(xp, ym))
+
+ world.get_unchecked(pos(xm, yo))
+
+ world.get_unchecked(pos(xp, yo))
+
+ world.get_unchecked(pos(xm, yp))
+
+ world.get_unchecked(pos(xo, yp))
+
+ world.get_unchecked(pos(xp, yp));
+
*new_world.get_unchecked_mut(pos(xo, yo)) =
+
(neighbours == 3 || (neighbours == 2 && was)) as u8;
+
}
+
}
+
}
+
+
swap(&mut world, &mut new_world);
+
+
// i hate the duplication here :(
+
unsafe {
+
if stuck {
+
*world.get_unchecked_mut(pos(1, 1)) = 1;
+
*world.get_unchecked_mut(pos(size, 1)) = 1;
+
*world.get_unchecked_mut(pos(1, size)) = 1;
+
*world.get_unchecked_mut(pos(size, size)) = 1;
+
}
+
}
+
}
+
world
+
}
+
+
fn main() {
+
let input = include_str!("../../input.txt").trim();
+
let size = input.split_once("\n").expect("invalid input").0.len();
+
// reads the input but adds a line of buffer on the sides
+
let buffer_line = ".".repeat(size);
+
let input: Vec<u8> = format!("{buffer_line}\n{input}\n{buffer_line}")
+
.split("\n")
+
.map(|line| -> Vec<u8> {
+
format!(".{}.", line)
+
.chars()
+
.map(|v| (v == '#') as u8)
+
.collect()
+
})
+
.flatten()
+
.collect();
+
+
let part_1 = generations(100, input.clone(), size, false)
+
.iter()
+
.filter(|v| **v == 1)
+
.count();
+
println!("Part 1: {}", part_1);
+
+
let part_2 = generations(100, input.clone(), size, true)
+
.iter()
+
.filter(|v| **v == 1)
+
.count();
+
println!("Part 2: {}", part_2);
+
}
+40 -18
2015/19/rust/src/main.rs
···
-
struct Combination {
-
original: String,
-
target: String,
-
}
fn main() {
-
let input: String = std::fs::read_to_string("../input.txt").expect("invalid input!!");
-
let input: Vec<&str> = input.split("\n").collect();
-
let combinations: Vec<Combination> = &input[..input.len() - 2].iter().map(|v| {
-
let v: Vec<&str> = v.split(" ").collect();
-
match v[..] {
-
[original, _, target] => Combination {
-
original: original.to_string(),
-
target: target.to_string(),
-
},
-
_ => Combination {
-
original: "".to_string(),
-
target: "".to_string(),
-
},
}
-
}).
}
···
+
use std::collections::{HashMap, HashSet};
fn main() {
+
let input = include_str!("../../input.txt");
+
let input: Vec<&str> = input.trim().split("\n").collect();
+
+
let combinations: HashMap<String, Vec<String>> = {
+
let mut combinations = HashMap::new();
+
input[..input.len() - 2].iter().for_each(|v| {
+
let v: Vec<&str> = v.split(" ").collect();
+
match v[..] {
+
[original, "=>", target] => {
+
let entry = combinations
+
.entry(original.to_string())
+
.or_insert(Vec::with_capacity(1));
+
entry.push(target.to_string());
+
}
+
_ => panic!("{:?}", v),
+
}
+
});
+
combinations
+
};
+
+
let medicine_mol = input.last().unwrap();
+
+
// part 1
+
{
+
let mol_len = medicine_mol.len();
+
let mut possibilities: HashSet<String> = HashSet::new();
+
for i in 0..mol_len {
+
let (a, b) = medicine_mol.split_at(i);
+
combinations.iter().for_each(|(from, to)| {
+
to.iter().for_each(|to| {
+
possibilities.insert(format!(
+
"{}{}",
+
a,
+
b.replacen(from, to, 1)
+
));
+
})
+
});
}
+
println!("Part 1: {}", possibilities.len() - 1)
+
}
}
+2 -1
2015/2/rust/src/main.rs
···
use itertools::Itertools;
fn main() {
-
let input = std::fs::read_to_string("../input.txt").expect("invalid input!!");
let input = input
.trim()
.split("\n")
···
use itertools::Itertools;
fn main() {
+
let input =
+
std::fs::read_to_string("../input.txt").expect("invalid input!!");
let input = input
.trim()
.split("\n")
+7
2015/20/rust/Cargo.lock
···
···
+
# This file is automatically @generated by Cargo.
+
# It is not intended for manual editing.
+
version = 4
+
+
[[package]]
+
name = "rust"
+
version = "0.1.0"
+6
2015/20/rust/Cargo.toml
···
···
+
[package]
+
name = "rust"
+
version = "0.1.0"
+
edition = "2024"
+
+
[dependencies]
+33
2015/20/rust/src/main.rs
···
···
+
fn main() {
+
let input: u64 = include_str!("../../input.txt")
+
.trim()
+
.parse()
+
.expect("bad input");
+
let input = input / 10;
+
+
let mut highest_house = (0, 0);
+
let mut house: u64 = 1;
+
// while highest_house.1 < input {
+
while house < 10 {
+
let presents = if house % 2 == 0 {
+
(1..house + 1).fold(0, |acc, elf| {
+
if house % elf == 0 { acc + elf } else { acc }
+
})
+
} else {
+
(1..house.div_ceil(2) + 1).fold(0, |acc, elf| {
+
if house % (elf * 2) == 0 {
+
acc + elf
+
} else {
+
acc
+
}
+
})
+
};
+
if presents > highest_house.1 {
+
highest_house = (house, presents);
+
}
+
house += 1;
+
println!("{} {}", house, presents);
+
}
+
+
println!("Part 1: {:?}", highest_house);
+
}
+2 -1
2015/4/rust/src/main.rs
···
}
fn main() {
-
let input = std::fs::read_to_string("../input.txt").expect("invalid input!!");
let input = input.trim();
let res = find(input, 5);
···
}
fn main() {
+
let input =
+
std::fs::read_to_string("../input.txt").expect("invalid input!!");
let input = input.trim();
let res = find(input, 5);
+13 -13
2025/1/gleam/src/main.gleam
···
import simplifile as file
pub type RotationState {
-
RotationState(number: Int, zeroes: Int)
}
pub fn main() {
···
|> list.map(fn(l) {
case l {
"R" <> turn -> turn |> int.parse |> result.unwrap(0)
-
"L" <> turn -> 0 - { turn |> int.parse |> result.unwrap(0) }
_ -> panic as "bad input"
}
})
···
input
|> list.fold(RotationState(50, 0), fn(acc, v) {
let new_number =
-
int.modulo(acc.number + v, 100)
|> result.unwrap(0)
RotationState(new_number, case new_number {
0 -> acc.zeroes + 1
···
let part2 =
input
|> list.fold(RotationState(50, 0), fn(acc, v) {
-
let raw_new_number = acc.number + v
-
let new_number = int.modulo(raw_new_number, 100) |> result.unwrap(0)
-
let times_it_went_zero = {
-
let value = int.absolute_value(raw_new_number / 100)
-
case acc.number != 0, raw_new_number > 0 {
-
True, False -> value + 1
-
_, _ -> value
}
-
}
-
RotationState(new_number, acc.zeroes + times_it_went_zero)
})
-
part2.zeroes
|> int.to_string
|> io.println
···
import simplifile as file
pub type RotationState {
+
RotationState(turn: Int, zeroes: Int)
}
pub fn main() {
···
|> list.map(fn(l) {
case l {
"R" <> turn -> turn |> int.parse |> result.unwrap(0)
+
"L" <> turn -> -{ turn |> int.parse |> result.unwrap(0) }
_ -> panic as "bad input"
}
})
···
input
|> list.fold(RotationState(50, 0), fn(acc, v) {
let new_number =
+
int.modulo(acc.turn + v, 100)
|> result.unwrap(0)
RotationState(new_number, case new_number {
0 -> acc.zeroes + 1
···
let part2 =
input
|> list.fold(RotationState(50, 0), fn(acc, v) {
+
let raw_new_number = acc.turn + v
+
let raw_zeroes = int.absolute_value(raw_new_number / 100)
+
let zeroes =
+
acc.zeroes
+
+ case acc.turn != 0 && raw_new_number <= 0 {
+
// if it is below zero before being moduloed and the original number itself wasn't zero it means that it did touch zero but the division thing wouldn't count it, so we give this extra support.
+
// of course, there is no need to deal with a negative to positive situation because the acc.turn will never be negative!!!
+
True -> raw_zeroes + 1
+
False -> raw_zeroes
}
+
RotationState(int.modulo(raw_new_number, 100) |> result.unwrap(0), zeroes)
})
part2.zeroes
|> int.to_string
|> io.println
-10
2025/1/input_example.txt
···
-
L68
-
L30
-
R48
-
L5
-
R60
-
L55
-
L1
-
L99
-
R14
-
L82
···
+7
2025/1/rust/Cargo.lock
···
···
+
# This file is automatically @generated by Cargo.
+
# It is not intended for manual editing.
+
version = 4
+
+
[[package]]
+
name = "rust"
+
version = "0.1.0"
+6
2025/1/rust/Cargo.toml
···
···
+
[package]
+
name = "rust"
+
version = "0.1.0"
+
edition = "2024"
+
+
[dependencies]
+53
2025/1/rust/src/main.rs
···
···
+
struct State {
+
turn: i32,
+
zeroes: i32,
+
}
+
+
fn main() {
+
let input: Vec<i32> = include_str!("../../input.txt")
+
.trim()
+
.split("\n")
+
.map(|n| {
+
n.replace("L", "-")
+
.replace("R", "")
+
.parse::<i32>()
+
.expect("invalid input")
+
})
+
.collect();
+
+
let part_1 = input.iter().fold(
+
State {
+
turn: 50,
+
zeroes: 0,
+
},
+
|acc, n| {
+
let turn = (acc.turn + n).rem_euclid(100);
+
State {
+
turn,
+
zeroes: acc.zeroes + (turn == 0) as i32,
+
}
+
},
+
);
+
println!("{}", part_1.zeroes);
+
+
let part_2 = input.iter().fold(
+
State {
+
turn: 50,
+
zeroes: 0,
+
},
+
|acc, n| {
+
let raw_turn = acc.turn + n;
+
let turn = raw_turn.rem_euclid(100);
+
let raw_zeroes = (raw_turn / 100).abs();
+
State {
+
turn,
+
// if it is below zero before being moduloed and the original number itself wasn't zero it means that it did touch zero but the division thing wouldn't count it, so we give this extra support.
+
// of course, there is no need to deal with a negative to positive situation because the acc.turn will never be negative!!!
+
zeroes: acc.zeroes
+
+ raw_zeroes
+
+ (acc.turn != 0 && raw_turn <= 0) as i32,
+
}
+
},
+
);
+
println!("{}", part_2.zeroes);
+
}
+39
2025/1/zig/build.zig
···
···
+
const std = @import("std");
+
+
pub fn build(b: *std.Build) void {
+
const target = b.standardTargetOptions(.{});
+
+
const optimize = b.standardOptimizeOption(.{});
+
+
const exe = b.addExecutable(.{
+
.name = "zig",
+
.root_module = b.createModule(.{
+
.root_source_file = b.path("src/main.zig"),
+
+
.target = target,
+
.optimize = optimize,
+
}),
+
});
+
+
b.installArtifact(exe);
+
+
const run_step = b.step("run", "Run the app");
+
+
const run_cmd = b.addRunArtifact(exe);
+
run_step.dependOn(&run_cmd.step);
+
+
run_cmd.step.dependOn(b.getInstallStep());
+
+
if (b.args) |args| {
+
run_cmd.addArgs(args);
+
}
+
+
const exe_tests = b.addTest(.{
+
.root_module = exe.root_module,
+
});
+
+
const run_exe_tests = b.addRunArtifact(exe_tests);
+
+
const test_step = b.step("test", "Run tests");
+
test_step.dependOn(&run_exe_tests.step);
+
}
+40
2025/1/zig/src/main.zig
···
···
+
const std = @import("std");
+
+
const State = struct { turn: i32, zeroes: u32 };
+
+
pub fn main() !void {
+
const allocator = std.heap.page_allocator;
+
+
const input_raw = @embedFile("./input.txt");
+
const input_str = std.mem.trim(u8, input_raw, "\t\r\n");
+
var turns_str = std.mem.splitScalar(u8, input_str, '\n');
+
+
const turns_len =
+
std.mem.count(u8, input_str, "\n") + 1;
+
const turns = try allocator.alloc(i32, turns_len);
+
defer allocator.free(turns);
+
+
var i: u32 = 0;
+
while (turns_str.next()) |turn_str| {
+
const mult: i32 = if (turn_str[0] == 'L') -1 else 1;
+
turns[i] = try std.fmt.parseInt(i32, turn_str[1..], 10) * mult;
+
i += 1;
+
}
+
+
var part_1 = State{ .turn = 50, .zeroes = 0 };
+
for (turns) |turn| {
+
part_1.turn = @mod(part_1.turn + turn, 100);
+
part_1.zeroes += @intFromBool(part_1.turn == 0);
+
}
+
std.debug.print("Part 1: {}\n", .{part_1.zeroes});
+
+
var part_2 = State{ .turn = 50, .zeroes = 0 };
+
for (turns) |turn| {
+
const raw_turn: i32 = part_2.turn + turn;
+
// if it is below zero before being moduloed and the original number itself wasn't zero it means that it did touch zero but the division thing wouldn't count it, so we give this extra support.
+
// of course, there is no need to deal with a negative to positive situation because the acc.turn will never be negative!!!
+
part_2.zeroes += @abs(raw_turn) / 100 + @intFromBool(part_2.turn != 0 and raw_turn <= 0);
+
part_2.turn = @mod(raw_turn, 100);
+
}
+
std.debug.print("Part 2: {}\n", .{part_2.zeroes});
+
}
+20
2025/2/gleam/gleam.toml
···
···
+
name = "main"
+
version = "1.0.0"
+
+
# Fill out these fields if you intend to generate HTML documentation or publish
+
# your project to the Hex package manager.
+
#
+
# description = ""
+
# licences = ["Apache-2.0"]
+
# repository = { type = "github", user = "", repo = "" }
+
# links = [{ title = "Website", href = "" }]
+
#
+
# For a full reference of all the available options, you can have a look at
+
# https://gleam.run/writing-gleam/gleam-toml/.
+
+
[dependencies]
+
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
+
simplifile = ">= 2.3.0 and < 3.0.0"
+
+
[dev-dependencies]
+
gleeunit = ">= 1.0.0 and < 2.0.0"
+14
2025/2/gleam/manifest.toml
···
···
+
# This file was generated by Gleam
+
# You typically do not need to edit this file
+
+
packages = [
+
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
+
{ name = "gleam_stdlib", version = "0.65.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "7C69C71D8C493AE11A5184828A77110EB05A7786EBF8B25B36A72F879C3EE107" },
+
{ name = "gleeunit", version = "1.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "CD701726CBCE5588B375D157B4391CFD0F2F134CD12D9B6998A395484DE05C58" },
+
{ name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" },
+
]
+
+
[requirements]
+
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
+
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
+
simplifile = { version = ">= 2.3.0 and < 3.0.0" }
+70
2025/2/gleam/src/main.gleam
···
···
+
import gleam/int
+
import gleam/io
+
import gleam/list
+
import gleam/result
+
import gleam/string
+
import simplifile as file
+
+
type Range {
+
Range(start: Int, end: Int)
+
}
+
+
pub fn main() {
+
let assert Ok(input) = file.read(from: "../input.txt")
+
as "Input file not found"
+
let input =
+
input
+
|> string.trim
+
|> string.split(",")
+
|> list.map(fn(s) {
+
case string.split(s, "-") {
+
[start, end] ->
+
Range(
+
start |> int.parse |> result.unwrap(0),
+
end |> int.parse |> result.unwrap(0),
+
)
+
_ -> panic as "invalid input"
+
}
+
})
+
+
input
+
|> list.fold(0, fn(acc, r) {
+
list.range(r.start, r.end)
+
|> list.fold(acc, fn(acc, i) {
+
let s = int.to_string(i)
+
let len = string.length(s)
+
case string.slice(s, 0, len / 2) |> string.repeat(2) == s {
+
True -> acc + i
+
False -> acc
+
}
+
})
+
})
+
|> int.to_string
+
|> io.println
+
+
input
+
|> list.fold(0, fn(acc, r) {
+
list.range(r.start, r.end)
+
|> list.fold(acc, fn(acc, i) {
+
case i > 10 {
+
True -> {
+
let s = int.to_string(i)
+
let len = string.length(s)
+
list.range(len / 2, 1)
+
|> list.fold_until(acc, fn(acc, cur_len) {
+
let n =
+
string.slice(s, 0, cur_len)
+
|> string.repeat(int.max(2, len / cur_len))
+
case n == s {
+
True -> list.Stop(acc + i)
+
False -> list.Continue(acc)
+
}
+
})
+
}
+
False -> acc
+
}
+
})
+
})
+
|> int.to_string
+
|> io.println
+
}
+7
2025/2/rust/Cargo.lock
···
···
+
# This file is automatically @generated by Cargo.
+
# It is not intended for manual editing.
+
version = 4
+
+
[[package]]
+
name = "rust"
+
version = "0.1.0"
+6
2025/2/rust/Cargo.toml
···
···
+
[package]
+
name = "rust"
+
version = "0.1.0"
+
edition = "2024"
+
+
[dependencies]
+73
2025/2/rust/src/main.rs
···
···
+
use std::collections::HashSet;
+
+
struct Range {
+
start: u64,
+
end: u64,
+
}
+
+
const MAX_LENGTH: usize = 10;
+
+
fn main() {
+
let input: Vec<Range> = include_str!("../../input.txt")
+
.trim()
+
.split(",")
+
.map(|v| {
+
let range = v.split_once("-");
+
match range {
+
Some((start, end)) => Range {
+
start: start.parse().expect("invalid number"),
+
end: end.parse().expect("invalid number"),
+
},
+
_ => panic!("bad input!"),
+
}
+
})
+
.collect();
+
+
let powers_of_ten: Vec<u64> =
+
(0..=MAX_LENGTH as u32).map(|i| 10_u64.pow(i)).collect();
+
+
let [invalid_part_1, invalid_part_2] = {
+
let mut part_1: HashSet<u64> = HashSet::new();
+
let mut part_2: HashSet<u64> = HashSet::new();
+
+
for len in 1..=MAX_LENGTH / 2 {
+
// 1-9, 10-99, 100-999, 100000-999999
+
for combination in *powers_of_ten.get(len - 1).unwrap_or(&1)
+
..*powers_of_ten.get(len).unwrap()
+
{
+
let mut number = 0;
+
// 0 is just the number (9), 1 is one repetition (99)
+
for repeat in 0..MAX_LENGTH / len {
+
number += combination
+
* powers_of_ten.get((len * repeat) as usize).unwrap();
+
if repeat > 0 {
+
part_2.insert(number);
+
}
+
if repeat == 1 {
+
part_1.insert(number);
+
}
+
}
+
}
+
}
+
+
[part_1, part_2]
+
};
+
+
let part_1 = invalid_part_1.iter().fold(0, |acc, number| {
+
if input.iter().any(|r| *number >= r.start && *number <= r.end) {
+
acc + number
+
} else {
+
acc
+
}
+
});
+
println!("{}", part_1);
+
+
let part_2 = invalid_part_2.iter().fold(0, |acc, number| {
+
if input.iter().any(|r| *number >= r.start && *number <= r.end) {
+
acc + number
+
} else {
+
acc
+
}
+
});
+
println!("{}", part_2);
+
}
+20
2025/3/gleam/gleam.toml
···
···
+
name = "main"
+
version = "1.0.0"
+
+
# Fill out these fields if you intend to generate HTML documentation or publish
+
# your project to the Hex package manager.
+
#
+
# description = ""
+
# licences = ["Apache-2.0"]
+
# repository = { type = "github", user = "", repo = "" }
+
# links = [{ title = "Website", href = "" }]
+
#
+
# For a full reference of all the available options, you can have a look at
+
# https://gleam.run/writing-gleam/gleam-toml/.
+
+
[dependencies]
+
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
+
simplifile = ">= 2.3.0 and < 3.0.0"
+
+
[dev-dependencies]
+
gleeunit = ">= 1.0.0 and < 2.0.0"
+14
2025/3/gleam/manifest.toml
···
···
+
# This file was generated by Gleam
+
# You typically do not need to edit this file
+
+
packages = [
+
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
+
{ name = "gleam_stdlib", version = "0.65.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "7C69C71D8C493AE11A5184828A77110EB05A7786EBF8B25B36A72F879C3EE107" },
+
{ name = "gleeunit", version = "1.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "CD701726CBCE5588B375D157B4391CFD0F2F134CD12D9B6998A395484DE05C58" },
+
{ name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" },
+
]
+
+
[requirements]
+
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
+
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
+
simplifile = { version = ">= 2.3.0 and < 3.0.0" }
+71
2025/3/gleam/src/main.gleam
···
···
+
import gleam/int
+
import gleam/io
+
import gleam/list
+
import gleam/result
+
import gleam/string
+
import simplifile as file
+
+
pub fn do(input, digits) {
+
input
+
// ok so here we're just iterating through all the battery banks in the input
+
|> list.fold(0, fn(acc, bank) {
+
let #(n, _) =
+
// and here we're going and doing it the amount of times necessary. it's backwards for obvious reasons, we start from the end and this let's us not have like duplicated logic where we're doing digits - i constantly
+
// it needs to be digits - 1 to zero because otherwise it will cut too much when dropping stuff at list.reverse list.drop(i) list.reverse
+
list.range(digits - 1, 0)
+
// didn't want to create a type for it so yeah #(the digit we're at, the remaining part of the bank)
+
|> list.fold(#(0, bank), fn(acc, i) {
+
// annoying gleam stuff i wish i could destructure it from the function
+
let #(number, bank) = acc
+
+
// that's the part that matters, and the one i took forever in and ended up splitting in multiple variables when i didn't need to
+
// but like it's very simple
+
// gleam doesn't let you drop from the end of lists, so we reverse the list, drop the digits we cannot use because they will necessarily be used latter in the number. the last i is the minimum because like we need at the very least finish the number yk
+
// and then the really annoying part, we turn it into an index map, so we can get the location of the number to later drop that part off for the next digit
+
// and then we get the highest number
+
// and done here
+
// little assert because failing is better than the silent failing of unwrap
+
// list.take instead of drop would allow me to do it without reversing two times but like it would also need list.length which also goes through the whole list but without letting me put it in just pipes
+
// i mean i COULD count it once when starting it when then after getting the location subtracting from it but meh already did the rust version and this would put too much stuff on here
+
let assert Ok(#(max, loc)) =
+
bank
+
|> list.reverse
+
|> list.drop(i)
+
|> list.reverse
+
|> list.index_map(fn(n, i) { #(n, i) })
+
|> list.max(fn(a, b) { int.compare(a.0, b.0) })
+
+
// and then we send it off to the next digit
+
// i wasn't using this number trick when i was doing it, i was literally just finding a power of 10 and multiplying it but like the power thing in gleam sucks it's like float only. i now learned this trick from *someone* and will be using it. don't know how i didn't figure out myself. oh wait i do it's because i'm stupid
+
// but yeah it just multiplies the number by ten so like 4 becomes 40 and then we add our like 3 to it 43 and then 43 to 430 and the 5 you get the gist of it. again don't know how i didn't see it myself
+
// and then we drop the parts of the list that can't be used for the subsequent numbers. like off by one evil thing in here to not include the number we just used too
+
// why don't we add 1 to everything in the thing above? because that would be more math than just adding it only once here duh
+
#(number * 10 + max, list.drop(bank, loc + 1))
+
})
+
// and then like every advent of code we add it to the acc
+
acc + n
+
})
+
}
+
+
pub fn main() {
+
let assert Ok(input) = file.read(from: "../input.txt")
+
as "Input file not found"
+
let input =
+
input
+
|> string.trim
+
|> string.split("\n")
+
|> list.map(fn(bank) {
+
// just get all the battery banks, separate them by character and turn each character in a member of a list
+
// and here we unwrap because only let's you do it with variables and that would be less clean here
+
string.to_graphemes(bank)
+
|> list.map(fn(s) { int.parse(s) |> result.unwrap(0) })
+
})
+
+
do(input, 2)
+
|> int.to_string
+
|> io.println
+
+
do(input, 12)
+
|> int.to_string
+
|> io.println
+
}
+7
2025/3/rust/Cargo.lock
···
···
+
# This file is automatically @generated by Cargo.
+
# It is not intended for manual editing.
+
version = 4
+
+
[[package]]
+
name = "rust"
+
version = "0.1.0"
+6
2025/3/rust/Cargo.toml
···
···
+
[package]
+
name = "rust"
+
version = "0.1.0"
+
edition = "2024"
+
+
[dependencies]
+38
2025/3/rust/src/main.rs
···
···
+
// fun fact for this version, my biggest bug was integer overflow when i was using u32 because im not accustumed to this shit
+
+
fn solve(input: &Vec<Vec<u64>>, digits: usize) -> u64 {
+
input.iter().fold(0, |acc, bank| {
+
let bank_len = bank.len();
+
let (n, _) = (0..digits).rfold((0, 0), |(number, bank_index), i| {
+
let (loc, max) = bank[bank_index..bank_len - i]
+
.iter()
+
.enumerate()
+
// apparently the compiler is fine with reversing this and then using the standard max_by but im not. and it seems to have the same speed results. im not gonna be using tricks here ok im nice
+
.reduce(
+
|(maxi, max), (i, n)| {
+
if n > max { (i, n) } else { (maxi, max) }
+
},
+
)
+
// #yup #i'm unwrapping #idontwannausefold
+
.unwrap();
+
+
((number * 10) + max, bank_index + loc + 1)
+
});
+
acc + n
+
})
+
}
+
+
fn main() {
+
let input: Vec<Vec<u64>> = include_str!("../../input.txt")
+
.trim()
+
.split("\n")
+
.map(|bank| {
+
bank.chars()
+
.map(|s| s.to_digit(10).unwrap() as u64)
+
.collect()
+
})
+
.collect();
+
+
println!("Part 1: {}", solve(&input, 2));
+
println!("Part 2: {}", solve(&input, 12));
+
}
+20
2025/4/gleam/gleam.toml
···
···
+
name = "main"
+
version = "1.0.0"
+
+
# Fill out these fields if you intend to generate HTML documentation or publish
+
# your project to the Hex package manager.
+
#
+
# description = ""
+
# licences = ["Apache-2.0"]
+
# repository = { type = "github", user = "", repo = "" }
+
# links = [{ title = "Website", href = "" }]
+
#
+
# For a full reference of all the available options, you can have a look at
+
# https://gleam.run/writing-gleam/gleam-toml/.
+
+
[dependencies]
+
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
+
simplifile = ">= 2.3.0 and < 3.0.0"
+
+
[dev-dependencies]
+
gleeunit = ">= 1.0.0 and < 2.0.0"
+14
2025/4/gleam/manifest.toml
···
···
+
# This file was generated by Gleam
+
# You typically do not need to edit this file
+
+
packages = [
+
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
+
{ name = "gleam_stdlib", version = "0.65.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "7C69C71D8C493AE11A5184828A77110EB05A7786EBF8B25B36A72F879C3EE107" },
+
{ name = "gleeunit", version = "1.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "CD701726CBCE5588B375D157B4391CFD0F2F134CD12D9B6998A395484DE05C58" },
+
{ name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" },
+
]
+
+
[requirements]
+
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
+
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
+
simplifile = { version = ">= 2.3.0 and < 3.0.0" }
+96
2025/4/gleam/src/main.gleam
···
···
+
import gleam/bit_array
+
import gleam/int
+
import gleam/io
+
import gleam/list
+
import gleam/result
+
import gleam/string
+
import simplifile as file
+
+
fn get_place(x, y, map, size) {
+
case
+
case x, y {
+
_, -1 | -1, _ -> <<>>
+
s, _ | _, s if s == size -> <<>>
+
+
_, _ -> bit_array.slice(map, y * size + x, 1) |> result.unwrap(<<>>)
+
}
+
{
+
<<"@">> -> 1
+
_ -> 0
+
}
+
}
+
+
fn part_1(map, size) {
+
list.range(0, bit_array.byte_size(map) - 1)
+
|> list.fold(0, fn(acc, pos) {
+
let x = pos % size
+
let y = pos / size
+
+
let roll = get_place(x, y, map, size)
+
+
let neighbours =
+
get_place(x - 1, y - 1, map, size)
+
+ get_place(x, y - 1, map, size)
+
+ get_place(x + 1, y - 1, map, size)
+
+ get_place(x - 1, y, map, size)
+
+ get_place(x + 1, y, map, size)
+
+ get_place(x - 1, y + 1, map, size)
+
+ get_place(x, y + 1, map, size)
+
+ get_place(x + 1, y + 1, map, size)
+
+
case roll, neighbours < 4 {
+
1, True -> acc + 1
+
_, _ -> acc
+
}
+
})
+
}
+
+
fn part_2(map, size, rolls) {
+
let #(rolls, new_map) =
+
list.range(0, bit_array.byte_size(map) - 1)
+
|> list.fold(#(rolls, <<>>), fn(acc, pos) {
+
let #(total, new_map) = acc
+
let x = pos % size
+
let y = pos / size
+
+
let roll = get_place(x, y, map, size)
+
+
let neighbours =
+
get_place(x - 1, y - 1, map, size)
+
+ get_place(x, y - 1, map, size)
+
+ get_place(x + 1, y - 1, map, size)
+
+ get_place(x - 1, y, map, size)
+
+ get_place(x + 1, y, map, size)
+
+ get_place(x - 1, y + 1, map, size)
+
+ get_place(x, y + 1, map, size)
+
+ get_place(x + 1, y + 1, map, size)
+
+
case roll, neighbours < 4 {
+
1, True -> #(total + 1, bit_array.append(new_map, <<".">>))
+
1, _ -> #(total, bit_array.append(new_map, <<"@">>))
+
_, _ -> #(total, bit_array.append(new_map, <<".">>))
+
}
+
})
+
+
case map == new_map {
+
True -> rolls
+
False -> part_2(new_map, size, rolls)
+
}
+
}
+
+
pub fn main() {
+
let assert Ok(input) = file.read(from: "../input.txt")
+
as "Input file not found"
+
let input =
+
input |> string.trim |> string.split("\n") |> list.map(fn(v) { <<v:utf8>> })
+
let size = list.length(input)
+
let input = input |> list.fold(<<>>, fn(acc, l) { bit_array.append(acc, l) })
+
// @ and .
+
+
part_1(input, size)
+
|> int.to_string
+
|> io.println
+
part_2(input, size, 0)
+
|> int.to_string
+
|> io.println
+
}
+7
2025/4/rust/Cargo.lock
···
···
+
# This file is automatically @generated by Cargo.
+
# It is not intended for manual editing.
+
version = 4
+
+
[[package]]
+
name = "rust"
+
version = "0.1.0"
+6
2025/4/rust/Cargo.toml
···
···
+
[package]
+
name = "rust"
+
version = "0.1.0"
+
edition = "2024"
+
+
[dependencies]
+106
2025/4/rust/src/main.rs
···
···
+
use std::{
+
fs::{self, File},
+
io::Write,
+
mem::swap,
+
};
+
+
fn to_img(warehouse: &Vec<u8>, size: usize, name: usize) {
+
let mut bytes: Vec<u8> = [].to_vec();
+
bytes.extend(format!("P5\n{size} {size}\n1\n").as_bytes());
+
let mut i = size + 3;
+
for _ in 0..size {
+
for _ in 0..size {
+
bytes.push(*warehouse.get(i).unwrap());
+
i += 1;
+
}
+
i += 2;
+
}
+
let mut file = File::create(format!("out/{name}.pgm")).unwrap();
+
file.write_all(&bytes).unwrap();
+
}
+
+
fn solve(
+
mut warehouse: Vec<u8>,
+
size: usize,
+
part_2: bool,
+
visualise: bool,
+
) -> u32 {
+
if visualise {
+
fs::create_dir_all("out").unwrap();
+
}
+
+
let pos = |x, y| y * (size + 2) + x;
+
+
let sizep = size + 1;
+
+
let mut new_warehouse = vec![0_u8; (size + 2).pow(2)];
+
+
let mut rolls = 0;
+
+
let mut i = 0;
+
loop {
+
for yo in 1..sizep {
+
let ym = yo - 1;
+
let yp = yo + 1;
+
for xo in 1..sizep {
+
let xm = xo - 1;
+
let xp = xo + 1;
+
+
unsafe {
+
let was = *warehouse.get_unchecked(pos(xo, yo)) == 1;
+
let neighbours = warehouse.get_unchecked(pos(xm, ym))
+
+ warehouse.get_unchecked(pos(xo, ym))
+
+ warehouse.get_unchecked(pos(xp, ym))
+
+ warehouse.get_unchecked(pos(xm, yo))
+
+ warehouse.get_unchecked(pos(xp, yo))
+
+ warehouse.get_unchecked(pos(xm, yp))
+
+ warehouse.get_unchecked(pos(xo, yp))
+
+ warehouse.get_unchecked(pos(xp, yp));
+
*new_warehouse.get_unchecked_mut(pos(xo, yo)) =
+
match (was, neighbours < 4) {
+
(true, true) => {
+
rolls += 1;
+
0
+
}
+
(true, false) => 1,
+
(_, _) => 0,
+
};
+
}
+
}
+
}
+
+
if !part_2 || warehouse == new_warehouse {
+
break;
+
}
+
+
swap(&mut warehouse, &mut new_warehouse);
+
i += 1;
+
if visualise {
+
to_img(&warehouse, size, i);
+
}
+
}
+
rolls
+
}
+
+
fn main() {
+
let input = include_str!("../../input.txt").trim();
+
let size = input.split_once("\n").expect("invalid input").0.len();
+
// reads the input but adds a line of buffer on the sides
+
let buffer_line = ".".repeat(size);
+
let input: Vec<u8> = format!("{buffer_line}\n{input}\n{buffer_line}")
+
.split("\n")
+
.map(|line| -> Vec<u8> {
+
format!(".{}.", line)
+
.chars()
+
.map(|v| (v == '@') as u8)
+
.collect()
+
})
+
.flatten()
+
.collect();
+
+
let part_1 = solve(input.clone(), size, false, false);
+
println!("Part 1: {}", part_1);
+
+
let part_2 = solve(input.clone(), size, true, true);
+
println!("Part 2: {}", part_2);
+
}
+20
2025/5/gleam/gleam.toml
···
···
+
name = "main"
+
version = "1.0.0"
+
+
# Fill out these fields if you intend to generate HTML documentation or publish
+
# your project to the Hex package manager.
+
#
+
# description = ""
+
# licences = ["Apache-2.0"]
+
# repository = { type = "github", user = "", repo = "" }
+
# links = [{ title = "Website", href = "" }]
+
#
+
# For a full reference of all the available options, you can have a look at
+
# https://gleam.run/writing-gleam/gleam-toml/.
+
+
[dependencies]
+
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
+
simplifile = ">= 2.3.0 and < 3.0.0"
+
+
[dev-dependencies]
+
gleeunit = ">= 1.0.0 and < 2.0.0"
+14
2025/5/gleam/manifest.toml
···
···
+
# This file was generated by Gleam
+
# You typically do not need to edit this file
+
+
packages = [
+
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
+
{ name = "gleam_stdlib", version = "0.65.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "7C69C71D8C493AE11A5184828A77110EB05A7786EBF8B25B36A72F879C3EE107" },
+
{ name = "gleeunit", version = "1.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "CD701726CBCE5588B375D157B4391CFD0F2F134CD12D9B6998A395484DE05C58" },
+
{ name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" },
+
]
+
+
[requirements]
+
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
+
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
+
simplifile = { version = ">= 2.3.0 and < 3.0.0" }
+117
2025/5/gleam/src/main.gleam
···
···
+
import gleam/int
+
import gleam/io
+
import gleam/list
+
import gleam/order.{Eq, Gt, Lt}
+
import gleam/set
+
import gleam/string
+
import simplifile as file
+
+
pub fn main() {
+
let assert Ok(input) = file.read(from: "../input.txt")
+
as "Input file not found"
+
let assert [fresh_ranges, available] =
+
input |> string.trim |> string.split("\n\n")
+
let fresh_ranges =
+
fresh_ranges
+
|> string.trim
+
|> string.split("\n")
+
// |> list.reverse
+
// |> list.drop(5)
+
// |> list.take(12)
+
// |> list.reverse
+
|> list.map(fn(i) {
+
let assert [from, to] = i |> string.trim |> string.split("-")
+
let assert Ok(from) = int.parse(from)
+
let assert Ok(to) = int.parse(to)
+
// #(from / 100_000_000, to / 100_000_000)
+
#(from, to)
+
})
+
let available =
+
available
+
|> string.split("\n")
+
|> list.map(fn(i) {
+
let assert Ok(id) = int.parse(i)
+
id
+
})
+
+
available
+
|> list.fold(0, fn(acc, i) {
+
acc
+
+ case list.any(fresh_ranges, fn(range) { i >= range.0 && i <= range.1 }) {
+
True -> 1
+
False -> 0
+
}
+
})
+
|> int.to_string
+
|> io.println
+
+
// nicer looking but idc
+
// |> list.filter(fn(i) {
+
// list.any(fresh_ranges, fn(range) { i >= range.0 && i <= range.1 })
+
// })
+
// |> list.length
+
+
// this thing crashed my computer btw im stupid
+
// let haha =
+
// fresh_ranges
+
// |> list.fold(set.new(), fn(acc, i) {
+
// list.range(i.0, i.1) |> list.fold(acc, fn(acc, i) { set.insert(acc, i) })
+
// })
+
// io.println(set.size(haha) |> int.to_string)
+
+
let base_set: set.Set(#(Int, Int)) = set.new()
+
fresh_ranges
+
|> list.fold(base_set, fn(prev_seen_ranges, range) {
+
let #(range, seen_ranges) =
+
prev_seen_ranges
+
|> set.fold(#(range, prev_seen_ranges), fn(acc, seen_range) {
+
let #(range, seen_ranges) = acc
+
// echo #(
+
// range,
+
// seen_range,
+
// int.compare(range.0, seen_range.0),
+
// int.compare(range.1, seen_range.1),
+
// int.compare(range.0, seen_range.1),
+
// int.compare(range.1, seen_range.0),
+
// )
+
// btw im refusing to ever do something better than this idc about your sorting and whatever this is the way shut the fuck up i spent three hours on this i will be using it
+
case
+
int.compare(range.0, seen_range.0),
+
int.compare(range.1, seen_range.1),
+
int.compare(range.0, seen_range.1),
+
int.compare(range.1, seen_range.0)
+
{
+
// if there's no touching
+
Gt, Gt, Gt, Gt | Lt, Lt, Lt, Lt -> #(range, seen_ranges)
+
// if it's inside of the other one
+
Gt, Lt, _, _ | Eq, Lt, _, _ | Gt, Eq, _, _ | Eq, Eq, _, _ -> #(
+
#(-1, -1),
+
seen_ranges,
+
)
+
// if the other one is inside it
+
Lt, Gt, _, _ | Eq, Gt, _, _ | Lt, Eq, _, _ -> #(
+
range,
+
set.delete(seen_ranges, seen_range),
+
)
+
// if it's touching on the left side make them touch
+
Lt, Lt, _, _ -> #(
+
#(range.0, seen_range.1),
+
set.delete(seen_ranges, seen_range),
+
)
+
// if it's touching on the right size make them touch
+
Gt, Gt, _, _ -> #(
+
#(seen_range.0, range.1),
+
set.delete(seen_ranges, seen_range),
+
)
+
}
+
})
+
+
case range == #(-1, -1) {
+
False -> seen_ranges |> set.insert(range)
+
True -> seen_ranges
+
}
+
})
+
|> set.fold(0, fn(acc, range) { acc + range.1 - range.0 + 1 })
+
|> int.to_string
+
|> io.println
+
}
+7
2025/5/rust/Cargo.lock
···
···
+
# This file is automatically @generated by Cargo.
+
# It is not intended for manual editing.
+
version = 4
+
+
[[package]]
+
name = "rust"
+
version = "0.1.0"
+6
2025/5/rust/Cargo.toml
···
···
+
[package]
+
name = "rust"
+
version = "0.1.0"
+
edition = "2024"
+
+
[dependencies]
+75
2025/5/rust/src/main.rs
···
···
+
use std::{
+
cmp::Ordering::{Equal as Eq, Greater as Gt, Less as Lt},
+
collections::HashSet,
+
};
+
+
fn main() {
+
let input = include_str!("../../input.txt").trim();
+
let (fresh_ranges, available) = input.split_once("\n\n").unwrap();
+
let fresh_ranges: Vec<(u64, u64)> = fresh_ranges
+
.split("\n")
+
.map(|i| {
+
let (a, b) = i.split_once("-").unwrap();
+
(a.parse().unwrap(), b.parse().unwrap())
+
})
+
.collect();
+
let available = available.split("\n").map(|i| {
+
let i: u64 = i.parse().unwrap();
+
i
+
});
+
+
let part_1 = available.fold(0, |acc, i| {
+
acc + fresh_ranges
+
.iter()
+
.any(|(start, end)| &i >= start && &i <= end) as u64
+
});
+
println!("Part 1: {}", part_1);
+
+
let mut seen_ranges: HashSet<(u64, u64)> =
+
HashSet::with_capacity(fresh_ranges.len());
+
fresh_ranges.iter().for_each(|range| {
+
let range = seen_ranges.clone().iter().try_fold(
+
*range,
+
|range: (u64, u64), seen_range: &(u64, u64)| {
+
// btw im refusing to ever do something better than this idc about your sorting and whatever this is the way shut the fuck up i spent three hours on this i will be using it
+
match (
+
range.0.cmp(&seen_range.0),
+
range.1.cmp(&seen_range.1),
+
range.0.cmp(&seen_range.1),
+
range.1.cmp(&seen_range.0),
+
) {
+
// if there's no touching
+
(Gt, Gt, Gt, Gt) | (Lt, Lt, Lt, Lt) => Some(range),
+
// if it's inside of the other one
+
(Gt, Lt, _, _)
+
| (Eq, Lt, _, _)
+
| (Gt, Eq, _, _)
+
| (Eq, Eq, _, _) => None,
+
// if the other one is inside it
+
(Lt, Gt, _, _) | (Eq, Gt, _, _) | (Lt, Eq, _, _) => {
+
seen_ranges.remove(seen_range);
+
Some(range)
+
}
+
// if it's touching on the left side make them touch
+
(Lt, Lt, _, _) => {
+
seen_ranges.remove(seen_range);
+
Some((range.0, seen_range.1))
+
}
+
// if it's touching on the right size make them touch
+
(Gt, Gt, _, _) => {
+
seen_ranges.remove(seen_range);
+
Some((seen_range.0, range.1))
+
}
+
}
+
},
+
);
+
+
if range.is_some() {
+
seen_ranges.insert(range.unwrap());
+
}
+
});
+
let part_2 = seen_ranges
+
.into_iter()
+
.fold(0, |acc, range| acc + range.1 - range.0 + 1);
+
println!("Part 2: {}", part_2);
+
}
+20
2025/6/gleam/gleam.toml
···
···
+
name = "main"
+
version = "1.0.0"
+
+
# Fill out these fields if you intend to generate HTML documentation or publish
+
# your project to the Hex package manager.
+
#
+
# description = ""
+
# licences = ["Apache-2.0"]
+
# repository = { type = "github", user = "", repo = "" }
+
# links = [{ title = "Website", href = "" }]
+
#
+
# For a full reference of all the available options, you can have a look at
+
# https://gleam.run/writing-gleam/gleam-toml/.
+
+
[dependencies]
+
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
+
simplifile = ">= 2.3.0 and < 3.0.0"
+
+
[dev-dependencies]
+
gleeunit = ">= 1.0.0 and < 2.0.0"
+14
2025/6/gleam/manifest.toml
···
···
+
# This file was generated by Gleam
+
# You typically do not need to edit this file
+
+
packages = [
+
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
+
{ name = "gleam_stdlib", version = "0.65.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "7C69C71D8C493AE11A5184828A77110EB05A7786EBF8B25B36A72F879C3EE107" },
+
{ name = "gleeunit", version = "1.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "CD701726CBCE5588B375D157B4391CFD0F2F134CD12D9B6998A395484DE05C58" },
+
{ name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" },
+
]
+
+
[requirements]
+
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
+
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
+
simplifile = { version = ">= 2.3.0 and < 3.0.0" }
+140
2025/6/gleam/src/main.gleam
···
···
+
import gleam/dict
+
import gleam/int
+
import gleam/io
+
import gleam/list
+
import gleam/result
+
import gleam/string
+
import simplifile as file
+
+
type Part2Dict =
+
dict.Dict(Int, Int)
+
+
type Align {
+
Left
+
Right
+
}
+
+
type Operation {
+
Sum
+
Mul
+
}
+
+
type Part2Line {
+
Part2Line(align: Align, op: Operation, numbers: List(String))
+
}
+
+
pub fn main() {
+
let assert Ok(input) = file.read(from: "../input.txt")
+
as "Input file not found"
+
let input = input |> string.trim
+
let input_pt_1 =
+
list.fold(list.range(1, 10), input, fn(acc, _) {
+
acc |> string.replace(" ", " ")
+
})
+
+
input_pt_1
+
|> string.split("\n")
+
|> list.map(fn(i) { string.trim(i) |> string.split(" ") })
+
|> list.transpose
+
|> list.map(fn(i) {
+
let i = list.reverse(i)
+
let assert Ok(s) = list.first(i)
+
let i =
+
list.drop(i, 1) |> list.map(fn(i) { int.parse(i) |> result.unwrap(0) })
+
let r = case s {
+
"+" -> int.sum(i)
+
"*" -> list.reduce(i, int.multiply) |> result.unwrap(0)
+
_ -> panic as "invalid"
+
}
+
r
+
})
+
|> int.sum
+
|> int.to_string
+
|> io.println
+
+
let lines =
+
input
+
|> string.split("\n")
+
|> list.reverse
+
let assert Ok(last_line) = list.first(lines)
+
let #(_, bounds) =
+
{ last_line <> " *" }
+
|> string.to_graphemes
+
|> list.index_fold(#(0, list.new()), fn(acc, char, i) {
+
let #(bound_start, bounds) = acc
+
case char {
+
"*" | "+" if i > 0 -> #(i, list.append([#(bound_start, i - 1)], bounds))
+
_ -> acc
+
}
+
})
+
bounds
+
|> list.index_fold(dict.new(), fn(d, bound, i) {
+
let numbers =
+
list.map(lines, fn(line) {
+
string.slice(line, bound.0, bound.1 - bound.0)
+
})
+
let align =
+
numbers
+
|> list.drop(1)
+
|> list.fold_until(Left, fn(res, number) {
+
case
+
string.trim(number) == number,
+
string.trim_start(number) == number
+
{
+
True, _ -> list.Continue(res)
+
_, True -> list.Stop(Left)
+
_, _ -> list.Stop(Right)
+
}
+
})
+
let assert Ok(sign) = list.first(numbers)
+
let sign = case string.trim(sign) {
+
"*" -> Mul
+
"+" -> Sum
+
_ -> panic as sign
+
}
+
dict.insert(
+
d,
+
i,
+
Part2Line(
+
align,
+
sign,
+
numbers |> list.drop(1) |> list.map(string.trim) |> list.reverse,
+
),
+
)
+
})
+
|> dict.to_list
+
|> list.map(fn(i) { i.1 })
+
|> list.map(fn(line) {
+
let d: Part2Dict = dict.new()
+
let d =
+
line.numbers
+
|> list.fold(d, fn(d, number) {
+
let number_len = string.length(number)
+
string.to_graphemes(number)
+
|> list.index_fold(d, fn(d, digit, index) {
+
let assert Ok(digit) = digit |> int.parse
+
let pos = case line.align {
+
Right -> number_len - index
+
Left -> index
+
}
+
dict.insert(
+
d,
+
pos,
+
{ dict.get(d, pos) |> result.unwrap(0) } * 10 + digit,
+
)
+
})
+
})
+
let numbers =
+
dict.to_list(d)
+
|> list.map(fn(n) { n.1 })
+
+
let r = case line.op {
+
Sum -> int.sum(numbers)
+
Mul -> list.reduce(numbers, int.multiply) |> result.unwrap(0)
+
}
+
r
+
})
+
|> int.sum
+
|> int.to_string
+
|> io.println
+
}
+20
2025/7/gleam/gleam.toml
···
···
+
name = "main"
+
version = "1.0.0"
+
+
# Fill out these fields if you intend to generate HTML documentation or publish
+
# your project to the Hex package manager.
+
#
+
# description = ""
+
# licences = ["Apache-2.0"]
+
# repository = { type = "github", user = "", repo = "" }
+
# links = [{ title = "Website", href = "" }]
+
#
+
# For a full reference of all the available options, you can have a look at
+
# https://gleam.run/writing-gleam/gleam-toml/.
+
+
[dependencies]
+
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
+
simplifile = ">= 2.3.0 and < 3.0.0"
+
+
[dev-dependencies]
+
gleeunit = ">= 1.0.0 and < 2.0.0"
+14
2025/7/gleam/manifest.toml
···
···
+
# This file was generated by Gleam
+
# You typically do not need to edit this file
+
+
packages = [
+
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
+
{ name = "gleam_stdlib", version = "0.65.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "7C69C71D8C493AE11A5184828A77110EB05A7786EBF8B25B36A72F879C3EE107" },
+
{ name = "gleeunit", version = "1.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "CD701726CBCE5588B375D157B4391CFD0F2F134CD12D9B6998A395484DE05C58" },
+
{ name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" },
+
]
+
+
[requirements]
+
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
+
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
+
simplifile = { version = ">= 2.3.0 and < 3.0.0" }
+93
2025/7/gleam/src/main.gleam
···
···
+
import gleam/dict
+
import gleam/int
+
import gleam/io
+
import gleam/list
+
import gleam/set
+
import gleam/string
+
import simplifile as file
+
+
pub fn main() {
+
let assert Ok(input) = file.read(from: "../input.txt")
+
as "Input file not found"
+
let input = input |> string.trim |> string.split("\n")
+
let assert Ok(start) = input |> list.first
+
let start =
+
start
+
|> string.to_graphemes
+
|> list.index_fold(0, fn(acc, v, i) {
+
case v {
+
"S" -> i
+
_ -> acc
+
}
+
})
+
let splitters_map =
+
input
+
|> list.drop(1)
+
|> list.index_map(fn(line, i) {
+
case i % 2 {
+
0 -> ""
+
_ -> line
+
}
+
})
+
|> list.filter(fn(line) { line != "" })
+
|> list.map(fn(line) {
+
line
+
|> string.to_graphemes
+
|> list.index_fold(set.new(), fn(d, char, i) {
+
case char {
+
"^" -> set.insert(d, i)
+
_ -> d
+
}
+
})
+
})
+
let #(_beams, times) =
+
splitters_map
+
|> list.fold(#(set.new() |> set.insert(start), 0), fn(acc, splitters) {
+
let #(beams, times) = acc
+
beams
+
|> set.fold(#(beams, times), fn(acc, beam) {
+
let #(beams, times) = acc
+
case splitters |> set.contains(beam) {
+
False -> acc
+
True -> #(
+
beams
+
|> set.delete(beam)
+
|> set.insert(beam - 1)
+
|> set.insert(beam + 1),
+
times + 1,
+
)
+
}
+
})
+
})
+
+
times
+
|> int.to_string
+
|> io.println
+
+
let timelines =
+
splitters_map
+
|> list.index_fold(
+
dict.new() |> dict.insert("", start),
+
fn(timelines, splitters, i) {
+
echo i
+
// echo #(timelines, splitters)
+
timelines
+
|> dict.fold(timelines, fn(timelines, timeline, beam) {
+
case splitters |> set.contains(beam) {
+
False -> timelines
+
True -> {
+
timelines
+
|> dict.delete(timeline)
+
|> dict.insert(timeline <> "-", beam - 1)
+
|> dict.insert(timeline <> "+", beam + 1)
+
}
+
}
+
})
+
},
+
)
+
echo timelines
+
timelines
+
|> dict.size
+
|> int.to_string
+
|> io.println
+
}
+7
2025/7/rust/Cargo.lock
···
···
+
# This file is automatically @generated by Cargo.
+
# It is not intended for manual editing.
+
version = 4
+
+
[[package]]
+
name = "rust"
+
version = "0.1.0"
+6
2025/7/rust/Cargo.toml
···
···
+
[package]
+
name = "rust"
+
version = "0.1.0"
+
edition = "2024"
+
+
[dependencies]
+62
2025/7/rust/src/main.rs
···
···
+
use std::{
+
collections::{HashMap, HashSet},
+
mem::swap,
+
};
+
+
fn main() {
+
let input = include_str!("../../input.txt").trim();
+
+
let input: Vec<&str> = input.trim().split("\n").collect();
+
// let width = input[0].len() as u64;
+
let start = input[0].find("S").unwrap() as u64;
+
let splitters_map: Vec<HashSet<u64>> = input[0..input.len()]
+
.iter()
+
.enumerate()
+
.map(|(i, line)| if i % 2 != 0 { "" } else { line })
+
.filter(|line| line != &"")
+
.map(|line| {
+
line.chars()
+
.enumerate()
+
.fold(HashSet::new(), |mut s, (i, char)| {
+
if char == '^' {
+
s.insert(i as u64);
+
}
+
s
+
})
+
})
+
.collect();
+
+
let timelines = {
+
let mut timelines: HashMap<u64, u64> = HashMap::new();
+
timelines.insert(start, 1);
+
let mut timelines_new: HashMap<u64, u64> = HashMap::new();
+
for splitters in splitters_map {
+
for (pos, amount) in &timelines {
+
if splitters.contains(&pos) {
+
let m1 = timelines_new.entry(pos - 1).or_insert(0);
+
*m1 += amount;
+
let p1 = timelines_new.entry(pos + 1).or_insert(0);
+
*p1 += amount;
+
} else {
+
let e = timelines_new.entry(*pos).or_insert(0);
+
*e += amount;
+
}
+
}
+
// for pos in 0..width as u64 {
+
// if splitters.contains(&pos) {
+
// print!("^");
+
// } else if timelines_new.contains_key(&pos) {
+
// print!("|");
+
// } else {
+
// print!(".");
+
// }
+
// }
+
// print!("\n\n");
+
swap(&mut timelines, &mut timelines_new);
+
timelines_new.clear();
+
}
+
timelines
+
};
+
// println!("{:?}", timelines);
+
println!("{}", timelines.iter().fold(0, |acc, v| { acc + v.1 }))
+
}
+2
rustfmt.toml
···
···
+
edition = "2024"
+
max_width = 80
+2 -1
shell.nix
···
clippy
rustfmt
rust-analyzer
-
gcc
hyperfine
fish
···
clippy
rustfmt
rust-analyzer
+
+
clang
hyperfine
fish
+1 -1
template/rust/src/main.rs
···
fn main() {
-
let input = std::fs::read_to_string("../input.txt").expect("invalid input!!");
println!("{}", &input);
}
···
fn main() {
+
let input = include_str!("../../input.txt").trim();
println!("{}", &input);
}
+39
template/zig/build.zig
···
···
+
const std = @import("std");
+
+
pub fn build(b: *std.Build) void {
+
const target = b.standardTargetOptions(.{});
+
+
const optimize = b.standardOptimizeOption(.{});
+
+
const exe = b.addExecutable(.{
+
.name = "zig",
+
.root_module = b.createModule(.{
+
.root_source_file = b.path("src/main.zig"),
+
+
.target = target,
+
.optimize = optimize,
+
}),
+
});
+
+
b.installArtifact(exe);
+
+
const run_step = b.step("run", "Run the app");
+
+
const run_cmd = b.addRunArtifact(exe);
+
run_step.dependOn(&run_cmd.step);
+
+
run_cmd.step.dependOn(b.getInstallStep());
+
+
if (b.args) |args| {
+
run_cmd.addArgs(args);
+
}
+
+
const exe_tests = b.addTest(.{
+
.root_module = exe.root_module,
+
});
+
+
const run_exe_tests = b.addRunArtifact(exe_tests);
+
+
const test_step = b.step("test", "Run tests");
+
test_step.dependOn(&run_exe_tests.step);
+
}
+6
template/zig/src/main.zig
···
···
+
const std = @import("std");
+
const raw_input = @embedFile("./input.txt");
+
+
pub fn main() !void {
+
std.debug.print("{s}", .{raw_input});
+
}