Part 1 in "modern" Python complete with tests. I need to think a bit about part 2. Can it be done with some form of integration?
fromdataclassesimportdataclass,fieldfromtypingimportList,Generator,TypeVarimportpytest@dataclass(frozen=True)classVector:x:int=0y:int=0z:int=0defmagnitude(self):returnabs(self.x)+abs(self.y)+abs(self.z)def__add__(self,other):returnVector(self.x+other.x,self.y+other.y,self.z+other.z)@dataclass(frozen=True)classMoon:pos:Vectorvelocity:Vector=field(default_factory=Vector)defenergy(self):returnself.pos.magnitude()*self.velocity.magnitude()defload(text):"""
Load multi-line `text` into a collection of Moons
"""defvector(line):parts=line.strip("<>").split(",")returnVector(*[int(p.strip()[2:])forpinparts])return[Moon(pos=vector(line))forlineintext.strip().splitlines()]defsimulate(moons:List[Moon])->List[Moon]:"""
Simulate the motion of `moons`, returning a new collection of Moons
"""defcompare_axis(x,y):ifx<y:return1elifx==y:return0else:return-1defgravity_vector(a:Vector,b:Vector)->Vector:returnVector(x=compare_axis(a.x,b.x),y=compare_axis(a.y,b.y),z=compare_axis(a.z,b.z))defsimulate_moon(m:Moon)->Moon:gravity=Vector()forninmoons:gravity+=gravity_vector(m.pos,n.pos)velocity=m.velocity+gravityreturnMoon(pos=m.pos+velocity,velocity=velocity)return[simulate_moon(m)forminmoons]defsimulate_seq(moons:List[Moon])->Generator[List[Moon],None,None]:"""
Generate a sequence of simulated states for `moons`
"""m=moonswhileTrue:m=simulate(m)yieldmT=TypeVar("T")defafter(n:int,seq:Generator[T,None,None])->T:"""
Get the `n`th value from `seq`
"""forxinrange(n):r=next(seq)returnrdeftotal_energy(moons:List[Moon])->int:returnsum(m.energy()forminmoons)deftest_load():"""
Verify parsing text into Moons
"""r=load("""<x=-1, y=0, z=2>
<x=2, y=-10, z=-7>
<x=4, y=-8, z=8>
<x=3, y=5, z=-1>""")assertlen(r)==4assertr[0]==Moon(pos=Vector(-1,0,2))assertr[1]==Moon(pos=Vector(2,-10,-7))assertr[2]==Moon(pos=Vector(4,-8,8))assertr[3]==Moon(pos=Vector(3,5,-1))EXAMPLE_MOONS_1=[Moon(pos=Vector(-1,0,2)),Moon(pos=Vector(2,-10,-7)),Moon(pos=Vector(4,-8,8)),Moon(pos=Vector(3,5,-1))]EXAMPLE_MOONS_2=[Moon(pos=Vector(-8,-10,0)),Moon(pos=Vector(5,5,10)),Moon(pos=Vector(2,-7,3)),Moon(pos=Vector(9,-8,-3))]@pytest.mark.parametrize("moons,steps,expect",[(EXAMPLE_MOONS_1,1,[Moon(pos=Vector(2,-1,1),velocity=Vector(3,-1,-1)),Moon(pos=Vector(3,-7,-4),velocity=Vector(1,3,3)),Moon(pos=Vector(1,-7,5),velocity=Vector(-3,1,-3)),Moon(pos=Vector(2,2,0),velocity=Vector(-1,-3,1))]),(EXAMPLE_MOONS_1,2,[Moon(pos=Vector(5,-3,-1),velocity=Vector(3,-2,-2)),Moon(pos=Vector(1,-2,2),velocity=Vector(-2,5,6)),Moon(pos=Vector(1,-4,-1),velocity=Vector(0,3,-6)),Moon(pos=Vector(1,-4,2),velocity=Vector(-1,-6,2))]),(EXAMPLE_MOONS_1,10,[Moon(pos=Vector(2,1,-3),velocity=Vector(-3,-2,1)),Moon(pos=Vector(1,-8,0),velocity=Vector(-1,1,3)),Moon(pos=Vector(3,-6,1),velocity=Vector(3,2,-3)),Moon(pos=Vector(2,0,4),velocity=Vector(1,-1,-1))])])deftest_simulate_one_step(moons,steps,expect):"""
Verify moon simulation
"""assertafter(steps,simulate_seq(moons))==expect@pytest.mark.parametrize("moons,steps,energy",[(EXAMPLE_MOONS_1,10,179),(EXAMPLE_MOONS_2,100,1940)])deftest_energy(moons,steps,energy):final=after(steps,simulate_seq(moons))asserttotal_energy(final)==energydefpart1(moons):final=after(1000,simulate_seq(moons))print(f"Part 1 : {total_energy(final)}")if__name__=="__main__":withopen("input.txt","rt")asf:moons=load(f.read())part1(moons)
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 in "modern" Python complete with tests. I need to think a bit about part 2. Can it be done with some form of integration?