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.Interesting new solution for day 25Most 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.Code:
--- Day 25: Snowverload ---part 1 - 603368part 2 - free starElapsed - 70.487 ms.
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.
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()
Thus, spliting a cube looks like
Code:
setproperty!(r,z,w:getproperty(r,z)[end])
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