#Day 6
1 messages · Page 1 of 1 (latest)
My very unoptimised solution
part 1 | 3.245ms ±0.81
part 2 | 30.211ms ±0.114
https://github.com/giacomocavalieri/aoc_solutions/blob/main/src/aoc_solutions/year_2025/day_06.gleam
not the fastest
Ran 2025 day 6:
Part 1: ✅ (in 18.807 ms)
Part 2: ✅ (in 14.908 ms)
quickest solve so far at least
I made such a mess out of this one, but got there in the end..
Ran 2025 day 6:
Part 1: ✅ met expected value: _ (in 4.613 ms)
Part 2: ✅ met expected value: _ (in 15.642 ms)
helped bump me up in the gleam leaderboard
this is my favourite part of todays solution lol
p.1(p.0) is so cursed i love it
seems to be a few struggling with parsing pt.2 currently
very rotation
much confusion
struggling is an understatement
i did it with a little under 100 lines
time to clean up
Ran 2025 day 6:
Part 1: ✅ (in 2.783 ms)
Part 2: ✅ (in 1.425 ms)
getting better
finally managed to do it
again @unkempt berry thanks for the tip couldnt have figured it out on my own, i was thinking about the first way you suggested but it sounded painful in my head but i managed to do the second one with the counting the last line
i really dont like this one https://tangled.org/aylac.top/advent_of_code/blob/main/2025/6/gleam/src/main.gleam
glad you got there in the end c:
simplified my pt 2 a bit:
fn solve(nums: List(List(Int)), ops: List(fn(List(Int)) -> Int)) -> Int {
list.zip(nums, ops)
|> list.map(fn(p) { p.1(p.0) })
|> int.sum
}
pub fn pt_1(input: #(List(String), List(fn(List(Int)) -> Int))) -> Int {
let #(lines, ops) = input
list.map(lines, utils.parsed_fields(_, utils.unsafe_int_parse))
|> list.transpose
|> solve(ops)
}
fn do_group_columns(
chars: List(List(UtfCodepoint)),
groups: List(List(Int)),
cur_group: List(Int),
) -> List(List(Int)) {
case chars {
[] -> list.reverse([cur_group, ..groups])
[[], ..chars] -> do_group_columns(chars, [cur_group, ..groups], [])
[cs, ..chars] ->
do_group_columns(chars, groups, [
string.from_utf_codepoints(cs) |> utils.unsafe_int_parse,
..cur_group
])
}
}
pub fn pt_2(input: #(List(String), List(fn(List(Int)) -> Int))) -> Int {
let #(lines, ops) = input
let assert Ok(space) = string.utf_codepoint(32)
list.map(lines, string.to_utf_codepoints)
|> list.transpose
|> list.map(list.filter(_, fn(c) { c != space }))
|> do_group_columns([], [])
|> solve(ops)
}
let's gooooo
yeah this was a nice change of pace
not another regex problem
50% of AoC done, that's a new record 🥳
Anyone else used list.transpose ?
A real life saver
yeeee
Woooo
Yes, list.transpose was MVP in both parts for me
I opened this thread and I'm glad I'm not alone in having terribly unoptimised parsing
Ran 2025 day 6:
Part 1: _ (in 5.088 ms)
Part 2: _ (in 3.356 ms)
(including parsing today because that was most of the challenge)
omfg today's twist is absolutely brilliant
Yeah I would've been pretty lost without it lol
Indeed transpose saves the day
P2 is not that hard after thinking about it
Juste change of perspective and a lot of echo to validate transformations lol
I thought I saw p2 coming and then it was entirely not what I expected lol
Luckily I was prepared enough that it was still fairly easy
Parse deniers in shambles rn
i started out with a separate parse function
yep lol
but 1. both parts needed different parsing
My parse func is like 70 lines
and 2. it was 99% of the work
And then each part is basically also parsing, just the last bit of it :P
yeah I ended up not using a parse function at all because so little was shared
im a parse enjoyer
Still waiting for this year's excuse to use a parser combinator
i don't like the ones that are just really stupid parsing :(
at least in a language like gleam it's just list ops forever usually
can't imagine parsing some of these in something like C++
I wanted to do it in sql again 😂
Did part 1, not sure if I'll do part 2
maybe if literally parse it to row, col, char and then define a "parse integer" aggregate function hmm
Nah that's plenty fast
could improve it somewhat, im doing the parsing and solving in different passes
Ran 2025 day 6:
Part 1: _ (in 9.690 ms)
Part 2: ) (in 19.634 ms)
For part 1 i parse into a list of lists, then iterate over the outer list and reduce the inner list by the operator at the end
For part 2 i built up a dict (2d grid) from the input and iterate on it column by column
Since today was a bit parsing boring oriented. I have just tried to better understand the use keyword
I am really ashamed of the parsing of my Part 2 ahaha 🤣 I am surprised it works in 15ms though. (I used a "desperation-based approach": that is, hammering the data until it takes the shape I want ).
Oh well, time to make this more presentable...
let numbers =
lines
|> list.map(string.to_graphemes)
|> list.transpose
|> list.chunk(last_is_operator)
|> list.sized_chunk(2)
|> list.map(list.flatten)
|> list.map(fn(c) { list.map(c, fn(d) { list.take(d, lines_number) }) })
|> list.map(fn(c) { list.map(c, string.concat) })
|> list.map(fn(c) { list.map(c, fn(d) { string.trim(d) }) })
|> list.map(fn(c) { list.map(c, fn(d) { int.parse(d) }) })
|> list.map(fn(c) { list.filter(c, result.is_ok) })
|> list.map(fn(c) { result.all(c) })
|> list.map(fn(c) { result.unwrap(c, []) })
Btw using _ makes a lot of those list.map calls cleaner, i.e.
|> list.map(list.map(_, string.trim))
Also filtering by result.is_ok and then calling result.all is just the same as doing result.values
I just looked at the distances between the operation chars to get the width of a column, not sure if that’s the most widely used solution or not
Gotta love advent of parsing
I did it with list.group, but I end up throwing away the groups, so chunk looks like it makes more sense
let numbers =
list.map(lines, string.to_graphemes)
|> list.transpose
|> list.chunk(last_is_operator)
|> list.sized_chunk(2)
|> list.map(fn (c) {
list.flatten(c)
|> list.map(fn(d) {
let assert Ok(i) = list.take(d, lines_number)
|> string.concat
|> string.trim
|> int.parse
i
})
})
Mine got messy for pt2
pub type Operation {
Sum
Prod
}
pub type Instruction {
Instruction(operation: Operation, values: List(Int))
}
pub fn pt_2(input: String) {
let #(_accumulated_group_id, tagged_columns) =
string.split(input, "\n")
|> list.map(string.to_graphemes)
// Get the columns
|> list.transpose()
// Add a group ID, detected by columns of spaces
|> list.fold(#(0, []), fn(acc, e) {
let #(group_n, l) = acc
case list.all(e, fn(v) { v == " " }) {
True -> #(group_n + 1, l)
False -> #(group_n, [#(group_n, e), ..l])
}
})
// Group into columns with the same tag
list.chunk(tagged_columns, fn(v: #(Int, List(String))) -> Int { v.0 })
// Get rid of the group tags
|> list.map(fn(v) { list.map(v, fn(v) { v.1 }) })
// Find the group operation
|> list.map(fn(v) {
#(
list.fold(v, option.None, fn(acc, v) {
case list.find(v, fn(e) { e == "*" || e == "+" }) {
Error(_) -> acc
Ok("+") -> option.Some(Sum)
Ok("*") -> option.Some(Prod)
Ok(_) -> panic
}
}),
v,
)
})
// Get rid of options, since the operator has to be there somewhere in the chunk
|> list.map(fn(v) {
let assert option.Some(op) = v.0
#(op, v.1)
})
// Get rid non-number characters
|> list.map(fn(v) {
let #(op, v) = v
let v =
list.map(
v,
list.filter(_, fn(e) {
case e {
" " -> False
"*" -> False
"+" -> False
_ -> True
}
}),
)
#(op, v)
})
// Almost there
// Finally, get rid of one level of nesting
|> list.map(fn(v) {
let #(op, v) = v
let v = list.map(v, string.concat)
#(op, v)
})
// Parse numbers and map to instructions
|> list.map(fn(v) {
let #(op, v) = v
let v = list.filter_map(v, int.parse)
Instruction(op, v)
})
// Now, part 1 solution
|> list.map(calc)
|> int.sum
}
Not sure if I overcooked it, but I like my solution :) https://tangled.org/okk.moe/aoc2025/blob/main/day6/day6.gleam
need to take a look at how everyone else did it
Looks nice, better than my map soup
indeed 
not a big fan of today
but hey we are halfway!

