Part 1 was...not easy, exactly, but straightforward. Apply some logic, iterate 1000 times, cool.
Part 2 took me the rest of the day to work out, and the key insight turned out to be 2-pronged:
looking for a single satellite to repeat itself is probably faster than looking for all four to repeat at the same time. this turned out to be the wrong approach, but the idea of breaking it down into parts and then looking for a multiple turned out to be the right path...
satellite motion in a given direction is totally independent of the other directions, meaning that we can look for the four satellites to repeat themselves in just one axis, and they will have a consistent period of oscillation on that single axis. We can repeat on the other 2 axes to find 3 time periods and then the moment the satellites all find themselves at the starting location is the least common multiple of the 3 periods. I confess that this had me stumped for a looong time, and I went looking for hints on reddit before something jogged my brain.
Anyways, ruby code for part 2:
#!/usr/bin/env rubyclassMoonattr_accessor:posattr_accessor:vdefinitialize(pos)@pos=Vector3D.new(pos)@v=Vector3D.new([0,0,0])enddefapply_gravity(other_moon)dx=sign(@pos.x-other_moon.pos.x)dy=sign(@pos.y-other_moon.pos.y)dz=sign(@pos.z-other_moon.pos.z)@v.x-=dx@v.y-=dy@v.z-=dzother_moon.v.x+=dxother_moon.v.y+=dyother_moon.v.z+=dzenddefmove()@pos.x+=@v.x@pos.y+=@v.y@pos.z+=@v.zenddefpotential_energy()return@pos.x.abs+@pos.y.abs+@pos.z.absenddefkinetic_energy()return@v.x.abs+@v.y.abs+@v.z.absenddefenergy()returnpotential_energy()*kinetic_energy()enddefto_s()return"#{@pos}|#{@v}"enddefclone()returnMoon.new([@pos.x,@pos.y,@pos.z])endendclassVector3Dattr_accessor:xattr_accessor:yattr_accessor:zdefinitialize(coords)@x=coords[0]@y=coords[1]@z=coords[2]enddefto_s()return"#{@x},#{@y},#{@z}"endenddefsign(n)returnn<=>0enddefparse_position(line)stripped=line[1..-2]# get rid of <>chunks=stripped.split(",")nums=[]chunks.eachdo|c|bits=c.split("=")num=bits[1]nums.push(num.to_i)endreturnnumsenddefstep(moons)foriin0..moons.length-1m=moons[i]forjini+1..moons.length-1other=moons[j]m.apply_gravity(other)endendmoons.eachdo|m|m.move()endenddefpp(moons)moons.eachdo|m|puts"#{m.pos.x},#{m.pos.y},#{m.pos.z} || #{m.v.x},#{m.v.y},#{m.v.z}"endenddefstate(moons)s=""moons.eachdo|m|s+=m.to_s+"."endreturnsenddeffind_repeat_state(moons)initial_moons=moons.map{|m|m.clone()}periods=[nil,nil,nil]num_steps=0whiletruenum_steps+=1step(moons)# xifperiods[0]==nilxmatch=true4.timesdo|idx|current_moon=moons[idx]initial_state=initial_moons[idx]if!(current_moon.pos.x==initial_state.pos.x&¤t_moon.v.x==initial_state.v.x)xmatch=falseendendifxmatchperiods[0]=num_stepsendend# yifperiods[1]==nilymatch=true4.timesdo|idx|current_moon=moons[idx]initial_state=initial_moons[idx]if!(current_moon.pos.y==initial_state.pos.y&¤t_moon.v.y==initial_state.v.y)ymatch=falseendendifymatchperiods[1]=num_stepsendend# zifperiods[2]==nilzmatch=true4.timesdo|idx|current_moon=moons[idx]initial_state=initial_moons[idx]if!(current_moon.pos.z==initial_state.pos.z&¤t_moon.v.z==initial_state.v.z)zmatch=falseendendifzmatchperiods[2]=num_stepsendendif!periods.include?(nil)breakendendreturnperiods.reduce(1,:lcm)endif__FILE__==$0moons=[]File.open(ARGV[0],"r")do|file_handle|file_handle.each_linedo|line|pos=parse_position(line.chomp)moons.push(Moon.new(pos))endendputsfind_repeat_state(moons)end
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Part 1 was...not easy, exactly, but straightforward. Apply some logic, iterate 1000 times, cool.
Part 2 took me the rest of the day to work out, and the key insight turned out to be 2-pronged:
Anyways, ruby code for part 2: