├── 2018 ├── 10 │ └── 2.go ├── 11 │ └── 2.go ├── 12 │ └── 2.go ├── 13 │ └── 2.go ├── 14 │ └── 2.go ├── 01 │ ├── 1.go │ └── 2.go ├── 02 │ ├── 1.go │ └── 2.go ├── 03 │ └── 2.go ├── 04 │ ├── 1.go │ └── 2.go ├── 05 │ ├── 1.go │ └── 2.go ├── 06 │ └── 2.go ├── 07 │ ├── 1.go │ └── 2.go ├── 08 │ └── 2.go └── 09 │ └── 2.go ├── 2019 ├── 10 │ └── 2.go ├── 11 │ ├── 1.go │ └── 2.go ├── 12 │ ├── 1.go │ └── 2.go ├── 13 │ ├── 1.go │ └── 2.go ├── 14 │ └── 2.go ├── 15 │ └── 2.go ├── 16 │ ├── 1.go │ └── 2.go ├── 17 │ └── 2.go ├── 18 │ ├── 1.go │ ├── 2.go │ └── input2.txt ├── 19 │ ├── 1.go │ └── 2.go ├── 20 │ ├── 1.go │ └── 2.go ├── 21 │ └── 2.go ├── 22 │ ├── 1.go │ └── 2.go ├── 23 │ └── 2.go ├── 24 │ ├── 1.go │ └── 2.go ├── 01 │ ├── 1.go │ └── 2.go ├── 02 │ ├── 1.go │ └── 2.go ├── 03 │ ├── 1.go │ └── 2.go ├── 04 │ ├── 1.go │ └── 2.go ├── 05 │ └── 2.go ├── 06 │ ├── 1.go │ └── 2.go ├── 07 │ ├── 1.go │ └── 2.go ├── 08 │ ├── 1.go │ └── 2.go └── 09 │ └── 2.go ├── 2020 ├── 10 │ └── 2.go ├── 11 │ └── 2.go ├── 12 │ └── 2.go ├── 13 │ └── 2.go ├── 14 │ └── 2.go ├── 15 │ └── 2.go ├── 16 │ └── 2.go ├── 17 │ └── 2.go ├── 18 │ └── 2.go ├── 19 │ └── 2.go ├── 20 │ └── 2.go ├── 21 │ └── 2.go ├── 22 │ └── 2.go ├── 23 │ └── 2.go ├── 24 │ └── 2.go ├── 25 │ └── 1.go ├── 01 │ └── 2.go ├── 02 │ └── 2.go ├── 03 │ └── 2.go ├── 04 │ └── 2.go ├── 05 │ └── 2.go ├── 06 │ └── 2.go ├── 07 │ └── 2.go ├── 08 │ └── 2.go └── 09 │ └── 2.go ├── 2021 ├── 10 │ └── 2.go ├── 11 │ └── 2.go ├── 12 │ └── 2.go ├── 13 │ └── 2.go ├── 14 │ └── 2.go ├── 15 │ └── 2.go ├── 01 │ └── 2.go ├── 02 │ └── 2.go ├── 03 │ └── 2.go ├── 04 │ └── 2.go ├── 05 │ └── 2.go ├── 06 │ └── 2.go ├── 07 │ └── 2.go ├── 08 │ └── 2.go └── 09 │ └── 2.go ├── 2022 ├── 10 │ └── 1.go ├── 11 │ └── 1.go ├── 12 │ └── 1.go ├── 13 │ └── 1.go ├── 14 │ └── 1.go ├── 15 │ └── 1.go ├── 17 │ └── 1.go ├── 18 │ └── 1.go ├── 20 │ └── 1.go ├── 21 │ └── 1.go ├── 23 │ └── 1.go ├── 24 │ └── 1.go ├── 25 │ └── 1.go ├── 01 │ └── 1.go ├── 02 │ └── 1.go ├── 03 │ └── 1.go ├── 04 │ └── 1.go ├── 05 │ └── 1.go ├── 06 │ └── 1.go ├── 07 │ └── 1.go ├── 08 │ └── 1.go └── 09 │ └── 1.go ├── 2023 ├── 10 │ └── 1.go ├── 11 │ └── 1.go ├── 12 │ └── 1.go ├── 13 │ └── 1.go ├── 14 │ └── 1.go ├── 15 │ └── 1.go ├── 16 │ └── 1.go ├── 17 │ └── 1.go ├── 18 │ └── 1.go ├── 19 │ └── 1.go ├── 20 │ └── 1.go ├── 21 │ └── 1.go ├── 22 │ └── 1.go ├── 23 │ └── 1.go ├── 24 │ └── 1.go ├── 25 │ └── 1.go ├── 01 │ └── 1.go ├── 02 │ └── 1.go ├── 03 │ └── 1.go ├── 04 │ └── 1.go ├── 05 │ └── 1.go ├── 06 │ └── 1.go ├── 07 │ └── 1.go ├── 08 │ └── 1.go └── 09 │ └── 1.go ├── 2024 ├── 10 │ └── 1.go ├── 11 │ └── 1.go ├── 12 │ └── 1.go ├── 13 │ └── 1.go ├── 14 │ └── 1.go ├── 15 │ └── 1.go ├── 16 │ └── 1.go ├── 17 │ └── 1.go ├── 18 │ └── 1.go ├── 19 │ └── 1.go ├── 20 │ └── 1.go ├── 22 │ └── 1.go ├── 01 │ └── 1.go ├── 02 │ └── 1.go ├── 03 │ └── 1.go ├── 04 │ └── 1.go ├── 05 │ └── 1.go ├── 06 │ └── 1.go ├── 07 │ └── 1.go ├── 08 │ └── 1.go └── 09 │ └── 1.go ├── .gitignore ├── go.mod └── synacor ├── arch-spec ├── challenge.bin ├── input.txt └── synacor.go /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | /[0-9]*/**/input.txt 3 | -------------------------------------------------------------------------------- /2018/01/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | total := 0 14 | for _, s := range strings.Fields(string(input)) { 15 | i, _ := strconv.Atoi(s) 16 | total += i 17 | } 18 | fmt.Println(total) 19 | } 20 | -------------------------------------------------------------------------------- /2018/01/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | total := 0 14 | reached := map[int]struct{}{} 15 | for { 16 | for _, s := range strings.Fields(string(input)) { 17 | i, _ := strconv.Atoi(s) 18 | total += i 19 | if _, ok := reached[total]; ok { 20 | fmt.Println(total) 21 | return 22 | } 23 | reached[total] = struct{}{} 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /2018/02/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | input, _ := ioutil.ReadFile("input.txt") 11 | 12 | boxes := map[int]int{} 13 | for _, s := range strings.Fields(string(input)) { 14 | count := map[rune]int{} 15 | for _, r := range s { 16 | count[r]++ 17 | } 18 | has := map[int]struct{}{} 19 | for _, v := range count { 20 | if _, ok := has[v]; !ok { 21 | boxes[v] += 1 22 | } 23 | has[v] = struct{}{} 24 | } 25 | } 26 | fmt.Println(boxes[2] * boxes[3]) 27 | } 28 | -------------------------------------------------------------------------------- /2018/02/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | input, _ := ioutil.ReadFile("input.txt") 11 | 12 | seen := map[string]struct{}{} 13 | for _, s := range strings.Fields(string(input)) { 14 | for i := range s { 15 | t := s[:i] + " " + s[i+1:] 16 | if _, ok := seen[t]; ok { 17 | fmt.Println(strings.ReplaceAll(t, " ", "")) 18 | return 19 | } 20 | seen[t] = struct{}{} 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /2018/03/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | nclaims := map[image.Point]int{} 14 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 15 | var id, x, y, w, h int 16 | fmt.Sscanf(s, "#%d @ %d,%d: %dx%d", &id, &x, &y, &w, &h) 17 | for i := x; i < x+w; i++ { 18 | for j := y; j < y+h; j++ { 19 | nclaims[image.Point{i, j}]++ 20 | } 21 | } 22 | } 23 | 24 | area := 0 25 | for _, v := range nclaims { 26 | if v > 1 { 27 | area++ 28 | } 29 | } 30 | fmt.Println(area) 31 | 32 | out: 33 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 34 | var id, x, y, w, h int 35 | fmt.Sscanf(s, "#%d @ %d,%d: %dx%d", &id, &x, &y, &w, &h) 36 | for i := x; i < x+w; i++ { 37 | for j := y; j < y+h; j++ { 38 | if nclaims[image.Point{i, j}] > 1 { 39 | continue out 40 | } 41 | } 42 | } 43 | fmt.Println(id) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /2018/04/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "regexp" 7 | "sort" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | func main() { 13 | input, _ := ioutil.ReadFile("input.txt") 14 | split := strings.Split(strings.TrimSpace(string(input)), "\n") 15 | sort.Strings(split) 16 | 17 | re := regexp.MustCompile(`.*:(\d+)\] (\w+) .(\d+)?`) 18 | records := map[int]map[int]int{} 19 | total := map[int]int{} 20 | var id, falls, wakes int 21 | var maxID, maxMin int 22 | 23 | for _, s := range split { 24 | m := re.FindStringSubmatch(s) 25 | switch m[2] { 26 | case "Guard": 27 | id, _ = strconv.Atoi(m[3]) 28 | if _, ok := records[id]; !ok { 29 | records[id] = map[int]int{} 30 | } 31 | case "falls": 32 | falls, _ = strconv.Atoi(m[1]) 33 | case "wakes": 34 | wakes, _ = strconv.Atoi(m[1]) 35 | for i := falls; i < wakes; i++ { 36 | records[id][i]++ 37 | total[id]++ 38 | if total[id] > total[maxID] { 39 | maxID = id 40 | } 41 | } 42 | } 43 | } 44 | 45 | for k, v := range records[maxID] { 46 | if v > records[maxID][maxMin] { 47 | maxMin = k 48 | } 49 | } 50 | 51 | fmt.Println(maxID * maxMin) 52 | } 53 | -------------------------------------------------------------------------------- /2018/04/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "regexp" 7 | "sort" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | func main() { 13 | input, _ := ioutil.ReadFile("input.txt") 14 | split := strings.Split(strings.TrimSpace(string(input)), "\n") 15 | sort.Strings(split) 16 | 17 | re := regexp.MustCompile(`.*:(\d+)\] (\w+) .(\d+)?`) 18 | records := map[int]map[int]int{} 19 | var id, falls, wakes int 20 | var maxID, maxMin int 21 | 22 | for _, s := range split { 23 | m := re.FindStringSubmatch(s) 24 | switch m[2] { 25 | case "Guard": 26 | id, _ = strconv.Atoi(m[3]) 27 | if _, ok := records[id]; !ok { 28 | records[id] = map[int]int{} 29 | } 30 | case "falls": 31 | falls, _ = strconv.Atoi(m[1]) 32 | case "wakes": 33 | wakes, _ = strconv.Atoi(m[1]) 34 | for min := falls; min < wakes; min++ { 35 | records[id][min]++ 36 | if records[id][min] > records[maxID][maxMin] { 37 | maxID, maxMin = id, min 38 | } 39 | } 40 | } 41 | } 42 | 43 | fmt.Println(maxID * maxMin) 44 | } 45 | -------------------------------------------------------------------------------- /2018/05/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strings" 7 | "unicode" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | polymer := strings.TrimSpace(string(input)) 14 | for { 15 | old := polymer 16 | for r := 'a'; r <= 'z'; r++ { 17 | polymer = strings.ReplaceAll(polymer, string([]rune{r, unicode.ToUpper(r)}), "") 18 | polymer = strings.ReplaceAll(polymer, string([]rune{unicode.ToUpper(r), r}), "") 19 | } 20 | if polymer == old { 21 | fmt.Println(len(polymer)) 22 | return 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /2018/05/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strings" 7 | "unicode" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | min := int(^uint(0) >> 1) 14 | for r := 'a'; r <= 'z'; r++ { 15 | polymer := strings.TrimSpace(string(input)) 16 | polymer = strings.ReplaceAll(polymer, string(r), "") 17 | polymer = strings.ReplaceAll(polymer, string(unicode.ToUpper(r)), "") 18 | 19 | for { 20 | old := polymer 21 | for r := 'a'; r <= 'z'; r++ { 22 | polymer = strings.ReplaceAll(polymer, string([]rune{r, unicode.ToUpper(r)}), "") 23 | polymer = strings.ReplaceAll(polymer, string([]rune{unicode.ToUpper(r), r}), "") 24 | } 25 | if polymer == old { 26 | if len(polymer) < min { 27 | min = len(polymer) 28 | } 29 | break 30 | } 31 | } 32 | } 33 | fmt.Println(min) 34 | } 35 | -------------------------------------------------------------------------------- /2018/06/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strings" 8 | ) 9 | 10 | const MaxInt = int(^uint(0) >> 1) 11 | const MinInt = -MaxInt - 1 12 | 13 | func main() { 14 | input, _ := ioutil.ReadFile("input.txt") 15 | 16 | tl, br := image.Point{MaxInt, MaxInt}, image.Point{MinInt, MinInt} 17 | points := map[image.Point]int{} 18 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 19 | var x, y int 20 | fmt.Sscanf(s, "%d, %d", &x, &y) 21 | points[image.Point{x, y}] = 0 22 | tl, br = image.Point{Min(tl.X, x), Min(tl.Y, y)}, image.Point{Max(br.X, x), Max(br.Y, y)} 23 | } 24 | 25 | area := 0 26 | for y := tl.Y; y <= br.Y; y++ { 27 | for x := tl.X; x <= br.X; x++ { 28 | mp, md := image.Point{MaxInt, MaxInt}, MaxInt 29 | sum := 0 30 | 31 | for p := range points { 32 | d := Abs(x-p.X) + Abs(y-p.Y) 33 | if d < md { 34 | mp, md = p, d 35 | } else if d == md { 36 | mp = image.Point{MinInt, MinInt} 37 | } 38 | sum += d 39 | } 40 | 41 | if a, ok := points[mp]; ok && a != -1 { 42 | points[mp]++ 43 | if x <= tl.X || y <= tl.Y || x >= br.X || y >= br.Y { 44 | points[mp] = -1 45 | } 46 | } 47 | 48 | if sum < 10000 { 49 | area++ 50 | } 51 | } 52 | } 53 | 54 | max := 0 55 | for _, v := range points { 56 | max = Max(v, max) 57 | } 58 | fmt.Println(max) 59 | fmt.Println(area) 60 | } 61 | 62 | func Abs(x int) int { 63 | if x < 0 { 64 | return -x 65 | } 66 | return x 67 | } 68 | 69 | func Max(x ...int) int { 70 | max := x[0] 71 | for _, v := range x[1:] { 72 | if v > max { 73 | max = v 74 | } 75 | } 76 | return max 77 | } 78 | 79 | func Min(x ...int) int { 80 | min := x[0] 81 | for _, v := range x[1:] { 82 | if v < min { 83 | min = v 84 | } 85 | } 86 | return min 87 | } 88 | -------------------------------------------------------------------------------- /2018/07/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | input, _ := ioutil.ReadFile("input.txt") 11 | 12 | steps := map[rune]map[rune]struct{}{} 13 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 14 | var a, b rune 15 | fmt.Sscanf(s, "Step %c must be finished before step %c can begin.", &a, &b) 16 | if _, ok := steps[a]; !ok { 17 | steps[a] = map[rune]struct{}{} 18 | } 19 | if _, ok := steps[b]; !ok { 20 | steps[b] = map[rune]struct{}{} 21 | } 22 | steps[b][a] = struct{}{} 23 | } 24 | 25 | l := []rune{} 26 | for len(steps) > 0 { 27 | n := 'Z' 28 | for k, v := range steps { 29 | if k < n && len(v) == 0 { 30 | n = k 31 | } 32 | } 33 | delete(steps, n) 34 | l = append(l, n) 35 | for _, v := range steps { 36 | delete(v, n) 37 | } 38 | } 39 | fmt.Println(string(l)) 40 | } 41 | -------------------------------------------------------------------------------- /2018/07/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "sort" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | steps := map[rune]map[rune]struct{}{} 14 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 15 | var a, b rune 16 | fmt.Sscanf(s, "Step %c must be finished before step %c can begin.", &a, &b) 17 | if _, ok := steps[a]; !ok { 18 | steps[a] = map[rune]struct{}{} 19 | } 20 | if _, ok := steps[b]; !ok { 21 | steps[b] = map[rune]struct{}{} 22 | } 23 | steps[b][a] = struct{}{} 24 | } 25 | 26 | workers, seconds := map[rune]int{}, 0 27 | for len(steps) > 0 || len(workers) > 0 { 28 | l := []rune{} 29 | for k, v := range steps { 30 | if _, ok := workers[k]; !ok && len(v) == 0 { 31 | l = append(l, k) 32 | } 33 | } 34 | sort.Slice(l, func(i, j int) bool { return l[i] < l[j] }) 35 | 36 | for len(l) > 0 && len(workers) < 5 { 37 | workers[l[0]] = int(l[0]) - 4 38 | l = l[1:] 39 | } 40 | 41 | for w := range workers { 42 | if workers[w]--; workers[w] == 0 { 43 | delete(steps, w) 44 | for _, v := range steps { 45 | delete(v, w) 46 | } 47 | delete(workers, w) 48 | } 49 | } 50 | seconds++ 51 | } 52 | fmt.Println(seconds) 53 | } 54 | -------------------------------------------------------------------------------- /2018/08/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | type Node struct { 11 | Children []Node 12 | Metadata []int 13 | } 14 | 15 | func process(license []int) (Node, []int) { 16 | n, nc, nm := Node{}, license[0], license[1] 17 | license = license[2:] 18 | for i := 0; i < nc; i++ { 19 | var c Node 20 | c, license = process(license) 21 | n.Children = append(n.Children, c) 22 | } 23 | n.Metadata = license[:nm] 24 | return n, license[nm:] 25 | } 26 | 27 | func sum(tree Node) (s int) { 28 | for _, m := range tree.Metadata { 29 | s += m 30 | } 31 | for _, c := range tree.Children { 32 | s += sum(c) 33 | } 34 | return 35 | } 36 | 37 | func value(tree Node) (v int) { 38 | if len(tree.Children) == 0 { 39 | v = sum(tree) 40 | } else { 41 | for _, m := range tree.Metadata { 42 | if i := m - 1; i >= 0 && i < len(tree.Children) { 43 | v += value(tree.Children[i]) 44 | } 45 | } 46 | } 47 | return 48 | } 49 | 50 | func main() { 51 | input, _ := ioutil.ReadFile("input.txt") 52 | license := []int{} 53 | 54 | for _, s := range strings.Fields(string(input)) { 55 | i, _ := strconv.Atoi(s) 56 | license = append(license, i) 57 | } 58 | 59 | tree, _ := process(license) 60 | fmt.Println(sum(tree)) 61 | fmt.Println(value(tree)) 62 | } 63 | -------------------------------------------------------------------------------- /2018/09/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "container/ring" 5 | "fmt" 6 | "io/ioutil" 7 | ) 8 | 9 | func main() { 10 | input, _ := ioutil.ReadFile("input.txt") 11 | var nplayers, nmarbles int 12 | fmt.Sscanf(string(input), "%d players; last marble is worth %d points", &nplayers, &nmarbles) 13 | marbles := ring.New(1) 14 | marbles.Value = 0 15 | players := make([]int, nplayers) 16 | 17 | max := 0 18 | for i := 1; i <= nmarbles*100; i++ { 19 | if i%23 == 0 { 20 | marbles = marbles.Move(-6) 21 | players[i%len(players)] += i + marbles.Move(-2).Link(marbles).Value.(int) 22 | if players[i%len(players)] > max { 23 | max = players[i%len(players)] 24 | } 25 | } else { 26 | marbles = marbles.Next().Link(ring.New(1)).Prev() 27 | marbles.Value = i 28 | } 29 | if i == nmarbles { 30 | fmt.Println(max) 31 | } 32 | } 33 | fmt.Println(max) 34 | } 35 | -------------------------------------------------------------------------------- /2018/10/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strings" 8 | ) 9 | 10 | type Light struct { 11 | Pos image.Point 12 | Vel image.Point 13 | } 14 | 15 | const MaxInt = int(^uint(0) >> 1) 16 | const MinInt = -MaxInt - 1 17 | 18 | func main() { 19 | input, _ := ioutil.ReadFile("input.txt") 20 | 21 | lights := []Light{} 22 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 23 | l := Light{} 24 | fmt.Sscanf(s, "position=<%d, %d> velocity=<%d, %d>", &l.Pos.X, &l.Pos.Y, &l.Vel.X, &l.Vel.Y) 25 | lights = append(lights, l) 26 | } 27 | 28 | seconds := 0 29 | for { 30 | tl, br := image.Point{MaxInt, MaxInt}, image.Point{MinInt, MinInt} 31 | points := map[image.Point]struct{}{} 32 | for i := range lights { 33 | p := lights[i].Pos.Add(lights[i].Vel) 34 | lights[i].Pos = p 35 | tl, br = image.Point{Min(tl.X, p.X), Min(tl.Y, p.Y)}, image.Point{Max(br.X, p.X), Max(br.Y, p.Y)} 36 | points[p] = struct{}{} 37 | } 38 | seconds++ 39 | if br.Y-tl.Y <= 9 { 40 | for y := tl.Y; y <= br.Y; y++ { 41 | for x := tl.X; x <= br.X; x++ { 42 | _, ok := points[image.Point{x, y}] 43 | fmt.Print(map[bool]string{true: "#", false: " "}[ok]) 44 | } 45 | fmt.Println() 46 | } 47 | fmt.Println(seconds) 48 | break 49 | } 50 | } 51 | } 52 | 53 | func Max(x ...int) int { 54 | max := x[0] 55 | for _, v := range x[1:] { 56 | if v > max { 57 | max = v 58 | } 59 | } 60 | return max 61 | } 62 | 63 | func Min(x ...int) int { 64 | min := x[0] 65 | for _, v := range x[1:] { 66 | if v < min { 67 | min = v 68 | } 69 | } 70 | return min 71 | } 72 | -------------------------------------------------------------------------------- /2018/11/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | const serial, size = 7803, 300 6 | 7 | func main() { 8 | var cells [size + 1][size + 1]int 9 | for y := 1; y <= size; y++ { 10 | for x := 1; x <= size; x++ { 11 | cells[y][x] = ((x+10)*y+serial)*(x+10)/100%10 - 5 + cells[y-1][x] + cells[y][x-1] - cells[y-1][x-1] 12 | } 13 | } 14 | 15 | var p1m, p1x, p1y int 16 | var p2m, p2x, p2y, p2s int 17 | for y := 1; y <= size; y++ { 18 | for x := 1; x <= size; x++ { 19 | for s := 1; x+s <= size && y+s <= size; s++ { 20 | sum := cells[y+s-1][x+s-1] + cells[y-1][x-1] - cells[y-1][x+s-1] - cells[y+s-1][x-1] 21 | if s == 3 && sum > p1m { 22 | p1m, p1x, p1y = sum, x, y 23 | } 24 | if sum > p2m { 25 | p2m, p2x, p2y, p2s = sum, x, y, s 26 | } 27 | } 28 | } 29 | } 30 | fmt.Printf("%d,%d\n", p1x, p1y) 31 | fmt.Printf("%d,%d,%d\n", p2x, p2y, p2s) 32 | } 33 | -------------------------------------------------------------------------------- /2018/12/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | file, _ := os.Open("input.txt") 11 | 12 | var state string 13 | fmt.Fscanf(file, "initial state: %s\n\n", &state) 14 | 15 | notes := map[string]rune{} 16 | for { 17 | var k string 18 | var v rune 19 | n, _ := fmt.Fscanf(file, "%s => %c\n", &k, &v) 20 | if n < 2 { 21 | break 22 | } 23 | notes[k] = v 24 | } 25 | 26 | seen := map[string]int{} 27 | for g := 1; ; g++ { 28 | state = "....." + state + "....." 29 | 30 | new := []rune(state) 31 | for i := 2; i < len(state)-2; i++ { 32 | new[i] = notes[state[i-2:i+3]] 33 | } 34 | state = string(new) 35 | 36 | sum := 0 37 | for i, r := range state { 38 | if r == '#' { 39 | sum += i - (g * 5) 40 | } 41 | } 42 | 43 | if g == 20 { 44 | fmt.Println(sum) 45 | } 46 | if prev, ok := seen[strings.Trim(state, ".")]; ok { 47 | fmt.Println(sum + (sum-prev)*(50000000000-g)) 48 | break 49 | } 50 | seen[strings.Trim(state, ".")] = sum 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /2018/13/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "sort" 8 | "strings" 9 | ) 10 | 11 | type Cart struct { 12 | Dir int 13 | State int 14 | } 15 | 16 | func main() { 17 | input, _ := ioutil.ReadFile("input.txt") 18 | grid := strings.Split(strings.TrimRight(string(input), "\n"), "\n") 19 | 20 | carts := map[image.Point]Cart{} 21 | for y, s := range grid { 22 | for x, r := range s { 23 | if p, ok := map[rune]int{'^': 0, '>': 1, 'v': 2, '<': 3}[r]; ok { 24 | carts[image.Point{x, y}] = Cart{Dir: p} 25 | } 26 | } 27 | } 28 | 29 | var firstCrash *image.Point 30 | for len(carts) > 1 { 31 | ks := []image.Point{} 32 | for p := range carts { 33 | ks = append(ks, p) 34 | } 35 | sort.Slice(ks, func(i, j int) bool { 36 | return ks[i].Y < ks[j].Y || ks[i].Y == ks[j].Y && ks[i].X < ks[j].X 37 | }) 38 | 39 | for _, p := range ks { 40 | nc, ok := carts[p] 41 | if !ok { 42 | continue 43 | } 44 | delete(carts, p) 45 | 46 | np := p.Add([]image.Point{{0, -1}, {1, 0}, {0, 1}, {-1, 0}}[nc.Dir]) 47 | if _, ok := carts[np]; ok { 48 | if firstCrash == nil { 49 | firstCrash = &np 50 | } 51 | delete(carts, np) 52 | continue 53 | } 54 | 55 | switch grid[np.Y][np.X] { 56 | case '/': 57 | nc.Dir = []int{1, 0, 3, 2}[nc.Dir] 58 | case '\\': 59 | nc.Dir = []int{3, 2, 1, 0}[nc.Dir] 60 | case '+': 61 | nc.Dir = (nc.Dir + 3 + nc.State) % 4 62 | nc.State = (nc.State + 1) % 3 63 | } 64 | carts[np] = nc 65 | } 66 | } 67 | 68 | fmt.Printf("%d,%d\n", firstCrash.X, firstCrash.Y) 69 | for p := range carts { 70 | fmt.Printf("%d,%d\n", p.X, p.Y) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /2018/14/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | const input = 909441 10 | 11 | func main() { 12 | instr := strconv.Itoa(input) 13 | elf1, elf2 := 0, 1 14 | 15 | scores := []byte{'3', '7'} 16 | for len(scores) < len(instr) || string(scores[len(scores)-len(instr):]) != instr { 17 | scores = append(scores, []byte(strconv.Itoa(int(scores[elf1]-'0'+scores[elf2]-'0')))...) 18 | elf1 = (elf1 + 1 + int(scores[elf1]-'0')) % len(scores) 19 | elf2 = (elf2 + 1 + int(scores[elf2]-'0')) % len(scores) 20 | } 21 | fmt.Println(string(scores[input : input+10])) 22 | fmt.Println(strings.Index(string(scores), instr)) 23 | } 24 | -------------------------------------------------------------------------------- /2019/01/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "strconv" 8 | ) 9 | 10 | func main() { 11 | file, _ := os.Open("input.txt") 12 | scanner := bufio.NewScanner(file) 13 | total := 0 14 | 15 | for scanner.Scan() { 16 | mass, _ := strconv.Atoi(scanner.Text()) 17 | total += mass/3 - 2 18 | } 19 | 20 | fmt.Println(total) 21 | } 22 | -------------------------------------------------------------------------------- /2019/01/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "strconv" 8 | ) 9 | 10 | func fuel(mass int) int { 11 | return mass/3 - 2 12 | } 13 | 14 | func main() { 15 | file, _ := os.Open("input.txt") 16 | scanner := bufio.NewScanner(file) 17 | total := 0 18 | 19 | for scanner.Scan() { 20 | mass, _ := strconv.Atoi(scanner.Text()) 21 | 22 | for f := fuel(mass); f > 0; f = fuel(f) { 23 | total += f 24 | } 25 | } 26 | 27 | fmt.Println(total) 28 | } 29 | -------------------------------------------------------------------------------- /2019/02/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | split := strings.Split(string(input), ",") 13 | mem := make([]int, len(split)) 14 | 15 | for i, s := range split { 16 | mem[i], _ = strconv.Atoi(s) 17 | } 18 | 19 | mem[1], mem[2] = 12, 2 20 | 21 | for i := 0; i < len(mem); i += 4 { 22 | switch mem[i] { 23 | case 1: 24 | mem[mem[i+3]] = mem[mem[i+1]] + mem[mem[i+2]] 25 | case 2: 26 | mem[mem[i+3]] = mem[mem[i+1]] * mem[mem[i+2]] 27 | case 99: 28 | fmt.Println(mem[0]) 29 | i = len(mem) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /2019/02/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | split := strings.Split(string(input), ",") 13 | 14 | for n := 0; n <= 99; n++ { 15 | for v := 0; v <= 99; v++ { 16 | mem := make([]int, len(split)) 17 | 18 | for i, s := range split { 19 | mem[i], _ = strconv.Atoi(s) 20 | } 21 | 22 | mem[1], mem[2] = n, v 23 | 24 | for i := 0; i < len(mem); i += 4 { 25 | switch mem[i] { 26 | case 1: 27 | mem[mem[i+3]] = mem[mem[i+1]] + mem[mem[i+2]] 28 | case 2: 29 | mem[mem[i+3]] = mem[mem[i+1]] * mem[mem[i+2]] 30 | case 99: 31 | if mem[0] == 19690720 { 32 | fmt.Println(100*n + v) 33 | } 34 | i = len(mem) 35 | } 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /2019/03/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "math" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | func main() { 13 | input, _ := ioutil.ReadFile("input.txt") 14 | wires := strings.Fields(string(input)) 15 | seen := make([]map[image.Point]struct{}, len(wires)) 16 | min := 0 17 | 18 | for i, w := range wires { 19 | x, y := 0, 0 20 | seen[i] = map[image.Point]struct{}{} 21 | 22 | for _, s := range strings.Split(w, ",") { 23 | for j, _ := strconv.Atoi(s[1:]); j > 0; j-- { 24 | d := map[byte]image.Point{'U': {0, -1}, 'D': {0, 1}, 'L': {-1, 0}, 'R': {1, 0}}[s[0]] 25 | x, y = x+d.X, y+d.Y 26 | seen[i][image.Point{x, y}] = struct{}{} 27 | } 28 | } 29 | } 30 | 31 | for p := range seen[1] { 32 | if _, ok := seen[0][p]; ok { 33 | dist := int(math.Abs(float64(p.X)) + math.Abs(float64(p.Y))) 34 | if min == 0 || dist < min { 35 | min = dist 36 | } 37 | } 38 | } 39 | 40 | fmt.Println(min) 41 | } 42 | -------------------------------------------------------------------------------- /2019/03/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := ioutil.ReadFile("input.txt") 13 | wires := strings.Fields(string(input)) 14 | seen := make([]map[image.Point]int, len(wires)) 15 | min := 0 16 | 17 | for i, w := range wires { 18 | x, y := 0, 0 19 | steps := 0 20 | seen[i] = map[image.Point]int{} 21 | 22 | for _, s := range strings.Split(w, ",") { 23 | for j, _ := strconv.Atoi(s[1:]); j > 0; j-- { 24 | d := map[byte]image.Point{'U': {0, -1}, 'D': {0, 1}, 'L': {-1, 0}, 'R': {1, 0}}[s[0]] 25 | x, y = x+d.X, y+d.Y 26 | steps++ 27 | seen[i][image.Point{x, y}] = steps 28 | } 29 | } 30 | } 31 | 32 | for p := range seen[1] { 33 | if _, ok := seen[0][p]; ok { 34 | steps := seen[0][p] + seen[1][p] 35 | if min == 0 || steps < min { 36 | min = steps 37 | } 38 | } 39 | } 40 | 41 | fmt.Println(min) 42 | } 43 | -------------------------------------------------------------------------------- /2019/04/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | ) 7 | 8 | func main() { 9 | valid := 0 10 | 11 | passLoop: 12 | for i := 240298; i <= 784956; i++ { 13 | str := strconv.Itoa(i) 14 | count := map[byte]int{str[0]: 1} 15 | 16 | for i := 1; i < len(str); i++ { 17 | if str[i-1] > str[i] { 18 | continue passLoop 19 | } 20 | count[str[i]]++ 21 | } 22 | 23 | for _, v := range count { 24 | if v >= 2 { 25 | valid++ 26 | break 27 | } 28 | } 29 | } 30 | 31 | fmt.Println(valid) 32 | } 33 | -------------------------------------------------------------------------------- /2019/04/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | ) 7 | 8 | func main() { 9 | valid := 0 10 | 11 | passLoop: 12 | for i := 240298; i <= 784956; i++ { 13 | str := strconv.Itoa(i) 14 | count := map[byte]int{str[0]: 1} 15 | 16 | for i := 1; i < len(str); i++ { 17 | if str[i-1] > str[i] { 18 | continue passLoop 19 | } 20 | count[str[i]]++ 21 | } 22 | 23 | for _, v := range count { 24 | if v == 2 { 25 | valid++ 26 | break 27 | } 28 | } 29 | } 30 | 31 | fmt.Println(valid) 32 | } 33 | -------------------------------------------------------------------------------- /2019/05/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | split := strings.Split(strings.TrimSpace(string(input)), ",") 13 | mem := make([]int, len(split)) 14 | ip := 0 15 | 16 | for i, s := range split { 17 | mem[i], _ = strconv.Atoi(s) 18 | } 19 | 20 | for { 21 | ins := fmt.Sprintf("%05d", mem[ip]) 22 | op, _ := strconv.Atoi(ins[3:]) 23 | arg := func(i int) int { 24 | if ins[3-i] == '0' { 25 | return mem[mem[ip+i]] 26 | } 27 | return mem[ip+i] 28 | } 29 | 30 | switch op { 31 | case 1: 32 | mem[mem[ip+3]] = arg(1) + arg(2) 33 | case 2: 34 | mem[mem[ip+3]] = arg(1) * arg(2) 35 | case 3: 36 | fmt.Scan(&mem[mem[ip+1]]) 37 | case 4: 38 | fmt.Println(arg(1)) 39 | case 5: 40 | if arg(1) != 0 { 41 | ip = arg(2) 42 | continue 43 | } 44 | case 6: 45 | if arg(1) == 0 { 46 | ip = arg(2) 47 | continue 48 | } 49 | case 7: 50 | if arg(1) < arg(2) { 51 | mem[mem[ip+3]] = 1 52 | } else { 53 | mem[mem[ip+3]] = 0 54 | } 55 | case 8: 56 | if arg(1) == arg(2) { 57 | mem[mem[ip+3]] = 1 58 | } else { 59 | mem[mem[ip+3]] = 0 60 | } 61 | case 99: 62 | return 63 | } 64 | 65 | ip += []int{1, 4, 4, 2, 2, 3, 3, 4, 4}[op] 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /2019/06/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | file, _ := os.Open("input.txt") 12 | scanner := bufio.NewScanner(file) 13 | orbits := map[string]string{} 14 | total := 0 15 | 16 | for scanner.Scan() { 17 | obj := strings.Split(scanner.Text(), ")") 18 | orbits[obj[1]] = obj[0] 19 | } 20 | 21 | for o := range orbits { 22 | for o, ok := orbits[o]; ok; o, ok = orbits[o] { 23 | total++ 24 | } 25 | } 26 | 27 | fmt.Println(total) 28 | } 29 | -------------------------------------------------------------------------------- /2019/06/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | file, _ := os.Open("input.txt") 12 | scanner := bufio.NewScanner(file) 13 | orbits := map[string]string{} 14 | 15 | for scanner.Scan() { 16 | objs := strings.Split(scanner.Text(), ")") 17 | orbits[objs[1]] = objs[0] 18 | } 19 | 20 | you := map[string]int{} 21 | for o, ok := orbits["YOU"]; ok; o, ok = orbits[o] { 22 | you[o] = len(you) 23 | } 24 | 25 | san := 0 26 | for o, ok := orbits["SAN"]; ok; o, ok = orbits[o] { 27 | if _, ok := you[o]; ok { 28 | fmt.Println(san + you[o]) 29 | break 30 | } 31 | san++ 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /2019/07/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "math" 7 | "strconv" 8 | "strings" 9 | "sync" 10 | ) 11 | 12 | func main() { 13 | input, _ := ioutil.ReadFile("input.txt") 14 | split := strings.Split(strings.TrimSpace(string(input)), ",") 15 | seq := []int{0, 1, 2, 3, 4} 16 | 17 | mem := make([]int, len(split)) 18 | for i, s := range split { 19 | mem[i], _ = strconv.Atoi(s) 20 | } 21 | 22 | max := 0 23 | for _, p := range perms(seq) { 24 | chans := make([]chan int, len(seq)) 25 | for i := range seq { 26 | chans[i] = make(chan int, 1) 27 | } 28 | 29 | var wg sync.WaitGroup 30 | for i, v := range p { 31 | wg.Add(1) 32 | go run(append([]int(nil), mem...), chans[i], chans[(i+1)%len(seq)], &wg) 33 | chans[i] <- v 34 | } 35 | 36 | chans[0] <- 0 37 | wg.Wait() 38 | max = int(math.Max(float64(<-chans[0]), float64(max))) 39 | } 40 | 41 | fmt.Println(max) 42 | } 43 | 44 | func run(mem []int, in <-chan int, out chan<- int, wg *sync.WaitGroup) { 45 | ip := 0 46 | 47 | for { 48 | ins := fmt.Sprintf("%05d", mem[ip]) 49 | op, _ := strconv.Atoi(ins[3:]) 50 | par := func(i int) int { 51 | if ins[3-i] == '0' { 52 | return mem[mem[ip+i]] 53 | } 54 | return mem[ip+i] 55 | } 56 | 57 | switch op { 58 | case 1: 59 | mem[mem[ip+3]] = par(1) + par(2) 60 | case 2: 61 | mem[mem[ip+3]] = par(1) * par(2) 62 | case 3: 63 | mem[mem[ip+1]] = <-in 64 | case 4: 65 | out <- par(1) 66 | case 5: 67 | if par(1) != 0 { 68 | ip = par(2) 69 | continue 70 | } 71 | case 6: 72 | if par(1) == 0 { 73 | ip = par(2) 74 | continue 75 | } 76 | case 7: 77 | if par(1) < par(2) { 78 | mem[mem[ip+3]] = 1 79 | } else { 80 | mem[mem[ip+3]] = 0 81 | } 82 | case 8: 83 | if par(1) == par(2) { 84 | mem[mem[ip+3]] = 1 85 | } else { 86 | mem[mem[ip+3]] = 0 87 | } 88 | case 99: 89 | wg.Done() 90 | return 91 | } 92 | 93 | ip += []int{1, 4, 4, 2, 2, 3, 3, 4, 4}[op] 94 | } 95 | } 96 | 97 | func perms(ints []int) [][]int { 98 | out := [][]int{} 99 | 100 | if len(ints) == 1 { 101 | return [][]int{ints} 102 | } 103 | 104 | for i := range ints { 105 | c := append([]int(nil), ints...) 106 | for _, p := range perms(append(c[:i], c[i+1:]...)) { 107 | out = append(out, append([]int{ints[i]}, p...)) 108 | } 109 | } 110 | 111 | return out 112 | } 113 | -------------------------------------------------------------------------------- /2019/07/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "math" 7 | "strconv" 8 | "strings" 9 | "sync" 10 | ) 11 | 12 | func main() { 13 | input, _ := ioutil.ReadFile("input.txt") 14 | split := strings.Split(strings.TrimSpace(string(input)), ",") 15 | seq := []int{5, 6, 7, 8, 9} 16 | 17 | mem := make([]int, len(split)) 18 | for i, s := range split { 19 | mem[i], _ = strconv.Atoi(s) 20 | } 21 | 22 | max := 0 23 | for _, p := range perms(seq) { 24 | chans := make([]chan int, len(seq)) 25 | for i := range seq { 26 | chans[i] = make(chan int, 1) 27 | } 28 | 29 | var wg sync.WaitGroup 30 | for i, v := range p { 31 | wg.Add(1) 32 | go run(append([]int(nil), mem...), chans[i], chans[(i+1)%len(seq)], &wg) 33 | chans[i] <- v 34 | } 35 | 36 | chans[0] <- 0 37 | wg.Wait() 38 | max = int(math.Max(float64(<-chans[0]), float64(max))) 39 | } 40 | 41 | fmt.Println(max) 42 | } 43 | 44 | func run(mem []int, in <-chan int, out chan<- int, wg *sync.WaitGroup) { 45 | ip := 0 46 | 47 | for { 48 | ins := fmt.Sprintf("%05d", mem[ip]) 49 | op, _ := strconv.Atoi(ins[3:]) 50 | par := func(i int) int { 51 | if ins[3-i] == '0' { 52 | return mem[mem[ip+i]] 53 | } 54 | return mem[ip+i] 55 | } 56 | 57 | switch op { 58 | case 1: 59 | mem[mem[ip+3]] = par(1) + par(2) 60 | case 2: 61 | mem[mem[ip+3]] = par(1) * par(2) 62 | case 3: 63 | mem[mem[ip+1]] = <-in 64 | case 4: 65 | out <- par(1) 66 | case 5: 67 | if par(1) != 0 { 68 | ip = par(2) 69 | continue 70 | } 71 | case 6: 72 | if par(1) == 0 { 73 | ip = par(2) 74 | continue 75 | } 76 | case 7: 77 | if par(1) < par(2) { 78 | mem[mem[ip+3]] = 1 79 | } else { 80 | mem[mem[ip+3]] = 0 81 | } 82 | case 8: 83 | if par(1) == par(2) { 84 | mem[mem[ip+3]] = 1 85 | } else { 86 | mem[mem[ip+3]] = 0 87 | } 88 | case 99: 89 | wg.Done() 90 | return 91 | } 92 | 93 | ip += []int{1, 4, 4, 2, 2, 3, 3, 4, 4}[op] 94 | } 95 | } 96 | 97 | func perms(ints []int) [][]int { 98 | out := [][]int{} 99 | 100 | if len(ints) == 1 { 101 | return [][]int{ints} 102 | } 103 | 104 | for i := range ints { 105 | c := append([]int(nil), ints...) 106 | for _, p := range perms(append(c[:i], c[i+1:]...)) { 107 | out = append(out, append([]int{ints[i]}, p...)) 108 | } 109 | } 110 | 111 | return out 112 | } 113 | -------------------------------------------------------------------------------- /2019/08/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | input, _ := ioutil.ReadFile("input.txt") 11 | str := strings.TrimSpace(string(input)) 12 | w, h := 25, 6 13 | count := make([]map[rune]int, len(str)/(w*h)) 14 | min := 0 15 | 16 | for l := range count { 17 | count[l] = map[rune]int{} 18 | 19 | for _, r := range str[l*w*h : (l+1)*w*h] { 20 | count[l][r]++ 21 | } 22 | 23 | if count[l]['0'] < count[min]['0'] { 24 | min = l 25 | } 26 | } 27 | 28 | fmt.Println(count[min]['1'] * count[min]['2']) 29 | } 30 | -------------------------------------------------------------------------------- /2019/08/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | input, _ := ioutil.ReadFile("input.txt") 11 | str := strings.TrimSpace(string(input)) 12 | w, h := 25, 6 13 | 14 | for y := 0; y < h; y++ { 15 | for x := 0; x < w; x++ { 16 | for l := 0; l < len(str)/(w*h); l++ { 17 | if r := str[l*w*h+y*w+x]; r != '2' { 18 | fmt.Print(map[byte]string{'0': " ", '1': "██"}[r]) 19 | break 20 | } 21 | } 22 | } 23 | fmt.Println() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /2019/09/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | split := strings.Split(strings.TrimSpace(string(input)), ",") 13 | mem := map[int]int{} 14 | ip, rb := 0, 0 15 | 16 | for i, s := range split { 17 | mem[i], _ = strconv.Atoi(s) 18 | } 19 | 20 | for { 21 | ins := fmt.Sprintf("%05d", mem[ip]) 22 | op, _ := strconv.Atoi(ins[3:]) 23 | par := func(i int) int { 24 | switch ins[3-i] { 25 | case '1': 26 | return ip + i 27 | case '2': 28 | return rb + mem[ip+i] 29 | default: 30 | return mem[ip+i] 31 | } 32 | } 33 | 34 | switch op { 35 | case 1: 36 | mem[par(3)] = mem[par(1)] + mem[par(2)] 37 | case 2: 38 | mem[par(3)] = mem[par(1)] * mem[par(2)] 39 | case 3: 40 | var i int 41 | fmt.Scan(&i) 42 | mem[par(1)] = i 43 | case 4: 44 | fmt.Println(mem[par(1)]) 45 | case 5: 46 | if mem[par(1)] != 0 { 47 | ip = mem[par(2)] 48 | continue 49 | } 50 | case 6: 51 | if mem[par(1)] == 0 { 52 | ip = mem[par(2)] 53 | continue 54 | } 55 | case 7: 56 | if mem[par(1)] < mem[par(2)] { 57 | mem[par(3)] = 1 58 | } else { 59 | mem[par(3)] = 0 60 | } 61 | case 8: 62 | if mem[par(1)] == mem[par(2)] { 63 | mem[par(3)] = 1 64 | } else { 65 | mem[par(3)] = 0 66 | } 67 | case 9: 68 | rb += mem[par(1)] 69 | case 99: 70 | return 71 | } 72 | 73 | ip += []int{1, 4, 4, 2, 2, 3, 3, 4, 4, 2}[op] 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /2019/10/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "math" 8 | "sort" 9 | "strings" 10 | ) 11 | 12 | func main() { 13 | input, _ := ioutil.ReadFile("input.txt") 14 | asteroids := []image.Point{} 15 | bucket := map[float64][]image.Point{} 16 | station := image.Point{} 17 | 18 | for y, s := range strings.Fields(string(input)) { 19 | for x, r := range s { 20 | if r == '#' { 21 | asteroids = append(asteroids, image.Point{x, y}) 22 | } 23 | } 24 | } 25 | 26 | for _, s := range asteroids { 27 | b := map[float64][]image.Point{} 28 | for _, a := range asteroids { 29 | if a != s { 30 | angle := -math.Atan2(float64(a.X-s.X), float64(a.Y-s.Y)) 31 | b[angle] = append(b[angle], a) 32 | } 33 | } 34 | if len(b) > len(bucket) { 35 | bucket = b 36 | station = s 37 | } 38 | } 39 | fmt.Println(len(bucket)) 40 | 41 | for a := range bucket { 42 | sort.Slice(bucket[a], func(i, j int) bool { 43 | return dist(station, bucket[a][i]) > dist(station, bucket[a][j]) 44 | }) 45 | for len(bucket[a]) > 1 { 46 | i := a + 2*math.Pi*float64(len(bucket[a])-1) 47 | bucket[i] = append(bucket[i], bucket[a][0]) 48 | bucket[a] = bucket[a][1:] 49 | } 50 | } 51 | 52 | angles := []float64{} 53 | for a := range bucket { 54 | angles = append(angles, a) 55 | } 56 | sort.Float64s(angles) 57 | fmt.Println(100*bucket[angles[199]][0].X + bucket[angles[199]][0].Y) 58 | } 59 | 60 | func dist(a, b image.Point) float64 { 61 | return math.Sqrt(math.Pow(float64(b.X-a.X), 2) + math.Pow(float64(b.Y-a.Y), 2)) 62 | } 63 | -------------------------------------------------------------------------------- /2019/11/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := ioutil.ReadFile("input.txt") 13 | split := strings.Split(strings.TrimSpace(string(input)), ",") 14 | 15 | mem := map[int]int{} 16 | for i, s := range split { 17 | mem[i], _ = strconv.Atoi(s) 18 | } 19 | 20 | in, out := make(chan int, 1), make(chan int) 21 | go run(mem, in, out) 22 | hull := map[image.Point]int{} 23 | pos, dir := image.Point{}, 0 24 | 25 | in <- 0 26 | for hull[pos] = range out { 27 | dir = (dir + 2*<-out + 1) % 4 28 | pos = pos.Add([]image.Point{{0, -1}, {-1, 0}, {0, 1}, {1, 0}}[dir]) 29 | in <- hull[pos] 30 | } 31 | 32 | fmt.Println(len(hull)) 33 | } 34 | 35 | func run(mem map[int]int, in <-chan int, out chan<- int) { 36 | ip, rb := 0, 0 37 | 38 | for { 39 | ins := fmt.Sprintf("%05d", mem[ip]) 40 | op, _ := strconv.Atoi(ins[3:]) 41 | par := func(i int) int { 42 | switch ins[3-i] { 43 | case '1': 44 | return ip + i 45 | case '2': 46 | return rb + mem[ip+i] 47 | default: 48 | return mem[ip+i] 49 | } 50 | } 51 | 52 | switch op { 53 | case 1: 54 | mem[par(3)] = mem[par(1)] + mem[par(2)] 55 | case 2: 56 | mem[par(3)] = mem[par(1)] * mem[par(2)] 57 | case 3: 58 | mem[par(1)] = <-in 59 | case 4: 60 | out <- mem[par(1)] 61 | case 5: 62 | if mem[par(1)] != 0 { 63 | ip = mem[par(2)] 64 | continue 65 | } 66 | case 6: 67 | if mem[par(1)] == 0 { 68 | ip = mem[par(2)] 69 | continue 70 | } 71 | case 7: 72 | if mem[par(1)] < mem[par(2)] { 73 | mem[par(3)] = 1 74 | } else { 75 | mem[par(3)] = 0 76 | } 77 | case 8: 78 | if mem[par(1)] == mem[par(2)] { 79 | mem[par(3)] = 1 80 | } else { 81 | mem[par(3)] = 0 82 | } 83 | case 9: 84 | rb += mem[par(1)] 85 | case 99: 86 | close(out) 87 | return 88 | } 89 | 90 | ip += []int{1, 4, 4, 2, 2, 3, 3, 4, 4, 2}[op] 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /2019/11/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := ioutil.ReadFile("input.txt") 13 | split := strings.Split(strings.TrimSpace(string(input)), ",") 14 | 15 | mem := map[int]int{} 16 | for i, s := range split { 17 | mem[i], _ = strconv.Atoi(s) 18 | } 19 | 20 | in, out := make(chan int, 1), make(chan int) 21 | go run(mem, in, out) 22 | hull := map[image.Point]int{} 23 | pos, dir := image.Point{}, 0 24 | 25 | in <- 1 26 | for hull[pos] = range out { 27 | dir = (dir + 2*<-out + 1) % 4 28 | pos = pos.Add([]image.Point{{0, -1}, {-1, 0}, {0, 1}, {1, 0}}[dir]) 29 | in <- hull[pos] 30 | } 31 | 32 | for y := 0; y < 6; y++ { 33 | for x := 0; x < 50; x++ { 34 | fmt.Print([]string{" ", "██"}[hull[image.Point{x, y}]]) 35 | } 36 | fmt.Println() 37 | } 38 | } 39 | 40 | func run(mem map[int]int, in <-chan int, out chan<- int) { 41 | ip, rb := 0, 0 42 | 43 | for { 44 | ins := fmt.Sprintf("%05d", mem[ip]) 45 | op, _ := strconv.Atoi(ins[3:]) 46 | par := func(i int) int { 47 | switch ins[3-i] { 48 | case '1': 49 | return ip + i 50 | case '2': 51 | return rb + mem[ip+i] 52 | default: 53 | return mem[ip+i] 54 | } 55 | } 56 | 57 | switch op { 58 | case 1: 59 | mem[par(3)] = mem[par(1)] + mem[par(2)] 60 | case 2: 61 | mem[par(3)] = mem[par(1)] * mem[par(2)] 62 | case 3: 63 | mem[par(1)] = <-in 64 | case 4: 65 | out <- mem[par(1)] 66 | case 5: 67 | if mem[par(1)] != 0 { 68 | ip = mem[par(2)] 69 | continue 70 | } 71 | case 6: 72 | if mem[par(1)] == 0 { 73 | ip = mem[par(2)] 74 | continue 75 | } 76 | case 7: 77 | if mem[par(1)] < mem[par(2)] { 78 | mem[par(3)] = 1 79 | } else { 80 | mem[par(3)] = 0 81 | } 82 | case 8: 83 | if mem[par(1)] == mem[par(2)] { 84 | mem[par(3)] = 1 85 | } else { 86 | mem[par(3)] = 0 87 | } 88 | case 9: 89 | rb += mem[par(1)] 90 | case 99: 91 | close(out) 92 | return 93 | } 94 | 95 | ip += []int{1, 4, 4, 2, 2, 3, 3, 4, 4, 2}[op] 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /2019/12/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "math" 7 | "strings" 8 | ) 9 | 10 | type Moon struct { 11 | P [3]int 12 | V [3]int 13 | } 14 | 15 | func main() { 16 | input, _ := ioutil.ReadFile("input.txt") 17 | moons := []Moon{} 18 | 19 | for i, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 20 | moons = append(moons, Moon{}) 21 | fmt.Sscanf(s, "", &moons[i].P[0], &moons[i].P[1], &moons[i].P[2]) 22 | } 23 | 24 | for s := 0; s < 1000; s++ { 25 | for i := 0; i < 3; i++ { 26 | for m1 := range moons { 27 | for m2 := range moons { 28 | if moons[m1].P[i] < moons[m2].P[i] { 29 | moons[m1].V[i]++ 30 | } else if moons[m1].P[i] > moons[m2].P[i] { 31 | moons[m1].V[i]-- 32 | } 33 | } 34 | } 35 | 36 | for m := range moons { 37 | moons[m].P[i] += moons[m].V[i] 38 | } 39 | } 40 | } 41 | 42 | energy := 0 43 | for m := range moons { 44 | for i := range moons[m].P { 45 | for j := range moons[m].V { 46 | energy += int(math.Abs(float64(moons[m].P[i] * moons[m].V[j]))) 47 | } 48 | } 49 | } 50 | 51 | fmt.Println(energy) 52 | } 53 | -------------------------------------------------------------------------------- /2019/12/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strings" 7 | ) 8 | 9 | type Moon struct { 10 | P [3]int 11 | V [3]int 12 | } 13 | 14 | func main() { 15 | input, _ := ioutil.ReadFile("input.txt") 16 | moons := []Moon{} 17 | 18 | for i, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 19 | moons = append(moons, Moon{}) 20 | fmt.Sscanf(s, "", &moons[i].P[0], &moons[i].P[1], &moons[i].P[2]) 21 | } 22 | 23 | init := append([]Moon(nil), moons...) 24 | period := make([]int, 3) 25 | for s := 1; period[0] == 0 || period[1] == 0 || period[2] == 0; s++ { 26 | for i := range period { 27 | for m1 := range moons { 28 | for m2 := range moons { 29 | if moons[m1].P[i] < moons[m2].P[i] { 30 | moons[m1].V[i]++ 31 | } else if moons[m1].P[i] > moons[m2].P[i] { 32 | moons[m1].V[i]-- 33 | } 34 | } 35 | } 36 | 37 | for m := range moons { 38 | moons[m].P[i] += moons[m].V[i] 39 | } 40 | 41 | if period[i] == 0 { 42 | for m := range moons { 43 | if moons[m].V[i] != init[m].V[i] { 44 | break 45 | } 46 | if m == len(moons)-1 { 47 | period[i] = s * 2 48 | } 49 | } 50 | } 51 | } 52 | } 53 | 54 | fmt.Println(lcm(period...)) 55 | } 56 | 57 | func abs(x int) int { 58 | if x < 0 { 59 | return -x 60 | } 61 | return x 62 | } 63 | 64 | func gcd(x ...int) int { 65 | if len(x) == 0 { 66 | return 0 67 | } else if len(x) == 2 { 68 | for x[1] != 0 { 69 | x[0], x[1] = x[1], x[0]%x[1] 70 | } 71 | } else if len(x) > 2 { 72 | return gcd(x[0], gcd(x[1:]...)) 73 | } 74 | return abs(x[0]) 75 | } 76 | 77 | func lcm(x ...int) int { 78 | if len(x) > 2 { 79 | return lcm(x[0], lcm(x[1:]...)) 80 | } else if x[0] == 0 && x[1] == 0 { 81 | return 0 82 | } 83 | return abs(x[0]*x[1]) / gcd(x[0], x[1]) 84 | } 85 | -------------------------------------------------------------------------------- /2019/13/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | split := strings.Split(strings.TrimSpace(string(input)), ",") 13 | mem := map[int]int{} 14 | 15 | for i, s := range split { 16 | mem[i], _ = strconv.Atoi(s) 17 | } 18 | 19 | in, out := make(chan int, 1), make(chan int) 20 | go run(mem, in, out) 21 | count := 0 22 | 23 | for range out { 24 | <-out 25 | if <-out == 2 { 26 | count++ 27 | } 28 | } 29 | 30 | fmt.Println(count) 31 | } 32 | 33 | func run(mem map[int]int, in <-chan int, out chan<- int) { 34 | ip, rb := 0, 0 35 | 36 | for { 37 | ins := fmt.Sprintf("%05d", mem[ip]) 38 | op, _ := strconv.Atoi(ins[3:]) 39 | par := func(i int) int { 40 | switch ins[3-i] { 41 | case '1': 42 | return ip + i 43 | case '2': 44 | return rb + mem[ip+i] 45 | default: 46 | return mem[ip+i] 47 | } 48 | } 49 | 50 | switch op { 51 | case 1: 52 | mem[par(3)] = mem[par(1)] + mem[par(2)] 53 | case 2: 54 | mem[par(3)] = mem[par(1)] * mem[par(2)] 55 | case 3: 56 | mem[par(1)] = <-in 57 | case 4: 58 | out <- mem[par(1)] 59 | case 5: 60 | if mem[par(1)] != 0 { 61 | ip = mem[par(2)] 62 | continue 63 | } 64 | case 6: 65 | if mem[par(1)] == 0 { 66 | ip = mem[par(2)] 67 | continue 68 | } 69 | case 7: 70 | if mem[par(1)] < mem[par(2)] { 71 | mem[par(3)] = 1 72 | } else { 73 | mem[par(3)] = 0 74 | } 75 | case 8: 76 | if mem[par(1)] == mem[par(2)] { 77 | mem[par(3)] = 1 78 | } else { 79 | mem[par(3)] = 0 80 | } 81 | case 9: 82 | rb += mem[par(1)] 83 | case 99: 84 | close(out) 85 | return 86 | } 87 | 88 | ip += []int{1, 4, 4, 2, 2, 3, 3, 4, 4, 2}[op] 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /2019/13/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | split := strings.Split(strings.TrimSpace(string(input)), ",") 13 | mem := map[int]int{} 14 | 15 | for i, s := range split { 16 | mem[i], _ = strconv.Atoi(s) 17 | } 18 | 19 | mem[0] = 2 20 | in, out := make(chan int, 1), make(chan int) 21 | go run(mem, in, out) 22 | paddle := 0 23 | score := 0 24 | 25 | for x := range out { 26 | y := <-out 27 | id := <-out 28 | 29 | if x == -1 && y == 0 { 30 | score = id 31 | } else if id == 3 { 32 | paddle = x 33 | } else if id == 4 { 34 | if paddle < x { 35 | in <- 1 36 | } else if paddle > x { 37 | in <- -1 38 | } else { 39 | in <- 0 40 | } 41 | } 42 | } 43 | 44 | fmt.Println(score) 45 | } 46 | 47 | func run(mem map[int]int, in <-chan int, out chan<- int) { 48 | ip, rb := 0, 0 49 | 50 | for { 51 | ins := fmt.Sprintf("%05d", mem[ip]) 52 | op, _ := strconv.Atoi(ins[3:]) 53 | par := func(i int) int { 54 | switch ins[3-i] { 55 | case '1': 56 | return ip + i 57 | case '2': 58 | return rb + mem[ip+i] 59 | default: 60 | return mem[ip+i] 61 | } 62 | } 63 | 64 | switch op { 65 | case 1: 66 | mem[par(3)] = mem[par(1)] + mem[par(2)] 67 | case 2: 68 | mem[par(3)] = mem[par(1)] * mem[par(2)] 69 | case 3: 70 | mem[par(1)] = <-in 71 | case 4: 72 | out <- mem[par(1)] 73 | case 5: 74 | if mem[par(1)] != 0 { 75 | ip = mem[par(2)] 76 | continue 77 | } 78 | case 6: 79 | if mem[par(1)] == 0 { 80 | ip = mem[par(2)] 81 | continue 82 | } 83 | case 7: 84 | if mem[par(1)] < mem[par(2)] { 85 | mem[par(3)] = 1 86 | } else { 87 | mem[par(3)] = 0 88 | } 89 | case 8: 90 | if mem[par(1)] == mem[par(2)] { 91 | mem[par(3)] = 1 92 | } else { 93 | mem[par(3)] = 0 94 | } 95 | case 9: 96 | rb += mem[par(1)] 97 | case 99: 98 | close(out) 99 | return 100 | } 101 | 102 | ip += []int{1, 4, 4, 2, 2, 3, 3, 4, 4, 2}[op] 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /2019/14/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "sort" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | type Reac struct { 12 | Out int 13 | In map[string]int 14 | } 15 | 16 | func main() { 17 | input, _ := ioutil.ReadFile("input.txt") 18 | reacs := map[string]Reac{} 19 | 20 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 21 | reac := strings.Split(s, " => ") 22 | out := strings.Split(reac[1], " ") 23 | amount, _ := strconv.Atoi(out[0]) 24 | reacs[out[1]] = Reac{amount, map[string]int{}} 25 | 26 | for _, s := range strings.Split(reac[0], ", ") { 27 | in := strings.Split(s, " ") 28 | amount, _ := strconv.Atoi(in[0]) 29 | reacs[out[1]].In[in[1]] = amount 30 | } 31 | } 32 | 33 | fmt.Println(ore(map[string]int{"FUEL": 1}, reacs)) 34 | 35 | fmt.Println(sort.Search(1000000000000, func(n int) bool { 36 | return ore(map[string]int{"FUEL": n}, reacs) > 1000000000000 37 | }) - 1) 38 | } 39 | 40 | func ore(want map[string]int, reacs map[string]Reac) int { 41 | loop: 42 | for { 43 | for w := range want { 44 | if w != "ORE" && want[w] > 0 { 45 | amount := (want[w]-1)/reacs[w].Out + 1 46 | want[w] -= reacs[w].Out * amount 47 | 48 | for r := range reacs[w].In { 49 | want[r] += reacs[w].In[r] * amount 50 | } 51 | continue loop 52 | } 53 | } 54 | return want["ORE"] 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /2019/15/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := ioutil.ReadFile("input.txt") 13 | split := strings.Split(strings.TrimSpace(string(input)), ",") 14 | mem := map[int]int{} 15 | 16 | for i, s := range split { 17 | mem[i], _ = strconv.Atoi(s) 18 | } 19 | 20 | in, out := make(chan int), make(chan int) 21 | go run(mem, in, out) 22 | delta := map[int]image.Point{1: {0, -1}, 2: {0, 1}, 3: {-1, 0}, 4: {1, 0}} 23 | maze := map[image.Point]int{} 24 | pos := image.Point{0, 0} 25 | var back []int 26 | var oxy image.Point 27 | 28 | explore: 29 | for { 30 | for dir, dp := range delta { 31 | next := pos.Add(dp) 32 | if _, ok := maze[next]; !ok { 33 | in <- dir 34 | maze[next] = <-out 35 | if maze[next] > 0 { 36 | pos = next 37 | back = append(back, dir-1^1+1) 38 | } 39 | if maze[next] == 2 { 40 | oxy = next 41 | fmt.Println(len(back)) 42 | } 43 | continue explore 44 | } 45 | } 46 | if len(back) < 1 { 47 | break 48 | } 49 | in <- back[len(back)-1] 50 | <-out 51 | pos = pos.Add(delta[back[len(back)-1]]) 52 | back = back[:len(back)-1] 53 | } 54 | 55 | disc := map[image.Point]int{oxy: 0} 56 | queue := []image.Point{oxy} 57 | var point image.Point 58 | 59 | for len(queue) > 0 { 60 | point = queue[0] 61 | queue = queue[1:] 62 | for _, d := range delta { 63 | if _, ok := disc[point.Add(d)]; !ok && maze[point.Add(d)] > 0 { 64 | disc[point.Add(d)] = disc[point] + 1 65 | queue = append(queue, point.Add(d)) 66 | } 67 | } 68 | } 69 | 70 | fmt.Println(disc[point]) 71 | } 72 | 73 | func run(mem map[int]int, in <-chan int, out chan<- int) { 74 | ip, rb := 0, 0 75 | 76 | for { 77 | ins := fmt.Sprintf("%05d", mem[ip]) 78 | op, _ := strconv.Atoi(ins[3:]) 79 | par := func(i int) int { 80 | switch ins[3-i] { 81 | case '1': 82 | return ip + i 83 | case '2': 84 | return rb + mem[ip+i] 85 | default: 86 | return mem[ip+i] 87 | } 88 | } 89 | 90 | switch op { 91 | case 1: 92 | mem[par(3)] = mem[par(1)] + mem[par(2)] 93 | case 2: 94 | mem[par(3)] = mem[par(1)] * mem[par(2)] 95 | case 3: 96 | mem[par(1)] = <-in 97 | case 4: 98 | out <- mem[par(1)] 99 | case 5: 100 | if mem[par(1)] != 0 { 101 | ip = mem[par(2)] 102 | continue 103 | } 104 | case 6: 105 | if mem[par(1)] == 0 { 106 | ip = mem[par(2)] 107 | continue 108 | } 109 | case 7: 110 | if mem[par(1)] < mem[par(2)] { 111 | mem[par(3)] = 1 112 | } else { 113 | mem[par(3)] = 0 114 | } 115 | case 8: 116 | if mem[par(1)] == mem[par(2)] { 117 | mem[par(3)] = 1 118 | } else { 119 | mem[par(3)] = 0 120 | } 121 | case 9: 122 | rb += mem[par(1)] 123 | case 99: 124 | return 125 | } 126 | 127 | ip += []int{1, 4, 4, 2, 2, 3, 3, 4, 4, 2}[op] 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /2019/16/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | input, _ := ioutil.ReadFile("input.txt") 11 | signal := strings.TrimSpace(string(input)) 12 | 13 | for p := 0; p < 100; p++ { 14 | output := "" 15 | for i := range signal { 16 | sum := 0 17 | for j, r := range signal { 18 | sum += int(r-'0') * []int{0, 1, 0, -1}[(j+1)/(i+1)%4] 19 | } 20 | if sum < 0 { 21 | sum = -sum 22 | } 23 | output += string('0' + sum%10) 24 | } 25 | signal = output 26 | } 27 | 28 | fmt.Println(signal[:8]) 29 | } 30 | -------------------------------------------------------------------------------- /2019/16/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | signal := strings.Repeat(strings.TrimSpace(string(input)), 10000) 13 | offset, _ := strconv.Atoi(signal[:7]) 14 | output := []int{} 15 | 16 | for _, r := range signal[offset:] { 17 | output = append(output, int(r-'0')) 18 | } 19 | 20 | for p := 0; p < 100; p++ { 21 | sum := 0 22 | for i := len(output) - 1; i >= 0; i-- { 23 | sum += output[i] 24 | output[i] = sum % 10 25 | } 26 | } 27 | 28 | for _, i := range output[:8] { 29 | fmt.Print(i) 30 | } 31 | fmt.Println() 32 | } 33 | -------------------------------------------------------------------------------- /2019/17/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := ioutil.ReadFile("input.txt") 13 | 14 | mem := map[int]int{} 15 | for i, s := range strings.Split(strings.TrimSpace(string(input)), ",") { 16 | mem[i], _ = strconv.Atoi(s) 17 | } 18 | 19 | cur := image.Point{0, 0} 20 | scaff := map[image.Point]rune{} 21 | var pos image.Point 22 | var dir int 23 | 24 | for _, v := range run(mem, "") { 25 | switch r := rune(v); r { 26 | case '\n': 27 | cur.X = 0 28 | cur.Y++ 29 | case '^', '<', 'v', '>': 30 | pos = cur 31 | dir = map[rune]int{'^': 0, '<': 1, 'v': 2, '>': 3}[r] 32 | r = '#' 33 | fallthrough 34 | default: 35 | scaff[cur] = r 36 | cur.X++ 37 | } 38 | } 39 | 40 | d := []image.Point{{0, -1}, {-1, 0}, {0, 1}, {1, 0}} 41 | 42 | sum := 0 43 | for p := range scaff { 44 | if scaff[p.Add(d[0])] == '#' && scaff[p.Add(d[1])] == '#' && 45 | scaff[p.Add(d[2])] == '#' && scaff[p.Add(d[3])] == '#' { 46 | sum += p.X * p.Y 47 | } 48 | } 49 | fmt.Println(sum) 50 | 51 | path := "" 52 | for { 53 | if scaff[pos.Add(d[(dir+1)%4])] == '#' { 54 | dir = (dir + 1) % 4 55 | path += "L," 56 | } else if scaff[pos.Add(d[(dir+3)%4])] == '#' { 57 | dir = (dir + 3) % 4 58 | path += "R," 59 | } else { 60 | break 61 | } 62 | dist := 0 63 | for scaff[pos.Add(d[dir])] == '#' { 64 | pos = pos.Add(d[dir]) 65 | dist++ 66 | } 67 | path += strconv.Itoa(dist) + "," 68 | } 69 | 70 | var a, b, c string 71 | compress: 72 | for i := 2; i <= 21; i++ { 73 | for j := 2; j <= 21; j++ { 74 | for k := 2; k <= 21; k++ { 75 | str := path 76 | a = str[:i] 77 | str = strings.ReplaceAll(str, a, "") 78 | b = str[:j] 79 | str = strings.ReplaceAll(str, b, "") 80 | c = str[:k] 81 | str = strings.ReplaceAll(str, c, "") 82 | if str == "" { 83 | break compress 84 | } 85 | } 86 | } 87 | } 88 | 89 | a = strings.Trim(a, ",") 90 | b = strings.Trim(b, ",") 91 | c = strings.Trim(c, ",") 92 | path = strings.ReplaceAll(path, a, "A") 93 | path = strings.ReplaceAll(path, b, "B") 94 | path = strings.ReplaceAll(path, c, "C") 95 | path = strings.Trim(path, ",") 96 | 97 | mem[0] = 2 98 | out := run(mem, strings.Join([]string{path, a, b, c, "n", ""}, "\n")) 99 | fmt.Println(out[len(out)-1]) 100 | } 101 | 102 | func run(init map[int]int, in string) (out []int) { 103 | ip, rb := 0, 0 104 | mem := map[int]int{} 105 | for i, v := range init { 106 | mem[i] = v 107 | } 108 | 109 | for { 110 | ins := fmt.Sprintf("%05d", mem[ip]) 111 | op, _ := strconv.Atoi(ins[3:]) 112 | par := func(i int) int { 113 | switch ins[3-i] { 114 | case '1': 115 | return ip + i 116 | case '2': 117 | return rb + mem[ip+i] 118 | default: 119 | return mem[ip+i] 120 | } 121 | } 122 | 123 | switch op { 124 | case 1: 125 | mem[par(3)] = mem[par(1)] + mem[par(2)] 126 | case 2: 127 | mem[par(3)] = mem[par(1)] * mem[par(2)] 128 | case 3: 129 | mem[par(1)] = int(in[0]) 130 | in = in[1:] 131 | case 4: 132 | out = append(out, mem[par(1)]) 133 | case 5: 134 | if mem[par(1)] != 0 { 135 | ip = mem[par(2)] 136 | continue 137 | } 138 | case 6: 139 | if mem[par(1)] == 0 { 140 | ip = mem[par(2)] 141 | continue 142 | } 143 | case 7: 144 | if mem[par(1)] < mem[par(2)] { 145 | mem[par(3)] = 1 146 | } else { 147 | mem[par(3)] = 0 148 | } 149 | case 8: 150 | if mem[par(1)] == mem[par(2)] { 151 | mem[par(3)] = 1 152 | } else { 153 | mem[par(3)] = 0 154 | } 155 | case 9: 156 | rb += mem[par(1)] 157 | case 99: 158 | return 159 | } 160 | 161 | ip += []int{1, 4, 4, 2, 2, 3, 3, 4, 4, 2}[op] 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /2019/18/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strings" 8 | "unicode" 9 | ) 10 | 11 | type State struct { 12 | Pos image.Point 13 | Keys [26]bool 14 | } 15 | 16 | func main() { 17 | input, _ := ioutil.ReadFile("input.txt") 18 | maze := map[image.Point]rune{} 19 | var start State 20 | var goal [26]bool 21 | 22 | for y, s := range strings.Fields(string(input)) { 23 | for x, r := range s { 24 | if r == '@' { 25 | start = State{Pos: image.Point{x, y}} 26 | r = '.' 27 | } 28 | if unicode.IsLower(r) { 29 | goal[r-'a'] = true 30 | } 31 | maze[image.Point{x, y}] = r 32 | } 33 | } 34 | 35 | dist := map[State]int{start: 0} 36 | queue := []State{start} 37 | 38 | for len(queue) > 0 { 39 | state := queue[0] 40 | queue = queue[1:] 41 | 42 | if state.Keys == goal { 43 | fmt.Println(dist[state]) 44 | return 45 | } 46 | 47 | for _, d := range []image.Point{{0, -1}, {-1, 0}, {0, 1}, {1, 0}} { 48 | nextState := State{state.Pos.Add(d), state.Keys} 49 | nextTile := maze[nextState.Pos] 50 | 51 | if nextTile == '#' || unicode.IsUpper(nextTile) && !state.Keys[nextTile-'A'] { 52 | continue 53 | } 54 | if unicode.IsLower(nextTile) { 55 | nextState.Keys[nextTile-'a'] = true 56 | } 57 | if _, ok := dist[nextState]; !ok { 58 | dist[nextState] = dist[state] + 1 59 | queue = append(queue, nextState) 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /2019/18/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strings" 8 | "unicode" 9 | ) 10 | 11 | type State struct { 12 | Pos [4]image.Point 13 | Keys [26]bool 14 | Active int 15 | } 16 | 17 | func main() { 18 | input, _ := ioutil.ReadFile("input2.txt") 19 | maze := map[image.Point]rune{} 20 | var start State 21 | var goal [26]bool 22 | robots := 0 23 | 24 | for y, s := range strings.Fields(string(input)) { 25 | for x, r := range s { 26 | if r == '@' { 27 | start.Pos[robots] = image.Point{x, y} 28 | r = '.' 29 | robots++ 30 | } 31 | if unicode.IsLower(r) { 32 | goal[r-'a'] = true 33 | } 34 | maze[image.Point{x, y}] = r 35 | } 36 | } 37 | 38 | dist := map[State]int{} 39 | queue := []State{} 40 | 41 | for i := 0; i < robots; i++ { 42 | start.Active = i 43 | dist[start] = 0 44 | queue = append(queue, start) 45 | } 46 | 47 | for len(queue) > 0 { 48 | state := queue[0] 49 | queue = queue[1:] 50 | 51 | if state.Keys == goal { 52 | fmt.Println(dist[state]) 53 | return 54 | } 55 | 56 | for _, d := range []image.Point{{0, -1}, {-1, 0}, {0, 1}, {1, 0}} { 57 | nextState := state 58 | nextState.Pos[state.Active] = state.Pos[state.Active].Add(d) 59 | nextTile := maze[nextState.Pos[state.Active]] 60 | 61 | if nextTile == '#' || unicode.IsUpper(nextTile) && !state.Keys[nextTile-'A'] { 62 | continue 63 | } 64 | if unicode.IsLower(nextTile) { 65 | nextState.Keys[nextTile-'a'] = true 66 | } 67 | for i := 0; i < robots; i++ { 68 | if i != state.Active && nextState.Keys == state.Keys { 69 | continue 70 | } 71 | nextState.Active = i 72 | if _, ok := dist[nextState]; !ok { 73 | dist[nextState] = dist[state] + 1 74 | queue = append(queue, nextState) 75 | } 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /2019/19/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | mem := map[int]int{} 14 | for i, s := range strings.Split(strings.TrimSpace(string(input)), ",") { 15 | mem[i], _ = strconv.Atoi(s) 16 | } 17 | 18 | sum := 0 19 | for x := 0; x < 50; x++ { 20 | for y := 0; y < 50; y++ { 21 | sum += run(mem, []int{x, y})[0] 22 | } 23 | } 24 | 25 | fmt.Println(sum) 26 | } 27 | 28 | func run(init map[int]int, in []int) (out []int) { 29 | ip, rb := 0, 0 30 | mem := map[int]int{} 31 | for i, v := range init { 32 | mem[i] = v 33 | } 34 | 35 | for { 36 | ins := fmt.Sprintf("%05d", mem[ip]) 37 | op, _ := strconv.Atoi(ins[3:]) 38 | par := func(i int) int { 39 | switch ins[3-i] { 40 | case '1': 41 | return ip + i 42 | case '2': 43 | return rb + mem[ip+i] 44 | default: 45 | return mem[ip+i] 46 | } 47 | } 48 | 49 | switch op { 50 | case 1: 51 | mem[par(3)] = mem[par(1)] + mem[par(2)] 52 | case 2: 53 | mem[par(3)] = mem[par(1)] * mem[par(2)] 54 | case 3: 55 | mem[par(1)] = in[0] 56 | in = in[1:] 57 | case 4: 58 | out = append(out, mem[par(1)]) 59 | case 5: 60 | if mem[par(1)] != 0 { 61 | ip = mem[par(2)] 62 | continue 63 | } 64 | case 6: 65 | if mem[par(1)] == 0 { 66 | ip = mem[par(2)] 67 | continue 68 | } 69 | case 7: 70 | if mem[par(1)] < mem[par(2)] { 71 | mem[par(3)] = 1 72 | } else { 73 | mem[par(3)] = 0 74 | } 75 | case 8: 76 | if mem[par(1)] == mem[par(2)] { 77 | mem[par(3)] = 1 78 | } else { 79 | mem[par(3)] = 0 80 | } 81 | case 9: 82 | rb += mem[par(1)] 83 | case 99: 84 | return 85 | } 86 | 87 | ip += []int{1, 4, 4, 2, 2, 3, 3, 4, 4, 2}[op] 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /2019/19/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | mem := map[int]int{} 14 | for i, s := range strings.Split(strings.TrimSpace(string(input)), ",") { 15 | mem[i], _ = strconv.Atoi(s) 16 | } 17 | 18 | x, y := 0, 99 19 | for { 20 | for run(mem, []int{x, y})[0] != 1 { 21 | x++ 22 | } 23 | if run(mem, []int{x + 99, y - 99})[0] == 1 { 24 | fmt.Println(x*10000 + y - 99) 25 | return 26 | } 27 | y++ 28 | } 29 | } 30 | 31 | func run(init map[int]int, in []int) (out []int) { 32 | ip, rb := 0, 0 33 | mem := map[int]int{} 34 | for i, v := range init { 35 | mem[i] = v 36 | } 37 | 38 | for { 39 | ins := fmt.Sprintf("%05d", mem[ip]) 40 | op, _ := strconv.Atoi(ins[3:]) 41 | par := func(i int) int { 42 | switch ins[3-i] { 43 | case '1': 44 | return ip + i 45 | case '2': 46 | return rb + mem[ip+i] 47 | default: 48 | return mem[ip+i] 49 | } 50 | } 51 | 52 | switch op { 53 | case 1: 54 | mem[par(3)] = mem[par(1)] + mem[par(2)] 55 | case 2: 56 | mem[par(3)] = mem[par(1)] * mem[par(2)] 57 | case 3: 58 | mem[par(1)] = in[0] 59 | in = in[1:] 60 | case 4: 61 | out = append(out, mem[par(1)]) 62 | case 5: 63 | if mem[par(1)] != 0 { 64 | ip = mem[par(2)] 65 | continue 66 | } 67 | case 6: 68 | if mem[par(1)] == 0 { 69 | ip = mem[par(2)] 70 | continue 71 | } 72 | case 7: 73 | if mem[par(1)] < mem[par(2)] { 74 | mem[par(3)] = 1 75 | } else { 76 | mem[par(3)] = 0 77 | } 78 | case 8: 79 | if mem[par(1)] == mem[par(2)] { 80 | mem[par(3)] = 1 81 | } else { 82 | mem[par(3)] = 0 83 | } 84 | case 9: 85 | rb += mem[par(1)] 86 | case 99: 87 | return 88 | } 89 | 90 | ip += []int{1, 4, 4, 2, 2, 3, 3, 4, 4, 2}[op] 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /2019/20/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strings" 8 | "unicode" 9 | ) 10 | 11 | func main() { 12 | input, _ := ioutil.ReadFile("input.txt") 13 | maze := map[image.Point]rune{} 14 | 15 | for y, s := range strings.Split(strings.Trim(string(input), "\n"), "\n") { 16 | for x, r := range s { 17 | maze[image.Point{x, y}] = r 18 | } 19 | } 20 | 21 | delta := []image.Point{{0, -1}, {-1, 0}, {0, 1}, {1, 0}} 22 | labels := map[string][]image.Point{} 23 | portals := map[image.Point]image.Point{} 24 | 25 | for p := range maze { 26 | if maze[p] != '.' { 27 | continue 28 | } 29 | 30 | for _, d := range delta { 31 | if !unicode.IsUpper(maze[p.Add(d)]) { 32 | continue 33 | } 34 | 35 | label := string(maze[p.Add(d)]) + string(maze[p.Add(d).Add(d)]) 36 | if d.X < 0 || d.Y < 0 { 37 | label = string(maze[p.Add(d).Add(d)]) + string(maze[p.Add(d)]) 38 | } 39 | 40 | labels[label] = append(labels[label], p) 41 | if len(labels[label]) >= 2 { 42 | portals[labels[label][0]] = labels[label][1] 43 | portals[labels[label][1]] = labels[label][0] 44 | } 45 | } 46 | } 47 | 48 | dist := map[image.Point]int{labels["AA"][0]: 0} 49 | queue := []image.Point{labels["AA"][0]} 50 | 51 | for len(queue) > 0 { 52 | point := queue[0] 53 | queue = queue[1:] 54 | 55 | if point == labels["ZZ"][0] { 56 | fmt.Println(dist[point]) 57 | return 58 | } 59 | 60 | for _, d := range delta { 61 | next := point.Add(d) 62 | if n, ok := portals[point]; ok && unicode.IsUpper(maze[next]) { 63 | next = n 64 | } 65 | 66 | if _, ok := dist[next]; !ok && maze[next] == '.' { 67 | dist[next] = dist[point] + 1 68 | queue = append(queue, next) 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /2019/20/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strings" 8 | "unicode" 9 | ) 10 | 11 | type State struct { 12 | P image.Point 13 | L int 14 | } 15 | 16 | func main() { 17 | input, _ := ioutil.ReadFile("input.txt") 18 | maze := map[image.Point]rune{} 19 | var w, h int 20 | 21 | for y, s := range strings.Split(strings.Trim(string(input), "\n"), "\n") { 22 | for x, r := range s { 23 | maze[image.Point{x, y}] = r 24 | w, h = x+1, y+1 25 | } 26 | } 27 | 28 | delta := []image.Point{{0, -1}, {-1, 0}, {0, 1}, {1, 0}} 29 | labels := map[string][]State{} 30 | portals := map[image.Point]State{} 31 | 32 | for p := range maze { 33 | if maze[p] != '.' { 34 | continue 35 | } 36 | 37 | for _, d := range delta { 38 | if !unicode.IsUpper(maze[p.Add(d)]) { 39 | continue 40 | } 41 | 42 | label := string(maze[p.Add(d)]) + string(maze[p.Add(d).Add(d)]) 43 | if d.X < 0 || d.Y < 0 { 44 | label = string(maze[p.Add(d).Add(d)]) + string(maze[p.Add(d)]) 45 | } 46 | 47 | labels[label] = append(labels[label], State{p, 0}) 48 | if len(labels[label]) == 2 { 49 | portals[labels[label][0].P] = labels[label][1] 50 | portals[labels[label][1].P] = labels[label][0] 51 | } 52 | } 53 | } 54 | 55 | for p := range portals { 56 | portals[p] = State{portals[p].P, -1} 57 | if p.X > 2 && p.X < w-3 && p.Y > 2 && p.Y < h-3 { 58 | portals[p] = State{portals[p].P, 1} 59 | } 60 | } 61 | 62 | dist := map[State]int{labels["AA"][0]: 0} 63 | queue := []State{labels["AA"][0]} 64 | 65 | for len(queue) > 0 { 66 | state := queue[0] 67 | queue = queue[1:] 68 | 69 | if state == labels["ZZ"][0] { 70 | fmt.Println(dist[state]) 71 | return 72 | } 73 | 74 | for _, d := range delta { 75 | next := State{state.P.Add(d), state.L} 76 | if n, ok := portals[state.P]; ok && unicode.IsUpper(maze[next.P]) { 77 | next = State{n.P, state.L + n.L} 78 | } 79 | 80 | if _, ok := dist[next]; !ok && maze[next.P] == '.' && next.L >= 0 { 81 | dist[next] = dist[state] + 1 82 | queue = append(queue, next) 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /2019/21/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | mem := map[int]int{} 14 | for i, s := range strings.Split(strings.TrimSpace(string(input)), ",") { 15 | mem[i], _ = strconv.Atoi(s) 16 | } 17 | 18 | out := run(mem, `NOT D J 19 | OR C J 20 | AND A J 21 | NOT J J 22 | WALK 23 | `) 24 | fmt.Println(out[len(out)-1]) 25 | 26 | out = run(mem, `NOT H J 27 | OR C J 28 | AND B J 29 | AND A J 30 | NOT J J 31 | AND D J 32 | RUN 33 | `) 34 | fmt.Println(out[len(out)-1]) 35 | } 36 | 37 | func run(init map[int]int, in string) (out []int) { 38 | ip, rb := 0, 0 39 | mem := map[int]int{} 40 | for i, v := range init { 41 | mem[i] = v 42 | } 43 | 44 | for { 45 | ins := fmt.Sprintf("%05d", mem[ip]) 46 | op, _ := strconv.Atoi(ins[3:]) 47 | par := func(i int) int { 48 | switch ins[3-i] { 49 | case '1': 50 | return ip + i 51 | case '2': 52 | return rb + mem[ip+i] 53 | default: 54 | return mem[ip+i] 55 | } 56 | } 57 | 58 | switch op { 59 | case 1: 60 | mem[par(3)] = mem[par(1)] + mem[par(2)] 61 | case 2: 62 | mem[par(3)] = mem[par(1)] * mem[par(2)] 63 | case 3: 64 | mem[par(1)] = int(in[0]) 65 | in = in[1:] 66 | case 4: 67 | out = append(out, mem[par(1)]) 68 | case 5: 69 | if mem[par(1)] != 0 { 70 | ip = mem[par(2)] 71 | continue 72 | } 73 | case 6: 74 | if mem[par(1)] == 0 { 75 | ip = mem[par(2)] 76 | continue 77 | } 78 | case 7: 79 | if mem[par(1)] < mem[par(2)] { 80 | mem[par(3)] = 1 81 | } else { 82 | mem[par(3)] = 0 83 | } 84 | case 8: 85 | if mem[par(1)] == mem[par(2)] { 86 | mem[par(3)] = 1 87 | } else { 88 | mem[par(3)] = 0 89 | } 90 | case 9: 91 | rb += mem[par(1)] 92 | case 99: 93 | return 94 | } 95 | 96 | ip += []int{1, 4, 4, 2, 2, 3, 3, 4, 4, 2}[op] 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /2019/22/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | deck := make([]int, 10007) 14 | for i := 0; i < len(deck); i++ { 15 | deck[i] = i 16 | } 17 | 18 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 19 | switch s := strings.Fields(s); s[1] { 20 | case "into": 21 | for i := len(deck)/2 - 1; i >= 0; i-- { 22 | deck[i], deck[len(deck)-1-i] = deck[len(deck)-1-i], deck[i] 23 | } 24 | case "with": 25 | inc, _ := strconv.Atoi(s[3]) 26 | table := make([]int, len(deck)) 27 | for i := 0; i < len(deck); i++ { 28 | table[i*inc%len(deck)] = deck[i] 29 | } 30 | deck = table 31 | default: 32 | cut, _ := strconv.Atoi(s[1]) 33 | if cut > 0 { 34 | deck = append(deck[cut:], deck[:cut]...) 35 | } else { 36 | deck = append(deck[len(deck)+cut:], deck[:len(deck)+cut]...) 37 | } 38 | } 39 | } 40 | 41 | for i, v := range deck { 42 | if v == 2019 { 43 | fmt.Println(i) 44 | return 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /2019/22/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "math/big" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | cards, shuff := big.NewInt(119315717514047), big.NewInt(101741582076661) 13 | a, b := big.NewInt(1), big.NewInt(0) 14 | 15 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 16 | switch s := strings.Fields(s); s[1] { 17 | case "into": 18 | a.Neg(a) 19 | b.Add(b, a) 20 | case "with": 21 | inc, _ := new(big.Int).SetString(s[3], 10) 22 | a.Mul(a, new(big.Int).ModInverse(inc, cards)) 23 | default: 24 | cut, _ := new(big.Int).SetString(s[1], 10) 25 | b.Add(b, new(big.Int).Mul(a, cut)) 26 | } 27 | } 28 | 29 | b.Mul(b, new(big.Int).Sub(big.NewInt(1), new(big.Int).Exp(a, shuff, cards))) 30 | b.Mul(b, new(big.Int).ModInverse(new(big.Int).Sub(big.NewInt(1), a), cards)) 31 | a.Exp(a, shuff, cards) 32 | 33 | fmt.Println(new(big.Int).Mod(new(big.Int).Add(new(big.Int).Mul(a, big.NewInt(2020)), b), cards)) 34 | } 35 | -------------------------------------------------------------------------------- /2019/23/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | mem := map[int]int{} 14 | for i, s := range strings.Split(strings.TrimSpace(string(input)), ",") { 15 | mem[i], _ = strconv.Atoi(s) 16 | } 17 | 18 | in, out := make([]chan int, 50), make([]chan int, 50) 19 | for i := 0; i < 50; i++ { 20 | in[i], out[i] = make(chan int), make(chan int) 21 | go run(mem, in[i], out[i]) 22 | in[i] <- i 23 | in[i] <- -1 24 | } 25 | 26 | idle := 0 27 | var old, nat [2]int 28 | 29 | for i := 0; ; i = (i + 1) % 50 { 30 | select { 31 | case addr := <-out[i]: 32 | if addr == 255 { 33 | new := [2]int{<-out[i], <-out[i]} 34 | if nat == [2]int{} { 35 | fmt.Println(new[1]) 36 | } 37 | nat = new 38 | } else { 39 | in[addr] <- <-out[i] 40 | in[addr] <- <-out[i] 41 | } 42 | idle = 0 43 | case in[i] <- -1: 44 | idle++ 45 | } 46 | 47 | if idle >= 50 { 48 | if nat[1] == old[1] { 49 | fmt.Println(nat[1]) 50 | return 51 | } 52 | in[0] <- nat[0] 53 | in[0] <- nat[1] 54 | old = nat 55 | idle = 0 56 | } 57 | } 58 | } 59 | 60 | func run(init map[int]int, in <-chan int, out chan<- int) { 61 | ip, rb := 0, 0 62 | mem := map[int]int{} 63 | for i, v := range init { 64 | mem[i] = v 65 | } 66 | 67 | for { 68 | ins := fmt.Sprintf("%05d", mem[ip]) 69 | op, _ := strconv.Atoi(ins[3:]) 70 | par := func(i int) int { 71 | switch ins[3-i] { 72 | case '1': 73 | return ip + i 74 | case '2': 75 | return rb + mem[ip+i] 76 | default: 77 | return mem[ip+i] 78 | } 79 | } 80 | 81 | switch op { 82 | case 1: 83 | mem[par(3)] = mem[par(1)] + mem[par(2)] 84 | case 2: 85 | mem[par(3)] = mem[par(1)] * mem[par(2)] 86 | case 3: 87 | mem[par(1)] = <-in 88 | case 4: 89 | out <- mem[par(1)] 90 | case 5: 91 | if mem[par(1)] != 0 { 92 | ip = mem[par(2)] 93 | continue 94 | } 95 | case 6: 96 | if mem[par(1)] == 0 { 97 | ip = mem[par(2)] 98 | continue 99 | } 100 | case 7: 101 | if mem[par(1)] < mem[par(2)] { 102 | mem[par(3)] = 1 103 | } else { 104 | mem[par(3)] = 0 105 | } 106 | case 8: 107 | if mem[par(1)] == mem[par(2)] { 108 | mem[par(3)] = 1 109 | } else { 110 | mem[par(3)] = 0 111 | } 112 | case 9: 113 | rb += mem[par(1)] 114 | case 99: 115 | return 116 | } 117 | 118 | ip += []int{1, 4, 4, 2, 2, 3, 3, 4, 4, 2}[op] 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /2019/24/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | grid := map[image.Point]int{} 14 | for y, s := range strings.Fields(string(input)) { 15 | for x, r := range s { 16 | grid[image.Point{x, y}] = map[rune]int{'.': 0, '#': 1}[r] 17 | } 18 | } 19 | 20 | seen := map[int]struct{}{} 21 | for { 22 | bio := 0 23 | 24 | next := map[image.Point]int{} 25 | for p, r := range grid { 26 | adj := 0 27 | for _, d := range []image.Point{{0, -1}, {-1, 0}, {0, 1}, {1, 0}} { 28 | adj += grid[p.Add(d)] 29 | } 30 | 31 | next[p] = 0 32 | if adj == 1 || r == 0 && adj == 2 { 33 | next[p] = 1 34 | bio += 1 << (5*p.Y + p.X) 35 | } 36 | } 37 | grid = next 38 | 39 | if _, ok := seen[bio]; ok { 40 | fmt.Println(bio) 41 | return 42 | } 43 | seen[bio] = struct{}{} 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /2019/24/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | init := [5][5]int{} 14 | for y, s := range strings.Fields(string(input)) { 15 | for x, r := range s { 16 | if r == '#' { 17 | init[y][x] = 1 18 | } 19 | } 20 | } 21 | grid := map[int][5][5]int{0: init} 22 | 23 | var bugs int 24 | for i := 0; i < 200; i++ { 25 | bugs = 0 26 | 27 | next := map[int][5][5]int{} 28 | for z := -200; z <= 200; z++ { 29 | for y := 0; y < 5; y++ { 30 | for x := 0; x < 5; x++ { 31 | if y == 2 && x == 2 { 32 | continue 33 | } 34 | 35 | adj := 0 36 | for _, d := range []image.Point{{0, -1}, {-1, 0}, {0, 1}, {1, 0}} { 37 | n := image.Point{x, y}.Add(d) 38 | switch { 39 | case n.Y == -1 || n.Y == 5 || n.X == -1 || n.X == 5: 40 | adj += grid[z-1][2+d.Y][2+d.X] 41 | case n.Y == 2 && n.X == 2: 42 | for i := 0; i < 5; i++ { 43 | adj += grid[z+1][d.X&1*i-d.Y&1*2*(d.Y-1)][d.Y&1*i-d.X&1*2*(d.X-1)] 44 | } 45 | default: 46 | adj += grid[z][n.Y][n.X] 47 | } 48 | } 49 | 50 | if adj == 1 || grid[z][y][x] == 0 && adj == 2 { 51 | temp := next[z] 52 | temp[y][x] = 1 53 | next[z] = temp 54 | bugs++ 55 | } 56 | } 57 | } 58 | } 59 | grid = next 60 | } 61 | 62 | fmt.Println(bugs) 63 | } 64 | -------------------------------------------------------------------------------- /2020/01/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | entries := []int{} 14 | for _, s := range strings.Fields(string(input)) { 15 | i, _ := strconv.Atoi(s) 16 | entries = append(entries, i) 17 | } 18 | 19 | for i, x := range entries { 20 | for j, y := range entries[i+1:] { 21 | if x+y == 2020 { 22 | fmt.Println(x * y) 23 | } 24 | for _, z := range entries[j+1:] { 25 | if x+y+z == 2020 { 26 | fmt.Println(x * y * z) 27 | } 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /2020/02/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | input, _ := ioutil.ReadFile("input.txt") 11 | 12 | part1, part2 := 0, 0 13 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 14 | var min, max int 15 | var char byte 16 | var pass string 17 | fmt.Sscanf(s, "%v-%v %c: %v", &min, &max, &char, &pass) 18 | count := strings.Count(pass, string(char)) 19 | if count >= min && count <= max { 20 | part1++ 21 | } 22 | if (pass[min-1] == char) != (pass[max-1] == char) { 23 | part2++ 24 | } 25 | } 26 | fmt.Println(part1) 27 | fmt.Println(part2) 28 | } 29 | -------------------------------------------------------------------------------- /2020/03/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | grid := strings.Fields(string(input)) 14 | slopes := map[image.Point]int{{1, 1}: 0, {3, 1}: 0, {5, 1}: 0, {7, 1}: 0, {1, 2}: 0} 15 | mult := 1 16 | for s := range slopes { 17 | for p := (image.Point{}); p.Y < len(grid); p = p.Add(s) { 18 | if grid[p.Y][p.X%len(grid[0])] == '#' { 19 | slopes[s]++ 20 | } 21 | } 22 | mult *= slopes[s] 23 | } 24 | fmt.Println(slopes[image.Point{3, 1}]) 25 | fmt.Println(mult) 26 | } 27 | -------------------------------------------------------------------------------- /2020/04/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "regexp" 7 | "strings" 8 | ) 9 | 10 | var res = []*regexp.Regexp{ 11 | regexp.MustCompile(`(?:^|\s)(byr):(?:(19[2-9]\d|200[0-2])(?:\s|$))?`), 12 | regexp.MustCompile(`(?:^|\s)(iyr):(?:(201\d|2020)(?:\s|$))?`), 13 | regexp.MustCompile(`(?:^|\s)(eyr):(?:(202\d|2030)(?:\s|$))?`), 14 | regexp.MustCompile(`(?:^|\s)(hgt):(?:((?:1[5-8]\d|19[0-3])cm|(?:59|6\d|7[0-6])in)(?:\s|$))?`), 15 | regexp.MustCompile(`(?:^|\s)(hcl):(?:(#[\da-f]{6})(?:\s|$))?`), 16 | regexp.MustCompile(`(?:^|\s)(ecl):(?:(amb|blu|brn|gry|grn|hzl|oth)(?:\s|$))?`), 17 | regexp.MustCompile(`(?:^|\s)(pid):(?:(\d{9})(?:\s|$))?`), 18 | } 19 | 20 | func main() { 21 | input, _ := ioutil.ReadFile("input.txt") 22 | 23 | part1, part2 := 0, 0 24 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n\n") { 25 | d1, d2 := 1, 1 26 | for _, re := range res { 27 | if m := re.FindStringSubmatch(s); len(m) == 0 { 28 | d1, d2 = 0, 0 29 | } else if m[2] == "" { 30 | d2 = 0 31 | } 32 | } 33 | part1, part2 = part1+d1, part2+d2 34 | } 35 | fmt.Println(part1) 36 | fmt.Println(part2) 37 | } 38 | -------------------------------------------------------------------------------- /2020/05/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "sort" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := ioutil.ReadFile("input.txt") 13 | 14 | ids := []int{} 15 | for _, s := range strings.Fields(string(input)) { 16 | bin := strings.NewReplacer("F", "0", "B", "1", "L", "0", "R", "1").Replace(s) 17 | id, _ := strconv.ParseUint(bin, 2, 10) 18 | ids = append(ids, int(id)) 19 | } 20 | sort.Ints(ids) 21 | 22 | fmt.Println(ids[len(ids)-1]) 23 | for i := range ids { 24 | if ids[i+1] != ids[i]+1 { 25 | fmt.Println(ids[i] + 1) 26 | break 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /2020/06/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | input, _ := ioutil.ReadFile("input.txt") 11 | 12 | part1, part2 := 0, 0 13 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n\n") { 14 | yes := map[rune]int{} 15 | people := strings.Fields(s) 16 | for _, s := range people { 17 | for _, r := range s { 18 | yes[r]++ 19 | if yes[r] == len(people) { 20 | part2++ 21 | } 22 | } 23 | } 24 | part1 += len(yes) 25 | } 26 | fmt.Println(part1) 27 | fmt.Println(part2) 28 | } 29 | -------------------------------------------------------------------------------- /2020/07/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "regexp" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := ioutil.ReadFile("input.txt") 13 | 14 | bags := map[string]map[string]int{} 15 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 16 | out := strings.Split(s, " bags ")[0] 17 | bags[out] = map[string]int{} 18 | for _, in := range regexp.MustCompile(`(\d+) (\w+ \w+)`).FindAllStringSubmatch(s, -1) { 19 | bags[out][in[2]], _ = strconv.Atoi(in[1]) 20 | } 21 | } 22 | 23 | fmt.Println(len(parents(bags, "shiny gold"))) 24 | fmt.Println(count(bags, "shiny gold")) 25 | } 26 | 27 | func parents(bags map[string]map[string]int, bag string) map[string]struct{} { 28 | set := map[string]struct{}{} 29 | for out := range bags { 30 | for in := range bags[out] { 31 | if in == bag { 32 | set[out] = struct{}{} 33 | for b := range parents(bags, out) { 34 | set[b] = struct{}{} 35 | } 36 | break 37 | } 38 | } 39 | } 40 | return set 41 | } 42 | 43 | func count(bags map[string]map[string]int, bag string) (total int) { 44 | for b, c := range bags[bag] { 45 | total += c * (count(bags, b) + 1) 46 | } 47 | return 48 | } 49 | -------------------------------------------------------------------------------- /2020/08/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io/ioutil" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | ins := strings.Split(strings.TrimSpace(string(input)), "\n") 13 | 14 | acc, _ := run(ins) 15 | fmt.Println(acc) 16 | 17 | for i, s := range ins { 18 | tmp := make([]string, len(ins)) 19 | copy(tmp, ins) 20 | tmp[i] = strings.NewReplacer("jmp", "nop", "nop", "jmp").Replace(s) 21 | 22 | if acc, err := run(tmp); err == nil { 23 | fmt.Println(acc) 24 | break 25 | } 26 | } 27 | } 28 | 29 | func run(ins []string) (int, error) { 30 | pc, acc := 0, 0 31 | seen := map[int]struct{}{} 32 | 33 | for pc < len(ins) { 34 | if _, ok := seen[pc]; ok { 35 | return acc, errors.New("infinite loop") 36 | } 37 | seen[pc] = struct{}{} 38 | 39 | var op string 40 | var arg int 41 | fmt.Sscanf(ins[pc], "%s %d", &op, &arg) 42 | 43 | switch op { 44 | case "acc": 45 | acc += arg 46 | case "jmp": 47 | pc += arg - 1 48 | } 49 | pc++ 50 | } 51 | 52 | return acc, nil 53 | } 54 | -------------------------------------------------------------------------------- /2020/09/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "sort" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := ioutil.ReadFile("input.txt") 13 | split := strings.Split(strings.TrimSpace(string(input)), "\n") 14 | 15 | xmas := make([]int, len(split)) 16 | for i, s := range split { 17 | xmas[i], _ = strconv.Atoi(s) 18 | } 19 | 20 | invalid := 0 21 | out: 22 | for i := 25; i < len(xmas); i++ { 23 | for j := i - 25; j < i; j++ { 24 | for k := j + 1; k < i; k++ { 25 | if xmas[j]+xmas[k] == xmas[i] { 26 | continue out 27 | } 28 | } 29 | } 30 | invalid = xmas[i] 31 | break 32 | } 33 | fmt.Println(invalid) 34 | 35 | for i := 0; i < len(xmas); i++ { 36 | for j := i + 1; j < len(xmas); j++ { 37 | sum := 0 38 | for _, v := range xmas[i : j+1] { 39 | sum += v 40 | } 41 | if sum == invalid { 42 | sort.Ints(xmas[i : j+1]) 43 | fmt.Println(xmas[i] + xmas[j]) 44 | return 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /2020/10/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "sort" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := ioutil.ReadFile("input.txt") 13 | split := strings.Split(strings.TrimSpace(string(input)), "\n") 14 | 15 | jolts := make([]int, len(split)) 16 | for i, s := range split { 17 | jolts[i], _ = strconv.Atoi(s) 18 | } 19 | sort.Ints(jolts) 20 | jolts = append([]int{0}, append(jolts, jolts[len(jolts)-1]+3)...) 21 | 22 | diff, memo := map[int]int{}, map[int]int{0: 1} 23 | for i, v := range jolts[1:] { 24 | diff[v-jolts[i]]++ 25 | memo[v] = memo[v-1] + memo[v-2] + memo[v-3] 26 | } 27 | fmt.Println(diff[1] * diff[3]) 28 | fmt.Println(memo[jolts[len(jolts)-1]]) 29 | } 30 | -------------------------------------------------------------------------------- /2020/11/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | seats := map[image.Point]rune{} 14 | for y, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 15 | for x, r := range s { 16 | seats[image.Point{x, y}] = r 17 | } 18 | } 19 | 20 | fmt.Println(run(seats, 4, func(p, d image.Point) image.Point { return p.Add(d) })) 21 | fmt.Println(run(seats, 5, func(p, d image.Point) image.Point { 22 | for seats[p.Add(d)] == '.' { 23 | p = p.Add(d) 24 | } 25 | return p.Add(d) 26 | })) 27 | } 28 | 29 | func run(seats map[image.Point]rune, maxAdj int, adj func(p, d image.Point) image.Point) (occ int) { 30 | delta := []image.Point{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}} 31 | 32 | for diff := true; diff; { 33 | occ, diff = 0, false 34 | 35 | next := map[image.Point]rune{} 36 | for p, r := range seats { 37 | sum := 0 38 | for _, d := range delta { 39 | if seats[adj(p, d)] == '#' { 40 | sum++ 41 | } 42 | } 43 | 44 | if r == '#' && sum >= maxAdj { 45 | r = 'L' 46 | } else if r == 'L' && sum == 0 || r == '#' { 47 | r = '#' 48 | occ++ 49 | } 50 | next[p] = r 51 | diff = diff || next[p] != seats[p] 52 | } 53 | seats = next 54 | } 55 | return 56 | } 57 | -------------------------------------------------------------------------------- /2020/12/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "math" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := ioutil.ReadFile("input.txt") 13 | ins := strings.Split(strings.TrimSpace(string(input)), "\n") 14 | 15 | ship, wp := image.Point{0, 0}, image.Point{10, -1} 16 | fmt.Println(run(ins, &ship, &image.Point{1, 0}, &ship)) 17 | fmt.Println(run(ins, &image.Point{0, 0}, &wp, &wp)) 18 | } 19 | 20 | func run(ins []string, ship, dir, mov *image.Point) int { 21 | delta := map[rune]image.Point{'N': {0, -1}, 'S': {0, 1}, 'E': {1, 0}, 'W': {-1, 0}, 'L': {-1, 1}, 'R': {1, -1}} 22 | 23 | for _, s := range ins { 24 | var action rune 25 | var value int 26 | fmt.Sscanf(s, "%c%d", &action, &value) 27 | 28 | switch action { 29 | case 'N', 'S', 'E', 'W': 30 | *mov = mov.Add(delta[action].Mul(value)) 31 | case 'L', 'R': 32 | for i := 0; i < value/90; i++ { 33 | dir.X, dir.Y = delta[action].Y*dir.Y, delta[action].X*dir.X 34 | } 35 | case 'F': 36 | *ship = ship.Add(dir.Mul(value)) 37 | } 38 | } 39 | 40 | return int(math.Abs(float64(ship.X)) + math.Abs(float64(ship.Y))) 41 | } 42 | -------------------------------------------------------------------------------- /2020/13/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "math" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := ioutil.ReadFile("input.txt") 13 | lines := strings.Split(strings.TrimSpace(string(input)), "\n") 14 | time, _ := strconv.Atoi(lines[0]) 15 | 16 | part1, part2, step := math.MaxInt64, 0, 1 17 | for i, s := range strings.Split(lines[1], ",") { 18 | bus, err := strconv.Atoi(s) 19 | if err != nil { 20 | continue 21 | } 22 | 23 | if bus-time%bus < part1-time%part1 { 24 | part1 = bus 25 | } 26 | 27 | for (part2+i)%bus != 0 { 28 | part2 += step 29 | } 30 | step *= bus 31 | } 32 | fmt.Println(part1 * (part1 - time%part1)) 33 | fmt.Println(part2) 34 | } 35 | -------------------------------------------------------------------------------- /2020/14/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | 13 | var mask string 14 | mem1, part1 := map[int]int{}, 0 15 | mem2, part2 := map[int]int{}, 0 16 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 17 | if _, err := fmt.Sscanf(s, "mask = %s", &mask); err == nil { 18 | continue 19 | } 20 | var addr, value int 21 | fmt.Sscanf(s, "mem[%d] = %d", &addr, &value) 22 | 23 | for i, x := 0, strings.Count(mask, "X"); i < 1<= v[0] && n <= v[1] || n >= v[2] && n <= v[3]) { 36 | invalid[k] |= 1 << i 37 | } 38 | } 39 | 40 | if len(invalid) == len(rules) { 41 | part1 += n 42 | continue out 43 | } 44 | } 45 | 46 | for k, v := range invalid { 47 | masks[k] &^= v 48 | } 49 | } 50 | fmt.Println(part1) 51 | 52 | part2 := 1 53 | for used := uint(0); used != 1< 0 { 57 | for a, is := range aller { 58 | if len(is) != 1 { 59 | continue 60 | } 61 | 62 | for i := range is { 63 | for _, is := range aller { 64 | delete(is, i) 65 | } 66 | delete(aller, a) 67 | danger[i] = a 68 | part2 = append(part2, i) 69 | } 70 | } 71 | } 72 | sort.Slice(part2, func(i, j int) bool { return danger[part2[i]] < danger[part2[j]] }) 73 | fmt.Println(strings.Join(part2, ",")) 74 | } 75 | -------------------------------------------------------------------------------- /2020/22/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | split := strings.Split(strings.TrimSpace(string(input)), "\n\n") 13 | 14 | decks := make([][]int, len(split)) 15 | for i, s := range split { 16 | for _, s := range strings.Split(s, "\n")[1:] { 17 | c, _ := strconv.Atoi(s) 18 | decks[i] = append(decks[i], c) 19 | } 20 | } 21 | 22 | _, score := run([][]int{append([]int{}, decks[0]...), append([]int{}, decks[1]...)}, false) 23 | fmt.Println(score) 24 | _, score = run(decks, true) 25 | fmt.Println(score) 26 | } 27 | 28 | func run(ds [][]int, rec bool) (win int, score int) { 29 | seen := map[string]struct{}{} 30 | 31 | for len(ds[0]) > 0 && len(ds[1]) > 0 { 32 | win = 0 33 | if _, ok := seen[fmt.Sprint(ds)]; rec && ok { 34 | break 35 | } 36 | seen[fmt.Sprint(ds)] = struct{}{} 37 | 38 | if rec && len(ds[0]) > ds[0][0] && len(ds[1]) > ds[1][0] { 39 | win, _ = run([][]int{append([]int{}, ds[0][1:ds[0][0]+1]...), append([]int{}, ds[1][1:ds[1][0]+1]...)}, rec) 40 | } else if ds[0][0] < ds[1][0] { 41 | win = 1 42 | } 43 | 44 | ds[win] = append(ds[win], ds[win][0], ds[-win+1][0]) 45 | ds[0], ds[1] = ds[0][1:], ds[1][1:] 46 | } 47 | 48 | for i, c := range ds[win] { 49 | score += c * (len(ds[win]) - i) 50 | } 51 | return 52 | } 53 | -------------------------------------------------------------------------------- /2020/23/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "container/ring" 5 | "fmt" 6 | "io/ioutil" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := ioutil.ReadFile("input.txt") 12 | labels := strings.TrimSpace(string(input)) 13 | 14 | fmt.Println(run(labels, len(labels), 100)) 15 | fmt.Println(run(labels, 1000000, 10000000)) 16 | } 17 | 18 | func run(labels string, ncups int, moves int) (ans int) { 19 | cups := ring.New(ncups) 20 | ps := map[int]*ring.Ring{} 21 | 22 | for i := 1; i <= ncups; i++ { 23 | if cups.Value = i; i <= len(labels) { 24 | cups.Value = int(labels[i-1] - '0') 25 | } 26 | ps[cups.Value.(int)] = cups 27 | cups = cups.Next() 28 | } 29 | 30 | for i := 0; i < moves; i++ { 31 | pick := cups.Unlink(3) 32 | dest := (ncups+cups.Value.(int)-2)%ncups + 1 33 | 34 | unavail := map[int]bool{} 35 | for i := 0; i < 3; i++ { 36 | unavail[pick.Value.(int)] = true 37 | pick = pick.Next() 38 | } 39 | 40 | for unavail[dest] { 41 | dest = (ncups+dest-2)%ncups + 1 42 | } 43 | 44 | ps[dest].Link(pick) 45 | cups = cups.Next() 46 | } 47 | 48 | if ncups > len(labels) { 49 | return ps[1].Next().Value.(int) * ps[1].Move(2).Value.(int) 50 | } 51 | ps[1].Unlink(len(labels) - 1).Do(func(p interface{}) { 52 | ans = ans*10 + p.(int) 53 | }) 54 | return 55 | } 56 | -------------------------------------------------------------------------------- /2020/24/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/ioutil" 7 | "regexp" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := ioutil.ReadFile("input.txt") 13 | 14 | delta := map[string]image.Point{ 15 | "e": {2, 0}, "se": {1, 1}, "sw": {-1, 1}, 16 | "w": {-2, 0}, "nw": {-1, -1}, "ne": {1, -1}, 17 | } 18 | 19 | black := map[image.Point]struct{}{} 20 | for _, s := range strings.Fields(string(input)) { 21 | p := image.Point{0, 0} 22 | for _, s := range regexp.MustCompile(`(e|se|sw|w|nw|ne)`).FindAllString(s, -1) { 23 | p = p.Add(delta[s]) 24 | } 25 | 26 | if _, ok := black[p]; ok { 27 | delete(black, p) 28 | } else { 29 | black[p] = struct{}{} 30 | } 31 | } 32 | fmt.Println(len(black)) 33 | 34 | for i := 0; i < 100; i++ { 35 | neigh := map[image.Point]int{} 36 | for p := range black { 37 | for _, d := range delta { 38 | neigh[p.Add(d)]++ 39 | } 40 | } 41 | 42 | new := map[image.Point]struct{}{} 43 | for p, n := range neigh { 44 | if _, ok := black[p]; ok && n == 1 || n == 2 { 45 | new[p] = struct{}{} 46 | } 47 | } 48 | black = new 49 | } 50 | fmt.Println(len(black)) 51 | } 52 | -------------------------------------------------------------------------------- /2020/25/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | ) 7 | 8 | func main() { 9 | input, _ := ioutil.ReadFile("input.txt") 10 | 11 | var card, door int 12 | fmt.Sscanf(string(input), "%d\n%d", &card, &door) 13 | 14 | loop := 0 15 | for k := 1; k != card; loop++ { 16 | k = k * 7 % 20201227 17 | } 18 | 19 | key := 1 20 | for l := 0; l < loop; l++ { 21 | key = key * door % 20201227 22 | } 23 | fmt.Println(key) 24 | } 25 | -------------------------------------------------------------------------------- /2021/01/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | depths := []int{} 14 | for _, s := range strings.Fields(string(input)) { 15 | i, _ := strconv.Atoi(s) 16 | depths = append(depths, i) 17 | } 18 | 19 | part1, part2 := 0, 0 20 | for i := range depths { 21 | if i >= 1 && depths[i] > depths[i-1] { 22 | part1++ 23 | } 24 | if i >= 3 && depths[i] > depths[i-3] { 25 | part2++ 26 | } 27 | } 28 | fmt.Println(part1) 29 | fmt.Println(part2) 30 | } 31 | -------------------------------------------------------------------------------- /2021/02/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | delta := map[string]image.Point{"forward": {1, 0}, "down": {0, 1}, "up": {0, -1}} 13 | 14 | part1, part2 := image.Point{0, 0}, image.Point{0, 0} 15 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 16 | cmd, arg := "", 0 17 | fmt.Sscanf(s, "%s %d", &cmd, &arg) 18 | part1 = part1.Add(delta[cmd].Mul(arg)) 19 | part2 = part2.Add(image.Point{arg, arg * part1.Y}.Mul(delta[cmd].X)) 20 | } 21 | fmt.Println(part1.X * part1.Y) 22 | fmt.Println(part2.X * part2.Y) 23 | } 24 | -------------------------------------------------------------------------------- /2021/03/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | fields := strings.Fields(string(input)) 13 | 14 | gamma, epsilon := "", "" 15 | oxygen, co2 := fields, fields 16 | for i := range fields[0] { 17 | most, least := split(fields, i) 18 | gamma += string(most[0][i]) 19 | epsilon += string(least[0][i]) 20 | 21 | if len(oxygen) > 1 { 22 | oxygen, _ = split(oxygen, i) 23 | } 24 | if len(co2) > 1 { 25 | _, co2 = split(co2, i) 26 | } 27 | } 28 | fmt.Println(bs2i(gamma) * bs2i(epsilon)) 29 | fmt.Println(bs2i(oxygen[0]) * bs2i(co2[0])) 30 | } 31 | 32 | func split(report []string, index int) (most, least []string) { 33 | bit := map[byte][]string{} 34 | for _, s := range report { 35 | bit[s[index]] = append(bit[s[index]], s) 36 | } 37 | 38 | if len(bit['1']) >= len(bit['0']) { 39 | return bit['1'], bit['0'] 40 | } 41 | return bit['0'], bit['1'] 42 | } 43 | 44 | func bs2i(bs string) int { 45 | i, _ := strconv.ParseUint(bs, 2, len(bs)) 46 | return int(i) 47 | } 48 | -------------------------------------------------------------------------------- /2021/04/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "regexp" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | split := strings.Split(strings.TrimSpace(string(input)), "\n\n") 14 | re := regexp.MustCompile(`\d+`) 15 | 16 | boards := [][]int{} 17 | for i, s := range split { 18 | boards = append(boards, []int{}) 19 | for _, s := range re.FindAllString(s, -1) { 20 | d, _ := strconv.Atoi(s) 21 | boards[i] = append(boards[i], d) 22 | } 23 | } 24 | 25 | scores := []int{} 26 | for _, d := range boards[0] { 27 | for i := len(boards) - 1; i >= 1; i-- { 28 | b := boards[i] 29 | 30 | sum := 0 31 | for i, n := range b { 32 | if n == d { 33 | b[i] = ^n 34 | } else if n > 0 { 35 | sum += n 36 | } 37 | } 38 | 39 | for j := 0; j < 5; j++ { 40 | if b[j*5]&b[j*5+1]&b[j*5+2]&b[j*5+3]&b[j*5+4]| 41 | b[j]&b[j+5]&b[j+10]&b[j+15]&b[j+20] < 0 { 42 | scores = append(scores, sum*d) 43 | boards = append(boards[:i], boards[i+1:]...) 44 | break 45 | } 46 | } 47 | } 48 | } 49 | fmt.Println(scores[0]) 50 | fmt.Println(scores[len(scores)-1]) 51 | } 52 | -------------------------------------------------------------------------------- /2021/05/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | ortho, diag := map[image.Point]int{}, map[image.Point]int{} 14 | part1, part2 := 0, 0 15 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 16 | var p, q image.Point 17 | fmt.Sscanf(s, "%d,%d -> %d,%d", &p.X, &p.Y, &q.X, &q.Y) 18 | 19 | for d := (image.Point{sgn(q.X - p.X), sgn(q.Y - p.Y)}); p != q.Add(d); p = p.Add(d) { 20 | if diag[p]++; diag[p] == 2 { 21 | part2++ 22 | } 23 | if d.X != 0 && d.Y != 0 { 24 | continue 25 | } 26 | if ortho[p]++; ortho[p] == 2 { 27 | part1++ 28 | } 29 | } 30 | } 31 | fmt.Println(part1) 32 | fmt.Println(part2) 33 | } 34 | 35 | func sgn(i int) int { 36 | if i < 0 { 37 | return -1 38 | } else if i > 0 { 39 | return 1 40 | } 41 | return 0 42 | } 43 | -------------------------------------------------------------------------------- /2021/06/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | fish := make([]int, 9) 14 | for _, s := range strings.Split(strings.TrimSpace(string(input)), ",") { 15 | d, _ := strconv.Atoi(s) 16 | fish[d]++ 17 | } 18 | 19 | for i := 0; i < 256; i++ { 20 | if i == 80 { 21 | fmt.Println(sum(fish)) 22 | } 23 | fish = append(fish[1:7], fish[7]+fish[0], fish[8], fish[0]) 24 | } 25 | fmt.Println(sum(fish)) 26 | } 27 | 28 | func sum(xs []int) (sum int) { 29 | for _, x := range xs { 30 | sum += x 31 | } 32 | return 33 | } 34 | -------------------------------------------------------------------------------- /2021/07/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | crabs, max := []int{}, 0 14 | for _, s := range strings.Split(strings.TrimSpace(string(input)), ",") { 15 | p, _ := strconv.Atoi(s) 16 | crabs = append(crabs, p) 17 | if p > max { 18 | max = p 19 | } 20 | } 21 | fmt.Println(run(crabs, max, func(p int) int { return p })) 22 | fmt.Println(run(crabs, max, func(p int) int { return (p * (p + 1)) / 2 })) 23 | } 24 | 25 | func run(pos []int, max int, f func(int) int) int { 26 | min := int(^uint(0) >> 1) 27 | for b := 0; b <= max; b++ { 28 | sum := 0 29 | for _, a := range pos { 30 | sum += f(abs(b - a)) 31 | } 32 | if sum < min { 33 | min = sum 34 | } 35 | } 36 | return min 37 | } 38 | 39 | func abs(x int) int { 40 | if x < 0 { 41 | return -x 42 | } 43 | return x 44 | } 45 | -------------------------------------------------------------------------------- /2021/08/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | input, _ := os.ReadFile("input.txt") 11 | digits := map[int]int{42: 0, 17: 1, 34: 2, 39: 3, 30: 4, 37: 5, 41: 6, 25: 7, 49: 8, 45: 9} 12 | 13 | part1, part2 := 0, 0 14 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 15 | split := strings.Split(s, " | ") 16 | 17 | out := 0 18 | for _, s := range strings.Fields(split[1]) { 19 | if len(s) == 2 || len(s) == 3 || len(s) == 4 || len(s) == 7 { 20 | part1++ 21 | } 22 | 23 | hash := 0 24 | for _, r := range s { 25 | hash += strings.Count(split[0], string(r)) 26 | } 27 | out = 10*out + digits[hash] 28 | } 29 | part2 += out 30 | } 31 | fmt.Println(part1) 32 | fmt.Println(part2) 33 | } 34 | -------------------------------------------------------------------------------- /2021/09/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "sort" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | delta := []image.Point{{0, -1}, {-1, 0}, {0, 1}, {1, 0}} 14 | 15 | grid := map[image.Point]int{} 16 | for y, s := range strings.Fields(string(input)) { 17 | for x, r := range s { 18 | grid[image.Point{x, y}] = int(r - '0') 19 | } 20 | } 21 | 22 | part1, part2 := 0, []int{} 23 | out: 24 | for p, h := range grid { 25 | for _, d := range delta { 26 | if a, ok := grid[p.Add(d)]; ok && a <= h { 27 | continue out 28 | } 29 | } 30 | part1 += h + 1 31 | 32 | queue, size := []image.Point{p}, 0 33 | grid[p] = 9 34 | for len(queue) > 0 { 35 | p, queue = queue[0], queue[1:] 36 | size++ 37 | 38 | for _, d := range delta { 39 | p := p.Add(d) 40 | if h, ok := grid[p]; !ok || h == 9 { 41 | continue 42 | } 43 | 44 | queue = append(queue, p) 45 | grid[p] = 9 46 | } 47 | } 48 | part2 = append(part2, size) 49 | } 50 | 51 | fmt.Println(part1) 52 | sort.Sort(sort.Reverse(sort.IntSlice(part2))) 53 | fmt.Println(part2[0] * part2[1] * part2[2]) 54 | } 55 | -------------------------------------------------------------------------------- /2021/10/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "regexp" 7 | "sort" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | points := map[byte]int{ 14 | ')': 3, ']': 57, '}': 1197, '>': 25137, 15 | '(': 1, '[': 2, '{': 3, '<': 4, 16 | } 17 | re := regexp.MustCompile(`\(\)|\[]|{}|<>`) 18 | 19 | part1, part2 := 0, []int{} 20 | for _, s := range strings.Fields(string(input)) { 21 | for re.MatchString(s) { 22 | s = re.ReplaceAllString(s, "") 23 | } 24 | 25 | if i := strings.IndexAny(s, ")]}>"); i != -1 { 26 | part1 += points[s[i]] 27 | continue 28 | } 29 | 30 | score := 0 31 | for i := len(s) - 1; i >= 0; i-- { 32 | score = score*5 + points[s[i]] 33 | } 34 | part2 = append(part2, score) 35 | } 36 | fmt.Println(part1) 37 | sort.Ints(part2) 38 | fmt.Println(part2[len(part2)/2]) 39 | } 40 | -------------------------------------------------------------------------------- /2021/11/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | octo := map[image.Point]int{} 14 | for y, s := range strings.Fields(string(input)) { 15 | for x, r := range s { 16 | octo[image.Point{x, y}] = int(r - '0') 17 | } 18 | } 19 | 20 | part1, part2 := 0, 0 21 | for flashes := 0; flashes < len(octo); { 22 | for p := range octo { 23 | octo[p]++ 24 | } 25 | 26 | flashes = 0 27 | loop: 28 | for p := range octo { 29 | if octo[p] > 9 { 30 | flashes += flash(octo, p) 31 | goto loop 32 | } 33 | } 34 | 35 | if part2++; part2 <= 100 { 36 | part1 += flashes 37 | } 38 | } 39 | 40 | fmt.Println(part1) 41 | fmt.Println(part2) 42 | } 43 | 44 | func flash(octo map[image.Point]int, p image.Point) int { 45 | delta := []image.Point{ 46 | {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, 47 | {0, 1}, {1, -1}, {1, 0}, {1, 1}, 48 | } 49 | octo[p] = 0 50 | flashes := 1 51 | 52 | for _, d := range delta { 53 | n := p.Add(d) 54 | if octo[n] != 0 { 55 | octo[n]++ 56 | } 57 | if octo[n] > 9 { 58 | flashes += flash(octo, n) 59 | } 60 | } 61 | return flashes 62 | } 63 | -------------------------------------------------------------------------------- /2021/12/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | type State struct { 10 | Pos string 11 | Seen map[string]int 12 | } 13 | 14 | func main() { 15 | input, _ := os.ReadFile("input.txt") 16 | 17 | caves := map[string]map[string]struct{}{} 18 | for _, s := range strings.Fields(string(input)) { 19 | s := strings.Split(s, "-") 20 | 21 | for a, b := range []int{1, 0} { 22 | if caves[s[a]] == nil { 23 | caves[s[a]] = map[string]struct{}{} 24 | } 25 | caves[s[a]][s[b]] = struct{}{} 26 | } 27 | } 28 | 29 | fmt.Println(run(caves, true)) 30 | fmt.Println(run(caves, false)) 31 | } 32 | 33 | func run(caves map[string]map[string]struct{}, part1 bool) (count int) { 34 | queue := []State{{"start", map[string]int{"start": 1}}} 35 | for len(queue) > 0 { 36 | cur := queue[0] 37 | queue = queue[1:] 38 | 39 | if cur.Pos == "end" { 40 | count++ 41 | continue 42 | } 43 | 44 | out: 45 | for c := range caves[cur.Pos] { 46 | if c == "start" { 47 | continue 48 | } 49 | 50 | seen := map[string]int{} 51 | for k, v := range cur.Seen { 52 | seen[k] = v 53 | if (part1 || v == 2) && cur.Seen[c] > 0 { 54 | continue out 55 | } 56 | } 57 | 58 | if c == strings.ToLower(c) { 59 | seen[c]++ 60 | } 61 | 62 | queue = append(queue, State{c, seen}) 63 | } 64 | } 65 | return 66 | } 67 | -------------------------------------------------------------------------------- /2021/13/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | split := strings.Split(strings.TrimSpace(string(input)), "\n\n") 13 | 14 | dots := map[image.Point]struct{}{} 15 | for _, s := range strings.Fields(split[0]) { 16 | var p image.Point 17 | fmt.Sscanf(s, "%d,%d", &p.X, &p.Y) 18 | dots[p] = struct{}{} 19 | } 20 | 21 | size := map[rune]int{} 22 | for i, s := range strings.Split(split[1], "\n") { 23 | var axis rune 24 | var line int 25 | fmt.Sscanf(s, "fold along %c=%d", &axis, &line) 26 | 27 | for p := range dots { 28 | coord := map[rune]*int{'x': &p.X, 'y': &p.Y}[axis] 29 | if *coord < line { 30 | continue 31 | } 32 | delete(dots, p) 33 | *coord = 2*line - *coord 34 | dots[p] = struct{}{} 35 | size[axis] = line 36 | } 37 | 38 | if i == 0 { 39 | fmt.Println(len(dots)) 40 | } 41 | } 42 | 43 | for y := 0; y < size['y']; y++ { 44 | for x := 0; x < size['x']; x++ { 45 | _, ok := dots[image.Point{x, y}] 46 | fmt.Print(map[bool]string{true: "██", false: " "}[ok]) 47 | } 48 | fmt.Println() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /2021/14/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "sort" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | split := strings.Split(strings.TrimSpace(string(input)), "\n") 13 | 14 | rules := map[string]string{} 15 | for _, s := range split[2:] { 16 | split := strings.Split(s, " -> ") 17 | rules[split[0]] = split[1] 18 | } 19 | 20 | pairs := map[string]int{} 21 | for i := 0; i < len(split[0])-1; i++ { 22 | pairs[split[0][i:i+2]]++ 23 | } 24 | 25 | for i := 0; i < 40; i++ { 26 | np := map[string]int{} 27 | for k, v := range pairs { 28 | np[k[:1]+rules[k]] += v 29 | np[rules[k]+k[1:]] += v 30 | } 31 | pairs = np 32 | 33 | if i == 9 || i == 39 { 34 | counts := map[byte]int{split[0][len(split[0])-1]: 1} 35 | for k, v := range pairs { 36 | counts[k[0]] += v 37 | } 38 | 39 | vals := []int{} 40 | for _, v := range counts { 41 | vals = append(vals, v) 42 | } 43 | sort.Sort(sort.IntSlice(vals)) 44 | fmt.Println(vals[len(vals)-1] - vals[0]) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /2021/15/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | fields := strings.Fields(strings.TrimSpace(string(input))) 13 | w, h := len(fields[0]), len(fields) 14 | 15 | cave1, cave2 := map[image.Point]int{}, map[image.Point]int{} 16 | for y, s := range fields { 17 | for x, r := range s { 18 | v := int(r - '0') 19 | cave1[image.Point{x, y}] = v 20 | for j := 0; j < 5; j++ { 21 | for i := 0; i < 5; i++ { 22 | cave2[image.Point{i*w + x, j*h + y}] = (v+i+j-1)%9 + 1 23 | } 24 | } 25 | } 26 | } 27 | fmt.Println(dist(image.Point{w - 1, h - 1}, cave1)) 28 | fmt.Println(dist(image.Point{w*5 - 1, h*5 - 1}, cave2)) 29 | } 30 | 31 | func dist(end image.Point, cave map[image.Point]int) int { 32 | queue := map[image.Point]struct{}{{0, 0}: {}} 33 | dist := map[image.Point]int{{0, 0}: 0} 34 | 35 | for len(queue) > 0 { 36 | var cur *image.Point 37 | for p := range queue { 38 | if cur == nil || dist[p] < dist[*cur] { 39 | cur = &image.Point{p.X, p.Y} 40 | } 41 | } 42 | 43 | if *cur == end { 44 | return dist[*cur] 45 | } 46 | delete(queue, *cur) 47 | 48 | for _, d := range []image.Point{{-1, 0}, {0, 1}, {1, 0}, {0, -1}} { 49 | p := cur.Add(d) 50 | if _, ok := cave[p]; !ok { 51 | continue 52 | } 53 | 54 | alt := dist[*cur] + cave[p] 55 | if _, ok := dist[p]; !ok || alt < dist[p] { 56 | dist[p] = alt 57 | queue[p] = struct{}{} 58 | } 59 | } 60 | } 61 | return -1 62 | } 63 | -------------------------------------------------------------------------------- /2022/01/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "sort" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | split := strings.Split(strings.TrimSpace(string(input)), "\n\n") 14 | 15 | cals := make([]int, len(split)) 16 | for i, s := range split { 17 | for _, s := range strings.Fields(s) { 18 | c, _ := strconv.Atoi(s) 19 | cals[i] += c 20 | } 21 | } 22 | 23 | sort.Sort(sort.Reverse(sort.IntSlice(cals))) 24 | fmt.Println(cals[0]) 25 | fmt.Println(cals[0] + cals[1] + cals[2]) 26 | } 27 | -------------------------------------------------------------------------------- /2022/02/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | input, _ := os.ReadFile("input.txt") 11 | 12 | part1, part2 := 0, 0 13 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 14 | part1 += strings.Index("B XC YA ZA XB YC ZC XA YB Z", s)/3 + 1 15 | part2 += strings.Index("B XC XA XA YB YC YC ZA ZB Z", s)/3 + 1 16 | } 17 | fmt.Println(part1) 18 | fmt.Println(part2) 19 | } 20 | -------------------------------------------------------------------------------- /2022/03/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | input, _ := os.ReadFile("input.txt") 11 | split := strings.Fields(strings.TrimSpace(string(input))) 12 | 13 | part1, part2 := 0, 0 14 | for i, s := range split { 15 | part1 += common(s[:len(s)/2], s[len(s)/2:]) 16 | 17 | if i%3 == 0 { 18 | part2 += common(split[i : i+3]...) 19 | } 20 | } 21 | fmt.Println(part1) 22 | fmt.Println(part2) 23 | } 24 | 25 | func common(strs ...string) int { 26 | loop: 27 | for _, r := range strs[0] { 28 | for _, s := range strs[1:] { 29 | if !strings.ContainsRune(s, r) { 30 | continue loop 31 | } 32 | } 33 | return strings.IndexRune(" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", r) 34 | } 35 | return 0 36 | } 37 | -------------------------------------------------------------------------------- /2022/04/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | input, _ := os.ReadFile("input.txt") 11 | 12 | part1, part2 := 0, 0 13 | for _, s := range strings.Fields(strings.TrimSpace(string(input))) { 14 | var s1, e1, s2, e2 int 15 | fmt.Sscanf(s, "%d-%d,%d-%d", &s1, &e1, &s2, &e2) 16 | 17 | if s1 <= s2 && e1 >= e2 || s1 >= s2 && e1 <= e2 { 18 | part1++ 19 | } 20 | if s1 <= e2 && e1 >= s2 { 21 | part2++ 22 | } 23 | } 24 | fmt.Println(part1) 25 | fmt.Println(part2) 26 | } 27 | -------------------------------------------------------------------------------- /2022/05/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | "unicode" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | split := strings.Split(string(input), "\n\n") 13 | crates := strings.Split(split[0], "\n") 14 | keys := crates[len(crates)-1] 15 | 16 | stack1, stack2 := map[rune]string{}, map[rune]string{} 17 | for _, s := range crates { 18 | for i, r := range s { 19 | if unicode.IsLetter(r) { 20 | stack1[[]rune(keys)[i]] += string(r) 21 | stack2[[]rune(keys)[i]] += string(r) 22 | } 23 | } 24 | } 25 | 26 | for _, s := range strings.Split(strings.TrimSpace(split[1]), "\n") { 27 | var qty int 28 | var from, to rune 29 | fmt.Sscanf(s, "move %d from %c to %c", &qty, &from, &to) 30 | 31 | for i := 0; i < qty; i++ { 32 | stack1[to] = stack1[from][:1] + stack1[to] 33 | stack1[from] = stack1[from][1:] 34 | } 35 | stack2[to] = stack2[from][:qty] + stack2[to] 36 | stack2[from] = stack2[from][qty:] 37 | } 38 | 39 | part1, part2 := "", "" 40 | for _, r := range strings.ReplaceAll(keys, " ", "") { 41 | part1 += stack1[r][:1] 42 | part2 += stack2[r][:1] 43 | } 44 | fmt.Println(part1) 45 | fmt.Println(part2) 46 | } 47 | -------------------------------------------------------------------------------- /2022/06/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | input, _ := os.ReadFile("input.txt") 10 | fmt.Println(find(string(input), 4)) 11 | fmt.Println(find(string(input), 14)) 12 | } 13 | 14 | func find(s string, l int) int { 15 | for i := l; i <= len(s); i++ { 16 | m := map[rune]struct{}{} 17 | for _, r := range s[i-l : i] { 18 | m[r] = struct{}{} 19 | } 20 | if len(m) >= l { 21 | return i 22 | } 23 | } 24 | return -1 25 | } 26 | -------------------------------------------------------------------------------- /2022/07/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | fs, cd := map[string]int{}, "" 14 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 15 | var size int 16 | var name string 17 | 18 | if strings.HasPrefix(s, "$ cd") { 19 | cd = path.Join(cd, strings.Fields(s)[2]) 20 | } else if _, err := fmt.Sscanf(s, "%d %s", &size, &name); err == nil { 21 | for d := cd; d != "/"; d = path.Dir(d) { 22 | fs[d] += size 23 | } 24 | fs["/"] += size 25 | } 26 | } 27 | 28 | part1, part2 := 0, fs["/"] 29 | for _, s := range fs { 30 | if s <= 100000 { 31 | part1 += s 32 | } 33 | if s+70000000-fs["/"] >= 30000000 && s < part2 { 34 | part2 = s 35 | } 36 | } 37 | fmt.Println(part1) 38 | fmt.Println(part2) 39 | } 40 | -------------------------------------------------------------------------------- /2022/08/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | trees := map[image.Point]int{} 14 | for y, s := range strings.Fields(strings.TrimSpace(string(input))) { 15 | for x, r := range s { 16 | trees[image.Point{x, y}] = int(r - '0') 17 | } 18 | } 19 | 20 | part1, part2 := 0, 0 21 | for p, t := range trees { 22 | vis, score := 0, 1 23 | 24 | for _, d := range []image.Point{{0, -1}, {1, 0}, {0, 1}, {-1, 0}} { 25 | for i := 1; ; i++ { 26 | if nt, ok := trees[p.Add(d.Mul(i))]; !ok { 27 | vis, score = 1, score*(i-1) 28 | break 29 | } else if nt >= t { 30 | score *= i 31 | break 32 | } 33 | } 34 | } 35 | 36 | part1 += vis 37 | if score > part2 { 38 | part2 = score 39 | } 40 | } 41 | fmt.Println(part1) 42 | fmt.Println(part2) 43 | } 44 | -------------------------------------------------------------------------------- /2022/09/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | dirs := map[rune]image.Point{'U': {0, -1}, 'R': {1, 0}, 'D': {0, 1}, 'L': {-1, 0}} 13 | rope := make([]image.Point, 10) 14 | 15 | part1, part2 := map[image.Point]struct{}{}, map[image.Point]struct{}{} 16 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 17 | var dir rune 18 | var steps int 19 | fmt.Sscanf(s, "%c %d", &dir, &steps) 20 | 21 | for i := 0; i < steps; i++ { 22 | rope[0] = rope[0].Add(dirs[dir]) 23 | 24 | for i := 1; i < len(rope); i++ { 25 | if d := rope[i-1].Sub(rope[i]); abs(d.X) > 1 || abs(d.Y) > 1 { 26 | rope[i] = rope[i].Add(image.Point{sgn(d.X), sgn(d.Y)}) 27 | } 28 | } 29 | 30 | part1[rope[1]], part2[rope[len(rope)-1]] = struct{}{}, struct{}{} 31 | } 32 | } 33 | fmt.Println(len(part1)) 34 | fmt.Println(len(part2)) 35 | } 36 | 37 | func abs(x int) int { 38 | if x < 0 { 39 | return -x 40 | } 41 | return x 42 | } 43 | 44 | func sgn(x int) int { 45 | if x < 0 { 46 | return -1 47 | } else if x > 0 { 48 | return 1 49 | } 50 | return 0 51 | } 52 | -------------------------------------------------------------------------------- /2022/10/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | const w = 40 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | 14 | c, x := 0, 1 15 | part1, part2 := 0, "" 16 | 17 | tick := func() { 18 | part2 += map[bool]string{true: "██", false: " "}[c%w >= x-1 && c%w <= x+1] 19 | part2 += map[bool]string{true: "\n"}[c%w == w-1] 20 | if c++; (c+w/2)%w == 0 { 21 | part1 += c * x 22 | } 23 | } 24 | 25 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 26 | var ins string 27 | var v int 28 | fmt.Sscanf(s, "%s %d", &ins, &v) 29 | 30 | tick() 31 | if ins == "addx" { 32 | tick() 33 | x += v 34 | } 35 | } 36 | fmt.Println(part1) 37 | fmt.Println(strings.TrimSpace(part2)) 38 | } 39 | -------------------------------------------------------------------------------- /2022/11/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | "sort" 8 | "strings" 9 | ) 10 | 11 | type Monkey struct { 12 | Items []int 13 | Op func(int) int 14 | Test func(int) int 15 | } 16 | 17 | func main() { 18 | input, _ := os.ReadFile("input.txt") 19 | split := strings.Split(strings.TrimSpace(string(input)), "\n\n") 20 | 21 | monkeys, lcm := make([]Monkey, len(split)), 1 22 | for _, s := range split { 23 | var items, op string 24 | var i, v, test, t, f int 25 | fmt.Sscanf(strings.NewReplacer(", ", ",", "* old", "^ 2").Replace(s), 26 | `Monkey %d: 27 | Starting items: %s 28 | Operation: new = old %s %d 29 | Test: divisible by %d 30 | If true: throw to monkey %d 31 | If false: throw to monkey %d`, 32 | &i, &items, &op, &v, &test, &t, &f) 33 | 34 | json.Unmarshal([]byte("["+items+"]"), &monkeys[i].Items) 35 | monkeys[i].Op = map[string]func(int) int{ 36 | "+": func(o int) int { return o + v }, 37 | "*": func(o int) int { return o * v }, 38 | "^": func(o int) int { return o * o }, 39 | }[op] 40 | monkeys[i].Test = func(w int) int { 41 | if w%test == 0 { 42 | return t 43 | } 44 | return f 45 | } 46 | lcm *= test 47 | } 48 | 49 | fmt.Println(inspect(monkeys, 20, func(w int) int { return w / 3 })) 50 | fmt.Println(inspect(monkeys, 10000, func(w int) int { return w % lcm })) 51 | } 52 | 53 | func inspect(monkeys []Monkey, rounds int, op func(int) int) int { 54 | monkeys = append([]Monkey{}, monkeys...) 55 | inspected := make([]int, len(monkeys)) 56 | for i := 0; i < rounds; i++ { 57 | for i, m := range monkeys { 58 | for _, w := range m.Items { 59 | w = op(m.Op(w)) 60 | monkeys[m.Test(w)].Items = append(monkeys[m.Test(w)].Items, w) 61 | inspected[i]++ 62 | } 63 | monkeys[i].Items = nil 64 | } 65 | } 66 | sort.Sort(sort.Reverse(sort.IntSlice(inspected))) 67 | return inspected[0] * inspected[1] 68 | } 69 | -------------------------------------------------------------------------------- /2022/12/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | var start, end image.Point 14 | height := map[image.Point]rune{} 15 | for x, s := range strings.Fields(string(input)) { 16 | for y, r := range s { 17 | height[image.Point{x, y}] = r 18 | if r == 'S' { 19 | start = image.Point{x, y} 20 | } else if r == 'E' { 21 | end = image.Point{x, y} 22 | } 23 | } 24 | } 25 | height[start], height[end] = 'a', 'z' 26 | 27 | dist := map[image.Point]int{end: 0} 28 | queue := []image.Point{end} 29 | var shortest *image.Point 30 | 31 | for len(queue) > 0 { 32 | cur := queue[0] 33 | queue = queue[1:] 34 | 35 | if height[cur] == 'a' && shortest == nil { 36 | shortest = &cur 37 | } 38 | 39 | for _, d := range []image.Point{{0, -1}, {1, 0}, {0, 1}, {-1, 0}} { 40 | next := cur.Add(d) 41 | _, seen := dist[next] 42 | _, valid := height[next] 43 | 44 | if !seen && valid && height[cur] <= height[next]+1 { 45 | dist[next] = dist[cur] + 1 46 | queue = append(queue, next) 47 | } 48 | } 49 | } 50 | 51 | fmt.Println(dist[start]) 52 | fmt.Println(dist[*shortest]) 53 | } 54 | -------------------------------------------------------------------------------- /2022/13/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | "sort" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | 14 | pkts, part1 := []any{}, 0 15 | for i, s := range strings.Split(strings.TrimSpace(string(input)), "\n\n") { 16 | s := strings.Split(s, "\n") 17 | var a, b any 18 | json.Unmarshal([]byte(s[0]), &a) 19 | json.Unmarshal([]byte(s[1]), &b) 20 | pkts = append(pkts, a, b) 21 | 22 | if cmp(a, b) <= 0 { 23 | part1 += i + 1 24 | } 25 | } 26 | fmt.Println(part1) 27 | 28 | pkts = append(pkts, []any{[]any{2.}}, []any{[]any{6.}}) 29 | sort.Slice(pkts, func(i, j int) bool { return cmp(pkts[i], pkts[j]) < 0 }) 30 | 31 | part2 := 1 32 | for i, p := range pkts { 33 | if fmt.Sprint(p) == "[[2]]" || fmt.Sprint(p) == "[[6]]" { 34 | part2 *= i + 1 35 | } 36 | } 37 | fmt.Println(part2) 38 | } 39 | 40 | func cmp(a, b any) int { 41 | as, aok := a.([]any) 42 | bs, bok := b.([]any) 43 | 44 | switch { 45 | case !aok && !bok: 46 | return int(a.(float64) - b.(float64)) 47 | case !aok: 48 | as = []any{a} 49 | case !bok: 50 | bs = []any{b} 51 | } 52 | 53 | for i := 0; i < len(as) && i < len(bs); i++ { 54 | if c := cmp(as[i], bs[i]); c != 0 { 55 | return c 56 | } 57 | } 58 | return len(as) - len(bs) 59 | } 60 | -------------------------------------------------------------------------------- /2022/14/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | rock, maxy := map[image.Point]struct{}{}, 0 14 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 15 | s := strings.Split(s, " -> ") 16 | 17 | for i := 0; i < len(s)-1; i++ { 18 | var p, q image.Point 19 | fmt.Sscanf(s[i], "%d,%d", &p.X, &p.Y) 20 | fmt.Sscanf(s[i+1], "%d,%d", &q.X, &q.Y) 21 | 22 | for d := (image.Point{sgn(q.X - p.X), sgn(q.Y - p.Y)}); p != q.Add(d); p = p.Add(d) { 23 | rock[p] = struct{}{} 24 | if p.Y > maxy { 25 | maxy = p.Y 26 | } 27 | } 28 | } 29 | } 30 | 31 | d := []image.Point{{0, 1}, {-1, 1}, {1, 1}} 32 | 33 | part1, part2 := (*int)(nil), 0 34 | for { 35 | p := image.Point{500, 0} 36 | 37 | for i := 0; i < len(d); i++ { 38 | if _, ok := rock[p.Add(d[i])]; !ok && p.Add(d[i]).Y < maxy+2 { 39 | p = p.Add(d[i]) 40 | if c := part2; part1 == nil && p.Y >= maxy { 41 | part1 = &c 42 | } 43 | i = -1 44 | } 45 | } 46 | 47 | rock[p] = struct{}{} 48 | part2++ 49 | if p.Y == 0 { 50 | break 51 | } 52 | } 53 | fmt.Println(*part1) 54 | fmt.Println(part2) 55 | } 56 | 57 | func sgn(i int) int { 58 | if i < 0 { 59 | return -1 60 | } else if i > 0 { 61 | return 1 62 | } 63 | return 0 64 | } 65 | -------------------------------------------------------------------------------- /2022/15/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | sensors := map[image.Point]int{} 14 | line := map[int]struct{}{} 15 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 16 | var a, b image.Point 17 | fmt.Sscanf(s, "Sensor at x=%d, y=%d: closest beacon is at x=%d, y=%d", &a.X, &a.Y, &b.X, &b.Y) 18 | 19 | sensors[a] = abs(a.X-b.X) + abs(a.Y-b.Y) 20 | d := sensors[a] - abs(2000000-a.Y) 21 | 22 | for x := a.X - d; x <= a.X+d; x++ { 23 | if !(b.X == x && b.Y == 2000000) { 24 | line[x] = struct{}{} 25 | } 26 | } 27 | } 28 | fmt.Println(len(line)) 29 | 30 | for y := 0; y <= 4000000; y++ { 31 | loop: 32 | for x := 0; x <= 4000000; x++ { 33 | for s, d := range sensors { 34 | if dx, dy := s.X-x, s.Y-y; abs(dx)+abs(dy) <= d { 35 | x += d - abs(dy) + dx 36 | continue loop 37 | } 38 | } 39 | fmt.Println(x*4000000 + y) 40 | return 41 | } 42 | } 43 | } 44 | 45 | func abs(x int) int { 46 | if x < 0 { 47 | return -x 48 | } 49 | return x 50 | } 51 | -------------------------------------------------------------------------------- /2022/17/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | jets := strings.TrimSpace(string(input)) 13 | rocks := [][]image.Point{ 14 | {{0, 0}, {1, 0}, {2, 0}, {3, 0}}, 15 | {{1, 2}, {0, 1}, {1, 1}, {2, 1}, {1, 0}}, 16 | {{2, 2}, {2, 1}, {0, 0}, {1, 0}, {2, 0}}, 17 | {{0, 3}, {0, 2}, {0, 1}, {0, 0}}, 18 | {{0, 1}, {1, 1}, {0, 0}, {1, 0}}, 19 | } 20 | 21 | grid := map[image.Point]struct{}{} 22 | move := func(rock []image.Point, delta image.Point) bool { 23 | nrock := make([]image.Point, len(rock)) 24 | for i, p := range rock { 25 | p = p.Add(delta) 26 | if _, ok := grid[p]; ok || p.X < 0 || p.X >= 7 || p.Y < 0 { 27 | return false 28 | } 29 | nrock[i] = p 30 | } 31 | copy(rock, nrock) 32 | return true 33 | } 34 | 35 | cache := map[[2]int][]int{} 36 | 37 | height, jet := 0, 0 38 | for i := 0; i < 1000000000000; i++ { 39 | if i == 2022 { 40 | fmt.Println(height) 41 | } 42 | 43 | k := [2]int{i % len(rocks), jet} 44 | if c, ok := cache[k]; ok { 45 | if n, d := 1000000000000-i, i-c[0]; n%d == 0 { 46 | fmt.Println(height + n/d*(height-c[1])) 47 | break 48 | } 49 | } 50 | cache[k] = []int{i, height} 51 | 52 | rock := []image.Point{} 53 | for _, p := range rocks[i%len(rocks)] { 54 | rock = append(rock, p.Add(image.Point{2, height + 3})) 55 | } 56 | 57 | for { 58 | move(rock, image.Point{int(jets[jet]) - int('='), 0}) 59 | jet = (jet + 1) % len(jets) 60 | 61 | if !move(rock, image.Point{0, -1}) { 62 | for _, p := range rock { 63 | grid[p] = struct{}{} 64 | if p.Y+1 > height { 65 | height = p.Y + 1 66 | } 67 | } 68 | break 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /2022/18/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | type Point struct { 11 | X, Y, Z int 12 | } 13 | 14 | func (p Point) Add(q Point) Point { 15 | return Point{p.X + q.X, p.Y + q.Y, p.Z + q.Z} 16 | } 17 | 18 | func main() { 19 | input, _ := os.ReadFile("input.txt") 20 | 21 | lava := map[Point]struct{}{} 22 | min := Point{math.MaxInt, math.MaxInt, math.MaxInt} 23 | max := Point{math.MinInt, math.MinInt, math.MinInt} 24 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 25 | var p Point 26 | fmt.Sscanf(s, "%d,%d,%d", &p.X, &p.Y, &p.Z) 27 | lava[p] = struct{}{} 28 | 29 | min = Point{Min(min.X, p.X), Min(min.Y, p.Y), Min(min.Z, p.Z)} 30 | max = Point{Max(max.X, p.X), Max(max.Y, p.Y), Max(max.Z, p.Z)} 31 | } 32 | min = min.Add(Point{-1, -1, -1}) 33 | max = max.Add(Point{1, 1, 1}) 34 | 35 | delta := []Point{ 36 | {-1, 0, 0}, {0, -1, 0}, {0, 0, -1}, 37 | {1, 0, 0}, {0, 1, 0}, {0, 0, 1}, 38 | } 39 | 40 | part1 := 0 41 | for p := range lava { 42 | for _, d := range delta { 43 | if _, ok := lava[p.Add(d)]; !ok { 44 | part1++ 45 | } 46 | } 47 | } 48 | fmt.Println(part1) 49 | 50 | queue := []Point{min} 51 | visited := map[Point]struct{}{min: {}} 52 | 53 | part2 := 0 54 | for len(queue) > 0 { 55 | cur := queue[0] 56 | queue = queue[1:] 57 | 58 | for _, d := range delta { 59 | next := cur.Add(d) 60 | 61 | if _, ok := lava[next]; ok { 62 | part2++ 63 | } else if _, ok := visited[next]; !ok && 64 | next.X >= min.X && next.X <= max.X && 65 | next.Y >= min.Y && next.Y <= max.Y && 66 | next.Z >= min.Z && next.Z <= max.Z { 67 | visited[next] = struct{}{} 68 | queue = append(queue, next) 69 | } 70 | } 71 | } 72 | fmt.Println(part2) 73 | } 74 | 75 | func Min(a, b int) int { 76 | if a < b { 77 | return a 78 | } 79 | return b 80 | } 81 | 82 | func Max(a, b int) int { 83 | if a > b { 84 | return a 85 | } 86 | return b 87 | } 88 | -------------------------------------------------------------------------------- /2022/20/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "container/ring" 5 | "fmt" 6 | "os" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | 14 | fmt.Println(mix(string(input), 1, 1)) 15 | fmt.Println(mix(string(input), 811589153, 10)) 16 | } 17 | 18 | func mix(input string, key, times int) int { 19 | split := strings.Fields(input) 20 | 21 | r, idx, z := ring.New(len(split)), map[int]*ring.Ring{}, (*ring.Ring)(nil) 22 | for i, s := range split { 23 | v, _ := strconv.Atoi(s) 24 | if v == 0 { 25 | z = r 26 | } 27 | r.Value, idx[i], r = v*key, r, r.Next() 28 | } 29 | 30 | for i := 0; i < times; i++ { 31 | for i := 0; i < len(idx); i++ { 32 | r = idx[i].Prev() 33 | c := r.Unlink(1) 34 | r.Move(c.Value.(int) % (len(idx) - 1)).Link(c) 35 | } 36 | } 37 | 38 | return z.Move(1000).Value.(int) + z.Move(2000).Value.(int) + z.Move(3000).Value.(int) 39 | } 40 | -------------------------------------------------------------------------------- /2022/21/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "sort" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | var monkeys = map[string]string{} 12 | 13 | func main() { 14 | input, _ := os.ReadFile("input.txt") 15 | 16 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 17 | s := strings.Split(s, ": ") 18 | monkeys[s[0]] = s[1] 19 | } 20 | fmt.Println(solve("root")) 21 | 22 | monkeys["humn"] = "0" 23 | s := strings.Fields(monkeys["root"]) 24 | if solve(s[0]) < solve(s[2]) { 25 | s[0], s[2] = s[2], s[0] 26 | } 27 | 28 | part2, _ := sort.Find(1e16, func(v int) int { 29 | monkeys["humn"] = strconv.Itoa(v) 30 | return solve(s[0]) - solve(s[2]) 31 | }) 32 | fmt.Println(part2) 33 | } 34 | 35 | func solve(expr string) int { 36 | if v, err := strconv.Atoi(monkeys[expr]); err == nil { 37 | return v 38 | } 39 | 40 | s := strings.Fields(monkeys[expr]) 41 | return map[string]func(int, int) int{ 42 | "+": func(a, b int) int { return a + b }, 43 | "-": func(a, b int) int { return a - b }, 44 | "*": func(a, b int) int { return a * b }, 45 | "/": func(a, b int) int { return a / b }, 46 | }[s[1]](solve(s[0]), solve(s[2])) 47 | } 48 | -------------------------------------------------------------------------------- /2022/23/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "reflect" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | 14 | grid := map[image.Point]struct{}{} 15 | for y, s := range strings.Fields(string(input)) { 16 | for x, r := range s { 17 | if r == '#' { 18 | grid[image.Point{x, y}] = struct{}{} 19 | } 20 | } 21 | } 22 | 23 | sides := [][]image.Point{ 24 | {{0, -1}, {1, -1}, {-1, -1}}, 25 | {{0, 1}, {1, 1}, {-1, 1}}, 26 | {{-1, 0}, {-1, -1}, {-1, 1}}, 27 | {{1, 0}, {1, -1}, {1, 1}}, 28 | } 29 | 30 | for i := 0; ; i++ { 31 | prop := map[image.Point]image.Point{} 32 | count := map[image.Point]int{} 33 | 34 | for p := range grid { 35 | neigh := map[int]int{} 36 | for i := range sides { 37 | for _, q := range sides[i] { 38 | if _, ok := grid[p.Add(q)]; ok { 39 | neigh[i]++ 40 | } 41 | } 42 | } 43 | 44 | if len(neigh) == 0 { 45 | continue 46 | } 47 | 48 | for d := 0; d < len(sides); d++ { 49 | if dir := (i + d) % len(sides); neigh[dir] == 0 { 50 | prop[p] = p.Add(sides[dir][0]) 51 | count[prop[p]]++ 52 | break 53 | } 54 | } 55 | } 56 | 57 | newGrid := map[image.Point]struct{}{} 58 | for p := range grid { 59 | if _, ok := prop[p]; ok && count[prop[p]] == 1 { 60 | p = prop[p] 61 | } 62 | newGrid[p] = struct{}{} 63 | } 64 | 65 | if i == 9 { 66 | var r image.Rectangle 67 | for p := range newGrid { 68 | r = r.Union(image.Rectangle{p, p.Add(image.Point{1, 1})}) 69 | } 70 | fmt.Println(r.Dx()*r.Dy() - len(newGrid)) 71 | } 72 | if reflect.DeepEqual(grid, newGrid) { 73 | fmt.Println(i + 1) 74 | break 75 | } 76 | 77 | grid = newGrid 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /2022/24/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | type State struct { 11 | P image.Point 12 | T int 13 | } 14 | 15 | func main() { 16 | input, _ := os.ReadFile("input.txt") 17 | 18 | vall := map[image.Point]rune{} 19 | for y, s := range strings.Fields(string(input)) { 20 | for x, r := range s { 21 | vall[image.Point{x, y}] = r 22 | } 23 | } 24 | 25 | var bliz image.Rectangle 26 | for p := range vall { 27 | bliz = bliz.Union(image.Rectangle{p, p.Add(image.Point{1, 1})}) 28 | } 29 | bliz.Min, bliz.Max = bliz.Min.Add(image.Point{1, 1}), bliz.Max.Sub(image.Point{1, 1}) 30 | 31 | bfs := func(start image.Point, end image.Point, time int) int { 32 | delta := map[rune]image.Point{ 33 | '#': {0, 0}, '^': {0, -1}, '>': {1, 0}, 'v': {0, 1}, '<': {-1, 0}, 34 | } 35 | 36 | queue := []State{{start, time}} 37 | seen := map[State]struct{}{queue[0]: {}} 38 | 39 | for len(queue) > 0 { 40 | cur := queue[0] 41 | queue = queue[1:] 42 | 43 | loop: 44 | for _, d := range delta { 45 | next := State{cur.P.Add(d), cur.T + 1} 46 | if next.P == end { 47 | return next.T 48 | } 49 | 50 | if _, ok := seen[next]; ok { 51 | continue 52 | } 53 | if r, ok := vall[next.P]; !ok || r == '#' { 54 | continue 55 | } 56 | 57 | if next.P.In(bliz) { 58 | for r, d := range delta { 59 | if vall[next.P.Sub(d.Mul(next.T)).Mod(bliz)] == r { 60 | continue loop 61 | } 62 | } 63 | } 64 | 65 | seen[next] = struct{}{} 66 | queue = append(queue, next) 67 | } 68 | } 69 | return -1 70 | } 71 | 72 | start, end := bliz.Min.Sub(image.Point{0, 1}), bliz.Max.Sub(image.Point{1, 0}) 73 | fmt.Println(bfs(start, end, 0)) 74 | fmt.Println(bfs(start, end, bfs(end, start, bfs(start, end, 0)))) 75 | } 76 | -------------------------------------------------------------------------------- /2022/25/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | input, _ := os.ReadFile("input.txt") 11 | 12 | sum := 0 13 | for _, s := range strings.Fields(string(input)) { 14 | n := 0 15 | for _, r := range s { 16 | n = 5*n + map[rune]int{'=': -2, '-': -1, '0': 0, '1': 1, '2': 2}[r] 17 | } 18 | sum += n 19 | } 20 | 21 | snafu := "" 22 | for sum > 0 { 23 | snafu = string("=-012"[(sum+2)%5]) + snafu 24 | sum = (sum + 2) / 5 25 | } 26 | fmt.Println(snafu) 27 | } 28 | -------------------------------------------------------------------------------- /2023/01/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | input, _ := os.ReadFile("input.txt") 11 | 12 | calc := func(r *strings.Replacer) (result int) { 13 | for _, s := range strings.Fields(string(input)) { 14 | s = r.Replace(r.Replace(s)) 15 | result += 10 * int(s[strings.IndexAny(s, "123456789")]-'0') 16 | result += int(s[strings.LastIndexAny(s, "123456789")] - '0') 17 | } 18 | return 19 | } 20 | 21 | fmt.Println(calc(strings.NewReplacer())) 22 | fmt.Println(calc(strings.NewReplacer("one", "o1e", "two", "t2o", "three", "t3e", "four", 23 | "f4r", "five", "f5e", "six", "s6x", "seven", "s7n", "eight", "e8t", "nine", "n9e"))) 24 | } 25 | -------------------------------------------------------------------------------- /2023/02/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "regexp" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | re := regexp.MustCompile(`(\d+) (\w+)`) 14 | 15 | part1, part2 := 0, 0 16 | for i, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 17 | mins := map[string]int{} 18 | 19 | for _, m := range re.FindAllStringSubmatch(s, -1) { 20 | n, _ := strconv.Atoi(m[1]) 21 | mins[m[2]] = max(mins[m[2]], n) 22 | } 23 | 24 | if mins["red"] <= 12 && mins["green"] <= 13 && mins["blue"] <= 14 { 25 | part1 += i + 1 26 | } 27 | part2 += mins["red"] * mins["green"] * mins["blue"] 28 | } 29 | fmt.Println(part1) 30 | fmt.Println(part2) 31 | } 32 | -------------------------------------------------------------------------------- /2023/03/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "regexp" 8 | "strconv" 9 | "strings" 10 | "unicode" 11 | ) 12 | 13 | func main() { 14 | input, _ := os.ReadFile("input.txt") 15 | 16 | grid := map[image.Point]rune{} 17 | for y, s := range strings.Fields(string(input)) { 18 | for x, r := range s { 19 | if r != '.' && !unicode.IsDigit(r) { 20 | grid[image.Point{x, y}] = r 21 | } 22 | } 23 | } 24 | 25 | part1, part2 := 0, 0 26 | parts := map[image.Point][]int{} 27 | for y, s := range strings.Fields(string(input)) { 28 | for _, m := range regexp.MustCompile(`\d+`).FindAllStringIndex(s, -1) { 29 | bounds := map[image.Point]struct{}{} 30 | for x := m[0]; x < m[1]; x++ { 31 | for _, d := range []image.Point{ 32 | {-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}, 33 | } { 34 | bounds[image.Point{x, y}.Add(d)] = struct{}{} 35 | } 36 | } 37 | 38 | n, _ := strconv.Atoi(s[m[0]:m[1]]) 39 | for p := range bounds { 40 | if _, ok := grid[p]; ok { 41 | parts[p] = append(parts[p], n) 42 | part1 += n 43 | } 44 | } 45 | } 46 | } 47 | 48 | for p, ns := range parts { 49 | if grid[p] == '*' && len(ns) == 2 { 50 | part2 += ns[0] * ns[1] 51 | } 52 | } 53 | fmt.Println(part1) 54 | fmt.Println(part2) 55 | } 56 | -------------------------------------------------------------------------------- /2023/04/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "regexp" 7 | "slices" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | re := regexp.MustCompile(`((?:\s+\d+)*) \|((?:\s+\d+)*)`) 14 | copies := map[int]int{} 15 | 16 | part1, part2 := 0, 0 17 | for i, m := range re.FindAllStringSubmatch(string(input), -1) { 18 | matching := 0 19 | for _, n := range strings.Fields(m[1]) { 20 | if slices.Contains(strings.Fields(m[2]), n) { 21 | matching++ 22 | } 23 | } 24 | part1 += 1 << matching >> 1 25 | 26 | copies[i]++ 27 | for j := 1; j <= matching; j++ { 28 | copies[i+j] += copies[i] 29 | } 30 | part2 += copies[i] 31 | } 32 | fmt.Println(part1) 33 | fmt.Println(part2) 34 | } 35 | -------------------------------------------------------------------------------- /2023/05/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "math" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | split := strings.Split(strings.TrimSpace(string(input)), "\n\n") 14 | 15 | var seeds []int 16 | json.Unmarshal([]byte("["+strings.Join(strings.Fields(strings.Split(split[0], ": ")[1]), ",")+"]"), &seeds) 17 | 18 | maps := [][][3]int{} 19 | for i, s := range split[1:] { 20 | maps = append(maps, [][3]int{}) 21 | 22 | for j, s := range strings.Split(strings.Split(s, ":\n")[1], "\n") { 23 | maps[i] = append(maps[i], [3]int{}) 24 | fmt.Sscanf(s, "%d %d %d", &maps[i][j][0], &maps[i][j][1], &maps[i][j][2]) 25 | } 26 | } 27 | 28 | calc := func(seed int) int { 29 | for _, m := range maps { 30 | for _, r := range m { 31 | if seed >= r[1] && seed < r[1]+r[2] { 32 | seed = r[0] + seed - r[1] 33 | break 34 | } 35 | } 36 | } 37 | return seed 38 | } 39 | 40 | part1, part2 := math.MaxInt, math.MaxInt 41 | for i, s := range seeds { 42 | part1 = min(part1, calc(s)) 43 | if i%2 == 0 { 44 | for s := seeds[i]; s < seeds[i]+seeds[i+1]; s++ { 45 | part2 = min(part2, calc(s)) 46 | } 47 | } 48 | } 49 | fmt.Println(part1) 50 | fmt.Println(part2) 51 | } 52 | -------------------------------------------------------------------------------- /2023/06/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "os" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | split := strings.Split(strings.TrimSpace(string(input)), "\n") 14 | 15 | calc := func(time, dist []string) int { 16 | r := 1 17 | for i := range time { 18 | t, _ := strconv.ParseFloat(time[i], 64) 19 | d, _ := strconv.ParseFloat(dist[i], 64) 20 | b := math.Sqrt(math.Pow(t, 2) - 4*d) 21 | r *= int(math.Ceil((t+b)/2) - math.Floor((t-b)/2) - 1) 22 | } 23 | return r 24 | } 25 | 26 | fmt.Println(calc(strings.Fields(split[0])[1:], strings.Fields(split[1])[1:])) 27 | fmt.Println(calc( 28 | []string{strings.Join(strings.Fields(split[0])[1:], "")}, 29 | []string{strings.Join(strings.Fields(split[1])[1:], "")}, 30 | )) 31 | } 32 | -------------------------------------------------------------------------------- /2023/07/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "slices" 7 | "strings" 8 | ) 9 | 10 | type Hand struct { 11 | Cards string 12 | Bid int 13 | } 14 | 15 | func main() { 16 | input, _ := os.ReadFile("input.txt") 17 | 18 | hands := []Hand{} 19 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 20 | h := Hand{} 21 | fmt.Sscanf(s, "%s %d", &h.Cards, &h.Bid) 22 | hands = append(hands, h) 23 | } 24 | 25 | winnings := func(jokers bool) (w int) { 26 | slices.SortFunc(hands, func(a, b Hand) int { 27 | return cmp(a.Cards, b.Cards, jokers) 28 | }) 29 | for i, h := range hands { 30 | w += (i + 1) * h.Bid 31 | } 32 | return 33 | } 34 | 35 | fmt.Println(winnings(false)) 36 | fmt.Println(winnings(true)) 37 | } 38 | 39 | func cmp(a, b string, jokers bool) int { 40 | j, r := "J", "TAJBQCKDAE" 41 | if jokers { 42 | j, r = "23456789TQKA", "TAJ0QCKDAE" 43 | } 44 | 45 | typ := func(cards string) string { 46 | k := 0 47 | for _, j := range strings.Split(j, "") { 48 | n, t := strings.ReplaceAll(cards, "J", j), 0 49 | for _, s := range n { 50 | t += strings.Count(n, string(s)) 51 | } 52 | k = max(k, t) 53 | } 54 | return map[int]string{5: "0", 7: "1", 9: "2", 11: "3", 13: "4", 17: "5", 25: "6"}[k] 55 | } 56 | 57 | return strings.Compare( 58 | typ(a)+strings.NewReplacer(strings.Split(r, "")...).Replace(a), 59 | typ(b)+strings.NewReplacer(strings.Split(r, "")...).Replace(b), 60 | ) 61 | } 62 | -------------------------------------------------------------------------------- /2023/08/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "regexp" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | split := strings.Split(strings.TrimSpace(string(input)), "\n\n") 13 | re := regexp.MustCompile(`(.*) = \((.*), (.*)\)`) 14 | 15 | network := map[string]map[rune]string{} 16 | for _, m := range re.FindAllStringSubmatch(split[1], -1) { 17 | network[m[1]] = map[rune]string{'L': m[2], 'R': m[3]} 18 | } 19 | 20 | walk := func(start, end string) int { 21 | result := 1 22 | for n := range network { 23 | if !strings.HasSuffix(n, start) { 24 | continue 25 | } 26 | 27 | steps := 0 28 | for !strings.HasSuffix(n, end) { 29 | n = network[n][rune(split[0][steps%len(split[0])])] 30 | steps++ 31 | } 32 | 33 | result = lcm(result, steps) 34 | } 35 | return result 36 | } 37 | 38 | fmt.Println(walk("AAA", "ZZZ")) 39 | fmt.Println(walk("A", "Z")) 40 | } 41 | 42 | func gcd(a, b int) int { 43 | for b != 0 { 44 | a, b = b, a%b 45 | } 46 | return a 47 | } 48 | 49 | func lcm(a, b int) int { 50 | return a * b / gcd(a, b) 51 | } 52 | -------------------------------------------------------------------------------- /2023/09/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | "slices" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | 14 | var next func([]int) int 15 | next = func(s []int) int { 16 | h := []int{} 17 | for i := 0; i < len(s)-1; i++ { 18 | h = append(h, s[i+1]-s[i]) 19 | } 20 | if !slices.ContainsFunc(h, func(x int) bool { return x != 0 }) { 21 | return s[len(s)-1] 22 | } 23 | return s[len(s)-1] + next(h) 24 | } 25 | 26 | part1, part2 := 0, 0 27 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 28 | var seq []int 29 | json.Unmarshal([]byte("["+strings.ReplaceAll(s, " ", ",")+"]"), &seq) 30 | 31 | part1 += next(seq) 32 | slices.Reverse(seq) 33 | part2 += next(seq) 34 | } 35 | fmt.Println(part1) 36 | fmt.Println(part2) 37 | } 38 | -------------------------------------------------------------------------------- /2023/10/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "math" 7 | "os" 8 | "slices" 9 | "strings" 10 | ) 11 | 12 | func main() { 13 | input, _ := os.ReadFile("input.txt") 14 | 15 | grid, start := map[image.Point]rune{}, image.Point{} 16 | for y, s := range strings.Fields(string(input)) { 17 | for x, r := range s { 18 | grid[image.Point{x, y}] = r 19 | if r == 'S' { 20 | start = image.Point{x, y} 21 | } 22 | } 23 | } 24 | 25 | grid[start] = map[[4]bool]rune{ 26 | {true, false, true, false}: '|', {false, true, false, true}: '-', 27 | {true, true, false, false}: 'L', {true, false, false, true}: 'J', 28 | {false, false, true, true}: '7', {false, true, true, false}: 'F', 29 | }[[4]bool{ 30 | strings.ContainsRune("7F|", grid[start.Add(image.Point{0, -1})]), 31 | strings.ContainsRune("-7J", grid[start.Add(image.Point{1, 0})]), 32 | strings.ContainsRune("JL|", grid[start.Add(image.Point{0, 1})]), 33 | strings.ContainsRune("-FL", grid[start.Add(image.Point{-1, 0})]), 34 | }] 35 | 36 | path, area := []image.Point{}, 0 37 | for p, n := start, start; p == start || n != start; path = append(path, p) { 38 | p, n = n, start 39 | 40 | for _, d := range map[rune][]image.Point{ 41 | '|': {{0, -1}, {0, 1}}, '-': {{1, 0}, {-1, 0}}, 'L': {{0, -1}, {1, 0}}, 42 | 'J': {{0, -1}, {-1, 0}}, '7': {{0, 1}, {-1, 0}}, 'F': {{0, 1}, {1, 0}}, 43 | }[grid[p]] { 44 | if !slices.Contains(path, p.Add(d)) { 45 | n = p.Add(d) 46 | } 47 | } 48 | 49 | area += p.X*n.Y - p.Y*n.X 50 | } 51 | 52 | fmt.Println(len(path) / 2) 53 | fmt.Println((int(math.Abs(float64(area)))-len(path))/2 + 1) 54 | } 55 | -------------------------------------------------------------------------------- /2023/11/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "math" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | split := strings.Fields(string(input)) 14 | 15 | dists := func(expand int) (d int) { 16 | galaxies := []image.Point{} 17 | dy := 0 18 | for y, s := range split { 19 | if !strings.Contains(s, "#") { 20 | dy += expand - 1 21 | } 22 | 23 | dx := 0 24 | for x, r := range s { 25 | col := "" 26 | for _, s := range split { 27 | col += string(s[x]) 28 | } 29 | if !strings.Contains(col, "#") { 30 | dx += expand - 1 31 | } 32 | 33 | if r == '#' { 34 | for _, g := range galaxies { 35 | d += int(math.Abs(float64(x+dx-g.X)) + math.Abs(float64(y+dy-g.Y))) 36 | } 37 | galaxies = append(galaxies, image.Point{x + dx, y + dy}) 38 | } 39 | } 40 | } 41 | return 42 | } 43 | 44 | fmt.Println(dists(2)) 45 | fmt.Println(dists(1000000)) 46 | } 47 | -------------------------------------------------------------------------------- /2023/12/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | part1, part2 := 0, 0 14 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 15 | s, ls := strings.Fields(s), []int{} 16 | json.Unmarshal([]byte("["+s[1]+"]"), &ls) 17 | part1 += count(s[0]+"?", ls) 18 | json.Unmarshal([]byte("["+strings.Repeat(","+s[1], 5)[1:]+"]"), &ls) 19 | part2 += count(strings.Repeat(s[0]+"?", 5), ls) 20 | } 21 | fmt.Println(part1) 22 | fmt.Println(part2) 23 | } 24 | 25 | var cache = map[string]int{} 26 | 27 | func count(s string, c []int) (r int) { 28 | if r, ok := cache[fmt.Sprint(s, c)]; ok { 29 | return r 30 | } 31 | defer func() { recover(); cache[fmt.Sprint(s, c)] = r }() 32 | 33 | if s == "" { 34 | if len(c) == 0 { 35 | return 1 36 | } 37 | return 0 38 | } 39 | 40 | if s[0] == '.' || s[0] == '?' { 41 | r += count(s[1:], c) 42 | } 43 | if (s[0] == '#' || s[0] == '?') && 44 | !strings.Contains(s[:c[0]], ".") && 45 | s[c[0]] != '#' { 46 | r += count(s[c[0]+1:], c[1:]) 47 | } 48 | return 49 | } 50 | -------------------------------------------------------------------------------- /2023/13/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "slices" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | part1, part2 := 0, 0 14 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n\n") { 15 | rows, cols := []string{}, make([]string, len(strings.Fields(s)[0])) 16 | for _, s := range strings.Fields(s) { 17 | rows = append(rows, s) 18 | for i, r := range s { 19 | cols[i] += string(r) 20 | } 21 | } 22 | 23 | part1 += mirror(cols, slices.Equal) + 100*mirror(rows, slices.Equal) 24 | part2 += mirror(cols, smudge) + 100*mirror(rows, smudge) 25 | } 26 | fmt.Println(part1) 27 | fmt.Println(part2) 28 | } 29 | 30 | func mirror(s []string, equal func([]string, []string) bool) int { 31 | for i := 1; i < len(s); i++ { 32 | l := min(i, len(s)-i) 33 | a, b := slices.Clone(s[i-l:i]), s[i:i+l] 34 | slices.Reverse(a) 35 | if equal(a, b) { 36 | return i 37 | } 38 | } 39 | return 0 40 | } 41 | 42 | func smudge(a, b []string) bool { 43 | diffs := 0 44 | for i := range a { 45 | for j := range a[i] { 46 | if a[i][j] != b[i][j] { 47 | diffs++ 48 | } 49 | } 50 | } 51 | return diffs == 1 52 | } 53 | -------------------------------------------------------------------------------- /2023/14/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "slices" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | dish := rotate(strings.Fields(string(input))) 13 | 14 | fmt.Println(load(tilt(dish))) 15 | 16 | cycles, seen := 1000000000, map[string]int{} 17 | for i := 0; i < cycles; i++ { 18 | if s, ok := seen[fmt.Sprint(dish)]; ok { 19 | i = cycles - (cycles-i)%(i-s) 20 | } 21 | seen[fmt.Sprint(dish)] = i 22 | for i := 0; i < 4; i++ { 23 | dish = rotate(tilt(dish)) 24 | } 25 | } 26 | fmt.Println(load(dish)) 27 | } 28 | 29 | func rotate(dish []string) []string { 30 | rot := make([]string, len(dish[0])) 31 | for r := range dish { 32 | for c := range dish[r] { 33 | rot[c] += string(dish[len(dish)-r-1][c]) 34 | } 35 | } 36 | return rot 37 | } 38 | 39 | func tilt(dish []string) []string { 40 | dish = slices.Clone(dish) 41 | for i := range dish { 42 | for strings.Contains(dish[i], "O.") { 43 | dish[i] = strings.ReplaceAll(dish[i], "O.", ".O") 44 | } 45 | } 46 | return dish 47 | } 48 | 49 | func load(dish []string) (l int) { 50 | for i, s := range rotate(dish) { 51 | l += strings.Count(s, "O") * (i + 1) 52 | } 53 | return 54 | } 55 | -------------------------------------------------------------------------------- /2023/15/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "regexp" 7 | "slices" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | re := regexp.MustCompile(`(\w+)([-=])(\d*)`) 13 | 14 | part1, part2 := 0, 0 15 | boxes, focal := [256][]string{}, map[string]int{} 16 | for _, m := range re.FindAllStringSubmatch(string(input), -1) { 17 | h := hash(m[1]) 18 | i := slices.Index(boxes[h], m[1]) 19 | 20 | if m[2] == "-" && i != -1 { 21 | boxes[h] = slices.Delete(boxes[h], i, i+1) 22 | } else if m[2] == "=" { 23 | focal[m[1]] = int(m[3][0] - '0') 24 | if i == -1 { 25 | boxes[h] = append(boxes[h], m[1]) 26 | } 27 | } 28 | 29 | part1 += hash(m[0]) 30 | } 31 | 32 | for i, b := range boxes { 33 | for j, l := range b { 34 | part2 += (i + 1) * (j + 1) * focal[l] 35 | } 36 | } 37 | fmt.Println(part1) 38 | fmt.Println(part2) 39 | } 40 | 41 | func hash(s string) (h int) { 42 | for _, r := range s { 43 | h = (h + int(r)) * 17 % 256 44 | } 45 | return 46 | } 47 | -------------------------------------------------------------------------------- /2023/16/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | type State struct { 11 | Pos image.Point 12 | Dir image.Point 13 | } 14 | 15 | var ( 16 | U = image.Point{0, -1} 17 | R = image.Point{1, 0} 18 | D = image.Point{0, 1} 19 | L = image.Point{-1, 0} 20 | ) 21 | 22 | func main() { 23 | input, _ := os.ReadFile("input.txt") 24 | split := strings.Fields(string(input)) 25 | 26 | grid, border := map[image.Point]rune{}, []State{} 27 | for y, s := range split { 28 | border = append(border, State{image.Point{0, y}, R}, State{image.Point{len(s) - 1, y}, L}) 29 | for x, r := range s { 30 | grid[image.Point{x, y}] = r 31 | } 32 | } 33 | for x := range split[0] { 34 | border = append(border, State{image.Point{x, 0}, D}, State{image.Point{x, len(split) - 1}, U}) 35 | } 36 | 37 | bfs := func(start State) int { 38 | energized := map[image.Point]struct{}{} 39 | queue := []State{start} 40 | seen := map[State]struct{}{start: {}} 41 | 42 | for len(queue) > 0 { 43 | state := queue[0] 44 | queue = queue[1:] 45 | 46 | for _, d := range map[rune]map[image.Point][]image.Point{ 47 | '.': {U: {U}, R: {R}, D: {D}, L: {L}}, 48 | '/': {U: {R}, R: {U}, D: {L}, L: {D}}, 49 | '\\': {U: {L}, R: {D}, D: {R}, L: {U}}, 50 | '|': {U: {U}, R: {U, D}, D: {D}, L: {U, D}}, 51 | '-': {U: {L, R}, R: {R}, D: {L, R}, L: {L}}, 52 | }[grid[state.Pos]][state.Dir] { 53 | energized[state.Pos] = struct{}{} 54 | next := State{state.Pos.Add(d), d} 55 | 56 | if _, ok := seen[next]; !ok { 57 | seen[next] = struct{}{} 58 | queue = append(queue, next) 59 | } 60 | } 61 | } 62 | 63 | return len(energized) 64 | } 65 | 66 | fmt.Println(bfs(State{image.Point{0, 0}, R})) 67 | 68 | part2 := 0 69 | for _, s := range border { 70 | part2 = max(part2, bfs(s)) 71 | } 72 | fmt.Println(part2) 73 | } 74 | -------------------------------------------------------------------------------- /2023/17/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "container/heap" 5 | "fmt" 6 | "image" 7 | "math" 8 | "os" 9 | "strings" 10 | ) 11 | 12 | type pqi[T any] struct { 13 | v T 14 | p int 15 | } 16 | 17 | type PQ[T any] []pqi[T] 18 | 19 | func (q PQ[_]) Len() int { return len(q) } 20 | func (q PQ[_]) Less(i, j int) bool { return q[i].p < q[j].p } 21 | func (q PQ[_]) Swap(i, j int) { q[i], q[j] = q[j], q[i] } 22 | func (q *PQ[T]) Push(x any) { *q = append(*q, x.(pqi[T])) } 23 | func (q *PQ[_]) Pop() (x any) { x, *q = (*q)[len(*q)-1], (*q)[:len(*q)-1]; return x } 24 | func (q *PQ[T]) GPush(v T, p int) { heap.Push(q, pqi[T]{v, p}) } 25 | func (q *PQ[T]) GPop() (T, int) { x := heap.Pop(q).(pqi[T]); return x.v, x.p } 26 | 27 | type State struct { 28 | Pos image.Point 29 | Dir image.Point 30 | } 31 | 32 | func main() { 33 | input, _ := os.ReadFile("input.txt") 34 | 35 | grid, end := map[image.Point]int{}, image.Point{0, 0} 36 | for y, s := range strings.Fields(string(input)) { 37 | for x, r := range s { 38 | grid[image.Point{x, y}] = int(r - '0') 39 | end = image.Point{x, y} 40 | } 41 | } 42 | 43 | run := func(min, max int) int { 44 | queue, seen := PQ[State]{}, map[State]struct{}{} 45 | queue.GPush(State{image.Point{0, 0}, image.Point{1, 0}}, 0) 46 | queue.GPush(State{image.Point{0, 0}, image.Point{0, 1}}, 0) 47 | 48 | for len(queue) > 0 { 49 | state, heat := queue.GPop() 50 | 51 | if state.Pos == end { 52 | return heat 53 | } 54 | if _, ok := seen[state]; ok { 55 | continue 56 | } 57 | seen[state] = struct{}{} 58 | 59 | for i := -max; i <= max; i++ { 60 | n := state.Pos.Add(state.Dir.Mul(i)) 61 | if _, ok := grid[n]; !ok || i > -min && i < min { 62 | continue 63 | } 64 | h, s := 0, int(math.Copysign(1, float64(i))) 65 | for j := s; j != i+s; j += s { 66 | h += grid[state.Pos.Add(state.Dir.Mul(j))] 67 | } 68 | queue.GPush(State{n, image.Point{state.Dir.Y, state.Dir.X}}, heat+h) 69 | } 70 | } 71 | return -1 72 | } 73 | 74 | fmt.Println(run(1, 3)) 75 | fmt.Println(run(4, 10)) 76 | } 77 | -------------------------------------------------------------------------------- /2023/18/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "regexp" 8 | "strconv" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | re := regexp.MustCompile(`(.) (.*) \(#(.*)(.)\)`) 14 | delta := map[string]image.Point{ 15 | "R": {1, 0}, "D": {0, 1}, "L": {-1, 0}, "U": {0, -1}, 16 | "0": {1, 0}, "1": {0, 1}, "2": {-1, 0}, "3": {0, -1}, 17 | } 18 | 19 | run := func(di, li, base int) int { 20 | dig, a2 := image.Point{0, 0}, 0 21 | for _, m := range re.FindAllStringSubmatch(string(input), -1) { 22 | l, _ := strconv.ParseInt(m[li], base, strconv.IntSize) 23 | n := dig.Add(delta[m[di]].Mul(int(l))) 24 | a2 += dig.X*n.Y - dig.Y*n.X + int(l) 25 | dig = n 26 | } 27 | return a2/2 + 1 28 | } 29 | 30 | fmt.Println(run(1, 2, 10)) 31 | fmt.Println(run(4, 3, 16)) 32 | } 33 | -------------------------------------------------------------------------------- /2023/19/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "maps" 7 | "os" 8 | "regexp" 9 | "strconv" 10 | "strings" 11 | ) 12 | 13 | type Rule struct { 14 | Cat string 15 | Op string 16 | Val int 17 | Next string 18 | } 19 | 20 | func main() { 21 | input, _ := os.ReadFile("input.txt") 22 | re1 := regexp.MustCompile(`(\w+){(.*),(\w+)}`) 23 | re2 := regexp.MustCompile(`(\w+)(<|>)(\d+):(\w+)`) 24 | 25 | workflows := map[string][]Rule{} 26 | for _, m := range re1.FindAllStringSubmatch(string(input), -1) { 27 | w := m[1] 28 | for _, m := range re2.FindAllStringSubmatch(m[2], -1) { 29 | v, _ := strconv.Atoi(m[3]) 30 | workflows[w] = append(workflows[w], Rule{m[1], m[2], v, m[4]}) 31 | } 32 | workflows[w] = append(workflows[w], Rule{Next: m[3]}) 33 | } 34 | 35 | var comb func(string, map[string][2]int) int 36 | comb = func(workflow string, ranges map[string][2]int) (c int) { 37 | for _, r := range ranges { 38 | if r[1] < r[0] { 39 | return 0 40 | } 41 | } 42 | if workflow == "R" { 43 | return 0 44 | } 45 | if workflow == "A" { 46 | c = 1 47 | for _, r := range ranges { 48 | c *= r[1] - r[0] + 1 49 | } 50 | return 51 | } 52 | 53 | for _, r := range workflows[workflow] { 54 | next := maps.Clone(ranges) 55 | 56 | switch r.Op { 57 | case "<": 58 | next[r.Cat] = [2]int{next[r.Cat][0], min(next[r.Cat][1], r.Val-1)} 59 | ranges[r.Cat] = [2]int{max(next[r.Cat][0], r.Val), ranges[r.Cat][1]} 60 | case ">": 61 | next[r.Cat] = [2]int{max(next[r.Cat][0], r.Val+1), next[r.Cat][1]} 62 | ranges[r.Cat] = [2]int{ranges[r.Cat][0], min(next[r.Cat][1], r.Val)} 63 | } 64 | c += comb(r.Next, next) 65 | } 66 | return c 67 | } 68 | 69 | part1 := 0 70 | for _, s := range strings.Fields(strings.Split(strings.TrimSpace(string(input)), "\n\n")[1]) { 71 | s = strings.NewReplacer(`{`, `{"`, `,`, `,"`, `=`, `":`).Replace(s) 72 | var rating map[string]int 73 | json.Unmarshal([]byte(s), &rating) 74 | 75 | ranges := map[string][2]int{} 76 | for c, r := range rating { 77 | ranges[c] = [2]int{r, r} 78 | } 79 | if comb("in", ranges) == 1 { 80 | part1 += rating["x"] + rating["m"] + rating["a"] + rating["s"] 81 | } 82 | } 83 | fmt.Println(part1) 84 | 85 | ranges := map[string][2]int{ 86 | "x": {1, 4000}, "m": {1, 4000}, "a": {1, 4000}, "s": {1, 4000}, 87 | } 88 | fmt.Println(comb("in", ranges)) 89 | } 90 | -------------------------------------------------------------------------------- /2023/20/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | type Module struct { 10 | Type rune 11 | Dests []string 12 | Memory map[string]bool 13 | } 14 | 15 | type Pulse struct { 16 | Source string 17 | Value bool 18 | Dest string 19 | } 20 | 21 | func main() { 22 | input, _ := os.ReadFile("input.txt") 23 | 24 | modules := map[string]Module{} 25 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 26 | split := strings.Split(s, " -> ") 27 | 28 | name := split[0][1:] 29 | if split[0] == "broadcaster" { 30 | name = split[0] 31 | } 32 | 33 | modules[name] = Module{ 34 | Type: rune(split[0][0]), 35 | Dests: strings.Split(split[1], ", "), 36 | Memory: map[string]bool{}, 37 | } 38 | } 39 | 40 | inputs := func(src string) (s []string) { 41 | for k, m := range modules { 42 | for _, d := range m.Dests { 43 | if d == src { 44 | s = append(s, k) 45 | } 46 | } 47 | } 48 | return 49 | } 50 | 51 | counts, cycles := map[bool]int{}, map[string]int{} 52 | for i := 1; len(cycles) != len(inputs(inputs("rx")[0])); i++ { 53 | pulses := []Pulse{{"button", false, "broadcaster"}} 54 | for len(pulses) > 0 { 55 | p := pulses[0] 56 | pulses, counts[p.Value] = pulses[1:], counts[p.Value]+1 57 | 58 | m := modules[p.Dest] 59 | switch m.Type { 60 | case '%': 61 | if p.Value { 62 | continue 63 | } 64 | m.Memory[p.Dest] = !m.Memory[p.Dest] 65 | case '&': 66 | m.Memory[p.Source], m.Memory[p.Dest] = p.Value, false 67 | for _, i := range inputs(p.Dest) { 68 | if !m.Memory[i] { 69 | m.Memory[p.Dest] = true 70 | } 71 | } 72 | } 73 | 74 | modules[p.Dest] = m 75 | for _, d := range m.Dests { 76 | pulses = append(pulses, Pulse{p.Dest, m.Memory[p.Dest], d}) 77 | } 78 | 79 | for _, k := range inputs(inputs("rx")[0]) { 80 | if _, ok := cycles[k]; !ok && modules[inputs("rx")[0]].Memory[k] { 81 | cycles[k] = i 82 | } 83 | } 84 | } 85 | 86 | if i == 1000 { 87 | fmt.Println(counts[false] * counts[true]) 88 | } 89 | } 90 | 91 | part2 := 1 92 | for _, v := range cycles { 93 | part2 *= v 94 | } 95 | fmt.Println(part2) 96 | } 97 | -------------------------------------------------------------------------------- /2023/21/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "maps" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | 14 | grid, start, bounds := map[image.Point]rune{}, image.Point{}, image.Rectangle{} 15 | for y, s := range strings.Fields(string(input)) { 16 | for x, r := range s { 17 | p := image.Point{x, y} 18 | if r == 'S' { 19 | start = p 20 | r = '.' 21 | } 22 | grid[p] = r 23 | bounds = bounds.Union(image.Rectangle{p, p.Add(image.Point{1, 1})}) 24 | } 25 | } 26 | w := bounds.Dx() 27 | 28 | garden := map[image.Point]struct{}{start: {}} 29 | seen := map[image.Point]struct{}{start: {}} 30 | plots := map[int]int{0: 1} 31 | 32 | var s int 33 | loop: 34 | for s = 1; ; s++ { 35 | ng := map[image.Point]struct{}{} 36 | for p := range garden { 37 | for _, d := range []image.Point{{0, -1}, {1, 0}, {0, 1}, {-1, 0}} { 38 | q := p.Add(d) 39 | if _, ok := seen[q]; !ok && grid[q.Mod(bounds)] == '.' { 40 | ng[q] = struct{}{} 41 | } 42 | } 43 | } 44 | maps.Copy(seen, ng) 45 | plots[s] = plots[s-2] + len(ng) 46 | garden = ng 47 | 48 | for i := s; i > s-w; i-- { 49 | d1 := (plots[i] - plots[i-2]) - (plots[i-w] - plots[i-w-2]) 50 | d2 := (plots[i-w] - plots[i-w-2]) - (plots[i-2*w] - plots[i-2*w-2]) 51 | if d1 != d2 { 52 | continue loop 53 | } 54 | } 55 | break 56 | } 57 | 58 | for ; s <= 26501365; s++ { 59 | plots[s] = plots[s-2] + 2*plots[s-w] - 2*plots[s-w-2] - plots[s-2*w] + plots[s-2*w-2] 60 | } 61 | 62 | fmt.Println(plots[64]) 63 | fmt.Println(plots[26501365]) 64 | } 65 | -------------------------------------------------------------------------------- /2023/22/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "cmp" 5 | "fmt" 6 | "os" 7 | "slices" 8 | "strings" 9 | ) 10 | 11 | type Brick struct { 12 | x1, y1, z1 int 13 | x2, y2, z2 int 14 | } 15 | 16 | func main() { 17 | input, _ := os.ReadFile("input.txt") 18 | 19 | bricks := []Brick{} 20 | for _, s := range strings.Fields(string(input)) { 21 | var b Brick 22 | fmt.Sscanf(s, "%d,%d,%d~%d,%d,%d", &b.x1, &b.y1, &b.z1, &b.x2, &b.y2, &b.z2) 23 | bricks = append(bricks, b) 24 | } 25 | slices.SortFunc(bricks, func(a, b Brick) int { return cmp.Compare(a.z1, b.z1) }) 26 | 27 | for n, ok := 0, true; ok; ok = n != 0 { 28 | bricks, n = drop(bricks) 29 | } 30 | 31 | part1, part2 := 0, 0 32 | for i := range bricks { 33 | _, n := drop(slices.Delete(slices.Clone(bricks), i, i+1)) 34 | if n == 0 { 35 | part1++ 36 | } 37 | part2 += n 38 | } 39 | fmt.Println(part1) 40 | fmt.Println(part2) 41 | } 42 | 43 | func drop(bricks []Brick) (bs []Brick, n int) { 44 | bs = slices.Clone(bricks) 45 | loop: 46 | for i, a := range bs { 47 | if a.z1 == 1 || a.z2 == 1 { 48 | continue 49 | } 50 | a.z1, a.z2 = a.z1-1, a.z2-1 51 | 52 | for _, b := range bs[:i] { 53 | if a.x1 <= b.x2 && a.x2 >= b.x1 && 54 | a.y1 <= b.y2 && a.y2 >= b.y1 && 55 | a.z1 <= b.z2 && a.z2 >= b.z1 { 56 | continue loop 57 | } 58 | } 59 | bs[i] = a 60 | n++ 61 | } 62 | return 63 | } 64 | -------------------------------------------------------------------------------- /2023/23/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | type State struct { 11 | P image.Point 12 | D int 13 | } 14 | 15 | func main() { 16 | input, _ := os.ReadFile("input.txt") 17 | 18 | grid := map[image.Point]rune{} 19 | start, end := image.Point{1, 0}, image.Point{} 20 | for y, s := range strings.Fields(string(input)) { 21 | for x, r := range s { 22 | grid[image.Point{x, y}] = r 23 | end = image.Point{x - 1, y} 24 | } 25 | } 26 | 27 | delta := map[rune]image.Point{'^': {0, -1}, '>': {1, 0}, 'v': {0, 1}, '<': {-1, 0}} 28 | seen := map[image.Point]struct{}{} 29 | 30 | var dfs func(image.Point, int, bool) int 31 | dfs = func(start image.Point, dist int, slopes bool) (best int) { 32 | if start == end { 33 | return dist 34 | } 35 | seen[start] = struct{}{} 36 | for _, d := range delta { 37 | p := start.Add(d) 38 | if n, ok := delta[grid[start]]; slopes && ok && n != d { 39 | continue 40 | } 41 | if _, ok := seen[p]; !ok && grid[p] != '#' && grid[p] != '\x00' { 42 | best = max(best, dfs(p, dist+1, slopes)) 43 | } 44 | } 45 | delete(seen, start) 46 | return best 47 | } 48 | 49 | fmt.Println(dfs(start, 0, true)) 50 | clear(seen) 51 | fmt.Println(dfs(start, 0, false)) 52 | } 53 | -------------------------------------------------------------------------------- /2023/24/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | type Point struct { 11 | X, Y, Z float64 12 | } 13 | 14 | func main() { 15 | input, _ := os.ReadFile("input.txt") 16 | 17 | hail := [][2]Point{} 18 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 19 | var p, v Point 20 | fmt.Sscanf(s, "%f, %f, %f @ %f, %f, %f", &p.X, &p.Y, &p.Z, &v.X, &v.Y, &v.Z) 21 | hail = append(hail, [2]Point{p, v}) 22 | } 23 | 24 | part1 := 0 25 | for i, h1 := range hail { 26 | for _, h2 := range hail[i+1:] { 27 | p1, v1, p2, v2 := h1[0], h1[1], h2[0], h2[1] 28 | det := v2.X*v1.Y - v2.Y*v1.X 29 | t1 := ((p2.Y-p1.Y)*v2.X - (p2.X-p1.X)*v2.Y) / det 30 | t2 := ((p2.Y-p1.Y)*v1.X - (p2.X-p1.X)*v1.Y) / det 31 | if x, y := p1.X+t1*v1.X, p1.Y+t1*v1.Y; t1 > 0 && t2 > 0 && 32 | x >= 200000000000000 && x <= 400000000000000 && 33 | y >= 200000000000000 && y <= 400000000000000 { 34 | part1++ 35 | } 36 | } 37 | } 38 | fmt.Println(part1) 39 | 40 | // https://github.com/0e4ef622/aoc/blob/master/2023/day24/a.py 41 | solve := func(h1, h2, h3 [2]Point) float64 { 42 | x1, y1, z1, vx1, vy1, vz1 := h1[0].X, h1[0].Y, h1[0].Z, h1[1].X, h1[1].Y, h1[1].Z 43 | x2, y2, z2, vx2, vy2, vz2 := h2[0].X, h2[0].Y, h2[0].Z, h2[1].X, h2[1].Y, h2[1].Z 44 | x3, y3, z3, vx3, vy3, vz3 := h3[0].X, h3[0].Y, h3[0].Z, h3[1].X, h3[1].Y, h3[1].Z 45 | yz := y1*(z2-z3) + y2*(-z1+z3) + y3*(z1-z2) 46 | xz := x1*(-z2+z3) + x2*(z1-z3) + x3*(-z1+z2) 47 | xy := x1*(y2-y3) + x2*(-y1+y3) + x3*(y1-y2) 48 | vxvy := vx1*(vy2-vy3) + vx2*(-vy1+vy3) + vx3*(vy1-vy2) 49 | vxvz := vx1*(-vz2+vz3) + vx2*(vz1-vz3) + vx3*(-vz1+vz2) 50 | vyvz := vy1*(vz2-vz3) + vy2*(-vz1+vz3) + vy3*(vz1-vz2) 51 | n := (vx2-vx3)*yz + (vy2-vy3)*xz + (vz2-vz3)*xy 52 | d := (z2-z3)*vxvy + (y2-y3)*vxvz + (x2-x3)*vyvz 53 | return n / d 54 | } 55 | 56 | t1 := solve(hail[0], hail[1], hail[2]) 57 | t2 := solve(hail[1], hail[0], hail[2]) 58 | 59 | p1, v1, p2, v2 := hail[0][0], hail[0][1], hail[1][0], hail[1][1] 60 | c1 := Point{p1.X + t1*v1.X, p1.Y + t1*v1.Y, p1.Z + t1*v1.Z} 61 | c2 := Point{p2.X + t2*v2.X, p2.Y + t2*v2.Y, p2.Z + t2*v2.Z} 62 | v := Point{(c2.X - c1.X) / (t2 - t1), (c2.Y - c1.Y) / (t2 - t1), (c2.Z - c1.Z) / (t2 - t1)} 63 | p := Point{p1.X + v1.X*t1 - v.X*t1, p1.Y + v1.Y*t1 - v.Y*t1, p1.Z + v1.Z*t1 - v.Z*t1} 64 | 65 | fmt.Println(int(math.Round(p.X + p.Y + p.Z))) 66 | } 67 | -------------------------------------------------------------------------------- /2023/25/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "maps" 6 | "math/rand" 7 | "os" 8 | "slices" 9 | "strings" 10 | ) 11 | 12 | func main() { 13 | input, _ := os.ReadFile("input.txt") 14 | 15 | edges := []map[string]struct{}{} 16 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 17 | split := strings.Split(s, ": ") 18 | for _, s := range strings.Fields(split[1]) { 19 | edges = append(edges, map[string]struct{}{split[0]: {}, s: {}}) 20 | } 21 | } 22 | 23 | for { 24 | es := []map[string]struct{}{} 25 | for _, e := range edges { 26 | es = append(es, maps.Clone(e)) 27 | } 28 | vs := func() int { 29 | vs := map[string]struct{}{} 30 | for _, e := range es { 31 | maps.Copy(vs, e) 32 | } 33 | return len(vs) 34 | } 35 | 36 | for vs() > 2 { 37 | edge := es[rand.Intn(len(es))] 38 | 39 | es = slices.DeleteFunc(es, func(e map[string]struct{}) bool { 40 | return maps.Equal(e, edge) 41 | }) 42 | 43 | name := "" 44 | for v := range edge { 45 | name += v + " " 46 | } 47 | 48 | for e := range es { 49 | for v := range es[e] { 50 | if _, ok := edge[v]; ok { 51 | delete(es[e], v) 52 | es[e][name] = struct{}{} 53 | } 54 | } 55 | } 56 | } 57 | 58 | if len(es) != 3 { 59 | continue 60 | } 61 | 62 | part1 := 1 63 | for v := range es[0] { 64 | part1 *= len(strings.Fields(v)) 65 | } 66 | fmt.Println(part1) 67 | break 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /2024/01/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "slices" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | var list1, list2 []int 14 | counts2 := map[int]int{} 15 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 16 | var n1, n2 int 17 | fmt.Sscanf(s, "%d %d", &n1, &n2) 18 | list1, list2 = append(list1, n1), append(list2, n2) 19 | counts2[n2]++ 20 | } 21 | 22 | slices.Sort(list1) 23 | slices.Sort(list2) 24 | 25 | part1, part2 := 0, 0 26 | for i := range list1 { 27 | part1 += abs(list2[i] - list1[i]) 28 | part2 += list1[i] * counts2[list1[i]] 29 | } 30 | fmt.Println(part1) 31 | fmt.Println(part2) 32 | } 33 | 34 | func abs(x int) int { 35 | if x < 0 { 36 | return -x 37 | } 38 | return x 39 | } 40 | -------------------------------------------------------------------------------- /2024/02/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | "slices" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | 14 | part1, part2 := 0, 0 15 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 16 | var report []int 17 | json.Unmarshal([]byte("["+strings.ReplaceAll(s, " ", ",")+"]"), &report) 18 | 19 | if check(report) { 20 | part1++ 21 | } 22 | for i := range report { 23 | if check(slices.Delete(slices.Clone(report), i, i+1)) { 24 | part2++ 25 | break 26 | } 27 | } 28 | } 29 | fmt.Println(part1) 30 | fmt.Println(part2) 31 | } 32 | 33 | func check(r []int) bool { 34 | for i := 1; i < len(r); i++ { 35 | if d := r[i] - r[i-1]; d*(r[1]-r[0]) <= 0 || d < -3 || d > 3 { 36 | return false 37 | } 38 | } 39 | return true 40 | } 41 | -------------------------------------------------------------------------------- /2024/03/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "regexp" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | re := regexp.MustCompile(`(?s)(?:^|do\(\)).*?(?:don't\(\)|$)`) 14 | fmt.Println(mul(string(input))) 15 | fmt.Println(mul(strings.Join(re.FindAllString(string(input), -1), ""))) 16 | } 17 | 18 | func mul(s string) (r int) { 19 | re := regexp.MustCompile(`mul\((\d+),(\d+)\)`) 20 | for _, m := range re.FindAllStringSubmatch(s, -1) { 21 | n1, _ := strconv.Atoi(m[1]) 22 | n2, _ := strconv.Atoi(m[2]) 23 | r += n1 * n2 24 | } 25 | return r 26 | } 27 | -------------------------------------------------------------------------------- /2024/04/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | grid := map[image.Point]rune{} 13 | for y, s := range strings.Fields(string(input)) { 14 | for x, r := range s { 15 | grid[image.Point{x, y}] = r 16 | } 17 | } 18 | 19 | adj := func(p image.Point, l int) []string { 20 | delta := []image.Point{ 21 | {0, -1}, {1, 0}, {0, 1}, {-1, 0}, 22 | {-1, -1}, {1, -1}, {1, 1}, {-1, 1}, 23 | } 24 | 25 | words := make([]string, len(delta)) 26 | for i, d := range delta { 27 | for n := range l { 28 | words[i] += string(grid[p.Add(d.Mul(n))]) 29 | } 30 | } 31 | return words 32 | } 33 | 34 | part1, part2 := 0, 0 35 | for p := range grid { 36 | part1 += strings.Count(strings.Join(adj(p, 4), " "), "XMAS") 37 | part2 += strings.Count("AMAMASASAMAMAS", strings.Join(adj(p, 2)[4:], "")) 38 | } 39 | fmt.Println(part1) 40 | fmt.Println(part2) 41 | } 42 | -------------------------------------------------------------------------------- /2024/05/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "slices" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | input, _ := os.ReadFile("input.txt") 13 | split := strings.Split(strings.TrimSpace(string(input)), "\n\n") 14 | 15 | cmp := func(a, b string) int { 16 | for _, s := range strings.Fields(split[0]) { 17 | if s := strings.Split(s, "|"); s[0] == a && s[1] == b { 18 | return -1 19 | } 20 | } 21 | return 0 22 | } 23 | 24 | run := func(sorted bool) (r int) { 25 | for _, s := range strings.Fields(split[1]) { 26 | if s := strings.Split(s, ","); slices.IsSortedFunc(s, cmp) == sorted { 27 | slices.SortFunc(s, cmp) 28 | n, _ := strconv.Atoi(s[len(s)/2]) 29 | r += n 30 | } 31 | } 32 | return r 33 | } 34 | 35 | fmt.Println(run(true)) 36 | fmt.Println(run(false)) 37 | } 38 | -------------------------------------------------------------------------------- /2024/06/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | grid, start := map[image.Point]rune{}, image.Point{} 14 | for y, s := range strings.Fields(string(input)) { 15 | for x, r := range s { 16 | if r == '^' { 17 | start = image.Point{x, y} 18 | } 19 | grid[image.Point{x, y}] = r 20 | } 21 | } 22 | 23 | patrol := func(o image.Point) map[image.Point]int { 24 | delta := []image.Point{{0, -1}, {1, 0}, {0, 1}, {-1, 0}} 25 | p, d, seen := start, 0, map[image.Point]int{} 26 | for { 27 | if _, ok := grid[p]; !ok { 28 | return seen 29 | } else if 1<= 0; file-- { 32 | for free := 0; free < file; free++ { 33 | if fs[file].ID != -1 && fs[free].ID == -1 && fs[free].Size >= fs[file].Size { 34 | fs = slices.Insert(fs, free, fs[file]) 35 | fs[file+1].ID = -1 36 | fs[free+1].Size = fs[free+1].Size - fs[file+1].Size 37 | } 38 | } 39 | } 40 | i := 0 41 | for _, f := range fs { 42 | for range f.Size { 43 | if f.ID != -1 { 44 | checksum += i * f.ID 45 | } 46 | i++ 47 | } 48 | } 49 | return checksum 50 | } 51 | -------------------------------------------------------------------------------- /2024/10/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | grid := map[image.Point]rune{} 14 | for y, s := range strings.Fields(string(input)) { 15 | for x, r := range s { 16 | grid[image.Point{x, y}] = r 17 | } 18 | } 19 | 20 | part1, part2 := 0, 0 21 | for p := range grid { 22 | if grid[p] == '0' { 23 | part1 += dfs(grid, p, map[image.Point]bool{}) 24 | part2 += dfs(grid, p, nil) 25 | } 26 | } 27 | fmt.Println(part1) 28 | fmt.Println(part2) 29 | } 30 | 31 | func dfs(grid map[image.Point]rune, p image.Point, seen map[image.Point]bool) (score int) { 32 | if grid[p] == '9' { 33 | if seen[p] { 34 | return 0 35 | } else if seen != nil { 36 | seen[p] = true 37 | } 38 | return 1 39 | } 40 | for _, d := range []image.Point{{0, -1}, {1, 0}, {0, 1}, {-1, 0}} { 41 | if n := p.Add(d); grid[n] == grid[p]+1 { 42 | score += dfs(grid, n, seen) 43 | } 44 | } 45 | return score 46 | } 47 | -------------------------------------------------------------------------------- /2024/11/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | stones := map[int]int{} 14 | for _, s := range strings.Fields(string(input)) { 15 | n, _ := strconv.Atoi(s) 16 | stones[n]++ 17 | } 18 | fmt.Println(run(stones, 25)) 19 | fmt.Println(run(stones, 75)) 20 | } 21 | 22 | func run(stones map[int]int, blinks int) (r int) { 23 | for range blinks { 24 | next := map[int]int{} 25 | for k, v := range stones { 26 | if k == 0 { 27 | next[1] += v 28 | } else if s := strconv.Itoa(k); len(s)%2 == 0 { 29 | n1, _ := strconv.Atoi(s[:len(s)/2]) 30 | n2, _ := strconv.Atoi(s[len(s)/2:]) 31 | next[n1] += v 32 | next[n2] += v 33 | } else { 34 | next[k*2024] += v 35 | } 36 | } 37 | stones = next 38 | } 39 | for _, v := range stones { 40 | r += v 41 | } 42 | return r 43 | } 44 | -------------------------------------------------------------------------------- /2024/12/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | grid := map[image.Point]rune{} 14 | for y, s := range strings.Fields(string(input)) { 15 | for x, r := range s { 16 | grid[image.Point{x, y}] = r 17 | } 18 | } 19 | 20 | seen := map[image.Point]bool{} 21 | part1, part2 := 0, 0 22 | for p := range grid { 23 | if seen[p] { 24 | continue 25 | } 26 | seen[p] = true 27 | 28 | area := 1 29 | perimeter, sides := 0, 0 30 | queue := []image.Point{p} 31 | for len(queue) > 0 { 32 | p := queue[0] 33 | queue = queue[1:] 34 | 35 | for _, d := range []image.Point{{0, -1}, {1, 0}, {0, 1}, {-1, 0}} { 36 | if n := p.Add(d); grid[n] != grid[p] { 37 | perimeter++ 38 | r := p.Add(image.Point{-d.Y, d.X}) 39 | if grid[r] != grid[p] || grid[r.Add(d)] == grid[p] { 40 | sides++ 41 | } 42 | } else if !seen[n] { 43 | seen[n] = true 44 | queue = append(queue, n) 45 | area++ 46 | } 47 | } 48 | } 49 | part1 += area * perimeter 50 | part2 += area * sides 51 | } 52 | fmt.Println(part1) 53 | fmt.Println(part2) 54 | } 55 | -------------------------------------------------------------------------------- /2024/13/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | part1, part2 := 0, 0 14 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n\n") { 15 | var a, b, c image.Point 16 | fmt.Sscanf(s, "Button A: X+%d, Y+%d\nButton B: X+%d, Y+%d\nPrize: X=%d, Y=%d", 17 | &a.X, &a.Y, &b.X, &b.Y, &c.X, &c.Y) 18 | part1 += calc(a, b, c) 19 | part2 += calc(a, b, c.Add(image.Point{10000000000000, 10000000000000})) 20 | } 21 | fmt.Println(part1) 22 | fmt.Println(part2) 23 | } 24 | 25 | func calc(a, b, c image.Point) int { 26 | ap := (b.Y*c.X - b.X*c.Y) / (a.X*b.Y - a.Y*b.X) 27 | bp := (a.Y*c.X - a.X*c.Y) / (a.Y*b.X - a.X*b.Y) 28 | if a.Mul(ap).Add(b.Mul(bp)) == c { 29 | return ap*3 + bp 30 | } 31 | return 0 32 | } 33 | -------------------------------------------------------------------------------- /2024/14/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | type Robot struct { 11 | P, V image.Point 12 | } 13 | 14 | func main() { 15 | input, _ := os.ReadFile("input.txt") 16 | area := image.Rectangle{image.Point{0, 0}, image.Point{101, 103}} 17 | 18 | robots, quads := []Robot{}, map[image.Point]int{} 19 | for _, s := range strings.Split(strings.TrimSpace(string(input)), "\n") { 20 | var r Robot 21 | fmt.Sscanf(s, "p=%d,%d v=%d,%d", &r.P.X, &r.P.Y, &r.V.X, &r.V.Y) 22 | robots = append(robots, r) 23 | r.P = r.P.Add(r.V.Mul(100)).Mod(area) 24 | quads[image.Point{sgn(r.P.X - area.Dx()/2), sgn(r.P.Y - area.Dy()/2)}]++ 25 | } 26 | fmt.Println(quads[image.Point{-1, -1}] * quads[image.Point{1, -1}] * 27 | quads[image.Point{1, 1}] * quads[image.Point{-1, 1}]) 28 | 29 | for t := 1; ; t++ { 30 | seen := map[image.Point]struct{}{} 31 | for i := range robots { 32 | robots[i].P = robots[i].P.Add(robots[i].V).Mod(area) 33 | seen[robots[i].P] = struct{}{} 34 | } 35 | if len(seen) == len(robots) { 36 | fmt.Println(t) 37 | break 38 | } 39 | } 40 | } 41 | 42 | func sgn(i int) int { 43 | if i < 0 { 44 | return -1 45 | } else if i > 0 { 46 | return 1 47 | } 48 | return 0 49 | } 50 | -------------------------------------------------------------------------------- /2024/15/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | split := strings.Split(strings.TrimSpace(string(input)), "\n\n") 13 | r := strings.NewReplacer("#", "##", "O", "[]", ".", "..", "@", "@.") 14 | 15 | fmt.Println(run(split[0], split[1])) 16 | fmt.Println(run(r.Replace(split[0]), split[1])) 17 | } 18 | 19 | func run(input, moves string) int { 20 | grid, robot := map[image.Point]rune{}, image.Point{} 21 | for y, s := range strings.Fields(input) { 22 | for x, r := range s { 23 | if r == '@' { 24 | robot = image.Point{x, y} 25 | r = '.' 26 | } 27 | grid[image.Point{x, y}] = r 28 | } 29 | } 30 | 31 | delta := map[rune]image.Point{ 32 | '^': {0, -1}, '>': {1, 0}, 'v': {0, 1}, '<': {-1, 0}, 33 | '[': {1, 0}, ']': {-1, 0}, 34 | } 35 | 36 | loop: 37 | for _, r := range strings.ReplaceAll(moves, "\n", "") { 38 | queue, boxes := []image.Point{robot}, map[image.Point]rune{} 39 | for len(queue) > 0 { 40 | p := queue[0] 41 | queue = queue[1:] 42 | 43 | if _, ok := boxes[p]; ok { 44 | continue 45 | } 46 | boxes[p] = grid[p] 47 | 48 | switch n := p.Add(delta[r]); grid[n] { 49 | case '#': 50 | continue loop 51 | case '[', ']': 52 | queue = append(queue, n.Add(delta[grid[n]])) 53 | fallthrough 54 | case 'O': 55 | queue = append(queue, n) 56 | } 57 | } 58 | 59 | for b := range boxes { 60 | grid[b] = '.' 61 | } 62 | for b := range boxes { 63 | grid[b.Add(delta[r])] = boxes[b] 64 | } 65 | robot = robot.Add(delta[r]) 66 | } 67 | 68 | gps := 0 69 | for p, r := range grid { 70 | if r == 'O' || r == '[' { 71 | gps += 100*p.Y + p.X 72 | } 73 | } 74 | return gps 75 | } 76 | -------------------------------------------------------------------------------- /2024/16/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "cmp" 5 | "fmt" 6 | "image" 7 | "maps" 8 | "math" 9 | "os" 10 | "slices" 11 | "strings" 12 | ) 13 | 14 | type State struct { 15 | Pos image.Point 16 | Dir image.Point 17 | } 18 | 19 | type QI struct { 20 | State State 21 | Cost int 22 | Path map[image.Point]struct{} 23 | } 24 | 25 | func main() { 26 | input, _ := os.ReadFile("input.txt") 27 | 28 | var start image.Point 29 | grid := map[image.Point]rune{} 30 | for y, s := range strings.Fields(string(input)) { 31 | for x, r := range s { 32 | if r == 'S' { 33 | start = image.Point{x, y} 34 | } 35 | grid[image.Point{x, y}] = r 36 | } 37 | } 38 | 39 | dist := map[State]int{} 40 | queue := []QI{{ 41 | State{start, image.Point{1, 0}}, 42 | 0, 43 | map[image.Point]struct{}{start: {}}, 44 | }} 45 | 46 | part1, part2 := math.MaxInt, map[image.Point]struct{}{} 47 | for len(queue) > 0 { 48 | slices.SortFunc(queue, func(a, b QI) int { 49 | return cmp.Compare(a.Cost, b.Cost) 50 | }) 51 | i := queue[0] 52 | queue = queue[1:] 53 | 54 | if c, ok := dist[i.State]; ok && c < i.Cost { 55 | continue 56 | } 57 | dist[i.State] = i.Cost 58 | 59 | if grid[i.State.Pos] == 'E' && i.Cost <= part1 { 60 | part1 = i.Cost 61 | maps.Copy(part2, i.Path) 62 | } 63 | 64 | for d, c := range map[image.Point]int{ 65 | i.State.Dir: 1, 66 | {-i.State.Dir.Y, i.State.Dir.X}: 1001, 67 | {i.State.Dir.Y, -i.State.Dir.X}: 1001, 68 | } { 69 | n := State{i.State.Pos.Add(d), d} 70 | if grid[n.Pos] == '#' { 71 | continue 72 | } 73 | path := maps.Clone(i.Path) 74 | path[n.Pos] = struct{}{} 75 | queue = append(queue, QI{n, i.Cost + c, path}) 76 | } 77 | } 78 | fmt.Println(part1) 79 | fmt.Println(len(part2)) 80 | } 81 | -------------------------------------------------------------------------------- /2024/17/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | "regexp" 8 | "slices" 9 | "strconv" 10 | "strings" 11 | ) 12 | 13 | func main() { 14 | input, _ := os.ReadFile("input.txt") 15 | m := regexp.MustCompile(`[\d,]+`).FindAllString(string(input), -1) 16 | 17 | a, _ := strconv.Atoi(m[0]) 18 | b, _ := strconv.Atoi(m[1]) 19 | c, _ := strconv.Atoi(m[2]) 20 | var pgm []int 21 | json.Unmarshal([]byte("["+m[3]+"]"), &pgm) 22 | 23 | out := fmt.Sprint(run(a, b, c, pgm)) 24 | fmt.Println(strings.Trim(strings.ReplaceAll(out, " ", ","), "[]")) 25 | 26 | a = 0 27 | for n := len(pgm) - 1; n >= 0; n-- { 28 | a <<= 3 29 | for !slices.Equal(run(a, b, c, pgm), pgm[n:]) { 30 | a++ 31 | } 32 | } 33 | fmt.Println(a) 34 | } 35 | 36 | func run(a, b, c int, pgm []int) (out []int) { 37 | for ip := 0; ip < len(pgm); ip += 2 { 38 | literal := pgm[ip+1] 39 | combo := []int{0, 1, 2, 3, a, b, c}[literal] 40 | 41 | switch pgm[ip] { 42 | case 0: 43 | a >>= combo 44 | case 1: 45 | b ^= literal 46 | case 2: 47 | b = combo % 8 48 | case 3: 49 | if a != 0 { 50 | ip = literal - 2 51 | } 52 | case 4: 53 | b ^= c 54 | case 5: 55 | out = append(out, combo%8) 56 | case 6: 57 | b = a >> combo 58 | case 7: 59 | c = a >> combo 60 | } 61 | } 62 | return out 63 | } 64 | -------------------------------------------------------------------------------- /2024/18/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | size := 70 13 | 14 | bytes := []image.Point{} 15 | for _, s := range strings.Fields(string(input)) { 16 | var x, y int 17 | fmt.Sscanf(s, "%d,%d", &x, &y) 18 | bytes = append(bytes, image.Point{x, y}) 19 | } 20 | 21 | grid := map[image.Point]bool{} 22 | for y := range size + 1 { 23 | for x := range size + 1 { 24 | grid[image.Point{x, y}] = true 25 | } 26 | } 27 | 28 | loop: 29 | for b := range bytes { 30 | grid[bytes[b]] = false 31 | 32 | queue, dist := []image.Point{{0, 0}}, map[image.Point]int{{0, 0}: 0} 33 | for len(queue) > 0 { 34 | p := queue[0] 35 | queue = queue[1:] 36 | 37 | if p == (image.Point{size, size}) { 38 | if b == 1024 { 39 | fmt.Println(dist[p]) 40 | } 41 | continue loop 42 | } 43 | 44 | for _, d := range []image.Point{{0, -1}, {1, 0}, {0, 1}, {-1, 0}} { 45 | n := p.Add(d) 46 | if _, ok := dist[n]; !ok && grid[n] { 47 | queue, dist[n] = append(queue, n), dist[p]+1 48 | } 49 | } 50 | } 51 | fmt.Printf("%d,%d\n", bytes[b].X, bytes[b].Y) 52 | break 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /2024/19/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | input, _ := os.ReadFile("input.txt") 11 | split := strings.Split(strings.TrimSpace(string(input)), "\n\n") 12 | patterns := strings.Split(split[0], ", ") 13 | 14 | var ways func(string) int 15 | cache := map[string]int{} 16 | 17 | ways = func(design string) (n int) { 18 | if n, ok := cache[design]; ok { 19 | return n 20 | } 21 | defer func() { cache[design] = n }() 22 | 23 | if design == "" { 24 | return 1 25 | } 26 | for _, s := range patterns { 27 | if strings.HasPrefix(design, s) { 28 | n += ways(design[len(s):]) 29 | } 30 | } 31 | return n 32 | } 33 | 34 | part1, part2 := 0, 0 35 | for _, s := range strings.Fields(split[1]) { 36 | if w := ways(s); w > 0 { 37 | part1++ 38 | part2 += w 39 | } 40 | } 41 | fmt.Println(part1) 42 | fmt.Println(part2) 43 | } 44 | -------------------------------------------------------------------------------- /2024/20/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | input, _ := os.ReadFile("input.txt") 12 | 13 | grid, p := map[image.Point]rune{}, image.Point{} 14 | for y, s := range strings.Fields(string(input)) { 15 | for x, r := range s { 16 | if r == 'S' { 17 | p = image.Point{x, y} 18 | } 19 | grid[image.Point{x, y}] = r 20 | } 21 | } 22 | 23 | dist := map[image.Point]int{p: 0} 24 | for grid[p] != 'E' { 25 | for _, d := range []image.Point{{0, -1}, {1, 0}, {0, 1}, {-1, 0}} { 26 | n := p.Add(d) 27 | if _, ok := dist[n]; !ok && grid[n] != '#' { 28 | p, dist[n] = n, dist[p]+1 29 | } 30 | } 31 | } 32 | 33 | part1, part2 := 0, 0 34 | for p := range dist { 35 | for q := range dist { 36 | d := abs(q.X-p.X) + abs(q.Y-p.Y) 37 | if d <= 20 && dist[q]-dist[p]-d >= 100 { 38 | if d <= 2 { 39 | part1++ 40 | } 41 | part2++ 42 | } 43 | } 44 | } 45 | fmt.Println(part1) 46 | fmt.Println(part2) 47 | } 48 | 49 | func abs(x int) int { 50 | if x < 0 { 51 | return -x 52 | } 53 | return x 54 | } 55 | -------------------------------------------------------------------------------- /2024/22/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "cmp" 5 | "fmt" 6 | "maps" 7 | "os" 8 | "slices" 9 | "strconv" 10 | "strings" 11 | ) 12 | 13 | func main() { 14 | input, _ := os.ReadFile("input.txt") 15 | 16 | part1, part2 := 0, map[[4]int]int{} 17 | for _, s := range strings.Fields(string(input)) { 18 | n, _ := strconv.Atoi(s) 19 | 20 | secrets, diff := []int{n}, []int{} 21 | for i := range 2000 { 22 | n ^= n * 64 % 16777216 23 | n ^= n / 32 % 16777216 24 | n ^= n * 2048 % 16777216 25 | secrets = append(secrets, n) 26 | diff = append(diff, n%10-secrets[i]%10) 27 | } 28 | part1 += n 29 | 30 | seen := map[[4]int]bool{} 31 | for i := range len(secrets) - 4 { 32 | if p := [4]int(diff[i : i+4]); !seen[p] { 33 | part2[p] += secrets[i+4] % 10 34 | seen[p] = true 35 | } 36 | } 37 | } 38 | fmt.Println(part1) 39 | fmt.Println(part2[slices.MaxFunc(slices.Collect(maps.Keys(part2)), 40 | func(a, b [4]int) int { return cmp.Compare(part2[a], part2[b]) })]) 41 | } 42 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module aoc 2 | 3 | go 1.23.3 4 | -------------------------------------------------------------------------------- /synacor/arch-spec: -------------------------------------------------------------------------------- 1 | == Synacor Challenge == 2 | In this challenge, your job is to use this architecture spec to create a 3 | virtual machine capable of running the included binary. Along the way, 4 | you will find codes; submit these to the challenge website to track 5 | your progress. Good luck! 6 | 7 | 8 | == architecture == 9 | - three storage regions 10 | - memory with 15-bit address space storing 16-bit values 11 | - eight registers 12 | - an unbounded stack which holds individual 16-bit values 13 | - all numbers are unsigned integers 0..32767 (15-bit) 14 | - all math is modulo 32768; 32758 + 15 => 5 15 | 16 | == binary format == 17 | - each number is stored as a 16-bit little-endian pair (low byte, high byte) 18 | - numbers 0..32767 mean a literal value 19 | - numbers 32768..32775 instead mean registers 0..7 20 | - numbers 32776..65535 are invalid 21 | - programs are loaded into memory starting at address 0 22 | - address 0 is the first 16-bit value, address 1 is the second 16-bit value, etc 23 | 24 | == execution == 25 | - After an operation is executed, the next instruction to read is immediately after the last argument of the current operation. If a jump was performed, the next operation is instead the exact destination of the jump. 26 | - Encountering a register as an operation argument should be taken as reading from the register or setting into the register as appropriate. 27 | 28 | == hints == 29 | - Start with operations 0, 19, and 21. 30 | - Here's a code for the challenge website: zHekYDdpoqSh 31 | - The program "9,32768,32769,4,19,32768" occupies six memory addresses and should: 32 | - Store into register 0 the sum of 4 and the value contained in register 1. 33 | - Output to the terminal the character with the ascii code contained in register 0. 34 | 35 | == opcode listing == 36 | halt: 0 37 | stop execution and terminate the program 38 | set: 1 a b 39 | set register to the value of 40 | push: 2 a 41 | push onto the stack 42 | pop: 3 a 43 | remove the top element from the stack and write it into ; empty stack = error 44 | eq: 4 a b c 45 | set to 1 if is equal to ; set it to 0 otherwise 46 | gt: 5 a b c 47 | set to 1 if is greater than ; set it to 0 otherwise 48 | jmp: 6 a 49 | jump to 50 | jt: 7 a b 51 | if is nonzero, jump to 52 | jf: 8 a b 53 | if is zero, jump to 54 | add: 9 a b c 55 | assign into the sum of and (modulo 32768) 56 | mult: 10 a b c 57 | store into the product of and (modulo 32768) 58 | mod: 11 a b c 59 | store into the remainder of divided by 60 | and: 12 a b c 61 | stores into the bitwise and of and 62 | or: 13 a b c 63 | stores into the bitwise or of and 64 | not: 14 a b 65 | stores 15-bit bitwise inverse of in 66 | rmem: 15 a b 67 | read memory at address and write it to 68 | wmem: 16 a b 69 | write the value from into memory at address 70 | call: 17 a 71 | write the address of the next instruction to the stack and jump to 72 | ret: 18 73 | remove the top element from the stack and jump to it; empty stack = halt 74 | out: 19 a 75 | write the character represented by ascii code to the terminal 76 | in: 20 a 77 | read a character from the terminal and write its ascii code to ; it can be assumed that once input starts, it will continue until a newline is encountered; this means that you can safely read whole lines from the keyboard and trust that they will be fully read 78 | noop: 21 79 | no operation 80 | -------------------------------------------------------------------------------- /synacor/challenge.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mnml/aoc/b1bfada506ca21bc2089a4b7ba654e43eab89584/synacor/challenge.bin -------------------------------------------------------------------------------- /synacor/input.txt: -------------------------------------------------------------------------------- 1 | take tablet 2 | use tablet 3 | doorway 4 | north 5 | north 6 | bridge 7 | continue 8 | down 9 | east 10 | take empty lantern 11 | west 12 | west 13 | passage 14 | ladder 15 | west 16 | south 17 | north 18 | take can 19 | use can 20 | use lantern 21 | west 22 | ladder 23 | darkness 24 | continue 25 | west 26 | west 27 | west 28 | west 29 | north 30 | take red coin 31 | north 32 | west 33 | take blue coin 34 | up 35 | take shiny coin 36 | down 37 | east 38 | east 39 | take concave coin 40 | down 41 | take corroded coin 42 | up 43 | west 44 | use blue coin 45 | use red coin 46 | use shiny coin 47 | use concave coin 48 | use corroded coin 49 | north 50 | take teleporter 51 | use teleporter 52 | take business card 53 | take strange book 54 | use teleporter 55 | north 56 | north 57 | north 58 | north 59 | north 60 | north 61 | north 62 | north 63 | north 64 | take orb 65 | north 66 | east 67 | east 68 | north 69 | west 70 | south 71 | east 72 | east 73 | west 74 | north 75 | north 76 | east 77 | vault 78 | take mirror 79 | use mirror 80 | -------------------------------------------------------------------------------- /synacor/synacor.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "image" 7 | "os" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | const ( 13 | size = 1 << 15 14 | nreg = 8 15 | ) 16 | 17 | func main() { 18 | f, _ := os.Open("challenge.bin") 19 | fi, _ := f.Stat() 20 | 21 | mem := make([]uint16, size+nreg+1) 22 | binary.Read(f, binary.LittleEndian, mem[:fi.Size()/2]) 23 | 24 | // coins := map[int]string{9: "blue", 2: "red", 5: "shiny", 7: "concave", 3: "corroded"} 25 | // for _, p := range perms(2, 3, 5, 7, 9) { 26 | // if p[0]+p[1]*p[2]*p[2]+p[3]*p[3]*p[3]-p[4] == 399 { 27 | // for _, v := range p { 28 | // fmt.Printf("use %s coin\n", coins[v]) 29 | // } 30 | // break 31 | // } 32 | // } 33 | 34 | // disasm(mem[:fi.Size()/2]) 35 | 36 | // for r7 := uint16(0); r7 < size; r7++ { 37 | // if telecheck(4, 1, r7, &[5][size]uint16{}) == 6 { 38 | // fmt.Println(r7) 39 | // break 40 | // } 41 | // } 42 | 43 | // fmt.Print(vault()) 44 | 45 | // fmt.Println(putMyThingDownFlipItAndReverseIt("dxTdMYpudWbp")) 46 | 47 | mem[0x154d] = 0x178f 48 | mem[0x178b] = 1 // set 49 | mem[0x178c] = 32768 // r0 50 | mem[0x178d] = 6 51 | mem[0x178e] = 18 // ret 52 | mem[0x178f] = 1 // set 53 | mem[0x1790] = 32775 // r7 54 | mem[0x1791] = 25734 // (teleport check) 55 | mem[0x1792] = 6 // jmp 56 | mem[0x1793] = 0x15e5 57 | run(mem) 58 | } 59 | 60 | func run(mem []uint16) { 61 | pc := &mem[size+nreg] 62 | op := func() *uint16 { 63 | defer func() { *pc++ }() 64 | if mem[*pc] >= size { 65 | return &mem[mem[*pc]] 66 | } 67 | return &mem[*pc] 68 | } 69 | btou := func(b bool, t, f uint16) uint16 { 70 | if b { 71 | return t 72 | } 73 | return f 74 | } 75 | 76 | for { 77 | switch *op() { 78 | case 0: 79 | return 80 | case 1: 81 | *op() = *op() 82 | case 2: 83 | mem = append(mem, *op()) 84 | case 3: 85 | *op(), mem = mem[len(mem)-1], mem[:len(mem)-1] 86 | case 4: 87 | *op() = btou(*op() == *op(), 1, 0) 88 | case 5: 89 | *op() = btou(*op() > *op(), 1, 0) 90 | case 6: 91 | *pc = *op() 92 | case 7: 93 | *pc = btou(*op() != 0, *op(), *pc) 94 | case 8: 95 | *pc = btou(*op() == 0, *op(), *pc) 96 | case 9: 97 | *op() = (*op() + *op()) % size 98 | case 10: 99 | *op() = *op() * *op() % size 100 | case 11: 101 | *op() = *op() % *op() 102 | case 12: 103 | *op() = *op() & *op() 104 | case 13: 105 | *op() = *op() | *op() 106 | case 14: 107 | *op() = ^*op() % size 108 | case 15: 109 | *op() = mem[*op()] 110 | case 16: 111 | mem[*op()] = *op() 112 | case 17: 113 | *pc, mem = *op(), append(mem, *pc) 114 | case 18: 115 | *pc, mem = mem[len(mem)-1], mem[:len(mem)-1] 116 | case 19: 117 | os.Stdout.Write([]byte{byte(*op())}) 118 | case 20: 119 | b := make([]byte, 1) 120 | os.Stdin.Read(b) 121 | *op() = uint16(b[0]) 122 | } 123 | } 124 | } 125 | 126 | func perms(xs ...int) (ps [][]int) { 127 | if len(xs) == 1 { 128 | return [][]int{xs} 129 | } 130 | for i := range xs { 131 | c := make([]int, len(xs)) 132 | copy(c, xs) 133 | for _, x := range perms(append(c[:i], c[i+1:]...)...) { 134 | ps = append(ps, append([]int{xs[i]}, x...)) 135 | } 136 | } 137 | return 138 | } 139 | 140 | func disasm(mem []uint16) { 141 | names := []string{"halt", "set", "push", "pop", "eq", "gt", "jmp", "jt", "jf", "add", 142 | "mult", "mod", "and", "or", "not", "rmem", "wmem", "call", "ret", "out", "in", "noop"} 143 | nops := map[uint16]int{0: 0, 1: 2, 2: 1, 3: 1, 4: 3, 5: 3, 6: 1, 7: 2, 8: 2, 9: 3, 10: 3, 144 | 11: 3, 12: 3, 13: 3, 14: 2, 15: 2, 16: 2, 17: 1, 18: 0, 19: 1, 20: 1, 21: 0} 145 | 146 | for pc := 0; pc < len(mem); pc += nops[mem[pc]] + 1 { 147 | if _, ok := nops[mem[pc]]; !ok { 148 | continue 149 | } 150 | 151 | fmt.Printf("%04x %s", pc, names[mem[pc]]) 152 | for i := 1; i < nops[mem[pc]]+1; i++ { 153 | fmt.Printf(map[bool]string{true: " r%d", false: " %#x"}[mem[pc+i] >= size], mem[pc+i]%size) 154 | } 155 | fmt.Println() 156 | } 157 | } 158 | 159 | func telecheck(r0, r1, r7 uint16, cache *[5][size]uint16) (r uint16) { 160 | if cache[r0][r1] != 0 { 161 | return cache[r0][r1] 162 | } 163 | defer func() { r %= size; cache[r0][r1] = r }() 164 | 165 | switch r0 { 166 | case 2: 167 | return (r1+2)*r7 + r1 + 1 168 | case 1: 169 | return r7 + r1 + 1 170 | case 0: 171 | return r1 + 1 172 | } 173 | 174 | if r1 == 0 { 175 | return telecheck(r0-1, r7, r7, cache) 176 | } 177 | return telecheck(r0-1, telecheck(r0, r1-1, r7, cache), r7, cache) 178 | } 179 | 180 | func vault() string { 181 | type State struct { 182 | Pos image.Point 183 | Val int 184 | } 185 | 186 | s := `* 8 - 1 187 | 4 * 11 * 188 | + 4 - 18 189 | 22 - 9 *` 190 | 191 | grid := map[image.Point]string{} 192 | for y, s := range strings.Split(s, "\n") { 193 | for x, s := range strings.Fields(s) { 194 | grid[image.Point{x, y}] = s 195 | } 196 | } 197 | 198 | start := State{image.Point{0, 3}, 22} 199 | end := State{image.Point{3, 0}, 30} 200 | 201 | queue := []State{start} 202 | path := map[State]string{start: ""} 203 | 204 | for len(queue) > 0 { 205 | if queue[0] == end { 206 | return path[queue[0]] 207 | } 208 | 209 | for s, d := range map[string]image.Point{"north": {0, -1}, "east": {1, 0}, "south": {0, 1}, "west": {-1, 0}} { 210 | next := State{queue[0].Pos.Add(d), queue[0].Val} 211 | 212 | switch v, _ := strconv.Atoi(grid[next.Pos]); grid[queue[0].Pos] { 213 | case "*": 214 | next.Val *= v 215 | case "+": 216 | next.Val += v 217 | case "-": 218 | next.Val -= v 219 | } 220 | 221 | if _, ok := grid[next.Pos]; !ok || 222 | next.Pos == start.Pos || 223 | next.Pos == end.Pos && next.Val != end.Val { 224 | continue 225 | } 226 | 227 | if _, ok := path[next]; !ok { 228 | path[next] = path[queue[0]] + s + "\n" 229 | queue = append(queue, next) 230 | } 231 | } 232 | 233 | queue = queue[1:] 234 | } 235 | 236 | return "" 237 | } 238 | 239 | func putMyThingDownFlipItAndReverseIt(s string) (rs string) { 240 | for _, r := range s { 241 | rs = string(r) + rs 242 | } 243 | return strings.NewReplacer("b", "d", "d", "b", "p", "q", "q", "p").Replace(rs) 244 | } 245 | --------------------------------------------------------------------------------