125 lines
6.0 KiB
Erlang
125 lines
6.0 KiB
Erlang
|
-module(day20).
|
||
|
-export([start/0, simulate_particle/6]).
|
||
|
|
||
|
process_input_string(Input)
|
||
|
-> Lines = re:split(Input, "\n"),
|
||
|
process_input_lines(Lines, 0, []).
|
||
|
|
||
|
process_input_lines([], _Index, Particles)
|
||
|
-> Particles;
|
||
|
process_input_lines([Line|Tail], Index, Particles)
|
||
|
-> [Position,Velocity,Acceleration|_] = re:split(Line, ", "),
|
||
|
PositionTuple = process_input_coordinate(Position),
|
||
|
VelocityTuple = process_input_coordinate(Velocity),
|
||
|
AccTuple = process_input_coordinate(Acceleration),
|
||
|
process_input_lines(Tail, Index + 1, lists:append(Particles, [{ Index, PositionTuple, VelocityTuple, AccTuple }])).
|
||
|
|
||
|
process_input_coordinate(RawCoord)
|
||
|
-> Coord = string:slice(RawCoord, 3, string:length(RawCoord) - 4),
|
||
|
[X,Y,Z|_] = re:split(Coord, ","),
|
||
|
{ XInt, _ } = string:to_integer(X),
|
||
|
{ YInt, _ } = string:to_integer(Y),
|
||
|
{ ZInt, _ } = string:to_integer(Z),
|
||
|
{ XInt, YInt, ZInt }.
|
||
|
|
||
|
find_closest_particle(Particles)
|
||
|
-> spawn_processors(Particles),
|
||
|
get_processor_output(length(Particles)).
|
||
|
|
||
|
get_processor_output(Iterations)
|
||
|
-> get_processor_output(Iterations, { -1, -1 }).
|
||
|
|
||
|
get_processor_output(Iterations, Result)
|
||
|
when Iterations == 0 -> Result;
|
||
|
get_processor_output(Iterations, Result)
|
||
|
-> { _MinIndex, MinDistance } = Result,
|
||
|
receive
|
||
|
{ Index, Distance } when MinDistance == -1; Distance < MinDistance -> NewResult = { Index, Distance }, get_processor_output(Iterations - 1, NewResult);
|
||
|
{ _Index, _Distance } -> get_processor_output(Iterations - 1, Result)
|
||
|
end.
|
||
|
|
||
|
spawn_processors(Particles)
|
||
|
-> Iterations = 1000,
|
||
|
spawn_processors(Particles, Iterations).
|
||
|
|
||
|
spawn_processors([], _Iterations)
|
||
|
-> true;
|
||
|
spawn_processors([Head|Tail], Iterations)
|
||
|
-> { Index, Position, Velocity, Acceleration } = Head,
|
||
|
spawn(?MODULE, simulate_particle, [self(), Index, Position, Velocity, Acceleration, Iterations]),
|
||
|
spawn_processors(Tail, Iterations).
|
||
|
|
||
|
simulate_particle(Parent, Index, Position, _Velocity, _Acceleration, Iterations)
|
||
|
when Iterations == 0 -> { X, Y, Z } = Position,
|
||
|
Distance = abs(X) + abs(Y) + abs(Z),
|
||
|
Parent ! { Index, Distance };
|
||
|
simulate_particle(Parent, Index, Position, Velocity, Acceleration, Iterations)
|
||
|
-> { PX, PY, PZ } = Position,
|
||
|
{ VX, VY, VZ } = Velocity,
|
||
|
{ AX, AY, AZ } = Acceleration,
|
||
|
NewVX = AX + VX,
|
||
|
NewVY = AY + VY,
|
||
|
NewVZ = AZ + VZ,
|
||
|
NewV = { NewVX, NewVY, NewVZ },
|
||
|
NewPX = NewVX + PX,
|
||
|
NewPY = NewVY + PY,
|
||
|
NewPZ = NewVZ + PZ,
|
||
|
NewP = { NewPX, NewPY, NewPZ },
|
||
|
simulate_particle(Parent, Index, NewP, NewV, Acceleration, Iterations - 1).
|
||
|
|
||
|
calc_collisions(Iterations, _Positions, BadParticles, TotalParticleCount)
|
||
|
when Iterations == 0 -> io:fwrite("found ~p collided particles of ~p total particles, ~p remain~n", [length(BadParticles), TotalParticleCount, TotalParticleCount - length(BadParticles)]), BadParticles;
|
||
|
calc_collisions(Iterations, Positions, BadParticles, TotalParticleCount)
|
||
|
-> %io:fwrite("calculating collisions on ~p~n", [Iterations]),
|
||
|
{ CheckPositions, NextPositions } = lists:partition(fun(X) -> { _Index, Iteration, _Position } = X, Iteration == Iterations end, Positions),
|
||
|
%io:fwrite("check positions ~p~n", [CheckPositions]),
|
||
|
{ _, FilteredPositions } = lists:partition(fun(X) -> { Index, _Iteration, _Position } = X, lists:any(fun(Y) -> Y == Index end, BadParticles) end, CheckPositions),
|
||
|
CollidedPositions = lists:filter(fun(CheckPosition) ->
|
||
|
{ Index, _Iteration, Position } = CheckPosition,
|
||
|
{ X, Y, Z } = Position,
|
||
|
lists:any(fun(NextPosition) ->
|
||
|
{ OtherIndex, _OtherIteration, OtherPosition } = NextPosition,
|
||
|
{ OtherX, OtherY, OtherZ } = OtherPosition,
|
||
|
(Index /= OtherIndex) and (OtherX == X) and (OtherY == Y) and (OtherZ == Z)
|
||
|
end, CheckPositions)
|
||
|
end, FilteredPositions),
|
||
|
%io:fwrite("collidedpositions ~p~n", [CollidedPositions]),
|
||
|
Found = lists:map(fun(X) -> { Index, _Iteration, _Position } = X, Index end, CollidedPositions),
|
||
|
calc_collisions(Iterations - 1, NextPositions, lists:append(BadParticles, Found), TotalParticleCount).
|
||
|
|
||
|
get_all_positions(_Particle, Steps, Positions)
|
||
|
when Steps == 0 -> Positions;
|
||
|
get_all_positions(Particle, Steps, Positions)
|
||
|
-> { Index, Position, Velocity, Acceleration } = Particle,
|
||
|
{ PX, PY, PZ } = Position,
|
||
|
{ VX, VY, VZ } = Velocity,
|
||
|
{ AX, AY, AZ } = Acceleration,
|
||
|
NewVX = AX + VX,
|
||
|
NewVY = AY + VY,
|
||
|
NewVZ = AZ + VZ,
|
||
|
NewV = { NewVX, NewVY, NewVZ },
|
||
|
NewPX = NewVX + PX,
|
||
|
NewPY = NewVY + PY,
|
||
|
NewPZ = NewVZ + PZ,
|
||
|
NewP = { NewPX, NewPY, NewPZ },
|
||
|
get_all_positions({ Index, NewP, NewV, Acceleration }, Steps - 1, lists:append(Positions, [{ Index, Steps, NewP }])).
|
||
|
|
||
|
find_collided_particles(Particles)
|
||
|
-> Iterations = 1000,
|
||
|
Positions = lists:flatten(lists:map(fun(X) -> get_all_positions(X, Iterations, []) end, Particles)),
|
||
|
calc_collisions(Iterations, Positions, [], length(Particles)).
|
||
|
|
||
|
start()
|
||
|
-> Sample = "p=<3,0,0>, v=<2,0,0>, a=<-1,0,0>
|
||
|
p=<4,0,0>, v=<0,0,0>, a=<-2,0,0>",
|
||
|
io:fwrite("closest particle sample ~p~n", [find_closest_particle(process_input_string(Sample))]),
|
||
|
{ ok, File } = file:read_file("input"),
|
||
|
ProblemInput = process_input_string(unicode:characters_to_list(string:chomp(File))),
|
||
|
io:fwrite("closest particle problem input ~p~n", [find_closest_particle(ProblemInput)]),
|
||
|
Sample2 = "p=<-6,0,0>, v=<3,0,0>, a=<0,0,0>
|
||
|
p=<-4,0,0>, v=<2,0,0>, a=<0,0,0>
|
||
|
p=<-2,0,0>, v=<1,0,0>, a=<0,0,0>
|
||
|
p=<3,0,0>, v=<-1,0,0>, a=<0,0,0>",
|
||
|
io:fwrite("collided particle sample ~p~n", [find_collided_particles(process_input_string(Sample2))]),
|
||
|
io:fwrite("collided particle problem input ~p~n", [find_collided_particles(ProblemInput)]).
|