package main import ( "bufio" "fmt" "os" "strings" "strconv" ) type maprange struct { src uint64 dst uint64 } type mapval struct { cunt uint64 rnge maprange } type mapping struct { src string dst string val []mapval } func parse(f *os.File) (seeds []uint64, maps map[string]mapping) { s := bufio.NewScanner(f) maps = make(map[string]mapping) inmap := false var curmap mapping for s.Scan() { line := s.Text() switch { case strings.HasPrefix(line, "seeds: "): thing := strings.Split(line[7:], " ") for _, v := range thing { val, _ := strconv.ParseUint(v, 0, 64) seeds = append(seeds, val) } case strings.HasSuffix(line, " map:"): if inmap { maps[curmap.src] = curmap } curmap = mapping{} inmap = true split1 := strings.Index(line, "-to-") split2 := strings.Index(line, " ") src := line[:split1] dst := line[split1 + 4:split2] curmap.src = src curmap.dst = dst case strings.Count(line, " ") >= 2 && inmap: thing := strings.Split(line, " ") var val mapval val.rnge.dst, _ = strconv.ParseUint(thing[0], 0, 64) val.rnge.src, _ = strconv.ParseUint(thing[1], 0, 64) val.cunt, _ = strconv.ParseUint(thing[2], 0, 64) curmap.val = append(curmap.val, val) } } if inmap { maps[curmap.src] = curmap } return } func part1(init_seeds []uint64, maps map[string]mapping) uint64 { seeds := append(make([]uint64, 0, len(init_seeds)), init_seeds...) currency := "seed" for currency != "location" { map_cur := maps[currency] currency = map_cur.dst for i, v := range seeds { for _, x := range map_cur.val { tmp := v - x.rnge.src if tmp > 0 && tmp < x.cunt { v += x.rnge.dst - x.rnge.src break } } seeds[i] = v } } min := seeds[0] for _, v := range seeds[1:] { if v < min { min = v } } return min } func part2(init_seeds []uint64, maps map[string]mapping) uint64 { seeds := make([]maprange, 0) for i, _ := range init_seeds { if i % 2 == 1 { continue } var rnge maprange rnge.src = init_seeds[i + 0] rnge.dst = rnge.src + init_seeds[i + 1] seeds = append(seeds, rnge) } currency := "seed" for currency != "location" { map_cur := maps[currency] currency = map_cur.dst newseedrnge := make([]maprange, 0) for _, v := range seeds { for _, x := range map_cur.val { src := x.rnge.src end := x.rnge.src + x.cunt if src <= v.src && v.src < end && src <= v.dst && v.dst < end { newseedrnge = append(newseedrnge, maprange{ src: v.src + x.rnge.dst - x.rnge.src, dst: v.dst + x.rnge.dst - x.rnge.src, }) v.src = v.dst } else if src <= v.src && v.src < end { newseedrnge = append(newseedrnge, maprange{ src: v.src + x.rnge.dst - x.rnge.src, dst: x.rnge.dst + x.cunt, }) v.src = end } else if src <= v.dst && v.dst < end { newseedrnge = append(newseedrnge, maprange{ src: x.rnge.dst, dst: v.dst + x.rnge.dst - x.rnge.src, }) v.dst = src } if v.src == v.dst { break } } if v.src != v.dst { newseedrnge = append(newseedrnge, v) } } seeds = newseedrnge } min := seeds[0].src for _, v := range seeds[1:] { if v.src < min { min = v.src } } return min } func main() { f, _ := os.Open(os.Args[1]) seeds, maps := parse(f) fmt.Println(part1(seeds, maps)) fmt.Println(part2(seeds, maps)) }