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

Compare changes

Choose any two refs to compare.

Changed files
+1083 -255
2015
16
18
rust
src
19
rust
src
2
rust
src
20
4
rust
src
2025
template
rust
src
zig
+9
.gitignore
···
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
+50 -42
2015/18/rust/src/main.rs
···
-
use std::{iter::once, mem::swap};
+
use std::mem::swap;
-
fn generations(times: u32, mut world: Vec<u8>, size: usize, stuck: bool) -> Vec<u8> {
-
#[inline]
-
fn get_at(world: &Vec<u8>, size: usize, x: usize, y: usize) -> u8 {
-
// benefits from the integer overflow to simplify code
-
if x >= size || y >= size {
-
return 0;
-
};
-
// this is in known bounds
-
unsafe { *world.get_unchecked(y * size + x) }
-
}
+
fn generations(
+
times: u32,
+
mut world: Vec<u8>,
+
size: usize,
+
stuck: bool,
+
) -> Vec<u8> {
+
let pos = |x, y| y * (size + 2) + x;
-
let mut new_world = vec![0_u8; size * size];
-
let sizem = size - 1;
-
if stuck {
-
world[0] = 1;
-
world[sizem] = 1;
-
world[(size * size) - 1] = 1;
-
world[size * sizem] = 1;
+
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..=size {
+
for yo in 1..sizep {
let ym = yo - 1;
let yp = yo + 1;
-
for xo in 1..=size {
+
for xo in 1..sizep {
let xm = xo - 1;
let xp = xo + 1;
-
let was = get_at(&world, size, xo, yo) == 1;
-
let neighbours = get_at(&world, size, xm, ym)
-
+ get_at(&world, size, xo, ym)
-
+ get_at(&world, size, xp, ym)
-
+ get_at(&world, size, xm, yo)
-
+ get_at(&world, size, xp, yo)
-
+ get_at(&world, size, xm, yp)
-
+ get_at(&world, size, xo, yp)
-
+ get_at(&world, size, xp, yp);
-
new_world[yo * size + xo] = (neighbours == 3 || (neighbours == 2 && was)) as u8;
+
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 :(
-
if stuck {
-
world[0] = 1;
-
world[sizem] = 1;
-
world[(size * size) - 1] = 1;
-
world[size * sizem] = 1;
+
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();
-
let input: Vec<u8> = once(".".repeat(size))
-
.chain(input.split("\n"))
-
.chain(".".repeat(size))
-
.map(|line| {
-
once(0)
-
.chain(line.chars().map(|v| (v == '#') as u8))
-
.chain(once(0))
+
// 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();
+40 -18
2015/19/rust/src/main.rs
···
-
struct Combination {
-
original: String,
-
target: String,
-
}
+
use std::collections::{HashMap, HashSet};
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(),
-
},
+
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 =
+
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 =
+
std::fs::read_to_string("../input.txt").expect("invalid input!!");
let input = input.trim();
let res = find(input, 5);
+3 -1
2025/1/rust/src/main.rs
···
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,
+
zeroes: acc.zeroes
+
+ raw_zeroes
+
+ (acc.turn != 0 && raw_turn <= 0) as i32,
}
},
);
+2 -88
2025/1/zig/build.zig
···
const std = @import("std");
-
// Although this function looks imperative, it does not perform the build
-
// directly and instead it mutates the build graph (`b`) that will be then
-
// executed by an external runner. The functions in `std.Build` implement a DSL
-
// for defining build steps and express dependencies between them, allowing the
-
// build runner to parallelize the build automatically (and the cache system to
-
// know when a step doesn't need to be re-run).
pub fn build(b: *std.Build) void {
-
// Standard target options allow the person running `zig build` to choose
-
// what target to build for. Here we do not override the defaults, which
-
// means any target is allowed, and the default is native. Other options
-
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
-
// Standard optimization options allow the person running `zig build` to select
-
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
-
// set a preferred release mode, allowing the user to decide how to optimize.
+
const optimize = b.standardOptimizeOption(.{});
-
// It's also possible to define more custom flags to toggle optional features
-
// of this build script using `b.option()`. All defined flags (including
-
// target and optimize options) will be listed when running `zig build --help`
-
// in this directory.
-
// This creates a module, which represents a collection of source files alongside
-
// some compilation options, such as optimization mode and linked system libraries.
-
// Zig modules are the preferred way of making Zig code available to consumers.
-
// addModule defines a module that we intend to make available for importing
-
// to our consumers. We must give it a name because a Zig package can expose
-
// multiple modules and consumers will need to be able to specify which
-
// module they want to access.
-
-
// Here we define an executable. An executable needs to have a root module
-
// which needs to expose a `main` function. While we could add a main function
-
// to the module defined above, it's sometimes preferable to split business
-
// logic and the CLI into two separate modules.
-
//
-
// If your goal is to create a Zig library for others to use, consider if
-
// it might benefit from also exposing a CLI tool. A parser library for a
-
// data serialization format could also bundle a CLI syntax checker, for example.
-
//
-
// If instead your goal is to create an executable, consider if users might
-
// be interested in also being able to embed the core functionality of your
-
// program in their own executable in order to avoid the overhead involved in
-
// subprocessing your CLI tool.
-
//
-
// If neither case applies to you, feel free to delete the declaration you
-
// don't need and to put everything under a single module.
const exe = b.addExecutable(.{
.name = "zig",
.root_module = b.createModule(.{
-
// b.createModule defines a new module just like b.addModule but,
-
// unlike b.addModule, it does not expose the module to consumers of
-
// this package, which is why in this case we don't have to give it a name.
.root_source_file = b.path("src/main.zig"),
-
// Target and optimization levels must be explicitly wired in when
-
// defining an executable or library (in the root module), and you
-
// can also hardcode a specific target for an executable or library
-
// definition if desireable (e.g. firmware for embedded devices).
+
.target = target,
.optimize = optimize,
-
// List of modules available for import in source files part of the
-
// root module.
}),
});
-
// This declares intent for the executable to be installed into the
-
// install prefix when running `zig build` (i.e. when executing the default
-
// step). By default the install prefix is `zig-out/` but can be overridden
-
// by passing `--prefix` or `-p`.
b.installArtifact(exe);
-
// This creates a top level step. Top level steps have a name and can be
-
// invoked by name when running `zig build` (e.g. `zig build run`).
-
// This will evaluate the `run` step rather than the default step.
-
// For a top level step to actually do something, it must depend on other
-
// steps (e.g. a Run step, as we will see in a moment).
const run_step = b.step("run", "Run the app");
-
// This creates a RunArtifact step in the build graph. A RunArtifact step
-
// invokes an executable compiled by Zig. Steps will only be executed by the
-
// runner if invoked directly by the user (in the case of top level steps)
-
// or if another step depends on it, so it's up to you to define when and
-
// how this Run step will be executed. In our case we want to run it when
-
// the user runs `zig build run`, so we create a dependency link.
const run_cmd = b.addRunArtifact(exe);
run_step.dependOn(&run_cmd.step);
-
// By making the run step depend on the default step, it will be run from the
-
// installation directory rather than directly from within the cache directory.
run_cmd.step.dependOn(b.getInstallStep());
-
// This allows the user to pass arguments to the application in the build
-
// command itself, like this: `zig build run -- arg1 arg2 etc`
if (b.args) |args| {
run_cmd.addArgs(args);
}
-
// Creates an executable that will run `test` blocks from the executable's
-
// root module. Note that test executables only test one module at a time,
-
// hence why we have to create two separate ones.
const exe_tests = b.addTest(.{
.root_module = exe.root_module,
});
-
// A run step that will run the second test executable.
const run_exe_tests = b.addRunArtifact(exe_tests);
-
// A top level step for running all tests. dependOn can be called multiple
-
// times and since the two run steps do not depend on one another, this will
-
// make the two of them run in parallel.
const test_step = b.step("test", "Run tests");
test_step.dependOn(&run_exe_tests.step);
-
-
// Just like flags, top level steps are also listed in the `--help` menu.
-
//
-
// The Zig build system is entirely implemented in userland, which means
-
// that it cannot hook into private compiler APIs. All compilation work
-
// orchestrated by the build system will result in other Zig compiler
-
// subcommands being invoked with the right flags defined. You can observe
-
// these invocations when one fails (or you pass a flag to increase
-
// verbosity) to validate assumptions and diagnose problems.
-
//
-
// Lastly, the Zig build system is relatively simple and self-contained,
-
// and reading its source code will allow you to master it.
}
+6 -4
2025/2/rust/src/main.rs
···
})
.collect();
-
let powers_of_ten: Vec<u64> = (0..=MAX_LENGTH as u32).map(|i| 10_u64.pow(i)).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();
···
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()
+
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();
+
number += combination
+
* powers_of_ten.get((len * repeat) as usize).unwrap();
if repeat > 0 {
part_2.insert(number);
}
+3 -1
2025/3/gleam/src/main.gleam
···
// 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
···
// 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
-
// wky 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
+
// 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
+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
+1 -1
template/rust/src/main.rs
···
fn main() {
-
let input = include_str!("../../input.txt");
+
let input = include_str!("../../input.txt").trim();
println!("{}", &input);
}
+2 -88
template/zig/build.zig
···
const std = @import("std");
-
// Although this function looks imperative, it does not perform the build
-
// directly and instead it mutates the build graph (`b`) that will be then
-
// executed by an external runner. The functions in `std.Build` implement a DSL
-
// for defining build steps and express dependencies between them, allowing the
-
// build runner to parallelize the build automatically (and the cache system to
-
// know when a step doesn't need to be re-run).
pub fn build(b: *std.Build) void {
-
// Standard target options allow the person running `zig build` to choose
-
// what target to build for. Here we do not override the defaults, which
-
// means any target is allowed, and the default is native. Other options
-
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
-
// Standard optimization options allow the person running `zig build` to select
-
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
-
// set a preferred release mode, allowing the user to decide how to optimize.
+
const optimize = b.standardOptimizeOption(.{});
-
// It's also possible to define more custom flags to toggle optional features
-
// of this build script using `b.option()`. All defined flags (including
-
// target and optimize options) will be listed when running `zig build --help`
-
// in this directory.
-
// This creates a module, which represents a collection of source files alongside
-
// some compilation options, such as optimization mode and linked system libraries.
-
// Zig modules are the preferred way of making Zig code available to consumers.
-
// addModule defines a module that we intend to make available for importing
-
// to our consumers. We must give it a name because a Zig package can expose
-
// multiple modules and consumers will need to be able to specify which
-
// module they want to access.
-
-
// Here we define an executable. An executable needs to have a root module
-
// which needs to expose a `main` function. While we could add a main function
-
// to the module defined above, it's sometimes preferable to split business
-
// logic and the CLI into two separate modules.
-
//
-
// If your goal is to create a Zig library for others to use, consider if
-
// it might benefit from also exposing a CLI tool. A parser library for a
-
// data serialization format could also bundle a CLI syntax checker, for example.
-
//
-
// If instead your goal is to create an executable, consider if users might
-
// be interested in also being able to embed the core functionality of your
-
// program in their own executable in order to avoid the overhead involved in
-
// subprocessing your CLI tool.
-
//
-
// If neither case applies to you, feel free to delete the declaration you
-
// don't need and to put everything under a single module.
const exe = b.addExecutable(.{
.name = "zig",
.root_module = b.createModule(.{
-
// b.createModule defines a new module just like b.addModule but,
-
// unlike b.addModule, it does not expose the module to consumers of
-
// this package, which is why in this case we don't have to give it a name.
.root_source_file = b.path("src/main.zig"),
-
// Target and optimization levels must be explicitly wired in when
-
// defining an executable or library (in the root module), and you
-
// can also hardcode a specific target for an executable or library
-
// definition if desireable (e.g. firmware for embedded devices).
+
.target = target,
.optimize = optimize,
-
// List of modules available for import in source files part of the
-
// root module.
}),
});
-
// This declares intent for the executable to be installed into the
-
// install prefix when running `zig build` (i.e. when executing the default
-
// step). By default the install prefix is `zig-out/` but can be overridden
-
// by passing `--prefix` or `-p`.
b.installArtifact(exe);
-
// This creates a top level step. Top level steps have a name and can be
-
// invoked by name when running `zig build` (e.g. `zig build run`).
-
// This will evaluate the `run` step rather than the default step.
-
// For a top level step to actually do something, it must depend on other
-
// steps (e.g. a Run step, as we will see in a moment).
const run_step = b.step("run", "Run the app");
-
// This creates a RunArtifact step in the build graph. A RunArtifact step
-
// invokes an executable compiled by Zig. Steps will only be executed by the
-
// runner if invoked directly by the user (in the case of top level steps)
-
// or if another step depends on it, so it's up to you to define when and
-
// how this Run step will be executed. In our case we want to run it when
-
// the user runs `zig build run`, so we create a dependency link.
const run_cmd = b.addRunArtifact(exe);
run_step.dependOn(&run_cmd.step);
-
// By making the run step depend on the default step, it will be run from the
-
// installation directory rather than directly from within the cache directory.
run_cmd.step.dependOn(b.getInstallStep());
-
// This allows the user to pass arguments to the application in the build
-
// command itself, like this: `zig build run -- arg1 arg2 etc`
if (b.args) |args| {
run_cmd.addArgs(args);
}
-
// Creates an executable that will run `test` blocks from the executable's
-
// root module. Note that test executables only test one module at a time,
-
// hence why we have to create two separate ones.
const exe_tests = b.addTest(.{
.root_module = exe.root_module,
});
-
// A run step that will run the second test executable.
const run_exe_tests = b.addRunArtifact(exe_tests);
-
// A top level step for running all tests. dependOn can be called multiple
-
// times and since the two run steps do not depend on one another, this will
-
// make the two of them run in parallel.
const test_step = b.step("test", "Run tests");
test_step.dependOn(&run_exe_tests.step);
-
-
// Just like flags, top level steps are also listed in the `--help` menu.
-
//
-
// The Zig build system is entirely implemented in userland, which means
-
// that it cannot hook into private compiler APIs. All compilation work
-
// orchestrated by the build system will result in other Zig compiler
-
// subcommands being invoked with the right flags defined. You can observe
-
// these invocations when one fails (or you pass a flag to increase
-
// verbosity) to validate assumptions and diagnose problems.
-
//
-
// Lastly, the Zig build system is relatively simple and self-contained,
-
// and reading its source code will allow you to master it.
}