#AoC 2022 | Day 6 | Solutions & Spoilers
1578 messages ยท Page 2 of 2 (latest)
it extends Iterator, basically
Yeah
That's going to take some getting used to
Never had crates extending other crates before
I would like to show off my ruby solution for today in here as i see we are sharing other languages: https://github.com/imsofi/advent-of-code/blob/main/2022/day_06.rb
While Ruby has been a pleasure to write, its frustrating that a sliding window is called each_cons, instead of window or sliding_window as one would expect.
what in the
are we talking about
i feel like i would die if someone in real life walked up to me having a conversation and said "what in the ferrisBongoHyper are we talkling about?"
def find_marker(sequence, num_characters):
unique_characters = {}
start_idx = 0
end_idx = num_characters - 1
for i in range(end_idx+1):
unique_characters[sequence[i]] = unique_characters.get(sequence[i], 0) + 1
while end_idx < len(sequence) and len(unique_characters.keys()) < num_characters:
unique_characters[sequence[start_idx]] = unique_characters.get(sequence[start_idx], 0) - 1
if unique_characters[sequence[start_idx]] == 0:
unique_characters.pop(sequence[start_idx])
start_idx += 1
end_idx += 1
unique_characters[sequence[end_idx]] = unique_characters.get(sequence[end_idx], 0) + 1
return end_idx + 1
with open("problem_6_input", "r") as input_file:
sequence = input_file.read()
print(find_marker(sequence, 4))
print(find_marker(sequence, 14))
Both parts solved in one
my rust solution is hilarious looking
part one looks innocent enough
fn part1(input: &[u8]) -> AocResult<i32> {
let mut count = [0u8; 256];
let mut dupes = 0;
let mut inc = |b: u8| {
count[b as usize] += 1;
if count[b as usize] == 2 {
dupes += 1;
}
};
inc(input[0]);
inc(input[1]);
inc(input[2]);
inc(input[3]);
let mut res = 4;
for &[l, _, _, _, r] in input.array_windows() {
count[l as usize] -= 1;
if count[l as usize] == 1 {
dupes -= 1;
}
count[r as usize] += 1;
if count[r as usize] == 2 {
dupes += 1;
}
res += 1;
if dupes == 0 {
break;
}
}
Ok(res)
}
[[print(min([b+a for b,c in enumerate(l[a:])if all([int(l[b:b+a].count(x))<2for x in l[b:b+a]])]))for l in open('day6_input')]for a in(4,14)]
any suggestions on how to further golf this?
part 2 just looks dumb
fn part2(input: &[u8]) -> AocResult<i32> {
let mut count = [0u8; 256];
let mut dupes = 0;
let mut inc = |b: u8| {
count[b as usize] += 1;
if count[b as usize] == 2 {
dupes += 1;
}
};
inc(input[0]);
inc(input[1]);
inc(input[2]);
inc(input[3]);
inc(input[4]);
inc(input[5]);
inc(input[6]);
inc(input[7]);
inc(input[8]);
inc(input[9]);
inc(input[10]);
inc(input[11]);
inc(input[12]);
inc(input[13]);
let mut res = 14;
for &[l, _, _, _, _, _, _, _, _, _, _, _, _, _, r] in input.array_windows() {
count[l as usize] -= 1;
if count[l as usize] == 1 {
dupes -= 1;
}
count[r as usize] += 1;
if count[r as usize] == 2 {
dupes += 1;
}
res += 1;
if dupes == 0 {
break;
}
}
Ok(res)
}
same code, just wider
bruh what
I'm also not sure whether array windows is cheap or not 
I hope it returns a sized view
it's a view, yeah
actually, never mind, I unpack it ๐คก
I should not do that
I mean, the idea of my solution is easy enough, build the initial window and then move it along
we're already at 69 chars
ik
I don't think you can do it much cheaper than this
(other than me being dumb and unpacking)
why didn't you use a loop for...that part
for the inc part?
mhm
yeah, probably should have
but with vim macros it's so easy to just generate the other lines
yyp<c-a>
copy line, paste line, increment number
(yes, vim has commands to increment and decrement numbers)
(it's very useful)
ya, but like...๐
but I get the point, I should be able to just unify the functions
got this output
with some const generics
works on my machine ยฏ_(ใ)_/ยฏ
weird
i assume the first part is right
both parts are right. just none none at end for somr reason
i'm guessing you're running in a repl
it's amusing to me that adding inc here is an error
You could use range instead of enumerate and save 1. also see this one:
#1049551574449520690 message
because mutable borrows
ive looked at it, i want to stay in one line tho
but the other loop is fine
thx
actually, can some rust person explain why that is?
same thing in one line:
#1049551574449520690 message
๐ญ
why is it an error in the first loop I posted?
oh, it complains about dupes being borrowed?
the previous loop is before any immutable borrows, so the compiler can prove the lifetime of the mutable borrow ends before any immutable ones, so it's safe. it can't for the other loop
i think
it's not before immutable borrows
dupes and count are mutably borrowed
lol all codes are one lineable with exec
I feel like day 6 was suspiciously easy, day 7 is gonna be the 2022 equivalent to the lanternfish problem
can you show the code
fn part1(input: &[u8]) -> AocResult<i32> {
let mut count = [0u8; 256];
let mut dupes = 0;
let mut inc = |b: u8| {
count[b as usize] += 1;
if count[b as usize] == 2 {
dupes += 1;
}
};
for i in 0..4 {
inc(input[i]);
}
let mut res = 4;
for &[l, _, _, _, r] in input.array_windows() {
count[l as usize] -= 1;
if count[l as usize] == 1 {
dupes -= 1;
}
inc(r); // if the function is inlined, this works
res += 1;
if dupes == 0 {
break;
}
}
Ok(res)
}
everythong is 1 line if you exec(bytes)
I feel this is rust's borrow checker being too dumb to understand what's doing on 
maybe something here will be useful ?
s=len(data:=open(filename).read());print([next(i for i in range(s) if len(set(data[i-n:i]))==n)for n in (4,14)])
late but I will share my code
import numpy as np
found = False
index = 0
with open("inp.txt", "r") as f:
for line in f:
q = []
line = line.replace("\n", "")
for i in range(len(line)):
q.append(line[i])
if(len(q) == 14): #PART ONE JUST WRITE 4
if np.unique(q).size == len(q):
index += i+1
found = True
else:
q.pop(0)
if found:
found = False
break
print(index)
hm
initially the i for i loop was then converted to a while + counter structure. too many chars otherwise :/
also, 4,14 loop is 2 lined, not possible for list comprehension
oml len(set) is so smart
and ^ instead == to save char as well
going to be pretty much impossible to go below 69 today
does someone know if set had method unique or sth like that to know if set has unique elements?
a set by definition only has unique elements
oh. i think it's kinda trivial actually. your function needs to make mutable references to things to change them, but you already have mutable references, so it errors. when you inline the function, you use the existing mutable references, so it's fine
if you passed those references, it would work, probably
what mutable borrow do I have?
oh im dumb thx
when you mutate them, count[l as usize] -= 1 and stuff
what's the lifetime of that borrow?
I would have assumed it was taken and immediately released after the expression
but apparently not
hm. actually, idk
ah, this did work. i think for different reasons though
I know lambdas with mutable captures have issues in general...
because they don't annotate lifetimes properly
wdym. set itself has unique elements
I think this is what I've run into before https://github.com/rust-lang/rust/issues/22340
returning references from a lambda
but this case here seems far more mundane
also, wtf const generics
can I really not do this?
and no, no you can't
https://users.rust-lang.org/t/arithmetic-on-const-generics/73266
pub struct Elev_Layer { pub row_major_data: Vec,} impl Elev_Layer { #[inline(always)] pub fn idx(y: usize, x: usize) -> usize { y * N + x} pub fn div_2(&self) -> Elev_Layer { } } For example, div_2 will do 512x512 -> 256x256; 256x256 -> 128x128, etc ... Question: is it possible to do arithmetic (or even div by 2) ...
that's...not great
yeah, this kind of generics is very much a weak point of rust
even without looking at variadic generics
oh. it's borrowed when the closure is created, duh
so since you mutably borrow it a second time between the creation of the closure and using the closure, you get an error
sometimes I hate rust...
fn solve<const N: usize>(input: &[u8]) -> AocResult<i32> {
let mut count = [0u8; 256];
let mut dupes = 0;
let mut inc = |b: u8| {
count[b as usize] += 1;
if count[b as usize] == 2 {
dupes += 1;
}
};
for i in 0..N-1 {
inc(input[i]);
}
let mut res = (N-1) as i32;
for window in input.array_windows::<N>() {
let l = window[0];
count[l as usize] -= 1;
if count[l as usize] == 1 {
dupes -= 1;
}
let r = window[N-1];
count[r as usize] += 1;
if count[r as usize] == 2 {
dupes += 1;
}
res += 1;
if dupes == 0 {
break;
}
}
Ok(res)
}
fn part1(input: &[u8]) -> AocResult<i32> {
solve::<{4+1}>(input)
}
fn part2(input: &[u8]) -> AocResult<i32> {
solve::<{14+1}>(input)
}
that thread does give a solution it seems. and you're already using nightly with array_windows
yes, I could try using the nightly feature, but it's just an annoying restriction
yeah, definitely
I guess the concept of constexpr is very immature in rust
If you don't do this it's actually quite simple
also, if you did
let inc = |b: u8, c: &mut [u8; 256], d: &mut i32| {
c[b as usize] += 1;
if c[b as usize] == 2 {
*d += 1;
}
};
``` you could use it in the loop, but it's pretty much just as annoying
I can do that, I shifted my argument to the generic function up one and did -1 to all usages of N
which is...a bad workaround
I meant - ...
My entire Rust function is 9 lines
yes, this is what I would like to avoid
Works for both parts
what's your rust solution?
events/advent_of_code/2022/6/rust/src/main.rs lines 3 to 12
fn find_unique_window(text: &str, length: usize) -> usize {
let windows = text.as_bytes().windows(length);
for (index, window) in windows.enumerate() {
if window.iter().unique().count() == length {
return length + index;
}
}
panic!("did not find")
}```
you can easily get an O(N) sol without resorting to shenanigans though
you think my thing is shenanigans? it's just counting but with a sliding window
(actually making use of the fact that it's a sliding window)
Wait - is yours faster than mine?
I require proof
fairly clearly. unique() needs to iterate over the window each time
at these tiny input sizes it's hard to measure things
Ah. I see. Fair enough
i don't think you need array_windows, now, though
ignoring reading the string I get 5us for the actual logic
I really hope that array_windows is O(n) overall...
well, it's shenanigans due to rust, not the solution itself
Fenix do you have a job?
I do
Do you actually have to build for time complexity?
Would my solution be thrown out just because it was "too slow"?*
it depends, I do work a bunch with data processing pipelines, so I need to keep performance in mind there
granted, with distributed data pipelines there are bigger issues than just how long it takes to process stuff
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.num == 0 {
return None;
}
// SAFETY:
// This is safe because it's indexing into a slice guaranteed to be length > N.
let ret = unsafe { &*self.slice_head.cast::<[T; N]>() };
// SAFETY: Guaranteed that there are at least 1 item remaining otherwise
// earlier branch would've been hit
self.slice_head = unsafe { self.slice_head.add(1) };
self.num -= 1;
Some(ret)
}
```i think this is O(n)
#[inline]
That's a new one for me
hints to the compiler to inline
this is the source for array_windows?
yeah the next method for the struct it returns
oh, this is important too,
pub struct ArrayWindows<'a, T: 'a, const N: usize> {
slice_head: *const T,
num: usize,
marker: PhantomData<&'a [T; N]>,
}
PhantomData 
damn, yeah. why didn't we think of that
but yeah, it looks like it should be O(n)
the pointer cast is constant, so yeah
actually does it take any time? surely that's done at compile time
Neat. Didn't realize itertools::unique is a thing. I just converted the slice to Hashset<&char> and checked if the result had the same length as the original.
I expect it to be zero cost
it should compile away to nothing
yeah. what's the time complexity of that ๐ค still constant ig?
idk if it's worth talking about time complexity at that point ๐
ok but, do the c have to be non-zero?
notably 0 is in O(1) but 1 is not in O(0)
0/1 tends to a constant as the (irrelevant) parameter grows large
1/0...doesn't feel so well
do you have a typo in that message
ok, back to writing essays ๐
so wrt inc, it works fine if I call inc a bunch before doing any other mutable borrow
so the borrow checker is not that smart wrt to lambdas and lifetimes
unfortunate
if I were using C++ I would totally write small helper lambdas like this to not repeat code
(and make the overall logic more readable)
something akin to
for i in 0..N-1 {
inc(input[i]);
}
let mut res = (N-1) as i32;
for window in input.array_windows::<N>() {
dec(window[0]);
inc(window[N-1]);
res += 1;
if dupes == 0 {
break;
}
}
the issue is that the mutable borrow in the closure has to live for as long as you have calls to the closure
maybe with better names
why? 
it would be sensible if it borrowed for the call, but seems that's not the semantics of rust lambdas
I know it likely wouldn't be implemented like that, but the borrowing semantics that makes sense to me would be to grab ownership during the call
but I guess rust doesn't have a way of expressing that
(other than explicitly passing the arguments)
it has to have the mutable borrow when you define the closure, which makes more sense if you're passing the closure into things, i think
it does, but it feels like there are several flavors of lambdas at play here
some absolutely need to capture state and hold it, some could really capture as needed
but you can't express the latter in rust
(other than passing args explicitly)
yeah, i think you're right ๐ค
I could encapsulate the counter in a struct I guess
and expose two methods
I guess this is clean enough
struct DupCounter {
count: [u8; 256],
dupes: i32,
}
impl DupCounter {
fn new() -> Self{
DupCounter { count: [0; 256], dupes: 0 }
}
fn add(&mut self, b: u8) {
self.count[b as usize] += 1;
if self.count[b as usize] == 2 {
self.dupes += 1;
}
}
fn remove(&mut self, b: u8) {
self.count[b as usize] -= 1;
if self.count[b as usize] == 1 {
self.dupes -= 1;
}
}
}
fn solve<const N: usize>(input: &[u8]) -> AocResult<i32> {
let mut counter = DupCounter::new();
for i in 0..N-1 {
counter.add(input[i]);
}
let mut res = (N-1) as i32;
for window in input.array_windows::<N>() {
counter.remove(window[0]);
counter.add(window[N-1]);
res += 1;
if counter.dupes == 0 {
break;
}
}
Ok(res)
}
(modulo the N that is offset from what I want it to be)
maybe I should just use that nightly feature
just use windows instead of array_windows
lol
err...
but without array_windows the bounds checks probably won't be elided ๐ญ
(I could go unsafe...)
but yeah, maybe I should ditch the idea that felt correct in favor of the solution that the current state of rust likes
unsatisfying, but what can you do?
one of these days will actually cross the 1ms threshold
wasn't lanternfish day 6 last year?
(granted, the intended solution to lanternfish was cheap)
What do you use to time things?
nothing fancy
Timing the program affects the timing
just something that uses std::time::Instant::now
and runs the program N times and takes the average (after throwing out a fraction of outliers)
I hope Instant::now is fine for use for this 
Instants are always guaranteed, barring platform bugs, to be no less than any previously measured instant when created, and are often useful for tasks such as measuring benchmarks or timing how long an operation takes.
ok, seems like a sensible thing to use
Pretty happy i managed to get the answer in one line:
with open('day6\input.txt', 'r') as f:
input = f.read()
ans = [num for num, char in enumerate(input[14:], 14) if len(set([input[i] for i in range(num-14, num)])) == 14][0]```
more dumb shell solutions
solve() { perl -pe "s/(.)(?=(.{$(($1-1))}))/\1\2\n/g" | nl -v$1 | grep -vP "([a-z]).{0,$(($1-2))}\1" | head -n1; }
$ solve 4 < inputs/06input
1578 bdjq
$ solve 14 < inputs/06input
2178 mdcbnwqgshpvfj
Are you sure that's not a perl solution?
I like this solution!
Also note that
len(set([input[i] for i in range(num-14, num)])
is equivalent to
len(set([input[num-14:num]))
you should be able to do the entire program at compile time with rust
i would think
with procmacros
well yeah. you can run arbitrary code during compile time
also build scripts exists, so before compile time lol
Thanks! Yeah I noticed that earlier when I was looking at other peoples solutions, however when I try to implement it into my code it outputs IndexError: list index out of range, I have no idea why because also when I copied your replacement it worked, but when I hand type it doesn't, idk I'm very confused, this is my hand typed code
with open('day6\input.txt', 'r') as f:
input = f.read()
ans = [num for num, char in enumerate(input[14:], 14) if len(set([input[num-14:num]])) == 14][0]
set([input[num-14:num]])
^ ^ # shouldn't need these
Yeah I don't, that still doesn't fix my issue index error issue tho
it probably does
It doesn't I just tried it
I mean I don't even need the set() part, I can just contain input[num-14:num] with {}
that would make a set with a single string in it, not a set with each of the elements in input[num-14:num]
wat
how
HEH
NOW IT WORKS?
I literally swear I did that earlier
Im so confused
>>> set("abc")
{'b', 'c', 'a'}
>>> set(["abc"])
{'abc'}
So why doesn't this work
ans = [num for num, char in enumerate(input[14:], 14) if len({input[num-14:num]}) == 14][0]
wait
thats not what I meant to paste
one sec
fixed
that would make a set with a single string in it, not a set with each of the elements in input[num-14:num]
>>> num=100
>>> {input[num-14:num]}
{'bbbmwbwgggqccm'}
wth
set(...) # takes an iterable
{...} # takes individual values
# a string is both an iterable and an individual value
Isn't a list an iterable tho?
What list? input is a string; input[n-14:n] is a string of 14 chars
The list ['abcdefg'] has one item in it, which creates a set with one item, thus len 1
>>> stringy = "the elves keep asking me to help!"
>>> list(stringy)
['t', 'h', 'e', ' ', 'e', 'l', 'v', 'e', 's', ' ', 'k', 'e', 'e', 'p', ' ', 'a', 's', 'k', 'i', 'n', 'g', ' ', 'm', 'e', ' ', 't', 'o', ' ', 'h', 'e', 'l', 'p', '!']
>>> [stringy]
['the elves keep asking me to help!']
>>> set(stringy)
{'t', 'e', 'p', '!', 'l', 'h', 'n', ' ', 's', 'a', 'm', 'k', 'o', 'v', 'g', 'i'}
>>> {stringy}
{'the elves keep asking me to help!'}
Right, so in my code
ans = [num for num, char in enumerate(input[14:], 14) if len(set([input[num-14:num]])) == 14][0]
I made a list with one element in it, and then made a set out of that list, so the set had one element in it, thus a length of one, I see, my only remaining question is why did it give a type error then?
Wait... Don't tell me it's because of the [0] at the end
IndexError: Because the list comp came out empty (i.e. [][0])
because your set will always have one element, so your list comp will have nothing in it, so it errors
Bruhhhhhh I thought it was something to do with the num-14:num, this is the disadvantages of trying to code everything in one line :/
what disadvantages? seems pretty good for reducing char counts
also have we still not gone lower than 69?
No clue, not to my knowledge but I haven't really been keeping up with golf
Incredibly difficult to debug, (for a new programmer like me at least)
Thanks so much for all the help, I was really confused :P
this is why you should run code in your head, smh
๐ง
wdym
if you're the interpreter, then you can run the code however you like
can inspect each variable and stop execution whenever
Reject CPython - Return to ๐ง ๐
you don't need the [14],14 in the enumerate. I assume it's there to keep num-14 0 and higher, but it's not needed. try printing out your input[-3:3] Also, don't shadow the name input, that's already a function in python. You want to avoid that.
!e print("test"[-3:3])
@mighty oyster :white_check_mark: Your 3.11 eval job has completed with return code 0.
es
It's so that the character that the program is checking's index matches up with the value num
As in the program starts checking at index 14, and also the enumerate counter starts at 14
idek why it's there, my code went through so many iterations during writing and I probably just forgot it was there
because I originally i was confused and doing != 14 at the end, which would just return 0 all the time, so I did that ^ but then I corrected it to == and forgot to change the rest of the code
yes, but it will line up no matter what num you put there. ๐
it's very close to my original solution.
print(next(i for i,_ in enumerate(data) if len(set(data[i-n:i]))==n))
Does it? In my testing it doesn't
mylist = ['a','b','c','d','e','f','g']
for num, char in enumerate(mylist[3:]):
print(num, char)
Outputs:
1 e
2 f
3 g```
As you can see the index for each char does not match up with the enumerate counter
You still have the [3:] there which you do not need.
You have to remove both parts, not just the ,num part
!e
for i in range(6):
print('thisisatest'[i-4:i])
@devout rain :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 |
002 |
003 |
004 |
005 | this
006 | hisi
Oh I thought you were saying here that the index will line up with the counter whatever number you put in the [x:] part
no, the enumerate is fine, you don't have to build a second list and pass that to enumerate.
print(next(i for i,_ in enumerate(data) if len(set(data[i-n:i]))==n))
oh yeah it is, 2 questions:
- I assume that n is just a placeholder for either 14 or 4 right?
- What does
nextdo?
next gets the first one.
and if you next again you get the next, etc
ah, so is it just a different way of doing [0] at the end?
better than building the collection entirely and taking [0] from it. here you just get 1 and you're done.
Right, so whenever it gets the first element it stops building entirely and outputs that?
right.
Yeah that would be more efficient, interesting
>>> my_generator = (i**2 for i in range(100))
>>> next(my_generator)
0
>>> next(my_generator)
1
>>> next(my_generator)
4
>>> next(my_generator)
9
>>> next(my_generator)
16
>>> next(my_generator)
25
yeah, so there are 4096 chars in the input, with a list you have to look at all of them, with a generator is only goes as afar as it needs to.
Can you re-explain the [-3:3] part? What is that meant to demonstrate
Interesting, ty, that would become much more apparent if the input was much longer I'm sure as well
I should look into generator's more later, I'll write that down
in your code:
len(set(input[num-14:num])) == 14
I was guessing the reason you started your enumerate at 14, was to avoid num-14 being below 0.
I was trying to show that it did not matter.
Yeah that's right, why doesn't it matter?
I mean clearly it doesn't because when I run it without that, it just outputs exactly the same thing
Shouldn't that raise a index error?
ans = [num for num, _ in enumerate(input) if len(set(input[num-14:num])) == 14]
Slices don't care if the index is out of range, and backwards slices just stop before they start (i.e. empty string). Remember that negative indexes count from the end of the string (-1 is last, -2 is second last, etc.)
>>> "abcdefghijklmnopqrstuvwxyz"[0-14:0]
''
>>> "abcdefghijklmnopqrstuvwxyz"[20-14:20]
'ghijklmnopqrst'
>>> "abcdefghijklmnopqrstuvwxyz"[30-14:30]
'qrstuvwxyz'
>>> "abcdefghijklmnopqrstuvwxyz"[40-14:40]
''
>>> "abcdefghijklmnopqrstuvwxyz"[-20:20] # If you loop back far enough you can get a valid range
'ghijklmnopqrst'
oh
one question, why does that last line return 'ghijklmnopqrst'?
Shouldn't it just return the first 20 letters?
fun with negative indexes and slices. ๐
From the 20th-from-the-back letter to the 20th-from-the-front letter
it's from index -20 which is index 6, so -20:20 is [6:20]
ahhh I see, that hurts my brain lmao
but fir our example, the len of the listr is 4096, so there's no way that num-14:num will ever overlap.
I can't really imagine where [-20:20] would be useful, but [1:-1] is useful for stripping one leading and one trailing char (e.g. "<123>"[1:-1] is "123")
but [i-14:14] was on the other hand, quite useful last night.
*:i
Ohhh, so if for example, num = 10, this code ^ will create a set of the characters from the last 4 characters and the first 10 in the input string?
or rather, this code:
set(input[num-14:num])```
Because [num-14:num] when num = 10 is equivalent to [-4:10]
Not quite - it starts at the 4th-last char and moves until it is at or past the 10th char. It's already past the 10th char so the string is empty
ohh, well that's confusing xD
just do the math in your head. nagitive indexes are subtracted from the len.
[-4:10] is actually [4092:10] which is an empty string
Question, does that mean that it is possible that this code, in the edge case of the last 14 characters in input being unique, return the wrong number?
oh nvm
no, because there is no scenario where 4096 - (num-14) is less than num.
It doesn't even return the last 4 characters?
like 4093-4096
no.
start at 4092, end at 10, there is no wrapping so it's just an empty string. 4096 is already > 10 so it just stops.
think of it like this:
start = 4092
end = 10
while start < end:
yield data[start]
start += 1
ah I see, thanks for clearing that up :)
thanks both of you for helping me with everything I appreciate it :D
np, having to explain things is good for helping make sure I understand it right too ๐
with open("06_input.txt") as file:
data = file.read().splitlines()
message = data[0]
count = 14
while len(set(message[count - 14 : count])) != 14:
count += 1
print(count)
len(message[count - 14 : count]) should always be 14 (for 14<=count<len(message)), so you could replace that with 14
lmao
what approaches for unique character count did people use besides just len(set(buffer_list))?
import re
def solve_regex(amt: int) -> None:
c = []
f: str = ""
for i in range(1, amt+1):
c.append(f"\{i}")
f += "(.)(?!" + "|".join(c) + ")"
print(re.search(f, open("input.txt").read().strip()).end())
solve_regex(4)
solve_regex(14)```
I am being silly, but cannot see how the `solve_regex(14)` is giving none, but the `solve_regex(4)` gives the correct answer
pandas: rick and roll
I suspect that \10 is being interpreted as (?:\1)0
You could always use named patterns (?P<{i}>) and \k<{i}>
Also you should be using raw strings
(I think rf is a thing)
(it is)
KK. Will try that and see. Just messing around
Thanks for the feedback
got the time to get around to six ๐
this took me a good bit less time than 5
the solutions for part 1 and part 2 were both pretty similar as well
def part_1(raw_input: str) -> int:
return (
raw_input.index(
"".join([i for i in windowed(raw_input, 4) if len(set(i)) == 4][0])
)
+ 4
)
def part_2(raw_input: str) -> int:
return (
raw_input.index(
"".join([i for i in windowed(raw_input, 14) if len(set(i)) == 14][0])
)
+ 14
)
s=input();i=0
for j in 4,14:
while len({*s[i-j:i]})<j:i+=1
print(i)```
day 7 will compensate ๐
i like the problems that take longer
because i rank higher
5 min mistake on a 1 min problem vs 5 min mistake on a 10 min problem
Basically are the same, just with a different window size. Can make it into a single function also.
Loved that puzzle
Same. But for me it can take longer because I usually overcomplicate first before seeing a simpler method. Can be annoying for me.
for i in range(1, amt+1):
c.append(f"\{i}")
f += "(.)(?!" + "|".join(c) + ")"```
wouldnt this make more sense
```python
for i in range(1, amt+1):
f += "(.)(?!" + "|".join([f"\{i}"]*i) + ")"```
or i guess this even but thats unrelated
```python
for i in range(amt):
f += f"(.)(?!\{i}" + f"|\{i}"*i + ")"```
lol, I went for the leaderboards for part of my first AoC year
I don't think I ever will again
nice
unless I move to some other time zone
i think i have a good shot as long as i don't choke
I started doing AoC in unfamiliar languages instead
sounds fun
I learned rust last year and wrote pretty fast programs overall
(not fast to write, but fast to run)
I learned python by doing AOC. ๐ My code that year was, uh, not great.
Anybody's learning code sucks, the fact that you know it sucks means you've improved :)
(I would like to imagine my rust code isn't terrible)
I'm learning more about Rust BTW by copying my solutions from Python to Rust BTW
Immediately after I posted my solution, pstvm pointed out like three different things with a "why would you do that??" 
false, my java starter code was godly
everything was 1 line and ternary operators were sprinkled everywhere
my goal last year was for my total time to be <1s
which I made with some margin
~400ms, maybe a bit less
It's kinda hard to make awful Rust code without noticing because of how Rust works
250 of which is for one single problem ๐
now try less than 0.5s for this year
Which one?
day 23
probably a brute force graph problem
oh
Oh god that one
ok but 23 can be solved using a graph
ic what you mean
not on the graph of the board at least
I think I did Dijkstra, but the "nodes" were states of the board
I probably added an heuristic to get A* to squeeze some extra time out
oh beacons was as early as day 19?
I liked beacons, it completely stumped me for a bit
so far in 2022 I'm way below 1ms in total
~170us
looks interesting
if i were going for leaderboard, i could probably naively approach this
what's even the naive approach?
take the first beacon to have absolute coords, then try every orientation while translating some point in a beacon to the bottom left point in beacon 0; you can sliding window possible groups of 12 points
it would take a while to run, but that's probably the naive approach
*24 orientations for each
It was an interesting month. I started learning Python around thanksgiving. A week later I was doing Advent of Code, and as I was interviewing at the same time so I forced myself to do all my interviews in python (with some explanation). Some interviews went better than others, but I had a python job a few weeks later. Fun times.
Nice
I jumped between C++ and python when I did interviews
I even asked the interviewer which one they would prefer in one interview ๐
how long was the day 19 golf lol
true
or other kinds of solvers
The beacon one? I have a short (ish) solution somewhere, but not golfed.
but yeah, the approach is basically to try different rotations of one beacon point and match it to another and build up a graph of beacons
kinda
here i was thinking i could optimize it somehow ๐
you can avoid actually testing the 24 rotations for most beacons by computing all internal distances and seeing how big fraction matches the other beacon
and only if distances match, actually do the rotations
oh yeah that works
oh wow
down from probably 120 ish
I can't find the short one. but this is ~30 lines:
from itertools import combinations,product
def find_rotation(scan,rebased0):
for rot,rot_scan in rotations(scan).items():
rebased = {p1: {psub(p1,p2) for p2 in rot_scan} for p1 in rot_scan}
for p1,p2 in product(rebased0,rebased):
if len(rebased0[p1]&rebased[p2])>11: return p1,p2,rot
def make_absolute(scanners):
absolute,*task_list = scanners
scanner_locs = {(0,0,0)}
while task_list:
scan = task_list.pop(0)
rebased0 = {p1: {psub(p1,p2) for p2 in absolute} for p1 in absolute}
result = find_rotation(scan,rebased0)
if result is None:
task_list.append(scan)
else:
p1,p2,rot = result
absolute |= {padd(rotate(s,*rot), psub(p1,p2)) for s in scan}
scanner_locs.add(padd((0,0,0), psub(p1,p2)))
return len(absolute), scanner_locs
def psub(p1,p2): return p1[0]-p2[0],p1[1]-p2[1],p1[2]-p2[2]
def padd(p1,p2): return p1[0]+p2[0],p1[1]+p2[1],p1[2]+p2[2]
def rotate(s,a,b,c,i,j,k): return (a*s[i],b*s[j],c*s[k])
def rotations(scan): return {r: {rotate(s,*r) for s in scan} for r in orientations}
def mhd(a,b): return abs(a[0]-b[0])+abs(a[1]-b[1])+abs(a[2]-b[2])
scanners = [{eval(line) for line in scanner.splitlines() if '--' not in line}
for scanner in open(filename).read().split('\n\n')]
beacons, scanner_locs = make_absolute(scanners)
print('part1:', beacons)
print('part2:', max(mhd(a,b) for a,b in combinations(scanner_locs,2)))
basically what I did was build an MST of things that should connect based on the distances, then rotate them in place
def rotate(s,a,b,c,i,j,k): is one hell of a signature
ig aoc isn't like lc, sometimes the bruteforcey solution is the actual solution
yeah, coding in a rush... ๐
where is orientations defined?
that's...24 lines of my code
hmmm. I grabbed the code from my reddit post. it's just a list of the orientations, I'll have to check harddrive for it's value.
just saying the actual code it a bit longer with that included ๐
I went through different iterations of auto generating it vs just using the generated version.
I just wrote them out, it's not so hard if you know how to not create left handed systems
lol @ the beacons problem done in Dyalog:
โIOโ0
pโโยจโยจยจ'-'โR'ยฏ'ยจยจ1โยจ{โตโโจรโขยจโต}โโNGET'p19.txt'1
mโโ{โชโต,,({โต(1โฝ1โโต)}3 3โด1 0 0 0 0 1 0 ยฏ1 0)โ.(+.ร)โต}โฃโก,โโ.=โจโณ3
qโ0
aโ(โp){0=โขโต:โบ โ i jโโโธ12โคโข/zโโโบโ{{{โตโทโจrโณโ/rโโข/โต}{โบ(โขโต)}โธโต}โค2,[1 2]โต-โค1โค1 2โขโบ}ยจmโ(+.รโค2 1โค2 2)ยจโต โ (โชโบโช((jโทm)+.รโค2 1โค2 2โขiโโต)-โค1โขdโฃqโโ+/|dโ(โi j 0)โz)โโต/โจiโ โณโขโต}1โp
โขa โ part 1
q โ part 2
that language is crazy
holy hell
ah here we go, I had another paragraph about how I generated it:
orientations = [(1,1,1,0,1,2),(1,1,1,1,2,0),(1,1,1,2,0,1),(1,1,-1,2,1,0),(1,1,-1,1,0,2),(1,1,-1,0,2,1),(1,-1,-1,0,1,2),(1,-1,-1,1,2,0),(1,-1,-1,2,0,1),(1,-1,1,2,1,0),(1,-1,1,1,0,2),(1,-1,1,0,2,1),(-1,1,-1,0,1,2),(-1,1,-1,1,2,0),(-1,1,-1,2,0,1),(-1,1,1,2,1,0),(-1,1,1,1,0,2),(-1,1,1,0,2,1),(-1,-1,1,0,1,2),(-1,-1,1,1,2,0),(-1,-1,1,2,0,1),(-1,-1,-1,2,1,0),(-1,-1,-1,1,0,2),(-1,-1,-1,0,2,1)]
generated from::
views, faces = [(-1,-1,1),(-1,1,-1),(1,-1,-1),(1,1,1)],[(0,1,2),(1,2,0),(2,0,1)]
orientations = [v+f for v,f in product(views,faces)]
orientations += [(-a,-b,-c,k,j,i) for a,b,c,i,j,k in orientations]
what do the numbers mean 
here it my thing
let mappings: [fn(Point) -> Point; 24] = [
|Point { x, y, z }| Point::new(x, y, z),
|Point { x, y, z }| Point::new(-x, -y, z),
|Point { x, y, z }| Point::new(-x, y, -z),
|Point { x, y, z }| Point::new(x, -y, -z),
|Point { x, y, z }| Point::new(y, z, x),
|Point { x, y, z }| Point::new(-y, -z, x),
|Point { x, y, z }| Point::new(-y, z, -x),
|Point { x, y, z }| Point::new(y, -z, -x),
|Point { x, y, z }| Point::new(z, x, y),
|Point { x, y, z }| Point::new(-z, -x, y),
|Point { x, y, z }| Point::new(-z, x, -y),
|Point { x, y, z }| Point::new(z, -x, -y),
|Point { x, y, z }| Point::new(y, x, -z),
|Point { x, y, z }| Point::new(-y, -x, -z),
|Point { x, y, z }| Point::new(-y, x, z),
|Point { x, y, z }| Point::new(y, -x, z),
|Point { x, y, z }| Point::new(z, y, -x),
|Point { x, y, z }| Point::new(-z, -y, -x),
|Point { x, y, z }| Point::new(-z, y, x),
|Point { x, y, z }| Point::new(z, -y, x),
|Point { x, y, z }| Point::new(x, z, -y),
|Point { x, y, z }| Point::new(-x, -z, -y),
|Point { x, y, z }| Point::new(-x, z, y),
|Point { x, y, z }| Point::new(x, -z, y),
];
just represent orientation as a quaternion frfr
Pretty sus char โ
those are the a,b,c,i,j,k used in rotations, they represent the various orientations
way overkill when we're dealing with 90 degree rotations only
there are only so many valid rotations
Why are you destructuring a point (indicating that all its members are pub) then using its new function instead of just creating it lmao
the right hand side becomes prettier
no p.x p.y p.z noise
No but like
Point { x: z, y: x, z: y }
the short version is: the first scanner is in real space, and then for every other scanner rotate it until it maps on to that base space, and then update the base space, and if a scanner doesn't match yet, put it at the back of the queue and keep going.
I enjoyed the beacons problem.
I liked beacons more than the rotating puzzle find the seamonster puzzle.
usually I have a pretty good idea what to do immediately
same
oh right, that was a thing
my all time favorite is https://adventofcode.com/2019/day/22 though
the fun part is the second one
Finally, a deck worthy of shuffling!
Lemme go look at that one again lmao
you'll want some basic number theory knowledge, like modular inverses
I was lazy and realized it would just be some linear recurrence
and there is this magic algo to reconstruct linear recurrences from samples
That's kinda cool but I don't have the energy to understand it and there's no simple.wikipedia for it
Can you TL;DR?
(magic)
Understandable
iirc it's not that bad to understand if you actually sit down and look at it
but it's fun to use as a black box
simulate a bunch of steps, try finding the recurrence, extrapolate the recurrence
???
profit
can't you just track the position of 2019
yes, exactly
seems freelo to me
you want to simulate?
and then?
you could probably brute-force to find a cycle
cycle among 119315717514047 cards?
if you didn't feel like mathing
oh wait
i did not read that
reading comprehension diff
(fwiw that number is prime, which is actually helpful)
(because number theory reasons)
i haven't taken number theory ๐
but there should be a way to compose the shuffles into something predictable, unless i'm completely wrong
yeah
i haven't even looked at the different shuffles possible
but with numbers of this size, that has to be the case
"deal into new stack" = reverse
"cut N cards" = rotate N steps (as in a cyclic shift)
"deal with increment N" = this is the weirder one
basically deal first card at index 0, the next at N the next at 2N, ... (and wrap around the deck as needed)
(or in math terms ||multiply by N modulo length of the deck||)
yep
crucially, you can only invert that step (in general) if the modulo is prime
this just seems like modular arithmetic
it is
tbh not too difficult if you've seen modular math before
well, you can't even simulate it without the math, and simulation doesn't get you anywhere anyway
well, it gets you somewhere, but not far
any sane person knows that this is a math problem after they see those numbers
I think you could write a program to take the instructions given in the input and simplify it
and then you just need to extrapolate it
"just"
or you could run a few cycles of simulation to see what the pattern is
which requires some trick like exponentiation by squaring
so it's two things combined, some basic modular math knowledge to deal with the deck size, and some fast way of extrapolating to deal with the number of shuffles
yeah
let's say most people weren't too happy about the difficulty of this one ๐
Puzzle issue ๐
I'm kidding I like the 'rethink the approach'-type puzzle
Just not that one
Or the trains one
i should probably catch up on past aoc problems
I like 'rethink this in a way that doesn't require extensive googling but isn't simple'-type puzzles the best
And/or intcode
I really liked intcode
intcode was manageable if you had enough foresight to actually implement something that could easily be extended ๐
otherwise I imagine it would be painful
what's intcode?
I didn't until after the second intcode puzzle
Recurring 2019 puzzle
now i'm curious
intcode was building a virtual machine
oh fun
it was basically every two days for the whole month
building on top of the previous one
which was the first?
i see
https://adventofcode.com/2019/day/9 I think this one
day 2
5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25
so 2, 5 and every odd day after that
basically your intcode vm was used later on as a part of other puzzles
so if you had a bug or couldn't easily modify stuff as needed, sucks to be you
day 13 was amazing
when you realize what's going on and what they want you to do
I'll be honest I just rewrote it on day (I think 8 but I can check the git history) because I realised it would be used again lol
Ok it was day 9 I made the computer actually good
intcode killed my motivation in 2019. Was new to coding, so whatever I did was not expandable at all and I had to rewrite each time]
Would love to go do it now since I'm not brand new anymore. Pretty sure I'd enjoy it now xD
did they really link all of the signal puzzles in AoC here
Well it is significant
can someone explain how this (the example) is 5 ? ```
bvwbjplbgvbhsrlpgdmjqwftvncz
or share your thought process? i'm not sure how the answer is 5
so, you're essentially trying to find the number of characters it takes to get to the start of this stream of text to the point at which you can find a sequence of four characters, all of which are unique. with bvwbjplbgvbhsrlpgdmjqwftvncz, the first character is b, the first four are bvwb. This doesn't match the criteria, since b is repeated. We try again, this time starting at v. We go down, and four characters later end up with vwbj, all of which are unique. The j here is the fifth character in the text, which means we need to go down five characters to get to the point where we have had a sequence of four, unique, characters.
oh i thought you had to jump 4 characters... i was reading it like: bvwb jplb
thanks for the clarification
this is so easy lmao ```py
aoc problem 6
from collections import deque
def start_marker_i(buffer, length):
queue = deque(buffer[:length], length)
for i, c in enumerate(buffer[length:], length):
queue_chars = set(queue)
if len(queue_chars) == length:
return i
queue.append(c)
def main():
with open('6.txt') as f:
cont = f.read()
print(start_marker_i(cont, 4)) # part 1
print(start_marker_i(cont, 14)) # part 2
if name == 'main':
main()
with open('day6.in', 'r') as file:
stringa = file.read()
print(stringa)
consecutive = 0
caratteri_diversi = ""
count = 0
for carattere in stringa:
count += 1
if carattere not in caratteri_diversi:
caratteri_diversi += carattere
consecutive += 1
else:
consecutive = 0
caratteri_diversi = ""
if consecutive == 14:
break
print(count)