Posted to tcl by mjanssen at Wed Jul 29 11:03:45 GMT 2020view raw

  1. proc init {varname} {
  2. upvar #0 $varname moon
  3. set moon(1,x) 3
  4. set moon(1,y) 15
  5. set moon(1,z) 8
  6. set moon(1,vx) 0
  7. set moon(1,vy) 0
  8. set moon(1,vz) 0
  9.  
  10. set moon(2,x) 5
  11. set moon(2,y) -1
  12. set moon(2,z) -2
  13. set moon(2,vx) 0
  14. set moon(2,vy) 0
  15. set moon(2,vz) 0
  16.  
  17. set moon(3,x) -10
  18. set moon(3,y) 8
  19. set moon(3,z) 2
  20. set moon(3,vx) 0
  21. set moon(3,vy) 0
  22. set moon(3,vz) 0
  23.  
  24. set moon(4,x) 8
  25. set moon(4,y) 4
  26. set moon(4,z) -5
  27. set moon(4,vx) 0
  28. set moon(4,vy) 0
  29. set moon(4,vz) 0
  30. }
  31.  
  32. proc gravity {ax} {
  33. variable moon
  34. foreach {id1 id2} {1 2 1 3 1 4 2 3 2 4 3 4} {
  35. if {$moon($id1,$ax) < $moon($id2,$ax)} {
  36. incr moon($id1,v$ax)
  37. incr moon($id2,v$ax) -1
  38. }
  39. if {$moon($id1,$ax) > $moon($id2,$ax)} {
  40. incr moon($id2,v$ax)
  41. incr moon($id1,v$ax) -1
  42. }
  43. }
  44. }
  45. proc velocity {ax} {
  46. variable moon
  47. incr moon(1,$ax) $moon(1,v$ax)
  48. incr moon(2,$ax) $moon(2,v$ax)
  49. incr moon(3,$ax) $moon(3,v$ax)
  50. incr moon(4,$ax) $moon(4,v$ax)
  51. }
  52.  
  53. namespace import tcl::mathfunc::abs
  54. proc energy {} {
  55. variable moon
  56. set total 0
  57. foreach id {1 2 3 4} {
  58. set kin 0
  59. set pot 0
  60. foreach ax {x y z} {
  61. incr pot [abs $moon($id,$ax)]
  62. incr kin [abs $moon($id,v$ax)]
  63. }
  64. incr total [expr {$kin*$pot}]
  65. }
  66. return $total
  67. }
  68.  
  69. proc part1 {} {
  70. init moon
  71. for {set i 0} {$i < 1000} {incr i} {
  72. gravity x ; velocity x
  73. gravity y ; velocity y
  74. gravity z ; velocity z
  75. }
  76. energy
  77. }
  78.  
  79. proc period {ax} {
  80. variable moon
  81.  
  82. set step 0
  83. while {true} {
  84. gravity $ax
  85. velocity $ax
  86. incr step
  87. # if {$step % 1000 == 0} {puts $step}
  88. # Halfway between initial and period all velocities on an axis are 0 again (as in the intial condition)
  89. if {
  90. $moon(1,v$ax) == 0 &&
  91. $moon(2,v$ax) == 0 &&
  92. $moon(3,v$ax) == 0 &&
  93. $moon(4,v$ax) == 0
  94. } {
  95. return [expr {$step * 2}]
  96. }
  97. }
  98. }
  99.  
  100.  
  101. proc factors {n} {
  102. set top [expr {int(sqrt($n))+1}]
  103. set factor 2
  104. set factors {}
  105. # puts "########## $n"
  106. while {$factor <= $top && $n != 1} {
  107. # puts "$n : $factor < $top"
  108. if {$n % $factor == 0} {
  109. dict incr factors $factor
  110. set n [expr {$n / $factor}]
  111. } else {
  112. incr factor
  113. }
  114. }
  115. if {$n != 1} {
  116. dict incr factors $n
  117. }
  118. # puts "<<<<<<<<< $factors"
  119. return $factors
  120. }
  121.  
  122. proc part2 {} {
  123. namespace import tcl::mathop::*
  124. puts [time {
  125. init moon
  126. set total_factors {}
  127. set periods [list [period x] [period y] [period z]]
  128. foreach period $periods {
  129. set f [factors $period]
  130. # puts $f
  131. foreach k [dict keys $f] {
  132. # puts $k
  133. if {![dict exists $total_factors $k] || [dict get $f $k] > [dict get $total_factors $k]} {
  134. dict set total_factors $k [dict get $f $k]
  135. }
  136. }
  137. }
  138. set factors {}
  139. # puts $total_factors
  140. foreach {factor count} $total_factors {
  141. lappend factors {*}[lrepeat $count $factor]
  142. }
  143. }]
  144. return [* {*}$factors]
  145. }
  146.  
  147. puts [part2]