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

Teaching and learning resources • Re: Advent of Code 2023

$
0
0
Interesting new solution for day 25

Code:

--- Day 25: Snowverload ---part 1  - 603368part 2  - free starElapsed - 70.487 ms.
Most of the time it finds the solution and is 40 times faster than the previous exhaustive search. Because it injects a random component there may be a possibility that it fails to find the solution, in which case it aborts.
Maybe the randomized day 25 puzzle solution should automatically restart if it randomly fails. The worst case would be an extremely unlucky sequence of events in which the algorithm has to restart an arbitrary number of times. That could surpass the 15 second limit.

Alternatively, if the random algorithm fails, switch to the deterministic algorithm so it can't fail more than once. Then the worst case runtime is still bounded while the expected runtime could be estimated experimentally and likely still under 1 second.

I don't think Julia on the Pi Zero is fast enough to play the under one second game, but I did pretty well for day 19:

Code:

julia> include("day19.jl") # Pi Zero 700 MHzAdvent of Code 2023 Day 19 AplentyPart 1 The sum of the part ratings is 509597Part 2 The distinct combinations are 143219569011526Total execution time 2.75799919 seconds.julia> main()Advent of Code 2023 Day 19 AplentyPart 1 The sum of the part ratings is 509597Part 2 The distinct combinations are 143219569011526Total execution time 0.134143231 seconds.julia> main()Advent of Code 2023 Day 19 AplentyPart 1 The sum of the part ratings is 509597Part 2 The distinct combinations are 143219569011526Total execution time 0.132203242 seconds.
The code was

Code:

