···11+# Advent of Code 2025
22+33+Back to (mostly) Trilogy this time, depending on performance needs; Trilogy (post-rewrite) was just barely functioning this time around.
+238
all.rb
···11+#!/usr/bin/env ruby
22+33+require 'json'
44+55+def which cmd
66+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
77+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
88+ exts.each do |ext|
99+ exe = File.join(path, "#{cmd}#{ext}")
1010+ return exe if File.executable?(exe) && !File.directory?(exe)
1111+ end
1212+ end
1313+ nil
1414+end
1515+1616+def measure
1717+ before = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
1818+ yield
1919+ after = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
2020+ after - before
2121+end
2222+2323+def report label
2424+ answer = nil
2525+ time = measure do
2626+ answer = yield
2727+ end
2828+ return :program_error unless $?.success?
2929+ answer = answer.chomp
3030+ puts "\t#{label}: #{answer} in #{(time / 10000).to_f / 100}ms"
3131+ return {
3232+ duration_ns: time,
3333+ answer: answer
3434+ }
3535+end
3636+3737+module Rust
3838+ def self.available?
3939+ which "rustc" != nil
4040+ end
4141+4242+ def self.implemented? part
4343+ File.exist? "p#{part}.rs"
4444+ end
4545+4646+ def self.run part
4747+ `rustc p#{part}.rs 2> /dev/null`
4848+ return :rustc_error unless $?.success?
4949+ report "p#{part}.rs" do
5050+ `timeout 1m ./p#{part} < input`
5151+ end
5252+ end
5353+end
5454+5555+module Haskell
5656+ def self.available?
5757+ which "ghc" != nil
5858+ end
5959+6060+ def self.implemented? part
6161+ File.exist? "p#{part}.hs"
6262+ end
6363+6464+ def self.run part
6565+ `ghc p#{part}.hs 2> /dev/null`
6666+ return :ghc_error unless $?.success?
6767+ report "p#{part}.hs" do
6868+ `timeout 1m ./p#{part} < input`
6969+ end
7070+ end
7171+end
7272+7373+module Trilogy
7474+ def self.clang
7575+ return "clang" if which "clang"
7676+ return "clang-19" if which "clang-19"
7777+ nil
7878+ end
7979+8080+ def self.available?
8181+ which "trilogy" != nil and self.clang != nil
8282+ end
8383+8484+ def self.implemented? part
8585+ File.exist? "p#{part}.tri"
8686+ end
8787+8888+ def self.run part
8989+ `trilogy compile p#{part}.tri 2> /dev/null | #{self.clang} -O3 -o p#{part} -x ir -`
9090+ return :trilogy_error unless $?.success?
9191+ report "p#{part}.tri" do
9292+ `timeout 1m ./p#{part} < input`
9393+ end
9494+ end
9595+end
9696+9797+module C
9898+ def self.clang
9999+ return "clang" if which "clang"
100100+ return "clang-19" if which "clang-19"
101101+ return "gcc" if which "gcc"
102102+ nil
103103+ end
104104+105105+ def self.available?
106106+ self.clang != nil
107107+ end
108108+109109+ def self.implemented? part
110110+ File.exist? "p#{part}.c"
111111+ end
112112+113113+ def self.run part
114114+ `#{self.clang} -O3 -o p#{part} p#{part}.c`
115115+ return :clang_error unless $?.success?
116116+ report "p#{part}.c" do
117117+ `timeout 1m ./p#{part} < input`
118118+ end
119119+ end
120120+end
121121+122122+module Cpp
123123+ def self.available?
124124+ which "g++" != nil
125125+ end
126126+127127+ def self.implemented? part
128128+ File.exist? "p#{part}.cpp"
129129+ end
130130+131131+ def self.run part
132132+ `g++ -std=c++2c -O3 -o p#{part} p#{part}.cpp`
133133+ return :gcc_error unless $?.success?
134134+ report "p#{part}.cpp" do
135135+ `timeout 1m ./p#{part} < input`
136136+ end
137137+ end
138138+end
139139+140140+module Swift
141141+ def self.available?
142142+ which "swiftc" != nil
143143+ end
144144+145145+ def self.implemented? part
146146+ File.exist? "p#{part}.swift"
147147+ end
148148+149149+ def self.run part
150150+ `swiftc p#{part} p#{part}.swift`
151151+ return :swiftc_error unless $?.success?
152152+ report "p#{part}.swift" do
153153+ `timeout 1m ./p#{part} < input`
154154+ end
155155+ end
156156+end
157157+158158+module Python
159159+ def self.python
160160+ return "python3" if which "python3"
161161+ return "python" if which "python"
162162+ return nil
163163+ end
164164+165165+ def self.available?
166166+ self.python != nil
167167+ end
168168+169169+ def self.implemented? part
170170+ File.exist? "p#{part}.py"
171171+ end
172172+173173+ def self.run part
174174+ report "p#{part}.py" do
175175+ `timeout 1m #{self.python} p#{part}.py < input`
176176+ end
177177+ end
178178+end
179179+180180+module Ruby
181181+ def self.available?
182182+ which "ruby" != nil
183183+ end
184184+185185+ def self.implemented? part
186186+ File.exist? "p#{part}.rb"
187187+ end
188188+189189+ def self.run part
190190+ report "p#{part}.rb" do
191191+ `timeout 1m ruby p#{part}.rb < input`
192192+ end
193193+ end
194194+end
195195+196196+module TypeScript
197197+ def self.available?
198198+ which "deno" != nil
199199+ end
200200+201201+ def self.implemented? part
202202+ File.exist? "p#{part}.ts"
203203+ end
204204+205205+ def self.run part
206206+ report "p#{part}.ts" do
207207+ `timeout 1m deno p#{part}.ts < input`
208208+ end
209209+ end
210210+end
211211+212212+languages = [Haskell, Rust, Trilogy, C, Cpp, Swift, Python, Ruby, TypeScript]
213213+ .filter { |lang| lang.available? }
214214+215215+root = Dir.pwd
216216+report = {}
217217+218218+for year in `ls .`.split.filter { |x| /^\d+$/ =~ x } do
219219+ report[year] = {}
220220+ for day in 1..25 do
221221+ next unless Dir.exist? "#{year}/#{day}"
222222+ report[year][day] = {}
223223+ puts "year #{year} day #{day}"
224224+ `just get #{day} #{year} 2> /dev/null`
225225+226226+ Dir.chdir "#{year}/#{day}"
227227+ for part in ['1', '2'] do
228228+ report[year][day]["p#{part}"] = {}
229229+ for lang in languages do
230230+ next unless lang.implemented? part
231231+ report[year][day]["p#{part}"][lang] = lang.run part
232232+ end
233233+ end
234234+ Dir.chdir root
235235+ end
236236+end
237237+238238+File.write "report.json", JSON.pretty_generate(report)