#!/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
}

