#!/usr/bin/env tclsh8.6 namespace import ::tcl::mathop::* set maptype {} while {[gets stdin line] >= 0} { if {! [string length $line]} continue if {[string match seeds:* $line]} { foreach {start len} [lindex [split $line :] 1] { lappend ranges [list $start [expr {$start + $len - 1}]] } } elseif {[string match {*-to-* map:} $line]} { set maptype [lindex [split $line -] 0] set $maptype [list] } else { lappend $maptype $line } } # Sample map: {50 97} {98 99} # Sample inrange: 45 67 # Sample output: {45 49} {50 67} proc subranges {map inrange} { lassign $inrange start end # First, check whether inrange begins within one of the mapped ranges. foreach range $map { lassign $range rstart rend if {$start >= $rstart && $start <= $rend} { if {$end >= $rstart && $end <= $rend} { # Wholly contained within this range. Short circuit. # puts "$inrange is wholly contained" return [list $inrange] } # Starts in this range, but spills out. # puts "$inrange starts in subrange $range and spills out" lappend out [list $start $rend] \ {*}[subranges $map [list [+ $rend 1] $end]] return $out } } # inrange does not begin within any mapped range, so we need to find the # first range, if any, that it overlaps. foreach range $map { lassign $range rstart rend if {$rstart > $end} break if {$rend < $start} continue # We have some overlap. We've already determined that it's not # an overlap of the start, so it must overlap the end. # puts "$inrange ends in subrange $range" lappend out [list $start [- $rstart 1]] \ {*}[subranges $map [list $rstart $end]] return $out } # No mapped ranges intersect with inrange at all. # puts "$inrange does not intersect any subranges" return [list $inrange] } proc match {map inranges} { set outranges [list] # Convert the input triples into (start, end, delta) format and # also into (start, end). foreach triple $map { lassign $triple dstart sstart len lappend deltas \ $sstart [expr {$sstart+$len-1}] [- $dstart $sstart] lappend mapranges [list $sstart [expr {$sstart+$len-1}]] } set mapranges [lsort -integer -index 0 $mapranges] # puts "deltas=<$deltas> mapranges=<$mapranges>" # For each input range, break it into however many pieces are needed # such that each piece falls within at most one mapped range. Then # for each piece, add the delta to generate an output range. foreach range $inranges { lappend ranges {*}[subranges $mapranges $range] } # puts "ranges=<$ranges>" foreach range $ranges { lassign $range start end set matched 0 foreach {dstart dend delta} $deltas { if {$start >= $dstart && $start <= $dend && $end >= $dstart && $end <= $dend} { lappend outranges [list [+ $start $delta] [+ $end $delta]] set matched 1 break } } if {! $matched} { lappend outranges [list $start $end] } } # puts "map=<$map> inranges=<$inranges> outranges=<$outranges>" return $outranges } # set seed {{50 97} {98 99}} # puts "seed map: $seed" # puts "seed subranges for 45-67: [subranges $seed {45 67}]" # puts "seed subranges for 50-60: [subranges $seed {50 60}]" # puts "seed subranges for 55-60: [subranges $seed {55 60}]" # puts "seed subranges for 90-97: [subranges $seed {90 97}]" # puts "seed subranges for 90-98: [subranges $seed {90 98}]" # puts "seed subranges for 90-99: [subranges $seed {90 99}]" # puts "seed subranges for 90-101: [subranges $seed {90 101}]" # puts "seed subranges for 99-101: [subranges $seed {99 101}]" # puts "seed subranges for 10-20: [subranges $seed {10 20}]" # puts "seed subranges for 100-120: [subranges $seed {100 120}]" # puts "seed subranges for 10-120: [subranges $seed {10 120}]" # exit 0 # puts "Start ranges $ranges" set ranges [match $humidity [match $temperature [match $light \ [match $water [match $fertilizer [match $soil [match $seed $ranges]]]]]]] # puts "End ranges $ranges" set lowest [lindex $ranges 0 0] foreach range $ranges { lassign $range start end if {$start < $lowest} {set lowest $start} } puts $lowest