Posted to tcl by mjanssen at Wed Jul 29 11:03:45 GMT 2020view pretty
proc init {varname} { upvar #0 $varname moon set moon(1,x) 3 set moon(1,y) 15 set moon(1,z) 8 set moon(1,vx) 0 set moon(1,vy) 0 set moon(1,vz) 0 set moon(2,x) 5 set moon(2,y) -1 set moon(2,z) -2 set moon(2,vx) 0 set moon(2,vy) 0 set moon(2,vz) 0 set moon(3,x) -10 set moon(3,y) 8 set moon(3,z) 2 set moon(3,vx) 0 set moon(3,vy) 0 set moon(3,vz) 0 set moon(4,x) 8 set moon(4,y) 4 set moon(4,z) -5 set moon(4,vx) 0 set moon(4,vy) 0 set moon(4,vz) 0 } proc gravity {ax} { variable moon foreach {id1 id2} {1 2 1 3 1 4 2 3 2 4 3 4} { if {$moon($id1,$ax) < $moon($id2,$ax)} { incr moon($id1,v$ax) incr moon($id2,v$ax) -1 } if {$moon($id1,$ax) > $moon($id2,$ax)} { incr moon($id2,v$ax) incr moon($id1,v$ax) -1 } } } proc velocity {ax} { variable moon incr moon(1,$ax) $moon(1,v$ax) incr moon(2,$ax) $moon(2,v$ax) incr moon(3,$ax) $moon(3,v$ax) incr moon(4,$ax) $moon(4,v$ax) } namespace import tcl::mathfunc::abs proc energy {} { variable moon set total 0 foreach id {1 2 3 4} { set kin 0 set pot 0 foreach ax {x y z} { incr pot [abs $moon($id,$ax)] incr kin [abs $moon($id,v$ax)] } incr total [expr {$kin*$pot}] } return $total } proc part1 {} { init moon for {set i 0} {$i < 1000} {incr i} { gravity x ; velocity x gravity y ; velocity y gravity z ; velocity z } energy } proc period {ax} { variable moon set step 0 while {true} { gravity $ax velocity $ax incr step # if {$step % 1000 == 0} {puts $step} # Halfway between initial and period all velocities on an axis are 0 again (as in the intial condition) if { $moon(1,v$ax) == 0 && $moon(2,v$ax) == 0 && $moon(3,v$ax) == 0 && $moon(4,v$ax) == 0 } { return [expr {$step * 2}] } } } proc factors {n} { set top [expr {int(sqrt($n))+1}] set factor 2 set factors {} # puts "########## $n" while {$factor <= $top && $n != 1} { # puts "$n : $factor < $top" if {$n % $factor == 0} { dict incr factors $factor set n [expr {$n / $factor}] } else { incr factor } } if {$n != 1} { dict incr factors $n } # puts "<<<<<<<<< $factors" return $factors } proc part2 {} { namespace import tcl::mathop::* puts [time { init moon set total_factors {} set periods [list [period x] [period y] [period z]] foreach period $periods { set f [factors $period] # puts $f foreach k [dict keys $f] { # puts $k if {![dict exists $total_factors $k] || [dict get $f $k] > [dict get $total_factors $k]} { dict set total_factors $k [dict get $f $k] } } } set factors {} # puts $total_factors foreach {factor count} $total_factors { lappend factors {*}[lrepeat $count $factor] } }] return [* {*}$factors] } puts [part2]