123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- set fp [open "input"]
- set lines {}
- set line {}
- while {[gets $fp line] >= 0} {
- lappend lines $line
- }
- close $fp
- set height [llength $lines]
- set width [string length [lindex $lines 0]]
- proc char_at {x y} {
- global lines
- string index [lindex $lines $y] $x
- }
- proc out_of_range {x y} {
- global height width
- if {$x < 0 || $x >= $width} {
- return 1
- }
- if {$y < 0 || $y >= $height} {
- return 1
- }
- return 0
- }
- proc get_area_impl {pctx c x y} {
- upvar $pctx ctx
- if {[out_of_range $x $y]} {
- return
- }
- if {[dict exists [dict get $ctx cache] "$x,$y"]} {
- return
- }
- if {[char_at $x $y] != $c} {
- return
- }
- dict update ctx sum sum {incr sum}
- dict update ctx cache cache {
- dict set cache "$x,$y" {}
- }
- get_area_impl ctx $c [expr {$x + 1}] $y
- get_area_impl ctx $c [expr {$x - 1}] $y
- get_area_impl ctx $c $x [expr {$y + 1}]
- get_area_impl ctx $c $x [expr {$y - 1}]
- }
- proc get_area {x y} {
- set ctx {sum 0 cache {}}
- get_area_impl ctx [char_at $x $y] $x $y
- return [dict get $ctx sum]
- }
- proc get_peri_impl {pctx c x y} {
- proc is_outside {c x y} {
- if {[out_of_range $x $y]} {
- return 1
- }
- if {[char_at $x $y] != $c} {
- return 1
- }
- return 0
- }
- upvar $pctx ctx
- if {[out_of_range $x $y]} {
- return
- }
- if {[dict exists [dict get $ctx cache] "$x,$y"]} {
- return
- }
- if {[char_at $x $y] != $c} {
- return
- }
- set c [char_at $x $y]
- dict update ctx sum sum {
- set sum [expr {$sum + [is_outside $c [expr {$x - 1}] $y] \
- + [is_outside $c [expr {$x + 1}] $y] \
- + [is_outside $c $x [expr {$y + 1}]] \
- + [is_outside $c $x [expr {$y - 1}]]}]
- }
- dict update ctx cache cache {
- dict set cache "$x,$y" {}
- }
- get_peri_impl ctx $c [expr {$x + 1}] $y
- get_peri_impl ctx $c [expr {$x - 1}] $y
- get_peri_impl ctx $c $x [expr {$y + 1}]
- get_peri_impl ctx $c $x [expr {$y - 1}]
- }
- proc get_peri {x y} {
- set ctx {sum 0 cache {}}
- get_peri_impl ctx [char_at $x $y] $x $y
- return [dict get $ctx sum]
- }
- set visited {}
- proc mark_visited {c x y} {
- global visited
- if {[out_of_range $x $y]} return
- if {[char_at $x $y] != $c} return
- if {[dict exists $visited "$x,$y"]} return
- dict set visited "$x,$y" {}
- incr x
- mark_visited $c $x $y
- incr x -2
- mark_visited $c $x $y
- incr x
- incr y
- mark_visited $c $x $y
- incr y -2
- mark_visited $c $x $y
- }
- set sum 0
- for {set x 0} {$x < $width} {incr x} {
- for {set y 0} {$y < $height} {incr y} {
- if {[dict exists $visited "$x,$y"]} {
- continue
- }
- set peri [get_peri $x $y]
- set area [get_area $x $y]
- mark_visited [char_at $x $y] $x $y
- incr sum [expr {$peri * $area}]
- }
- }
- puts $sum
|