ace

joined 2 years ago
[–] ace@lemmy.ananace.dev 15 points 2 years ago* (last edited 2 years ago) (2 children)

It could be that running the game at full speed causes some lock contention that doesn't happen when slowed down by the log stream.
Or it could also be that under normal gameplay your system spins down the harddrive to save power due to a lack of accesses, which would cause slowdowns and choppiness when the game suddenly needs to load something - also something which would be helped by running the log in the background.

For testing the second point, I'd suggest running something like this in the background while playing; (i.e. generating some constant load)

while true; do
  uptime > $HOME/workaround-test
  sleep 1
done
[–] ace@lemmy.ananace.dev 1 points 2 years ago* (last edited 2 years ago)

There's a next if [...] to_visit.include?(off_p), and I also only visit points that haven't been flood filled yet (next unless %w[. I].include? val), so there shouldn't be any superfluous testing going on.

Went back and did a quick test of thing, and yep, converting the to_visit array to a set pulls execution time down to ~600ms. But the code becomes much messier.
Going to move the mutation of the map down to the point where I pick a point for visitation instead, so I can re-use the check for already flooded tiles instead.

[–] ace@lemmy.ananace.dev 2 points 2 years ago (2 children)

With the fully expanded map for the actual input it ends up working a 420x420 tile grid, and it has to do both value lookups as well as mutations into that, alongside inclusion testing for the search array (which could probably be made cheaper by building it as a set). It ends up somewhat expensive simply on the number of tests.

The sample I posted the picture of runs in 0.07s wall time though.

[–] ace@lemmy.ananace.dev 4 points 2 years ago (4 children)

The squeezing component in part 2 made this really interesting.

I had a thought on a naïve solution consisting of expanding the input grid, painting all the walked pipes, and then doing a flood fill from the outside of the expanded map. There are a lot cleverer ways to do it, but the idea stuck with me and so...

The code's a bit of a mess, but I actually kind of like the result. It visualizes really well and still runs both parts in under 8 seconds, so it's not even particularly slow considering how it does it.

E.g;
Picture of solution output

RubyA snippet from the expansion/flood fill;

def flood_fill(used: [])
  new_dim = @dim * 3
  new_map = Array.new(new_dim.size, '.')

  puts "Expanding #{@dim} to #{new_dim}, with #{used.size} visited pipes." if $args.verbose

  # Mark all real points as inside on the expanded map
  (0..(@dim.y - 1)).each do |y|
    (0..(@dim.x - 1)).each do |x|
      expanded_point = Point.new x * 3 + 1, y * 3 + 1
      new_map[expanded_point.y * new_dim.x + expanded_point.x] = 'I'
    end
  end

  # Paint all used pipes onto the expanded map
  used.each do |used_p|
    expanded_point = Point.new used_p.x * 3 + 1, used_p.y * 3 + 1

    new_map[expanded_point.y * new_dim.x + expanded_point.x] = '#'
    offsets = @links[used_p].connections
    offsets.shift

    offsets.each do |offs|
      diff = offs - used_p
      new_map[(expanded_point.y + diff.y) * new_dim.x + (expanded_point.x + diff.x)] = '#'
    end
  end

  puts "Flooding expanded map..." if $args.verbose

  # Flood fill the expanded map from the top-left corner
  to_visit = [Point.new(0, 0)]
  until to_visit.empty?
    at = to_visit.shift
    new_map[at.y * new_dim.x + at.x] = ' '

    (-1..1).each do |off_y|
      (-1..1).each do |off_x|
        next if (off_x.zero? && off_y.zero?) || !(off_x.zero? || off_y.zero?)

        off_p = at + Point.new(off_x, off_y)
        next if off_p.x < 0 || off_p.y < 0 \
          || off_p.x >= new_dim.x || off_p.y >= new_dim.y \
          || to_visit.include?(off_p)

        val = new_map[off_p.y * new_dim.x + off_p.x]
        next unless %w[. I].include? val

        to_visit << off_p
      end
    end
  end

  return new_map, new_dim
end

[–] ace@lemmy.ananace.dev 26 points 2 years ago (1 children)

The naïve and unoptimized version ran in under 4 seconds for me, that's nowhere near "Time to knuckle down and actually optimize this" territory.

[–] ace@lemmy.ananace.dev 2 points 2 years ago

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

puts "Part 1:", @races.map do |race|
  (0..race[:time]).count { |press_dur| press_dur * (race[:time] - press_dur) > race[:distance] }
end.inject(:*)

full_race_time = @races.map { |r| r[:time].to_s }.join.to_i
full_race_dist = @races.map { |r| r[:distance].to_s }.join.to_i

puts "Part 2:", (0..full_race_time).count { |press_dur| press_dur * (full_race_time - press_dur) > full_race_dist }

[–] ace@lemmy.ananace.dev 2 points 2 years ago

Not really, WSL seems like it was mainly supposed to stop people leaping ship to be able to develop Node without the horribly painful Windows JS experience. And wouldn't you know it, Microsoft has been making their own JavaScript language in Typescript.

[–] ace@lemmy.ananace.dev 3 points 2 years ago

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.

[–] ace@lemmy.ananace.dev 3 points 2 years ago

"It's a ndiswrapper miracle!" - a statement only uttered by the completely deranged.

[–] ace@lemmy.ananace.dev 6 points 2 years ago* (last edited 2 years ago) (2 children)

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.

[–] ace@lemmy.ananace.dev 13 points 2 years ago (4 children)

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.

[–] ace@lemmy.ananace.dev 2 points 2 years ago (2 children)

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.

view more: ‹ prev next ›