Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 4917

Teaching and learning resources • Re: Advent of Code 2023

$
0
0
No need for GMP. C++23 has float128_t.

Using your data:

Code:

pi@pi5:~/AoC-2023-cplusplus/day24 $ g++ -O3 -std=c++23 day24.cpp pi@pi5:~/AoC-2023-cplusplus/day24 $ ./a.out --- Day 24: Never Tell Me The Odds ---part 1 - 24627part 2 - 527310134398221Elapsed - 22.326 ms.
Woohoo! Day 24 is working for my data! Does it run on the Pico?

I finished my solution to the day 25 puzzle today.

Code:

julia> include("day25.jl") # Pi Zero 700 MHzAdvent of Code 2023 Day 25 SnowverloadPart 1 The product of the two groups is 567606Total execution time 52.94287787 seconds.julia> main()Advent of Code 2023 Day 25 SnowverloadPart 1 The product of the two groups is 567606Total execution time 48.092444726 seconds.julia> main()Advent of Code 2023 Day 25 SnowverloadPart 1 The product of the two groups is 567606Total execution time 48.938123044 seconds.
Though it doesn't meet the 15 seconds cutoff, it did finish before Lent.

After ruling out an exhaustive snipping of all possible combinations of three wires, the dog developer suggested treating the components as vertices in a graph and the wires as edges. Since it is known that the minimal cut is unique and equal three one can check if the maximum flow between a fixed vertex and each of the other vertices is greater than three. Then place those vertices for which it is in one group and the rest in the other.

The Julia code is

Code:

#=  Advent of Code 2023 Day 25 Snowverload    Written 2024 by Eric Olson =#struct DoExit <: Exceptionendimport Base.isequal, Base.hashfunction gobble(s::String,m::String)::Tuple{String,Bool}    if length(s)<length(m)        return s,false    end    if s[1:length(m)]==m        return s[length(m)+1:end],true    end    return s,falseendfunction wskip(s::String)::String    for i=1:length(s)        if !isspace(s[i])            return s[i:end]        end    end    return ""endfunction vskip(data,i::Int)::Int    while i<=length(data)&&length(data[i])==0        i+=1    end    return iend function getalpha(s::String)::Tuple{String,String}    for i=1:length(s)        if !isletter(s[i])            return s[i:end],s[1:i-1]        end    end    return "",sendfunction getint(s::String)::Tuple{String,Int64}    n=Int64(0); ε=1    for i=1:length(s)        if s[i]=='-'            ε=-1        elseif s[i]>='0'&&s[i]<='9'            n=n*10+Int64(s[i]-'0')        else            return s[i:end],ε*n        end    end    return "",ε*nendmutable struct Edog    a::String    d::Int    f::Int    Edog(a,d)=new(a,d,0)endfunction isequal(x::Edog,y::Edog)::Bool    return x.a==y.aendfunction hash(x::Edog)::UInt    return hash(x.a)endmutable struct Wire    c::String    e::Vector{Edog}endfunction getwire(s::String)::Wire    r=s    s,c=getalpha(s)    s,f=gobble(s,": ")    if f!=true        println(r,"\nMissing component separator!")        throw(DoExit())    end    e=Vector{Edog}()    while length(s)>0        s,z=getalpha(s)        push!(e,Edog(z,0))        s=wskip(s)    end    return Wire(c,e)endmutable struct Node    w::Wire    n::Intendfunction mkpriority()::Tuple{Function,Function}    heap=Node[]    function enqueue(p::Node)        push!(heap,p)        r=length(heap)        while true            s=r÷2            if s<1 break end            if heap[s].n<=p.n break end            heap[r]=heap[s]            r=s        end        heap[r]=p    end    function dequeue()::Node        if length(heap)==0            println("Tried to remove nonexistent point!\n")            throw(DoExit())        end        t=pop!(heap)        if length(heap)==0 return t end        p=heap[1]        s0=1        while true            r0=2*s0; r1=r0+1            if r0>length(heap) break end            s1=r0            if r1<=length(heap)                if heap[r0].n>heap[r1].n                    s1=r1                end            end            if t.n<=heap[s1].n break end            heap[s0]=heap[s1]            s0=s1        end        heap[s0]=t        return p    end    return enqueue,dequeueendfunction clearflow(wire::Vector{Wire})::Nothing    for i=1:length(wire)        for e in wire[i].e            e.f=0        end    endendfunction addflow(wire::Vector{Wire},a::Int,b::Int)::Vector{Int}    K=length(wire)    enc,deq=mkpriority()    g=Vector{Int}(undef,K)    g.=typemax(Int)    g[b]=0    enc(Node(wire[b],0))    while length(enc.heap)>0        v=deq()        n=v.n+1        for e in v.w.e            if e.f>-1&&g[e.d]>n                g[e.d]=n                enc(Node(wire[e.d],n))            end        end    end    function trace()::Vector{Int}        k=a        if g[a]==typemax(Int)            return []        end        n=g[a]-1        p=[k]        for i=1:2*K            for e in wire[k].e                if e.f<1&&g[e.d]==n                    push!(p,e.d)                    e.f+=1                    for er in wire[e.d].e                        if er.d==k                            er.f-=1                            break                        end                    end                    if e.d==b                        return p                    end                    k=e.d                    n-=1                end            end        end        println("Unable to trace path from $a to $(b)!")        throw(DoExit())    end    p=trace()    return pendfunction part1(wire::Vector{Wire})::Int    K=length(wire)    a=1    g=[a]    for b=1:K        if a==b continue end        clearflow(wire)        p=addflow(wire,a,b)        p=addflow(wire,a,b)        p=addflow(wire,a,b)        p=addflow(wire,a,b)        if length(p)>0            push!(g,b)        end    end    return length(g)*(K-length(g))endfunction doinit()    data=String[]    open("day25.txt","r") do fp        data=readlines(fp)    end    wmap=Dict{String,Int}()    wire=Vector{Wire}(undef,length(data))    for i=1:length(data)        wire[i]=getwire(data[i])        wmap[wire[i].c]=i    end    function fwire(w::Vector{Edog},c::String)::Bool        for e in w            if e.a==c                return true            end        end        return false    end    for i=1:length(wire)        for e in wire[i].e            k=get(wmap,e.a,nothing)            if k==nothing                push!(wire,Wire(e.a,Vector{Edog}()))                k=length(wire)                wmap[wire[k].c]=k            end            if !fwire(wire[k].e,wire[i].c)                push!(wire[k].e,Edog(wire[i].c,0))            end        end    end    for i=1:length(wire)        for e in wire[i].e            e.d=wmap[e.a]        end    end    p1=part1(wire)    println("Part 1 The product of the two groups is ",p1)endfunction main()::Nothing    t=@elapsed try        println("Advent of Code 2023 Day 25 Snowverload\n")        doinit()        throw(DoExit())    catch r        if !isa(r,DoExit)            rethrow(r)        end    end    println("\nTotal execution time ",t," seconds.")end main()
I originally used sets to store the edges but it ran 50 percent slower.

The code took a surprisingly long time to debug, likely because Fido computed the minimal path backwards b to a but then traced forwards a to b when updating the flow. In the end I think the signs might be reversed from the usual convention.

Statistics: Posted by ejolson — Fri Feb 09, 2024 5:08 am



Viewing all articles
Browse latest Browse all 4917

Trending Articles