view 2017/day20.d @ 26:8db386034a68

day 20
author Jordi Gutiérrez Hermoso <jordigh@octave.org>
date Thu, 21 Dec 2017 03:37:31 -0500
parents
children
line wrap: on
line source

import std.stdio;
import std.string: split;
import std.conv: to;
import std.algorithm: map, filter, minElement, sum, any;
import std.array: array;
import std.math: sqrt;
import std.range: enumerate;

struct particle {
  double[3] pos;
  double[3] vel;
  double[3] acc;
}

auto parseLine(string line) {
  auto p = line.split(", ").map!(
    x => x[3..$-1].split(",").map!(to!double).array.to!(double[3])
  );
  particle res = {p[0], p[1], p[2]};
  return res;
}

auto norm(double[3] v) {
  return v[].map!(x => x*x).sum.sqrt;
}

auto unit(particle p) {
  auto
    pos = p.pos,
    vel = p.vel,
    acc = p.acc;
  pos[] /= pos.norm;
  vel[] /= vel.norm;
  acc[] /= acc.norm;
  particle u = {pos, vel, acc};
  return u;
}

auto slowestParticle(particle[] particles) {
  // This should use minIndex, from later Phobos
  auto norms = particles.map!(p => p.acc.norm);
  auto min = norms.minElement;
  return norms.enumerate.filter!(x => x[1] == min).front[0];
}

void evolve(ref particle p) {
  p.vel[] += p.acc[];
  p.pos[] += p.vel[];
}

void collide(ref particle[] particles) {
  int[double[3]] counter;
  foreach(p; particles) {
    counter[p.pos] = counter.get(p.pos, 0) + 1;
  }
  particles = particles.filter!(p => counter[p.pos] == 1).array;
}

bool canCollide(particle[] particles) {
  return particles.map!(unit).any!(
    function(particle p) {
      // Check if the position, velocity, and acceleration fail to be
      // mostly collinear
      double[3] diff1 = p.pos, diff2 = p.vel;
      diff1[] -= p.vel[];
      diff2[] -= p.acc[];
      return norm(diff1) > 0.001 || norm(diff2) > 0.001;
    }
  );
}

auto evolve(particle[] particles) {
  while(particles.canCollide) {
    collide(particles);
    foreach(ref particle; particles) {
      evolve(particle);
    }
  }
  return particles.length;
}

void main(string[] args) {
  auto particles = File(args[1]).byLineCopy.map!(parseLine).array;
  writeln(particles.slowestParticle);
  writeln(particles.evolve);
}