#Advent of Code 2025
1 messages · Page 1 of 1 (latest)
day1pt1 with awk
||
#!/usr/bin/awk -f
BEGIN {
i=0
x=50
}
{
num=substr($1, 2)
if (substr($1, 0, 1) == "L")
x = (100 + x - (num % 100)) % 100
else
x = (x + num) % 100
fi
if (x == 0)
i = i + 1
fi
}
END {
print i
}
||
day1pt2 with awk
||
#!/usr/bin/awk -f
BEGIN {
i=0
x=50
}
{
num=substr($1, 2)
#print "---"
#print "x", x, "i", i
#print "NEW LINE", $1
if (substr($1, 0, 1) == "L")
{
if (int((num / 100)) > 0)
{
#print "ADD ROLL UNDER", i + int(num / 100)
i = i + int(num / 100)
}
flip=100 - x
if ((flip != 100) && (int((flip + (num % 100)) / 100) > 0) && ((flip + num) % 100 != 0))
{
#print "ADD ROLL UNDER", x, "-", (num % 100), ", i =", i + 1
i = i + 1
}
x = (100 + x - (num % 100)) % 100
}
else
{
if (int((num / 100)) > 0)
{
#print "ADD ROLL OVER", i + int(num / 100)
i = i + int(num / 100)
}
if ((int((x + (num % 100)) / 100) > 0) && ((x + num) % 100 != 0))
{
#print "ADD ROLL OVER, i =", i + 1
i = i + 1
}
x = (x + num) % 100
}
if (x == 0)
{
#print "ADD x == 0, i =", i + 1
i = i + 1
}
}
END {
print i
}
||
barren
Desolate lands 😔
oh, you figured out the math
i just made naive brute force approach after my math for part 2 was wrong
which is
for _ in 0..steps {
pos += dir;
if pos < 0 {
pos += 100;
}
if pos >= 100 {
pos -= 100;
}
if pos == 0 {
all_zeros += 1;
}
}
Yeah but that took way too much time and bashing my head against a wall..
i should write the solver in const lol
just for the extra challenge
input is already const
if only RA didn't just ignore include_str
now it builds in 2.5 seconds instead of 0.1 lol
but it solves at compile time!
did you know you can't match on strings in const
Not a match statement :(
I think match is cleaner
If you want a better reason, a match statement would force you to cover all of the possible values of a integer
pos will be in range 0 ..= 99 and dir is either -1 or 1, so pos + dir is -1 ..= 100
do it in const :3
it's mostly the same except some parts that you need to do manually
like splitting into lines
thatd mostly be ||parse letter, then the remaining int, skip newline|| right?
though you can't slice manually in const
and have to use split_at
and for parsing int you can't just .parse, you need to do $int::from_str_radix
oh 
it's same but different
and it makes compiler unhappy :3
runtime version compilation + run is faster than comptime version lol
new problem in three minutes
new problem in 30 seconds
does this help
i dont uiua
lmao
whwre do the invalid ids come from 😭
how is 222220-222224 = 222222
Oh day 2 is up
here is also my entire day 1
it's a range
it's "all numbers from 222220 to 222224"
which contains 222222, which is invalid
yea the uiua screenshot was day2 lmao
i tweaked it a bit
to show the symmetry better
the first image had "multiple then undo the multiplication" in it 😌
wdym
to step once and check zero
i'm not sure what you mean
like this
i don't understand uiua lol
wtf part 2
so i don't know what those symbols mean
brute force it babyyyy
the way to get all the steps is
scan
If this is the input: [50 ¯68 ¯30 48 ¯5 60 ¯55 ¯1 ¯99 14 ¯82]
After \+ (scan add), we have [50 ¯18 ¯48 0 ¯5 55 0 ¯1 ¯100 ¯86 ¯168]
second day needs to count all passes through 0
not second day
second stage
anyway, my solution for both steps of day 2
||```rust
const INPUT: &str = include_str!("../inputs/2");
pub fn main() {
let mut twice_sum = 0;
let mut many_sum = 0;
for range in INPUT.split(',') {
let (start, end) = range.split_once('-').unwrap();
let start: usize = start.parse().unwrap();
let end: usize = end.parse().unwrap();
for v in start..=end {
if v == 0 {
continue;
}
let width = v.ilog10() + 1;
'twice: {
if width % 2 == 1 {
break 'twice;
}
let power = 10usize.pow(width / 2);
let left = v / power;
let right = v % power;
if left == right {
twice_sum += v;
}
}
'many: {
'subwidth: for subwidth in 1 ..= width / 2 {
if width % subwidth != 0 {
continue;
}
let repeats = width / subwidth;
if repeats <= 1 {
continue;
}
let power = 10usize.pow(subwidth);
let number = v % power;
let mut rest = v / power;
for _ in 1..repeats {
let rep_number = rest % power;
if rep_number != number {
continue 'subwidth;
}
rest /= power;
}
many_sum += v;
break;
}
}
}
}
println!("{twice_sum}, {many_sum}");
}
yay
yes
so i scan, but after expanding every number into units
so 10 would become 1 1 1 1 1 1 1 1 1 1 1
then you cannot miss a zero
oh god
so much code,,,,
that sounds impossible
Yeah nah I'm still hard stuck 20mins later
I haven't even written any code yet
have you considered brute-forcing it
I don't even understand how to
Like how to, imperatively
oh, hm
How could I even catch the 824 824 824
like
||
let l = input.len();
for d in divsors(l):
let c = chunk(input, d);
if c.deduplicate().length() == 1: return invalid
return valid
||
||you take the substring of the number, and check if it repeats until the end of the number||
oh wow
it took 80 seconds to compute the constant-time solution
runtime is 0.4s for everything
the sample?
no, the whole input
wdym constant-time solution?
whar
through poor miri
oh 😭
and it spits out 5 warnings about const evaluation taking too long
also you have to code like a caveman
no for loops, no find in string
also is aoc website half dying for anyone else
it throws ssl errors for me sometimes
we've got that in uiua
oh ewewewew
i haven't had that occur
whatever
i was trying to find a solution that isnt just the dumbest loop in existence
but i failed, and wrote the dumbest loop
what the fuck
whats with the labels
so overcomplicated
separate first and second part of the solution
i thought this was replying to the uiua one '>.>
with strings?
or math
in part 1 i did math
in part 2 i did strings
||```rs
fn count_invalid(start: u64, end: u64) -> u64 {
(start..end + 1)
.filter(|&num| {
let half_divisor = 10u64.pow(num.ilog10().div_ceil(2));
num / half_divisor == num % half_divisor
})
.sum()
}
fn count_invalid_part_two(start: u64, end: u64) -> u64 {
(start..end + 1)
.filter(|&num| {
if num < 10 {
return false;
}
let num_string = num.to_string().into_bytes();
for chunk_size in (1..num_string.len().div_ceil(2) + 1).rev() {
let mut iter = num_string.chunks(chunk_size);
let first = iter.next().unwrap();
if iter.all(|c| c == first) {
return true;
}
}
false
})
.sum()
}
x..y+1 instead of x..=y 😔
=y is slower
that much slower?
no
but why write slower code on purpose
it adds an extra check every iteration or something like that
a couple nanoseconds won't matter if your runtime is in milliseconds
if it cant prove y is not u64::MAX
no
it cant
wdym it cant
it has a bool for if it has emitted the last element or not
x..=y cant be optimized to x..y+1 if it cant prove y is not u64::MAX
wdym "optimized to"
aren't they identical
no
y+1 may overflow
^
if curr < end { yield Some(curr) }
if curr <= end { yield Some(curr) }
i'm talking about not adding one at all
in the next implementation of RangeInclusive
is that not a thing
same thing, you need to have the next value
ill find the full explantion brb
which will overflow if the end is MAX
whar
its basically rust saving you from a cpp mistake
here, for the condition to return false, you need to have curr be end + 1 for the <=
im still not fully convinced there isnt a better way
is there anything wrong with turning for i in x..=y{thing(i)} into for i in x..y{thing(i)} thing(y)?
more code
okay but it should be faster than current x..=y
also ranges may not be directly used in for loops
hmm
they're iterators
true
though for iterator range specifically there should be a better way
fair enough
i guess adding another bool to keep track of if its done would be too much overhead
its an almost unmeasurable difference usually, but its only 1 more character to do it the fast way
so thats what i do
it still feels like the stupid solution
surely theres a more mathy way to go about it
my mathy way is slower than yours in release lol
120ms for the second part
though you probably just have a faster clock cpu
120ms at 3.6 ghz
no, i mean something that doesnt go through each number in the ranges
because usually part 1 is like
"here are 1000 numbers to do checks on"
and part 2 is "oops we meant 1000000000000000"
and anyone who did part 1 the naive way gets fucked
i know that this time its different
but i was expecting
also every person gets a different input
so its not exactly that for everyone
oh interesting
sometimes you might get "you got the answer to someone elses input!" when you submit
that's why it throws 400 bad request when i tried wgeting it
mhm
aoc-cli requires your cookie to fetch stuff
the owner of the site really cares about people cloning it for some reason
i wonder if there's an automatic bot that gives each day's problem to an llm then tries to compute the solution
okay i lied again
it took like 30 seconds to add rayon
||```rs
pub fn part_one(input: &str) -> Option<u64> {
let mut input = input.as_bytes();
let invalid = AtomicU64::new(0u64);
rayon::scope(|s| {
while !input.is_empty() {
let (start, rem) = fast_parse::<u64>(input);
let (end, rem) = fast_parse::<u64>(&rem[1..]);
input = &rem[1..];
let invalid_ref = &invalid;
s.spawn(move |_| count_invalid(start, end, invalid_ref));
}
});
Some(invalid.load(Relaxed))
}
fn count_invalid(start: u64, end: u64, invalid_counter: &AtomicU64) {
invalid_counter.fetch_add(
(start..end + 1)
.filter(|&num| {
let half_divisor = 10u64.pow(num.ilog10().div_ceil(2));
num / half_divisor == num % half_divisor
})
.sum(),
Relaxed,
);
}
There was a separate AI leaderboard for several years? Were there really that many rule breakers that the global leaderboard got nuked?
i have never seen a separate AI leaderboard
every day there were those 5s clears that were obvious cheaters
you probably mean some private leaderboard someone made for a subreddit or something
to be fair, the official response doesn't mention llms
thats my interpretation for part of the reason
What happened to the global leaderboard? The global leaderboard was one of the largest sources of stress for me, for the infrastructure, and for many users. People took things too seriously, going way outside the spirit of the contest; some people even resorted to things like DDoS attacks. Many people incorrectly concluded that they were somehow worse programmers because their own times didn't compare. What started as a fun feature in 2015 became an ever-growing problem, and so, after ten years of Advent of Code, I removed the global leaderboard. (However, I've made it so you can share a read-only view of your private leaderboard. Please don't use this feature or data to create a "new" global leaderboard.)
What happened to the global leaderboard? The global leaderboard was one of the largest sources of stress for me, for the infrastructure, and for many users. People took things too seriously, going way outside the spirit of the contest; some people even resorted to things like DDoS attacks. Many people incorrectly concluded that they were somehow worse programmers because their own times didn't compare. What started as a fun feature in 2015 became an ever-growing problem, and so, after ten years of Advent of Code, I removed the global leaderboard. (However, I've made it so you can share a read-only view of your private leaderboard. Please don't use this feature or data to create a "new" global leaderboard.)
i literally just pasted this
Your new messages didn't load before I pasted that :>
anyway
since llms are faster and can be artificially delayed
it is trivial to slip through any attempt to get rid of them
assuming its a day they have a decent chance of solving
i know they one shot older ones, but solutions for those are in the training set
Bleh can't see any old leaderboards without a login which I cba to do on mobile
I love abusing rust nightly
const unsafe fn ascii_to_usize(src: &'static [Char]) -> usize {
unsafe { usize::from_ascii(src.as_bytes()).unwrap_unchecked() }
}```
pub const INPUT: &[Char] = unsafe { include_str!("./input.txt").as_ascii_unchecked() };```
debug_assert!(range.0.iter().all(|c| c.to_char().is_numeric()));
debug_assert!(range.1.iter().all(|c| c.to_char().is_numeric()));
// SAFETY: Asserted that input only uses numbers :^)
unsafe { (ascii_to_usize(range.0), ascii_to_usize(range.1)) }```
it can have a little safety
as a treat
😭not even my test set w 3 id ranges runs that fast
tbf it is the opposite of optimization and has a bunch of dead code because
i haven't finished
damn
are your test ranges millions of elements long?
all the ranges in the input are fairly small
we are about to cry why isn't our solution working TwT day1p2
||
input() ->
{ok, IOdev}=file:open("input", read),
input(IOdev).
input(IOdev) ->
receive
close -> file:close(IOdev);
PID -> PID ! file:read_line(IOdev), input(IOdev)
end.
exec_line([$L|Tl], Total) ->
{Clicks, _}=string:to_integer(Tl),
(100 + (Total-Clicks)) rem 100;
exec_line([$R|Tl], Total) ->
{Clicks, _}=string:to_integer(Tl),
(Total + Clicks) rem 100.
exec_line_rev(Data=[Mov|N], Position) ->
{Diff,_} = string:to_integer(N),
Revs=case Mov of
$R -> floor((Diff+Position) / 100);
$L -> if
(Diff > Position) and (Position =/= 0) -> floor(abs(Diff-Position) / 100) + 1;
(Diff > Position) and (Position == 0) -> floor(abs(Diff-Position) / 100);
(Diff rem 100) == Position -> 1;
true -> 0
end
end,
NewPos=exec_line(Data,Position),
{Revs, NewPos}.
calc_crossed_zeroes() ->
put(file,spawn(fun() -> input() end)),
calc_crossed_zeroes(50,0).
calc_crossed_zeroes(Position, Count) ->
get(file) ! self(),
{Revolutions, NewPos}=receive
eof ->
get(file) ! close,
io:format("~nCount ~p~n", [Count]),
exit(0);
{ok, Data} ->
Revs=exec_line_rev(Data, Position),
io:format("~p -> ~p revs:~p~n", [Data, exec_line(Data,Position), Revs]),
Revs;
Error -> io:format("~nError: ~p~n", [Error])
end,
calc_crossed_zeroes(NewPos, Count+Revolutions).
||
ignore the terrible io handling :3
what's with the terrible io handling :3
the thread holding the file handle isn't the one that automatically closes it on termination but waits for the get(file) ! close message being sent <w>
by dr.jaska's solution we are lowballing it by a grand total of 38 edge cases TwT
we cheated TwT why the fuck isn't it working why can't we get the fucking math right what edge cases are we missing >:c
||
exec_line_rev(Data=[Mov|N], Position) ->
{Diff,_} = string:to_integer(N),
NewPos=exec_line(Data,Position),
Revs=case Mov of
$R -> floor((Diff+Position) / 100);
$L when Diff < Position -> 0;
$L when (Diff > Position) and (NewPos =/= 0)->
floor((Diff-Position) / 100);
$L when (Diff >= Position) ->
floor((Diff-Position) / 100) + 1
end,
{Revs, NewPos}.
||
about to Crash The Fuck Out
@brittle void could you explain how your solution works for day1p2?
anyone 🥺
definitely!
||for each divisor of the length d, chunk the input into chunks of size d. if all chunks are equal, it's invalid||
this approach is ||stringy (or array-y), it does not use math||
what the helly is d meant to be TwT
day 1 part 2
not day 2
the safe dial
-# ↪ @rapid pumice why are you dividing by 100?
to get how many times the operation "rolls over" zero OwO
so
||
you've got the input like -68 -30 48 -5 ...
i expand this out to a long sequence of -1 and 1, then do a scan (+)
||
then you just count the zeros
killing you /lh
cursed solution
you might think this will be absurdly slow, but it was pretty instant
||the numbers are pretty small||
hey, it's beautiful
look:
I think the last floor has to be a ceil?
cursed language
the only difference between the days is the multiply versus the backkeep
the backkeep is what does the ||expansion||
multiply, uh, multiplies instead
so you only check the exact values it lands on
(they both act on the signs and the magnitudes)
I'm confuse :3
what is this even doing
-# ↪ @rapid pumice I think the last floor has to be a ceil?
oh why? the floor is to get the "whole" part of the division, if we ceil we get a skewed result even in the example input
-# ↪ @wild otter what is this even doing
it's trying to calculate how many times a operation has the thingy go over zero :3
I was thinking of how weird ceil, floor, trunc, and round are
🫵 bracket typo
-# ↪ @wild otter so many cases
||```
first case is stuff like 5-3, never goes over zero
second case is for stuff like 53-100
third case is for stuff that lands on zero 53-153
i just had one simple division
and a correction of one for the negative case
that is so much code oh my god
three hundred lines
the solutions itself is like 20
i kept the important at the top
yeah most of it is the visual
i modifier this template repo to also have a tui flag
i should try to make one too
instead of just a solve flag
i posted a gif yesterday
very basic
first time using ratatui
canvas
like stuffing an svg into html when you need something complex
i still dont fully understand how ratatui works
what is .rem_euclid?
they have a weird separation between the coordinates and the buffer itself
modulu but not stupid
as in, it works on negatives as expected
huh
a rem euclid b = ((a%b)+b)%b
(fun fact, uiua's modulo does rem_euclid)
my main documentation contribution was realizing that, then adding a snippet to get standard %
meanwhile
this is exactly what i'm doing but with num and dial switched so i don't have to deal with doing abs on anything TwT
let virtual_dial = dial - num;
let passes = virtual_dial / 100;
why isn't mine working 😭
are you correcting for the negative case
when you go from positive to negative the division will be off by 1
i am attempting to google it and i'm getting 100% slop
only when the new position doesn't land on 0 tho right?
$L when (Diff > Position) and (NewPos =/= 0)->
floor((Diff-Position) / 100);
$L when (Diff >= Position) ->
floor((Diff-Position) / 100) + 1
this is that no? 🥺
wait
i dont really know this language so
dunno
youre not accounting for when you start at 0 i think
is that dial>0 because yours can be negative or because you didn't wanna type dial != 0?
i think i found the problem -w-
i dont see the issue
that last line is the dial set at 1, the comand being L2, and the result not being 1
should it not be 99
why is it not 1-2 then
because |a-b|=|b-a| and i don't want to make my life harder by having to think about the sign of variables :3
i dont think thats going to work
in fact it isn't TwT
oh
I was confused about that when you mentioned it earlier
but presumed I misunderstood something
you can, in fact, not just switch the bigger and smaller number in subtraction
it will give you they correct amount of passes, but only once
?
what?
em
-# ↪ @rapid pumice you can, in fact, not just switch the bigger and smaller number in subtract…
it's just for the sign of the result
no like
you don't want to use abs
you should not be using abs nor swapping the order
why would you want to use abs
i tried something similar at the some point
keep it positive, convert left movement to right movement from (100-dial)
because i'm trying to calculate the number of revolutions not the final dial position TwT
you get the correct amount of passes only on the first line
anyway
just do normal math
negative numbers exist
make sure your language does rem euclid
yea but... if you do abs you won't know if it passed 0
(my entire computation uses integers then does mod100 at the end)
what
if you take abs?
the thing you'd have to abs would be the result of the floor or division
not of the subtraction
my reasoning is: Diff/100 is how many revolutions happen if the thing starts at zero, Diff-Position is the NewDiff that corrects the original to have it beheave like it's starting at zero but looses the click for going from Position to 0 so you need to add 1 to NewDiff/100 to get the times it crosses 0.............. but it doesn't fucking workkkkkkkk
Diff+Position, no?
so diff is the amount of clicks you're turning left?
yes
that does sound okay
a bit overcomplicated
but should work
do you pass the example at least
not anymore TwT
we fiddled too much let me fix at least the example
ok now we do
and we are back at missing 38 edge cases from the proper input -w-
probably cases where you stopped at 0
if Position is 0 and Diff is 100...
Then NewPos is 0
floor((Diff - Position) / 100) + 1
= floor((100 - 0 ) / 100) + 1
= floor(1) + 1
So it counts the starting 0 in addition to the end one?
no?
wait let me resend because idk wtf that was
or is NewPos 100
||```hs
Revs=case Mov of
$R -> floor((Diff+Position) / 100);
$L when Diff < Position -> 0;
$L when (Diff >= Position) and ((Position=/=0) or (NewPos==0)) ->
floor((Diff-Position) / 100)+1;
$L when (Diff > Position) ->
floor((Diff-Position) / 100);
$L when (Diff == Position) -> 1
end,
ok
the or NewPos==0 is redundant
or at least didn't get us any closer to the proper solution
(i am trying to make the visualizer, but it seemed wrong)
(i made the pixels persist and got this shape)
ok so
Position 1, Diff 1000
floor((Diff - Position)/100)+1
=floor(999/100)+1
=floor(9.99)+1
=9+1
=10
shouldn't it be 9 here?
@mild temple :v
nope, straight from the aoc page :3
gwuh...
i'm manually stepping at each line to see where it fucks up cause this is too much
how
no idea
it should be fine
but it follows a very odd path
thank you discord for not embedding apngs
the dial is going negative????????????????????????????
FUCK
I FORGOT THE ABS IN THE FUCKING exec_line() FUNCTION WHEN I SIMPLIFIED IT AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
did that fix it?
they frogor the abdominals,,,
here have this combination input/output/debug file I just hacked together
ignore the start which I forgor has the cargo output
:Godo:
squint
L38 Hit 0 1 times current: 94
what
did you guys see the formula someone posted on reddit
no
https://www.reddit.com/r/adventofcode/comments/1pcbgai/2025_day_2_day_2_should_be_easy_right_closed/
-> Sum function
literally just for loop >:)
sure but it doesnt iterate on the range
it takes logarithmic time in relation to the upper range
oh gwuh
have better file where I don't forget to print half the lines
@mild temple have a source of truth you can compare your output against
just check when your thing doesn't line up with mine and you'll know what's wrong in theory :^)
thank you <3 we are awking your output to ours so we can diff the files and see where shit is the problem
you hit the problem in the head, i'm missing about 800 from your example !
They shared their input to you?
They got your input?
what the hell
hmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
because (15-717) mod 100 is -2.... which should be 100-2 in the wheel representation
yes
which is what I was confused about earlier when you talked about subtracting the position from the difference instead of the other way around
your problem wasn't in the 0 counting
it was when setting NewPos, seems like
which would explain why you couldn't find the mistake there
yeah
we did it...................................................................................................................................................................................................................
we hate it
||```hs
exec_line([$L|Tl], Total) ->
{Clicks, _}=string:to_integer(Tl),
if
(Total >= Clicks) or (Clicks rem 100 == Total) ->
Total - (Clicks rem 100);
true -> 100-(abs(Total-Clicks) rem 100)
end;
exec_line([$R|Tl], Total) ->
{Clicks, _}=string:to_integer(Tl),
(Total + Clicks) rem 100.
this is the monster that saved us
horrible thing
a blight to the eye
not worth the 2+ hours we spent on this problem
thank you so much for the help @rapid pumice and @wild otter <3
ew <3
(what language is this, again?)
erlang
Did day 2 in Haskell, which I haven't touched since 2nd year of uni hah
I might try and do a different lang every day
do it in brainfuck
ooh the snow in the day selector art is generated new on refresh
day 3!
done it :3
funny that code was easy to extend to part 2
and i think my algorithm is O(2*input.len()) lol
and it takes 1.5 seconds for miri to run the const time solver
way better than yesterday's 80 lol
actually no, nvm, that's just the best case
i should have collected into a vec
cant solve part 1 for some reason
🤔
passes example, fails real
no idea why
the result from every line i manually checked so far is correct
||scan through each line, if digit bigger than current tens digit, set it as tens digit and the following digit as ones digit, otherwise compare to ones digit and pick biggest||
||rs pub fn part_one(input: &str) -> Option<u64> { let mut input = input.as_bytes(); let mut sum = 0u64; let mut lines = 0u64; while !input.is_empty() { println!("new line"); lines += 1; let mut max_tens = input[0]; let mut max_ones = input[1]; input = &input[2..]; while input[0] != b'\n' { let digit = input[0]; if digit > max_tens && input[1] != b'\n' { max_tens = digit; max_ones = input[1]; input = &input[2..]; println!("{}{}", max_tens - b'0', max_ones - b'0'); continue; } else if digit > max_ones { max_ones = digit; println!("{}{}", max_tens - b'0', max_ones - b'0'); } input = &input[1..]; } // skip \n input = &input[1..]; sum += max_tens as u64 * 10 + max_ones as u64; } sum -= b'0' as u64 * 11 * lines; Some(sum) }||
prints are just debug
why are you not using .lines() and making it harder for yourself?
i think this may ||make the ones digit a digit before the tens digit||
actually no nvm
can you give me an input output pair to test
from my long input?
thanks
7 differences
nah im good
ah i got it
if theres a new tens digit immediately followed by another new tens digit, the result is wrong
fuck, still wrong
ok part 1 done
i had the same mistake if it happened on the first pair of the line
i dont like this part 2
seems tedious
||instead of two variables you'd do an array, in your case||
I know
i just dont like it
im going for a different approach
this time with lines
my algorithm was ||find first biggest digit in the line - few characters from the end so all digits fit, substr the line after it, search for the next digit in that line, repeat for all digits||
not clicking for now, i have an idea how to do it nicely
part 2 done
just clicked, yep thats what i did
nice :3
your first implementation is more or less linear
oh right
stupid lines
see its all its fault
Part 1: 16858 (18.0µs)
Part 2: 16858 (29.0µs)```
Part 1: 16858 (17.4µs)
Part 2: 167549941654721 (54.8µs)
i could combine the lines with the first max pass
probably makes it about as complicated as the normal single pass
mine is around 90us for both solutions combined
interesting that const solver is slower by about 10us
well
probably because its line splitting is slow
literally scanning forward for a \n
tried this:
||rs pub fn part_one(input: &str) -> Option<u64> { let mut input = input.as_bytes(); let mut sum = 0u64; let mut lines = 0u64; while !input.is_empty() { lines += 1; let mut tens = input[0]; let mut tens_index = 0usize; let mut curr_index = 0usize; while input[curr_index] != b'\n' { let digit = input[curr_index]; if digit > tens && input[curr_index + 1] != b'\n' { tens = digit; tens_index = curr_index; } curr_index += 1; } // go back and find the second digit let ones = *input[tens_index + 1..curr_index].iter().max().unwrap(); // skip to next line input = &input[curr_index + 1..]; sum += tens as u64 * 10 + ones as u64; } sum -= b'0' as u64 * 11 * lines; Some(sum) }||
its slower
a bit faster than setting part 2 to 2 digits
this is my part 2 btw
||rs pub fn part_two(input: &str) -> Option<u64> { const DIGITS: usize = 12; input .lines() .map(|line| { // println!("For {line}:"); let mut line = line.as_bytes(); let mut sum = 0u64; for digit in (0..DIGITS).rev() { let mut max = line[0]; let mut max_index = 0; // we need to reserve `digit` digits at the end of the line for the rest of the process for (index, &digit) in line[0..line.len() - digit].iter().enumerate() { if digit > max { max = digit; max_index = index; } } sum = sum * 10 + (max - b'0') as u64; line = &line[max_index + 1..]; } sum }) .sum::<u64>() .into() }||
btw you can optimize biggest digit scan by stopping on 9
mine is more code lol
||```rust
const fn find_max_joltage(bank: &str, batteries: usize) -> usize {
let mut rest = bank;
let mut value = 0;
let mut i = 0;
while i < batteries {
let remaining_batteries = batteries - i;
let minimum_remaining = remaining_batteries - 1;
let bank_search = rest.split_at(rest.len() - minimum_remaining).0;
let digit = find_biggest_digit(bank_search).unwrap();
rest = rest.split_at(digit.0 + 1).1;
value = value * 10 + digit.1 as usize;
i += 1;
}
value
}
const fn find_biggest_digit(s: &str) -> Option<(usize, u8)> {
let mut max_digit = None;
let mut i = 0;
while i < s.len() {
let digit = s.as_bytes()[i];
let digit = digit - b'0';
max_digit = Some(match max_digit {
None => (i, digit),
Some((_, md)) if md < digit => (i, digit),
Some(old) => old,
});
if digit == 9 {
break;
}
i += 1
}
max_digit
}
not beating compiletime calculated result /j
unless you count compilation time too
then easily
since it takes more than a second to calculate in const
no difference..
this benchmark is also not very stable
whoever wrote this template didnt make it easy to benchmark
oh it doesnt do any benchmarking if you dont pass --time
it just runs once
why
let bench_iterations =
(Duration::from_secs(1).as_nanos() / cmp::max(base_time.as_nanos(), 10)).clamp(10, 10000);
oh, --time is just "do you want to benchmark"
my ass has no idea how to do P2
i've got a rough idea
Tried out Zig for today's (my solution)
having never looked at Zig before today lol
It has a very interesting approach to heap allocation
I believe I have an O(m*2n) solution, where m is bank size and n is number of batteries
i think the base at the north pole might not survive our decorating lol
damn
part 2 generates nice patterns
looks like a map almost
also since the input is constant width, you only need to find the newline once
and then just assert that the line is still same width
would be cool if aoc had an ssh interface
since web ui is done like a terminal anyway
gcc is betraying me because why is the number array beheaving as if it starts in the same location as the line_buffer
when passed as char* parameter
char* are null-terminated, no?
not necessarily, only if you want to use them as string which for me number isn't, it is a simple array of chars
then I lack context for being helpful :3
fair day2p2
||```C
void find_largest(char const * const line_buffer, num line_remaining_length, char* remaining_digits, num digit_position) {
if( digit_position==12 ) return;
for(num idx=0; idx<line_remaining_length; idx++) {
if( remaining_digits[0] < line_buffer[idx] )
{
remaining_digits[0] = line_buffer[idx];
for(num n_idx=1; n_idx<12; n_idx++) remaining_digits[n_idx]='0';
}
find_largest(line_buffer+idx, line_remaining_length-idx, remaining_digits+1, digit_position+1);
}
if( digit_position==0 )
{
printf("\nLine: %s\n Joltage: ", line_buffer);
for(int i=0; i<12; i++) printf("%d", remaining_digits[i]);
printf("\n");
}
}
num get_line_joltage2()
{
char line_buffer[1024] = {0};
for(
num idx=0, curr_char = (num)getc(input);
curr_char != '\n' && curr_char != EOF;
curr_char=getc(input), idx++)
{
line_buffer[idx] = (char)curr_char;
}
printf("Line-first: %s; ", line_buffer);
num line_lenght = strlen(line_buffer);
char number[12];
memset(number, '0', 12);
find_largest(line_buffer, line_lenght, number, 0);
num final_number = 0;
for(num idx=0,dec_pow=12; idx < 12; idx++, dec_pow--)
{
final_number += (number[idx]-'0') * ipow(10, dec_pow);
}
return final_number;
}
the idea is to have a recursive alg like this
||
start with the biggest digit, iterate over the line and keep the biggest number you find
for the next digit do the same starting from the next position of the previous digit
when you find a bigger digit put to zero all the next digits to avoid having then be at an earlier position than the current
||
the algorithm isn't the problem.... it's gcc overlapping arrays
it's not that either, i'm fucking up in the find_largest
fixed it, i was overruning the array while resetting the next digits to '0'
I HATE 2D DAYS THAT DONT HAVE A BORDER
I DONT WANT TO HANDLE THE EDGES
finally finished the day
part 2 took a lot less time than part 1
because its ||just running part 1 multiple times||
char const * const 
black magic
instead of for i in 0..len you can do for i in 0..len+2
and i = 0 and i = len + 1 are special edge cases
what?
thats even more out of bounds
for these you either handle the edges with a bounds check on every indexing operation, or you split it into multiple loops
well for my solution it made sense to go 1 element past the end
how did you handle neighbors on the first row?
do you mean for 1..len+2?
it doesn't really makes sense going 1 before since it will overwrite zeros with zeros
or am I misunderstanding
what
must have a very different algorithm
ig
you either distribute your existence to your neighbors or count your neighbors
||
fn solve_row(above: Option<&[u8]>, row: &mut [u8], below: Option<&[u8]>) -> usize {
// [] sliding along, keeping track of counts
// i: v
// above: [x 0 1] 2 3 4 x
// middl: [x 0 1] 2 3 4 x
// below: [x 0 1] 2 3 4 x
let mut counts = [[0usize; 3]; 3];
let mut total_reachable = 0;
for i in 0..row.len() + 2 {
let rolls = if i == 0 \|\| i == row.len() + 1 {
[false; 3]
} else {
let i = i - 1;
let above = above.map(|s| s[i] == b'@').unwrap_or(false);
let middle = row[i] == b'@';
let below = below.map(|s| s[i] == b'@').unwrap_or(false);
[above, middle, below]
};
for row in counts.iter_mut() {
row.rotate_left(1);
row[2] = 0;
}
for (roll, counts) in rolls.into_iter().zip(counts.iter_mut()) {
if roll {
counts[0] += 1;
counts[1] += 1;
counts[2] += 1;
}
}
let mut reachable = false;
if i > 1 && row[i - 2] == b'@' {
let neighbours_with_center: usize = counts.iter().map(|c| c[0]).sum();
if neighbours_with_center - 1 < 4 {
reachable = true;
}
}
if i > 1 {
if reachable {
// print!("x");
total_reachable += 1;
row[i - 2] = b'.';
} else {
// print!("{}", char::from_u32(row[i - 2] as u32).unwrap());
}
}
}
// println!();
total_reachable
}
```||
omfg discord figure out your markdown
that's or
oh
you are doing the bounds check
exactly with that line with the or
thats my point
some AoC days have a border around the relevant grid
anyway
neat solution
now i'm confused what i was thinking when writing it
it works though
so i won't touch it
ah
also for the first solution, with .lines(), i was processing rows one off
so i had a reference to the row below
was something like
||```rust
let mut prev_rows = [None; 2];
for line in input.lines().map(Some).chain([None]) {
if let Some(prev_row) = prev_rows[1] {
solve_row(prev_rows[0], prev_row, line);
}
prev_rows[0] = prev_rows[1];
prev_rows[1] = line;
}
what a silly thing, who could have thought that the best time to recurse would be when you update the output
/sarcasm
ohhhhhhhhhhhhhhhhhhhh i wanna do day 4 with BQN but it's gonna suck so much asssss
if part2 isn't particualarly arraylanguageable i will cry
today was so niceee
it was array-y :D
my sol (unspoilered because yea)
I don't understand why D3 (for me, at least) spiked so hard
D2 and D4 were super nice
non-array-language user 😔
(why do you say it's gonna suck?)
No I'm going to bed
do the solve-y solve
:c
It's eepy time o clock
how does an array language solve this exactly?
with struggles
my biggest problem rn is idk how to get the diagonals of an element
what are you having trouble with?
its the same as non-diagonals neighbors but 2 changes to the coordinate instead of 1
........ i just realized i can iota the entire matrix and from that extract the x and y by using the rank of the input thank you B
that capital 'b' is supposed to be a '!' lol
calling it "rank" 
The problem is intrinsically array-y
You have a grid for P1 and a sequence of grids for P2
Yea it sucks
But it is what it is
I can walk you through my solution if you want
It's very array-y
Uses the classic Game of Life trick
i just dont see how an array language magically solves the edges
The game of life trick handles them for you
We check neighbors by rotating the array all right directions (so we get eight new arrays) and adding it up along the new axis
You can tell the rotation to not wrap, to instead insert whatever value you want
If you look at my solution, in Adjacents, you'll see something like
<purple square> 0 <rotation glyph>
This is that
After that, it's /+ (sum along the major axis)
how do you rotate the matrix diagonally? im having a hard time figuring it out
i'm spending time bugfixing the fast solution while slow solution isn't even that slow
and that's only the first part of the day
rot1_1 in uiua
The length of the amount to rotate by is how deep that value acts
(the yellow glyph that's three horizontal lines and the right angle that's white right next to it are superfluous, they can just be deleted)
(I didn't know rotate was semi pervasive and was told when i shared my sol)
yessss that was so worth it for the second part
part 2 was a simple one liner and solved in 0.42us after the first part
my day 5 algorithm is
||while reading ranges, read them in a BTreeMap::<start, end> and merge new ranges with existing ones, then for id checking it's trivial, search for the last start point before the id, then check if the range contains it ||
||first line is the new range to be added, second line is existing map of ranges, third line is new map of ranges||
lol
another easy day
O(N^2) algo, idc
||```rs
pub fn part_two(input: &str) -> Option<u64> {
let (mut fresh, _) = parse_fresh(input.as_bytes());
fresh.sort_unstable_by_key(|r| r.start);
// deduplicate ranges
let mut fresh_count = 0u64;
for i in 0..fresh.len() {
let (a, b) = fresh.split_at_mut(i + 1);
let this_range = &mut a[i];
if this_range.len() == 0 {
continue;
}
for other_range in b {
dedup(this_range, other_range);
}
fresh_count += this_range.len();
}
Some(fresh_count)
}
fn dedup(r1: &mut MyRange, r2: &mut MyRange) {
// r2 cant end before r1 starts because the ranges are sorted
if r1.end < r2.start {
return;
}
r1.start = (r1.start).min(r2.start);
r1.end = (r1.end).max(r2.end);
*r2 = MyRange {
start: u64::MAX,
end: u64::MAX - 1,
};
}
was missing a shortcircut:
||```rs
if this_range.end < other_range.start {
fresh_count += this_range.len();
continue 'outer;
}
only 5% in the O(N^2) part so whatever
parsing 69% and sorting 20%
mine is like O(nlogn+mlogn) for part 1 lol
except it's not logn but an abomination that is usually smaller than logn
because ||it combines ranges while parsing them||
sure but i time seperately
full parse in both
part 1 is N*M for me
could easily improve with some sorting and binsearch but meh
my range parsing does dedup
though i'm using a btreemap and not in the most efficient way
there's no straightforward way to get the item before/after some key
write your own btree
you can however ask it for a range of keys, it gives an iterator of kv pairs
My approach was to ||construct a 10-ary tree with Boolean leaves, you check an ID is valid by walking the tree digit-wise||
hmm
i tried to do p2 the easy way (materializing everything) but it said no 😔
it won't let me cheat 😭
that is indeed a lot of MB
f64
f..
yeag
the single numeric type of the language
(if the interpreter knows all values are ints less than 256, it'll store it as u8s, but it's not something the user has control over)
uiua is just like javascript
we have less datatypes than js 😔
your rune language just lost the very little respect it had left from me
hey wait hold on hold on
it's also got complex numbers
the types are:
number
complex
box
charac
err, it's all Array of
a scalar is still an array
cuz casenc is weirdo
was lazy with todays
solved part 2 by ||rotating the input||
||```rs
fn rotate_input(input: &[u8]) -> Vec<u8> {
let mut rotated = Vec::with_capacity(input.len());
let width = input.iter().position(|&c| c == b'\n').unwrap() + 1;
let height = input.len() / width;
for x in 0..width - 1 {
rotated.push(input[width * (height - 1) + x]);
for y in 0..height - 1 {
rotated.push(input[y * width + x]);
}
rotated.push(b'\n');
}
rotated
}
and then it makes the rest easy
making an unhinged day 6 const solution
cant you just write normal code in const
yes but that's boring
i did it by ||running over operators line, calculating column width, then manually indexing into correct places to fetch digits and build values||
i did not expect part 2 to be this little behind part 1
i could probably turn this function into an iterator and do that
generators when
does this include IO btw
or are you consting the input
not sure
its a template from gh
pretty sure it reads before running
and then passes the &str
ah
yep, it first reads the entire file at runtime, and then passes to each and measures just the solve function
it does include parsing
my times are about 78 and 43 us
with part 1 being lazy and collecting everything into vecs
2.6 seconds to run const solutions
should probably make these static
if only RA could tell me what the values are for the real input
lmao
the constants were too big for vscode to show me
yea that might be a bit too much
terminal window is 4x the size of my monitor
that's just around 130kb of consts what do you mean big values
I'm sure this isn't going to bite me in part 2
oh god scratch
this is true
seven hours?????
my average solve time for a aoc day :3
another easy day
after writing a 6.6us solution, i decided to test the brute force solution
||```rs
pub fn part_two(input: &str) -> Option<u64> {
let input = input.as_bytes();
let width = input.iter().position(|&c| c == b'\n').unwrap() + 1;
let start_index = width / 2 - 1;
debug_assert!(input[start_index] == b'S');
let jump_size = 2 * width;
Some(beam_splitter(input, start_index + jump_size, jump_size))
}
fn beam_splitter(input: &[u8], index: usize, jump_size: usize) -> u64 {
if index >= input.len() {
return 1;
}
if input[index] == b'^' {
beam_splitter(input, index + jump_size - 1, jump_size)
+ beam_splitter(input, index + jump_size + 1, jump_size)
} else {
beam_splitter(input, index + jump_size, jump_size)
}
}```||
trigger warning: its stupid
i stopped it after a few minutes
adding a cache: &mut HashMap<usize, u64> did lower it to 100us
this is my real solution btw
||```rs
pub fn part_two(input: &str) -> Option<u64> {
let input = input.as_bytes();
let width = input.iter().position(|&c| c == b'\n').unwrap() + 1;
let start_index = width / 2 - 1;
debug_assert!(input[start_index] == b'S');
let mut beams = vec![Beam {
col: start_index,
particles: 1u64,
}];
let mut next_beams: Vec<Beam> = vec![];
for layer in input.chunks_exact(width).step_by(2).skip(1) {
for &beam in beams.iter() {
if layer[beam.col] == b'^' {
// beam splits
if let Some(last_beam) = next_beams.last_mut()
&& last_beam.col == beam.col - 1
{
// there is a previous beam at that column
last_beam.particles += beam.particles;
} else {
next_beams.push(Beam {
col: beam.col - 1,
particles: beam.particles,
});
}
// right split can always be added
next_beams.push(Beam {
col: beam.col + 1,
particles: beam.particles,
});
} else if let Some(last_beam) = next_beams.last_mut() {
// no splitter
if last_beam.col == beam.col {
last_beam.particles += beam.particles;
} else {
next_beams.push(Beam {
col: beam.col,
particles: beam.particles,
});
}
}
}
swap(&mut beams, &mut next_beams);
next_beams.clear();
}
Some(beams.iter().map(|b| b.particles).sum())
}
interesting
the real or the stupid
real
isnt it kinda standard
another person i spoke with did something similar but hashmap instead of vec
||my beams array was just a Vec<usize> as wide as the input width, with 0 being no particles||
and hashset for part 1, while in part 1 i just had index instead of index and count
oh yeah sounds good too
probably faster
hmm, you do need to skip through the 0s in yours
but the flow is so simple
now i wanna try too
||and i iterate over input bytes without skipping rows, lines, all that, if the reader hits a \n, it does the array swapping||
no, i iterate over the input instead
not the beams
which is slower
actually maybe equal
||```rust
pub fn main() {
let start = Instant::now();
let line_width = INPUT.find('\n').unwrap();
let mut beam_timelines = vec![0; line_width];
let mut next_beam_timelines = vec![0; line_width];
let mut splits = 0;
let mut x = 0;
for b in INPUT
.trim_end()
.as_bytes()
{
match b {
b'S' => {
next_beam_timelines[x] = 1usize;
}
b'^' => {
if beam_timelines[x] > 0 {
next_beam_timelines[x - 1] += beam_timelines[x];
next_beam_timelines[x + 1] += beam_timelines[x];
splits += 1;
}
}
b'\n' => {
x = 0;
std::mem::swap(&mut beam_timelines, &mut next_beam_timelines);
next_beam_timelines.iter_mut().for_each(|v| *v = 0);
continue;
}
_ => {
next_beam_timelines[x] += beam_timelines[x];
}
}
x += 1;
}
let timelines: usize = next_beam_timelines.iter().copied().sum();
let time = start.elapsed();
println!("Part 1: {splits}");
println!("Part 2: {timelines}");
println!("Time: {:.02}us", time.as_secs_f64() * 1000000.0);
}```||
i also am not depending on input to be triangle shaped or that it skips every other line
but that would be even faster
or
split by lines and rayon it
also could probably be solved a bit backwards, ||for each point on line, find out how many particles will get to it from line above and splitters to the sides||
that should be rayon-able
||rs pub fn part_two(input: &str) -> Option<u64> { let input = input.as_bytes(); let width = input.iter().position(|&c| c == b'\n').unwrap() + 1; let start_index = width / 2 - 1; debug_assert!(input[start_index] == b'S'); let mut beams = vec![0; width]; beams[start_index] = 1; let mut next_beams = vec![0; width]; for layer in input.chunks_exact(width).step_by(2).skip(1) { for (col, &content) in layer[..width].iter().enumerate() { let prev_beam = beams[col]; if content == b'^' { next_beams[col - 1] += prev_beam; next_beams[col + 1] += prev_beam; } else { next_beams[col] += prev_beam; } } swap(&mut beams, &mut next_beams); next_beams.fill(0); } Some(beams.iter().sum()) }||
TIL about [T]::fill
i noticed that you didnt use it
no wonder time hasn't changed much there
(that thread was ||merging circuits by connections received from main thread and checked and calculated solutions||)
DAMN
what happens if you remove rayon
probably 8x to time
first "do you know your algorithms" day
since cpu usage jumps to 100%
i don't lol
easy if you know || kruskal's algorithm||
that sounds very overcomplicated
well i thought that took time but apparently that was just 0.1%
there are 2 well known algorithms for ||minimum spanning tree||
and the order this day asks for limits you to one of them
i know about ||union find|| but i struggle to see how it would look like in an array language, especially in a tacit one :/
hashtag going to uni paying off (i have no idea how to uiua it)
||union|| is just the assumed api for ||sets|| in most algorithms
i wanna visualize it, it probably draws something
uiua has native drawing array capabilities,,,
(including 3D)
the writes?
wires
i thought you meant the boxes and connections
hmm
i'm not sure how that would be written comfortably
actually, how would i even do that in 3d
if it was 2d it would be easy
ill just try 2d
project everything down
place the camera where it's looking from the vector that crosses (not exactly) the corner of a cube and project everything to it
ah
that would be alot of ram usage though
right?
funny that i ||later made a Vec<bool> to hold the info about made connections ||
||but didn't think to put the coords in it, coords are keys to it||
at worst N^2 u64s
||Vec<(distance, index1, index2)>|| no?
mhm
not bad at all for this scale
and you could improve it to linear memory
only store the best of each node at any given moment
and when you use it up, generate the next best for the node
i dont think theres anything here
i wonder what it'd look like if the straight line was superimposed, not bound by the grid
what do you mean?
i just noticed its slowing down, but im not sure if slow to draw or its because there are so many already used connections in the heap
it was the heap
i did 1 frame per pop instead of 1 frame per new valid connection
this is not the straightest line i've ever seen
it's jagged
because of the braille grid
well its a terminal
i could zoom out
i lied
i dont know how
just zooming out the terminal doesnt work
anyway
probably still nothing even with fixed lines
fair enough
i meant to just increase the resolution
not change the physical size on the screen
this day is
bullying me
i don't understand what it's asking
you seein this
this is the right answer for the sample, yes?
why do i get this after 19 pairs
yes
do i have to ignore idempotent joins??
you're asked to join 10 times
then print the answer
i join 10 times and i get this
for the first part
is array on the right junctions vertically in circuits horizontally?
yes
each "column" is a circuit
so the 862.. and the 984.. box share a circuit
my first 10 joins are
||```
{162, 817, 812} -> {425, 690, 689}
{162, 817, 812} -> {431, 825, 988}
{906, 360, 560} -> {805, 96, 715}
{431, 825, 988} -> {425, 690, 689}
{862, 61, 35} -> {984, 92, 344}
{52, 470, 668} -> {117, 168, 530}
{819, 987, 18} -> {941, 993, 340}
{906, 360, 560} -> {739, 650, 466}
{346, 949, 466} -> {425, 690, 689}
{906, 360, 560} -> {984, 92, 344}
for the sample input
||```
{162, 817, 812} -> {425, 690, 689} [2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
{162, 817, 812} -> {431, 825, 988} [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
{906, 360, 560} -> {805, 96, 715} [3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
{431, 825, 988} -> {425, 690, 689} [3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
{862, 61, 35} -> {984, 92, 344} [3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
{52, 470, 668} -> {117, 168, 530} [3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
{819, 987, 18} -> {941, 993, 340} [3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1]
{906, 360, 560} -> {739, 650, 466} [3, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1]
{346, 949, 466} -> {425, 690, 689} [4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1]
{906, 360, 560} -> {984, 92, 344} [5, 4, 2, 2, 1, 1, 1, 1, 1, 1, 1]
same but with circuit counts
here are mine
whar
oh
oh my god
it's symmetrical
it's 19 because it's double ten
😭
i hate it here /shitpost
exploding
how fast is it :3
final code
(these are in seconds)
ah, you're sorting
oops, i was spending most of the runtime on getting the square root of the distances,
not neccasary when all i do is compare them
now most of the time is building the binary heap
what
what is heap for
i was doing the cartesian product
which does both dist(A, B) and dist(B, A)
for the ordering
but now that i think about it
just sort would be fine
ill try
noob
yep
this says "sort by"
i switched from table to tuples, which not only simplified the code, it made it correct 😌
oh shit yea we don't need to sqrt
by the way check out "euclidean distance" in uiua
substract, then, under squaring, add up
baller
cursed
isn't it phenomenal?
literally "under square, add up; subtract"
the ordering seems weird
like
the addition is after squaring
but the small 2 is to the left
and theres also a random /??
it's because of the binding priority
the purple glyph is under, which is a dyadic ("two") modifier: it takes in two functions (squaring and add up)
all of that is one single unit
so the order of execution goes
- subtract
- what i just described (under square, add up)
(add up is /+)
+ adds two numbers, /+ adds up an array
it's reduce
(adds up along the main axis, but there's only one dimension here so w/e)
hate
it feels very natural
this is "squared euclidean distance"
add up after squaring after subtracting
there's not an under anymore