-
Notifications
You must be signed in to change notification settings - Fork 0
/
12.tcl
executable file
·147 lines (142 loc) · 3.84 KB
/
12.tcl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/usr/bin/env tclsh
proc aoc_12 { } {
global plant_edges plant_area
set d [aoc_read "12.data"]
set r [list]
parse $d
lappend r [analyze_all_area 1]
lappend r [analyze_all_area 2]
return $r
}
## -------------------------------------------------------------------
proc analyze_all_area { phase } {
global pos2plant analyzed
set count 0
foreach pos [lsort [array names pos2plant]] {
if {![info exists analyzed($pos)]} {
incr count [analyze_area $phase $pos]
}
}
unset analyzed
return $count
}
proc analyze_area { {phase 1} {pos {0 0}} {plant ""} } {
global pos2plant analyzed fences
set y [lindex $pos 0]
set x [lindex $pos 1]
if {$plant eq ""} {
unset -nocomplain fences
set plant $pos2plant($pos)
set first 1
} else {
set first 0
}
set analyzed($pos) $plant
set area 1
set edges 0
set next_moves [list]
foreach {side move} [list down [down {*}$pos] up [up {*}$pos] right [right {*}$pos] left [left {*}$pos]] {
if {[info exists analyzed($move)]} {
if {$analyzed($move) ne $plant} {
add_fence $side $pos
}
continue
}
if {![info exists pos2plant($move)]} {
add_fence $side $pos
continue
}
set move_plant $pos2plant($move)
if {$move_plant ne $plant} {
add_fence $side $pos
continue
}
lappend next_moves $move $move_plant
}
foreach {move move_plant} $next_moves {
if {![info exists analyzed($move)]} {
incr area [analyze_area $phase $move $move_plant]
}
}
if {$first} {
return [expr {$area * [count_fences $phase]}]
} else {
return $area
}
}
proc add_fence { dir pos } {
global fences
set fences([list {*}$pos $dir]) 1
}
proc count_fences { phase } {
global fences
if {$phase eq "1"} {
set count [llength [array names fences]]
unset -nocomplain fences
} else {
set count 0
while {[set fence [lindex [array names fences] 0]] ne ""} {
del_fence {*}$fence
incr count
}
}
return $count
}
proc del_fence { y x dir } {
global fences
set fun [list]
switch $dir {
"up" - "down" { set fun {left right} }
"left" - "right" { set fun {up down} }
}
unset fences([list $y $x $dir])
foreach f $fun {
for {set npos [$f $y $x $dir]} {[info exists fences($npos)]} {set npos [$f {*}$npos]} {
unset fences($npos)
}
}
}
## -------------------------------------------------------------------
proc down { y x args } {
return [list [expr $y + 1] $x {*}$args]
}
proc up { y x args } {
return [list [expr $y - 1] $x {*}$args]
}
proc left { y x args } {
return [list $y [expr $x - 1] {*}$args]
}
proc right { y x args } {
return [list $y [expr $x + 1] {*}$args]
}
## -------------------------------------------------------------------
proc parse { d } {
global pos2plant map_i map_j
unset -nocomplain pos2plant map_i map_j
set map_i 0
foreach line [split $d "\n"] {
set map_j 0
foreach col [split $line ""] {
set pos2plant([list $map_i $map_j]) $col
incr map_j
}
incr map_i
}
}
proc show { } {
global pos2plant plant2area map_i map_j
for {set i 0} {$i < $map_i} {incr i} {
for {set j 0} {$j < $map_j} {incr j} {
puts -nonewline $pos2plant([list $i $j])
}
puts ""
}
puts [array get plant2area]
}
## -------------------------------------------------------------------
if {[file tail $argv0] eq [file tail [info script]]} {
source "rd.tcl"
# Example results: 1930, 1206
# My results: 1437300, 849332
puts [aoc_12]
}