aboutsummaryrefslogtreecommitdiff
path: root/12/1.tcl
diff options
context:
space:
mode:
Diffstat (limited to '12/1.tcl')
-rw-r--r--12/1.tcl128
1 files changed, 128 insertions, 0 deletions
diff --git a/12/1.tcl b/12/1.tcl
new file mode 100644
index 0000000..f0df264
--- /dev/null
+++ b/12/1.tcl
@@ -0,0 +1,128 @@
+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