That’s exciting!!!
Can’t wait to get my sleep schedule back to normal 
https://github.com/frakappa/aoc/blob/main/src/aoc_2025/day_6.gleam
performance is not as bad as i tought it was gonna be to be fair
Ran 2025 day 6:
Part 1: ✅ met expected value: 5524274308182 (in 2.940 ms)
Part 2: ✅ met expected value: 8843673199391 (in 12.108 ms)
it is!!
i don't know how you manage to wake up just for aoc
morning people are scary
were you going to do it in sql?
yeah, but weird parsing is extremely annoying in sql
I already relied on sed too much for part 1 for my liking
why did I just implement this without list.transpose 😭 I swear I checked the docs for that first and couldn't find it
I had to define a product aggregate function 
-----------|
-- Setup --|
-----------|
create unlogged table input_lines (
row serial primary key,
value text not null
);
create unlogged table numbers (
col int not null,
value int not null
);
create unlogged table ops (
col serial primary key,
op char not null
);
create function product_sfunc(acc numeric, factor numeric)
returns numeric as $$
select $1 * $2
$$ language sql;
create aggregate product (
sfunc = product_sfunc,
basetype = numeric,
stype = numeric,
initcond = '1'
);
-----------------|
-- Parse input --|
-----------------|
-- Copy full lines into input table, not including the operator line!
\copy input_lines (value) from program 'head -n -1 input/2025/6.txt'
insert into numbers (col, value)
select
col.col,
col.value::int
from input_lines as line
cross join
lateral
-- Trim leading whitespace, then split into array on whitespace
-- and unnest into rows
unnest(regexp_split_to_array(trim(line.value), '\s+'))
with ordinality as col (value, col);
-- Copy last line into ops table. To transpose columns into rows, replace
-- white space with newlines. There's no way to change the row-delimiter
\copy ops (op) from program 'tail -n -1 input/2025/6.txt | sed -ze "s/\s\+/\n/g"'
------------|
-- Part 1 --|
------------|
with result as (
select
case
when op.op = '+' then sum(number.value)
else product(number.value)
end as value
from ops as op
inner join numbers as number on op.col = number.col
group by number.col, op.op
)
select sum(result.value)
from result;
Much better, ty for the parsing thingy @unkempt berry
It has an extra comment
Guess I shouldn’t have trimmed that whitespace from the end of my file.
Today's problem generated ... checks notes ... 8 TODO notes for what to change in my language 😂
today was a doozy imo
me creating mapmap in my shared utils file 😭
I had a bug and frustratingly tried fixing the wrong thing for about 50 minutes until I realized my last line was one character shorter than my other lines because I stripped the trailing whitespace.
I'm gonna be honest even in the aoc subreddit everyone is talking about whitespace, but it didn't even occur to me as a problem
ig mostly because I'm being evil & parsing it left to right anyways since it doesn't matter as the operations given are commutative
In the end I like the way I parsed part 2:
lines
|> list.map(fn(line) {
string.to_graphemes(line)
|> list.reverse
})
|> list.transpose
|> list.filter_map(fn(column) {
let l = list.length(column)
let #(numbers, operation) = list.split(column, l - 1)
use value <- result.map(
string.join(numbers, "") |> string.trim |> int.parse,
)
#(value, operation)
})
Just fyi it's a fair bit faster to go string.to_utf_codepoints <-> string.from_utf_codepoints rather than string.to_graphemes <-> string.join since codepoints are a lot less costly to calculate than graphemes
Oh... I did not know that. Thank you.
No problem
why is that?
answered my own question by looking at the code (and some research):
a unicode grapheme is made up of multiple codepoints, so finding graphemes means looking ahead for diacritics and combined codepoints and such.
even though codepoints can be 1-4 bytes, you can tell how long they will be from the first byte, so you can very quickly slice a string into codepoints
and when you're dealing with purely ASCII data, each codepoint effectively is just the byte value of the character in ascii
Ran 2025 day 6:
Part 1: _ (in 2.252 ms)
well, part 1 was mostly a parsing problem
Ran 2025 day 6:
Part 1: _(in 2.867 ms)
Part 2: _(in 102 µs)
time feels very not real for this one lol
huh???
99% of the work is in the parse
Part 2: _ (in 14.336 ms)
still actually not too bad with parsing pulled into it.
especially since i'm just chaining a ton of list ops that could be single pass
Everytime I do something like
my_variable
|> list.map(f)
|> list.map(g)
I feel a little bit dirty and whisper to myself map f . map g == map (f . g), no reason to iterate over the list twice. 😢
But alas with no function composition operator we have to make do. 
Wouldn't it be really straightforward to write your func for that?
See my post in #general
‘import gleam/lazy’ when
Contribute to ollien/advent-of-code-2025 development by creating an account on GitHub.
I'm fully prepared to read other solutions and see that I overcomplicated the parsing
my approach was to determine the column widths by counting the spaces between the operators
oh god dammit I could have just transposed the input couldn't I
sigh
well, at least I get to say I did it my own way :)
Very messy from me today but again no wrong submissions.
I was going to use filestreams as random access but I made a mess.
So on part 2 I just made a giant 2D list of the numbers lines and transposed it. Then joined and trimmed each row and folded that into data sets. Then I zipped it with the operations and folded that to sum/product each data set.
I discovered transpose and used it twice today. Such a nice utility function 
I like dabbling in array languages and transpose is a heavy lifter
Yeah, each time I have to use matrices I use it. No wonder why some languages/libs simplify it to one character (t or ')
A fellow matlab enjoyer I see
Not really. Python, julia and R 🙃
Uiua has ⍉, the diagonal line is the axis of reflection/rotation
How do you type all those symbols ? Are there plugins/helpers like in julia ? 🤔
You can type in the string name and have the compiler convert it. You don't even need to type the full name, just enough for it to be a unique match
The online playground does this automatically when you run - https://www.uiua.org/pad
big keyboard
Did try that too and then thrash it because transpose brrbrbrbrbr
OK, my day 6. Comments are welcomed. I am new to Gleam. https://github.com/Pierre-Thibault/Challenges-AdventCode/tree/main/2025/Day6
Btw you seem to have committed your input
As for the solutions, to start I would extract out that file reading and parsing in parts 1 and 2 into a separate read_file and parse function, then call those once in main and pass the parsed data to each part so it doesn't need to be done twice
For aoc you're usually fine to assert for stuff like reading and parsing the input file, so I would probably just do like
fn read_file(path: String) -> String {
let assert Ok(content) = simplifile.read(from: path) as "Missing input file"
content
}
fn parse(input: String) -> List(String) {
case file_content |> string.split("\n") {
[] -> panic as "File is empty"
[_] -> panic as "File contains only one line"
lines -> list.filter(lines, fn(line) { !string.is_empty(line) })
}
}
tbf, day 6 was particularly hard to unify parsing for part 1 and part 2
Yeah
Ok(
list.fold(symbols, #(0, grid), fn(acc, symbol) {
#(
acc.0
+ list.fold(
acc.1,
case symbol {
"+" -> 0
"*" -> 1
_ -> panic
},
fn(acc: Int, line: List(Int)) {
case list.length(line) {
0 -> panic
_ -> Nil
}
let value = result.unwrap(list.first(line), 0)
case symbol {
"+" -> acc + value
"*" -> acc * value
_ -> panic
}
},
),
list.map(acc.1, fn(line: List(Int)) { list.drop(line, 1) }),
)
}).0,
)
This to me is particularly unreadable. I would try to unpack the tuples and maybe make auxiliary functions to call instead of just using anonymous functions
This was my similar-ish part of the solution:
let ops =
ops
|> list.map(fn(op) {
case op {
"+" -> Add
"*" -> Mult
_ -> panic as "unexpected operator"
}
})
let nums =
nums
|> list.map(
list.map(_, fn(s) {
let assert Ok(num) = int.parse(s)
num
}),
)
let cols = nums |> list.transpose()
let assert Ok(zip) = list.strict_zip(cols, ops)
zip
|> list.map(fn(col) {
case col {
#(nums, Add) -> nums |> int.sum()
#(nums, Mult) -> nums |> int.product()
}
})
|> int.sum
Also list.zip(symbols, list.transpose(grid)) would remove a lot of the stuff that fold is doing
@unkempt berry Thank you for your comments. You are offering great advice to improve on my Gleam journey.