#=  Advent of Code 2023 Day 19 Aplenty    Written 2024 by Eric Olson =#struct DoExit <: Exceptionendfunction 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)    for i=1:length(s)        if s[i]>='0'&&s[i]<='9'            n=n*10+Int64(s[i]-'0')        else            return s[i:end],n        end    end    return "",nendmutable struct Cond    v::String    t::Int    n::Int    d::Stringendconst Work=Dict{String,Vector{Cond}}function addwork(s::String,work::Work)    r=s    s,k=getalpha(s)    s,b=gobble(s,"{")    work[k]=Cond[]    if b!=true        println(r,"\nNo beginning brace after key!\n")        throw(DoExit())    end    while true        s,v=getalpha(s)        if length(v)==0            println(r,"\nUnable to find rule in workflow!\n")            throw(DoExit())        end        if begin s,b=gobble(s,"<"); b==true end            s,n=getint(s)            s,b=gobble(s,":")            if b==false                println(r,"\nUnable to find colon after conditional!\n")                throw(DoExit())            end            s,d=getalpha(s)            if length(d)==0                println(r,"\nUnable to find branch after colon!\n")                throw(DoExit())            end            s,b=gobble(s,",")            if b==false                println(r,"\nUnable to find comma separator!\n")                throw(DoExit())            end            push!(work[k],Cond(v,-1,n,d))        elseif begin s,b=gobble(s,">"); b==true end            s,n=getint(s)            s,b=gobble(s,":")            if b==false                println(r,"\nUnable to find colon after conditional!\n")                throw(DoExit())            end            s,d=getalpha(s)            if length(d)==0                println(r,"\nUnable to find branch after colon!\n")                throw(DoExit())            end            s,b=gobble(s,",")            if b==false                println(r,"\nUnable to find comma separator!\n")                throw(DoExit())            end            push!(work[k],Cond(v,1,n,d))        else            s,b=gobble(s,"}")            if b==false                println(r,"\nUnable to find closing brace!\n")                throw(DoEXit())            end            push!(work[k],Cond("",0,0,v))            break        end    end    return workendmutable struct Part    x::Int    m::Int    a::Int    s::Intendfunction getpart(s::String)::Part    r=s    s,b=gobble(s,"{x=")    if b==false        println(r,"\nUnable to parse x label!\n")        throw(DoExit())    end    s,px=getint(s)    s,b=gobble(s,",m=")    if b==false        println(r,"\nUnable to parse m label!\n")        throw(DoExit())    end    s,pm=getint(s)    s,b=gobble(s,",a=")    if b==false        println(r,"\nUnable to parse a label!\n")        throw(DoExit())    end    s,pa=getint(s)    s,b=gobble(s,",s=")    if b==false        println(r,"\nUnable to parse s label!\n")        throw(DoExit())    end    s,ps=getint(s)    s,b=gobble(s,"}")    if b==false        println(r,"\nMissing closing brace!\n")        throw(DoExit())    end    return Part(px,pm,pa,ps)endfunction getcategory(s::String,p::Part)::Int    if s=="x"        return p.x    elseif s=="m"        return p.m    elseif s=="a"        return p.a    elseif s=="s"        return p.s    end    println("Tried to look up unknown category $s!")    throw(DoExit())endfunction applyrules(rules::Vector{Cond},part::Part)::String    for c in rules        if c.t==-1            q=getcategory(c.v,part)            if q<c.n                return c.d            end        elseif c.t==1            q=getcategory(c.v,part)            if q>c.n                return c.d            end        else            return c.d        end    endendfunction isaccepted(work::Dict{String,Vector{Cond}},part::Part)::Bool    k="in"    while true        k=applyrules(work[k],part)        if k=="A"            return true        end        if k=="R"            return false        end    end    return trueendfunction part1(parts::Vector{String},    work::Dict{String,Vector{Cond}})::Int    s=0    for i=1:length(parts)        p=getpart(parts[i])        b=isaccepted(work,p)        if b            s+=p.x+p.m+p.a+p.s        end    end    return sendmutable struct Cube    dx::UnitRange{Int}    dm::UnitRange{Int}    da::UnitRange{Int}    ds::UnitRange{Int}endfunction getrange(s::String)::Symbol    if s=="x"        return :dx    elseif s=="m"        return :dm    elseif s=="a"        return :da    elseif s=="s"        return :ds    end    println("Tried to look up unknown range $s!")    throw(DoExit())endfunction getleft(v::String,w::Int,cube::Cube)::Cube    z=getrange(v)    l=Cube(cube.dx,cube.dm,cube.da,cube.ds)    setproperty!(l,z,getproperty(l,z)[1]:w)    return lendfunction getright(v::String,w::Int,cube::Cube)::Cube    z=getrange(v)    r=Cube(cube.dx,cube.dm,cube.da,cube.ds)    setproperty!(r,z,w:getproperty(r,z)[end])    return rendfunction volume(c::Cube)::Int64    return Int64(length(c.dx))*length(c.dm)*        length(c.da)*length(c.ds)endfunction sumsplit(work::Dict{String,Vector{Cond}},    cube::Cube,k::String)::Int64    if volume(cube)==0        return Int64(0)    end    rsum::Int64=0    if k=="A"        return volume(cube)    elseif k=="R"        return Int64(0)    end    rules=get(work,k,nothing)    if rules==nothing        println("Error $k not in the rules!")        throw(DoExit())    end    for c in rules        if c.t==0            rsum+=sumsplit(work,cube,c.d)            break        end        if c.t==-1            lcube=getleft(c.v,c.n-1,cube)            rsum+=sumsplit(work,lcube,c.d)            cube=getright(c.v,c.n,cube)        elseif c.t==1            rcube=getright(c.v,c.n+1,cube)            rsum+=sumsplit(work,rcube,c.d)            cube=getleft(c.v,c.n,cube)        end    end    return rsumendfunction part2(work::Dict{String,Vector{Cond}})::Int64    cube=Cube(1:4000,1:4000,1:4000,1:4000)    return sumsplit(work,cube,"in")endfunction doinit()    data=String[]    open("day19.txt","r") do fp        data=readlines(fp)    end    ip=0    work=Dict{String,Vector{Cond}}()    for i=1:length(data)        if length(data[i])==0            ip=i+1            break        end        addwork(data[i],work)    end    p1=part1(data[ip:end],work)    p2=part2(work)    println("Part 1 The sum of the part ratings is ",p1)    println("Part 2 The distinct combinations are ",p2)endfunction main()    t=@elapsed try        println("Advent of Code 2023 Day 19 Aplenty\n")        doinit()        throw(DoExit())    catch r        if !isa(r,DoExit)            rethrow(r)        end    end    println("\nTotal execution time ",t," seconds.")end main()
As far as I can tell Julia doesn't let you create a pointer to an element of a structure. As a work around I passed labels and then accessed the desired member of a structure with that label using the setproperty! and getproperty function calls.

Thus, spliting a cube looks like

Code:

    setproperty!(r,z,w:getproperty(r,z)[end])
where z contains a label such as :dx that specifies along which category the cube is being split and w is the split point.

Another item of interest is the use of iteratable ranges of the form 1:4000 to specify the edges of a cube.

According to the head of quality assurance and barking the addwork function is verbose and contains too much cut and paste. I'm not refactoring it.

Statistics: Posted by ejolson — Tue Jan 16, 2024 3:09 am



Viewing all articles
Browse latest Browse all 5310

Trending Articles