Ugh! Part 2 was also straightforward. But only once you intuited (were hinted) that each dimension was independent. Definitely finding a way to cheat was the way to go!
importarrow.optics.opticsimportjava.math.BigIntegerimportjava.nio.file.Filesimportjava.nio.file.Pathsimportjava.util.*importkotlin.math.absvalZERO_3D=Point3d(0,0,0)@opticsdata classPoint3d(valx:Int,valy:Int,valz:Int){overridefuntoString()="<x=$x,y=$y,z=$z>"companionobject}typealiasVelocity3d=Point3dprivatefunPoint3d.asMoonLocation()=Moon(location=this)typealiasPointVel=Array<Int>funpv(p:Int):PointVel=arrayOf(p,0)varPointVel.pointget()=this[0]set(value){this[0]=value}varPointVel.velocityget()=this[1]set(value){this[1]=value}funPoint3d.sum()=abs(x)+abs(y)+abs(z)@opticsdata classMoon(vallocation:Point3d,valvelocity:Velocity3d=ZERO_3D.copy()){overridefuntoString()="$location, $velocity"companionobject}valMoon.potential:Intget()=location.sum()valMoon.kinetic:Intget()=velocity.sum()valMoon.total:Intget()=potential*kineticobjectDay12{privateconstvalFILENAME="src/main/resources/day12.txt"privatevalfileData=Files.readAllLines(Paths.get(FILENAME))funpart1():Int{returnmoons.step(1000).sumBy(Moon::total)}funpart2():BigInteger{returnlcm(moons.map{pv(it.location.x)}.findLoop(),lcm(moons.map{pv(it.location.y)}.findLoop(),moons.map{pv(it.location.z)}.findLoop()))}privatevalmoons=fileData.asSequence().map("""<x=(-?\d+), y=(-?\d+), z=(-?\d+)>""".toRegex()::matchEntire).map{o->Point3d(o!!.groupValues[1].toInt(),o.groupValues[2].toInt(),o.groupValues[3].toInt())}.map(Point3d::asMoonLocation).toList()}funInt.gravity1d(other:Int):Int{returnwhen{this>other->-1this<other->1else->0}}tailrecfunArray<PointVel>.stepForeverX(step:Int=0,seen:MutableMap<String,MutableList<Int>>=TreeMap(),max:Int=1000000):MutableMap<String,MutableList<Int>>{valblob=this.contentDeepToString()if(blobinseen){seen[blob]!!.add(step)}else{seen[blob]=mutableListOf(step)}when{(step<max)->{indices.forEach{a->indices.filterNot{b->a==b}.forEach{this[a].velocity+=this[a].point.gravity1d(this[it].point)}}indices.forEach{this[it].point+=this[it].velocity}returnthis.stepForeverX(step+1,seen)}else->returnseen}}privatetailrecfunList<Moon>.step(times:Int=1):List<Moon>{returnwhen(times){0->thiselse->{indices.map{a->this[a].copy(velocity=this[a].velocity+indices.filterNot{b->a==b}.fold(ZERO_3D){acc,it->acc+Velocity3d(x=this[a].location.x.gravity1d(this[it].location.x),y=this[a].location.y.gravity1d(this[it].location.y),z=this[a].location.z.gravity1d(this[it].location.z))})}.map{it.copy(location=it.location+it.velocity)}.step(times-1)}}}privateoperatorfunPoint3d.plus(other:Point3d)=this.copy(x=x+other.x,y=y+other.y,z=z+other.z)funmain(){println(Day12.part1())println(Day12.part2())}privatefunList<PointVel>.findLoop()=toTypedArray().stepForeverX().asSequence().filter{it.value.size>1}.flatMap{result->result.value.asSequence().windowed(2).map{(a,b)->b-a}.toSet().asSequence().map{ittoresult.value.first()}}.groupBy{it.first}.mapValues{it.value.map{v->v.second}.toSortedSet()}.asSequence().sortedBy{it.key}.first().keytailrecfungcd(n1:BigInteger,n2:BigInteger):BigInteger{require(n1>BigInteger.ZERO||n2>BigInteger.ZERO){"a or b is less than 1 ($n1,$n2)"}returnwhen(valremainder:BigInteger=n1%n2){BigInteger.ZERO->n2else->gcd(n2,remainder)}}funlcm(n1:BigInteger,n2:BigInteger)=(n1*n2)/gcd(n1,n2)funlcm(n1:Int,n2:Int):BigInteger=lcm(n1.toBigInteger(),n2.toBigInteger())funlcm(n1:Int,n2:BigInteger):BigInteger=lcm(n1.toBigInteger(),n2)
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. Straightforward.
Part 2 is... in progress. I'm trying to save every spare bit of heap space I can. :( I keep stalling out around 10 million.
Ugh! Part 2 was also straightforward. But only once you intuited (were hinted) that each dimension was independent. Definitely finding a way to cheat was the way to go!