-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path16.tcl
executable file
·160 lines (147 loc) · 4.68 KB
/
16.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
148
149
150
151
152
153
154
155
156
157
158
159
160
#!/usr/bin/env tclsh
# To solve the maze we are going to use a recursive algorithm with the
# following enhacements.
#
# 1. Positions are scored like in Dijkstra.
# 2. A grace score of 1500 to find same score paths (part 2)
# 3. Always turn right first.
proc aoc_16 { } {
set result [list]
set data [aoc_read "16.data"]
parse $data
set score_ways [search]
set score [lindex $score_ways 0]
set ways [lindex $score_ways 1]
lappend result $score
lappend result [llength [tiles $ways]]
return $result
}
# --------------------------------------------------------------------
proc tiles { ways } {
foreach way $ways {
foreach step $way {
set arr([xy $step]) 1
}
}
return [array names arr]
}
proc search { {pos "start"} {steps {}} {cval 0}} {
global start score best_steps best_value
if {$pos eq "start"} {
set pos $start
set best_steps {}
set best_value 1000000
interp recursionlimit {} 100000
}
set choices [ways $pos $cval]
lappend steps [xy $pos]
foreach {choice val} $choices {
if {[map_get $choice] eq "E"} {
if {$val < $best_value} {
puts "Found $val"
set best_value $val
set best_steps [list [list {*}$steps [xy $choice]]]
} elseif {$val == $best_value} {
puts "Found $val"
lappend best_steps [list {*}$steps [xy $choice]]
}
continue
}
if {$val > $best_value} {
continue
}
if {$val < $score([xy $choice])} {
set score([xy $choice]) $val
search $choice $steps $val
} elseif {($val - 1500) < $score([xy $choice])} {
search $choice $steps $val
}
}
return [list $best_value $best_steps]
}
proc ways { pos cval } {
global score
set result {}
set dirs {}
set value $cval
#$score([xy $pos])
set nposl1 {}
switch [d $pos] {
"^" { set dirs {"^" 1 ">" 1001 "<" 1001 } }
">" { set dirs {">" 1 "v" 1001 "^" 1001 } }
"<" { set dirs {"<" 1 "^" 1001 "v" 1001 } }
"v" { set dirs {"v" 1 "<" 1001 ">" 1001 } }
}
foreach {d c} $dirs {
switch $d {
"^" { lappend nposl1 [pos [x $pos] [expr [y $pos] - 1] "^"] [expr $value + $c] }
"v" { lappend nposl1 [pos [x $pos] [expr [y $pos] + 1] "v"] [expr $value + $c] }
"<" { lappend nposl1 [pos [expr [x $pos] - 1] [y $pos] "<"] [expr $value + $c] }
">" { lappend nposl1 [pos [expr [x $pos] + 1] [y $pos] ">"] [expr $value + $c] }
}
}
foreach {npos val} $nposl1 {
set ch [map_get $npos]
if {$ch ne "#" && $ch ne "@"} {
lappend result $npos $val
}
}
return $result
}
# --------------------------------------------------------------------
proc draw { {ways {}} } {
global map max
puts ""
puts "=========================================================="
puts ""
for {set y 0} {$y < [y $max]} {incr y} {
for {set x 0} {$x < [x $max]} {incr x} {
if {[lsearch $ways [pos $x $y]] != -1} {
puts -nonewline "x"
} else {
puts -nonewline [map_get [pos $x $y]]
}
}
puts ""
}
gets stdin
}
proc parse { data } {
global map max start score best_steps best_value
unset -nocomplain map max start score best_steps best_value
set y 0
foreach line [split $data "\n"] {
set x 0
foreach char [split $line ""] {
if {$char eq "S"} {
set start [pos $x $y ">"]
set value 0
} else {
set value 200000
}
set map([list $y $x]) $char
set score([xy [list $y $x "^"]]) $value
set score([xy [list $y $x ">"]]) $value
set score([xy [list $y $x "<"]]) $value
set score([xy [list $y $x "v"]]) $value
incr x
}
incr y
}
set max [pos $x $y]
}
# --------------------------------------------------------------------
proc x { l } { lindex $l 1 }
proc y { l } { lindex $l 0 }
proc d { l } { lindex $l 2 }
proc xy { l } { list [lindex $l 0] [lindex $l 1] }
proc pos { x y args } { list $y $x {*}$args }
proc map_get { p } { global map; return $map([list [y $p] [x $p]]) }
proc map_set { p v } { global map; set map([list [y $p] [x $p]]) $v }
# --------------------------------------------------------------------
if {[file tail $argv0] eq [file tail [info script]]} {
source "rd.tcl"
# Example results: 7036 45
# My results: 99448 498
puts [aoc_16]
}