main.go (5994B)
1 package main 2 3 import ( 4 "bufio" 5 "fmt" 6 "log" 7 "os" 8 "sort" 9 "strings" 10 ) 11 12 type Valve struct { 13 name string 14 rate int 15 open bool 16 connections []string 17 } 18 19 func (v Valve) String() string { 20 return fmt.Sprintf("%s,%d,[%s]", v.name, v.rate, 21 strings.Join(v.connections, ",")) 22 } 23 24 type Step struct { 25 name, parent string 26 } 27 type Path struct { 28 name string 29 valve *Valve 30 path Strings 31 nested Paths 32 sumRate int // valve.rate + max(nested rates) 33 } 34 35 func (p Path) Score() int { 36 return (10 + p.valve.rate) / len(p.path) 37 } 38 func (p Path) String() string { 39 s := fmt.Sprintf("(%s:%d:%d:%d sum:%d){", p.name, 40 p.valve.rate, len(p.path), p.Score(), p.sumRate) 41 s += strings.Join(p.path, "->") 42 s += "}" 43 if len(p.nested) > 0 { 44 for _, n := range p.nested { 45 s += "~>" 46 s += n.String() 47 } 48 } 49 return s 50 } 51 52 type Paths []Path 53 54 func (ps Paths) String() string { 55 var s string 56 for _, p := range ps { 57 s += p.String() + 58 "\n" 59 } 60 return s 61 } 62 func (ps Paths) Len() int { return len(ps) } 63 func (ps Paths) Swap(i, j int) { 64 ps[i], ps[j] = ps[j], ps[i] 65 } 66 func (ps Paths) Less(i, j int) bool { 67 //return ps[i].valve.rate > ps[j].valve.rate 68 /*if ps[i].sumRate == ps[j].sumRate { return len(ps[i].path) < len(ps[j].path) 69 }*/ 70 return ps[i].sumRate > ps[j].sumRate 71 } 72 func (ps Paths) Find(name string) *Path { 73 for _, p := range ps { 74 if p.name == name { 75 return &p 76 } 77 } 78 return nil 79 } 80 81 type Valves map[string]*Valve 82 83 func (vs Valves) SumRates(names Strings) int { 84 sum := 0 85 for _, n := range names { 86 sum += vs[n].rate 87 } 88 return sum 89 } 90 func (vs Valves) String() string { 91 var out string 92 for k, v := range vs { 93 out += "[" + k + "]:" + v.String() + "\n" 94 } 95 return out 96 } 97 98 func (vs Valves) FindRoutes(start string, steps int, visited Strings) Paths { 99 steps-- 100 // opening the valve costs 1 101 if steps <= 1 { 102 //fmt.Println("route exhausted") 103 return Paths{} 104 } 105 visited = append(visited, start) 106 paths := vs.GetPaths(start, visited, steps+1) 107 //fmt.Println("FindRoutes", steps, start) fmt.Println(paths) 108 for i, p := range paths { 109 paths[i].sumRate = paths[i].valve.rate * steps 110 paths[i].nested = vs.FindRoutes(p.name, steps-len(p.path), visited) 111 if len(paths[i].nested) > 0 { 112 sort.Sort(paths[i].nested) 113 paths[i].sumRate += paths[i].nested[0].sumRate 114 } 115 } 116 117 return paths 118 } 119 func (vs Valves) FindPath(start, end string) (Path, bool) { 120 var path Path 121 path.valve = vs[end] 122 path.name = end 123 var upcoming []Step 124 visited := make(map[string]string) // name:parent 125 126 upcoming = append(upcoming, Step{name: start, parent: ""}) 127 for len(upcoming) > 0 { 128 cur := upcoming[0].name 129 parent := upcoming[0].parent 130 upcoming = upcoming[1:] 131 if _, exists := visited[cur]; exists { 132 continue 133 } 134 visited[cur] = parent 135 for _, s := range vs[cur].connections { 136 if _, exists := visited[s]; !exists { 137 if s == end { 138 path.path = append(path.path, s, cur) 139 if parent != "" { 140 path.path = append(path.path, parent) 141 } 142 c := parent 143 for c != "" { 144 c = visited[c] 145 if c != "" { 146 path.path = append(path.path, c) 147 } 148 } 149 return path, true 150 } else { 151 upcoming = append(upcoming, Step{name: s, parent: cur}) 152 } 153 } 154 } 155 } 156 157 return path, false 158 } 159 160 func (vs Valves) GetPaths(start string, excluded Strings, limit int) Paths { 161 var paths Paths 162 for _, v := range vs { 163 if v.name == start || v.open || v.rate == 0 || excluded.Has(v.name) { 164 continue 165 } 166 if p, found := vs.FindPath(start, v.name); found && (len(p.path) <= limit) { 167 paths = append(paths, p) 168 } else { 169 //log.Fatal("no path:", start, v.name) 170 } 171 } 172 sort.Sort(paths) 173 return paths 174 } 175 176 type Strings []string 177 178 func (ss Strings) Has(s string) bool { 179 for _, s1 := range ss { 180 if s1 == s { 181 return true 182 } 183 } 184 return false 185 } 186 func main() { 187 if len(os.Args) > 1 { 188 day16(os.Args[1]) 189 } else if len(os.Args) == 1 { 190 fmt.Printf("usage: %s inputfile.txt\n", os.Args[0]) 191 } else { 192 fmt.Println("No input data") 193 } 194 } 195 196 func day16(input_file string) { 197 fmt.Printf("day 16 input filename: %s\n", input_file) 198 input, err := os.Open(input_file) 199 if err != nil { 200 log.Fatal(err) 201 } 202 defer input.Close() 203 valves := make(Valves) 204 scanner := bufio.NewScanner(input) 205 for scanner.Scan() { 206 in := scanner.Text() 207 in1, in2, found := strings.Cut(in, "; ") 208 if !found { 209 log.Fatal("parsing error") 210 } 211 var vname string 212 var vrate int 213 cnt, err := fmt.Sscanf(in1, "Valve %s has flow rate=%d", &vname, &vrate) 214 if cnt != 2 || err != nil { 215 log.Fatal("parsing error:", err) 216 } 217 in2s := strings.SplitN(in2, " ", 5) 218 conns_s := in2s[4] 219 conns := strings.Split(conns_s, ", ") 220 221 valves[vname] = &Valve{name: vname, rate: vrate, connections: conns} 222 223 } 224 if err = scanner.Err(); err != nil { 225 log.Fatal(err) 226 } 227 228 //fmt.Print(valves) 229 230 paths := valves.FindRoutes("AA", 29, Strings{}) 231 //fmt.Println("FindRoutes path:", paths) 232 var pathway Strings 233 sort.Sort(paths) 234 /*for _, p:=range paths{ 235 fmt.Println(p.sumRate) 236 }*/ 237 p := &paths[0] 238 for { 239 pathway = append(pathway, p.name) 240 //fmt.Println(p.sumRate) 241 if len(p.nested) > 0 { 242 sort.Sort(p.nested) 243 p = &p.nested[0] 244 } else { 245 break 246 } 247 } 248 fmt.Println(pathway) 249 250 rate := 0 251 pressure := 0 252 v := valves["AA"] 253 for i := 1; i <= 30; { 254 //paths := valves.GetPaths(v.name, Strings{}) fmt.Println("~~~>", v.name) 255 //fmt.Println(paths) 256 if len(pathway) > 0 { 257 //left := 30 - i 258 path, _ := valves.FindPath(v.name, pathway[0]) 259 plen := len(path.path) 260 pathway = pathway[1:] 261 fmt.Printf("%s -> %s (%d)\n", v.name, path.name, plen) 262 //fmt.Println(path) 263 pressure += rate * plen 264 i += plen - 1 265 v = valves[path.name] 266 v.open = true 267 rate += v.rate 268 fmt.Printf("[%d] rate:%d, pressure:%d\n", i, rate, pressure) 269 } else { 270 //fmt.Printf("[%d] no more paths\n", i) 271 pressure += rate 272 } 273 i++ 274 //fmt.Println("===============") 275 } 276 fmt.Printf("rate:%d, pressure:%d\n", rate, pressure) 277 } 278 279 //2591 too high 280 //1634 too low 281 //2096 too low 282 //2128 wrong 283 //2342 wrong 284 //2297 wrong