Writing and debugging 4D code is... interesting.
When your code can't just run forwards and backwards, but also left and right, up and down, and even inwards and outwards.
Writing and debugging 4D code is... interesting.
When your code can't just run forwards and backwards, but also left and right, up and down, and even inwards and outwards.
"It's a ndiswrapper miracle!" - a statement only uttered by the completely deranged.
Yep, funge has been used to describe any kind of multi-dimensional programming language - often with self-modifying code, I've personally found both 3D and 4D funge languages.
There's just something with the whole concept that amuses me, I've been trying to build some kind of funge-style programming puzzle game for a while now, but haven't figured out a good hook to take it past being just a PoC yet.
2D grids and parsing data from them in all manner of interesting ways is a real AoC staple.
I'm still hoping to be met with a problem at some point which can be solved by handling it as a type of funge program.
Amusingly enough, one of the HP laptops I used in that era actually worked better with ndiswrapper somehow.
It was the only one to do so though.
I get the feeling that I should include some default types for handling 2D maps in my boilerplate, it's a very recurring problem in AoC after all.
My solution is reasonably simplistic - and therefore also a bit slow, but the design meant I could do part 2 with just a few extra lines of code on the already processed data, here's the functional part of it; (I push the previous days solution as part of my workflow for starting with the current day so the full code won't be up until tomorrow)
Ruby
The code has been compressed for brevity.
Point = Struct.new('Point', :x, :y)
PartNumber = Struct.new('PartNumber', :number, :adjacent) do
def adjacent?(to); adjacent.include?(to); end
def irrelevant?; adjacent.empty?; end
def to_i; number; end
end
class Implementation
def initialize
@map = []; @dim = { width: 0, height: 0 }; @symbols = []; @numbers = []
end
def input(line)
@dim[:width] = line.size; @dim[:height] += 1
@map += line.chars
end
def calc
for y in (0..@dim[:height]-1) do
for x in (0..@dim[:width]-1) do
chr = get(x, y); next if chr =~ /\d/ || chr == '.'
@symbols << Point.new(x, y)
end
end
for y in (0..@dim[:height]-1) do
buf = ""; adj = []
for x in (0..@dim[:width]) do # Going one over, to fake a non-number as an end char on all lines
chr = get(x, y)
if chr =~ /\d/
buf += chr
(-1..1).each do |adj_x|
(-1..1).each do |adj_y|
next if adj_x == 0 && adj_y == 0 ||
(x + adj_x < 0) || (x + adj_x >= @dim[:width]) ||
(y + adj_y < 0) || (y + adj_y >= @dim[:height])
sym = Point.new(x + adj_x, y + adj_y)
adj << sym if @symbols.any? sym
end
end
elsif !buf.empty?
@numbers << PartNumber.new(buf.to_i, adj)
buf = ""; adj = []
end
end
end
end
def output
part1 = @numbers.reject(&:irrelevant?).map(&:to_i).sum
puts "Part 1:", part1
gears = @symbols.select do |sym|
next unless get(sym) == '*'
next unless @numbers.select { |num| num.adjacent? sym }.size == 2
true
end
part2 = gears.sum { |gear| @numbers.select { |num| num.adjacent? gear }.map(&:to_i).inject(:*) }
puts "Part 2:", part2
end
private
def get(x, y = -1)
y = x.y if x.is_a?(Point)
x = x.x if x.is_a?(Point)
return unless (0..@dim[:width]-1).include?(x) && (0..@dim[:height]-1).include?(y)
@map[y * @dim[:width] + x % @dim[:width]]
end
end
Definitely the third / middle left, but the bottom right definitely gets second place to me.
Not a major fan of too abstract art, and those are just both so serene.
People love to complain about CMake, often with valid complaints as well. But it - to this day - remains the only build system where I'll actually trust a project when they say they are cross-platform.
Being the Windows maintainer for OpenMW, it used to be absolute hell back a decade and half ago when an indirect dependency changed - and used something like SCons or Premake while claiming to be "cross-platform", used to be that I had to write my own build solutions for Windows since it was all hardcoded against Linux paths and libraries.
CMake might not be the coolest, most hip, build system, but it delivers on actually letting you build your software regardless of platform. So it remains my go-to for whenever I need to actually build something that's supposed to be used.
For personal things I still often hack together a couple of Makefiles though, it's just a lot faster to do.
Have a snippet of Ruby, something I hacked together as part of a solution during the WFH morning meeting;
class String
def to_numberstring(digits_only: false)
tokens = {
one: 1, two: 2, three: 3,
four: 4, five: 5, six: 6,
seven: 7, eight: 8, nine: 9
}.freeze
ret = ""
i = 0
loop do
if self[i] =~ /\d/
ret += self[i]
elsif !digits_only
tok = tokens.find { |k, _| self[i, k.size] == k.to_s }
ret += tok.last.to_s if tok
end
i += 1
break if i >= size
end
ret
end
end
It's basically just a copy of the main leaderboard, but the scores are given based on the size of the group.
It could be interesting with something like the old Pharaoh game and its receding riverbed farming, but you'd have to balance that compared to costs of resourcing in Factorio - or offer some reasonably simple way for the player to protect their resourcing operations against the rising lava.
Well, this one ended up being a really nice and terse solution when done naΓ―vely, here with a trimmed snippet from my simple solution;
Ruby