#!/bin/sh
# -*- tcl -*-
# The next line is executed by /bin/sh, but not tcl \
exec tclsh "$0" ${1+"$@"}
# Get input from file
set fhandle [open "advent12.txt"]
#set fhandle [open "temp12.txt"]
set input [read -nonewline $fhandle]
close $fhandle
# Day 12: Subterranean Sustainability
# Input: a string representing pots numbered from 0 up. "#" contains a plant;
# "." does not.
# Following: a list of rules, a la Conway's Life.
# Each pot will contain a plant on the next step based on its own content
# plus the two pots to the left and two to the right, represented as:
# a 5-char string, a marker, and a result (e.g.. ".#.#." => .)
foreach line [split $input "\n"] {
switch -regexp -matchvar matchL -- $line {
{[a-z]+: ([\.\#]+)} {
set potS [lindex $matchL 1]
}
{([\.\#]+) => ([\.\#])} {
set rules([lindex $matchL 1]) [lindex $matchL 2]
}
}
}
puts "potS: $potS"
proc generate {potS} {
set in "....$potS...."
set outS ""
for {set idx 0} {$idx < [string length $potS]+4} {incr idx} {
set pots [string range $in $idx $idx+4]
append outS $::rules($pots)
}
return "[string trimright $outS "."].."
}
# Part 1:
# After 20 generations, what is the sum of the numbers of all pots which
# contain a plant?
# Part 2:
# After 50 billion generations (i.e, after it's stable) what is the sum of all
# the pots that contain a plant?
set offset 0
set gens 0
set numGens 50000000000
#set numGens 200
set oldpotS $potS
set oldoff $offset
while {$gens < $numGens} {
if {$gens == 20} {
# Output Part 1 answer
set total [::tcl::mathop::+ {*}[lsearch -all [split $potS ""] "#"]]
incr total [expr {$offset * [llength [lsearch -all [split $potS ""] "#"]]}]
puts "After 20 generations, $total"
puts ""
}
if {[info exists pothist($offset,$potS)]} {
# One possible end condition - the first I coded, but not the actual end case we hit.
set total [::tcl::mathop::+ {*}[lmap idx [lsearch -all [split $potS ""] "#"] {expr {($idx + $offset}}]]
puts "At Generation $gens, we hit a repeat state. Sum is $total"
puts "Current is $potS; went to $pothist($offset,$potS) last time"
# Removed code for finding the length of the loop and the offset of numGens modulo loopLen
# because it's not relevant for the testcase
break
}
set potS [generate $potS]
incr gens
incr offset [expr {([string length $potS] - [string length [string trimleft $potS "."]]) - 2}]
set potS [string trimleft $potS "."]
set pothist($oldoff,$oldpotS) $offset,$potS
if {($oldpotS eq $potS) && ($oldoff != $offset)} {
# This is the termination case we actually hit.
puts "At Generation $gens, we're stable but moving: offset is $offset, was $oldoff"
# increment our offset by the number of remaining generations times the step size per generation.
set adjust [expr {(($numGens - $gens) * ($offset - $oldoff)) + $offset }]
set total [::tcl::mathop::+ {*}[lmap idx [lsearch -all [split $potS ""] "#"] {expr {$idx + $adjust}}]]
puts "After 50 billion ($numGens) gens, the total will be $total"
break
}
set oldpotS $potS
set oldoff $offset
}