Posted to tcl by mjanssen at Wed Jul 29 11:03:45 GMT 2020view raw
- 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]