--- /dev/null
+// https://adventofcode.com/2025/day/1
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strconv"
+)
+
+func part1(scanner *bufio.Scanner) {
+ var pos, zeros int64 = 50, 0
+ for scanner.Scan() {
+ rot := scanner.Bytes()
+ dir := rot[0]
+ num, _ := strconv.ParseInt(string(rot[1:]), 0, 0)
+ if dir == 'L' {
+ num = 100 - num
+ }
+ if pos = (pos + num) % 100; pos == 0 {
+ zeros++
+ }
+ }
+ println(zeros)
+}
+
+func part2(scanner *bufio.Scanner) {
+ var pos, zeros int64 = 50, 0
+ for scanner.Scan() {
+ rot := scanner.Bytes()
+ dir := rot[0]
+ num, _ := strconv.ParseInt(string(rot[1:]), 0, 0)
+ zeros += num / 100
+ num %= 100
+ if dir == 'L' {
+ num *= -1
+ }
+ if pos == 0 {
+ pos = (num + 100) % 100
+ } else {
+ pos += num
+ if dir == 'L' {
+ if pos < 1 {
+ pos = (pos + 100) % 100
+ zeros++
+ }
+ } else {
+ if pos > 99 {
+ pos %= 100
+ zeros++
+ }
+ }
+ }
+ }
+ println(zeros)
+}
+
+func main() {
+ var part func(*bufio.Scanner)
+ filename := "input.txt"
+ usage := func() {
+ fmt.Printf("usage: %v {1|2} [test]\n", os.Args[0])
+ os.Exit(1)
+ }
+ switch len(os.Args) {
+ case 3:
+ if os.Args[2] == "test" {
+ filename = "test.txt"
+ } else {
+ usage()
+ }
+ fallthrough
+ case 2:
+ switch os.Args[1] {
+ case "1":
+ part = part1
+ case "2":
+ part = part2
+ default:
+ usage()
+ }
+ case 1:
+ usage()
+ }
+ file, err := os.Open(filename)
+ if err != nil {
+ fmt.Printf("Unable to open %v\n", filename)
+ os.Exit(1)
+ }
+ defer file.Close()
+ part(bufio.NewScanner(file))
+}
--- /dev/null
+// https://adventofcode.com/2025/day/2
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+func part1(scanner *bufio.Scanner) {
+ scanner.Scan()
+ idRanges := strings.Split(scanner.Text(), ",")
+ total := 0
+ for _, idRange := range idRanges {
+ ids := strings.Split(idRange, "-")
+ start, _ := strconv.Atoi(ids[0])
+ end, _ := strconv.Atoi(ids[1])
+ for i := start; i <= end; i++ {
+ idString := strconv.Itoa(i)
+ l := len(idString) / 2
+ if idString[:l] == idString[l:] {
+ total += i
+ }
+ }
+ }
+ println(total)
+}
+
+func part2(scanner *bufio.Scanner) {
+ scanner.Scan()
+ idRanges := strings.Split(scanner.Text(), ",")
+ total := 0
+ for _, idRange := range idRanges {
+ ids := strings.Split(idRange, "-")
+ start, _ := strconv.Atoi(ids[0])
+ end, _ := strconv.Atoi(ids[1])
+ for i := start; i <= end; i++ {
+ idString := strconv.Itoa(i)
+ l := len(idString)
+ nextDivision:
+ for numDiv := 2; numDiv <= l; numDiv++ {
+ if l%numDiv == 0 {
+ subLen := l / numDiv
+ for j := 0; j < numDiv; j++ {
+ if idString[:subLen] != idString[j*subLen:(j+1)*subLen] {
+ continue nextDivision
+ }
+ }
+ total += i
+ break
+ }
+ }
+ }
+ }
+ println(total)
+}
+
+func main() {
+ var part func(*bufio.Scanner)
+ filename := "input.txt"
+ usage := func() {
+ fmt.Printf("usage: %v {1|2} [test]\n", os.Args[0])
+ os.Exit(1)
+ }
+ switch len(os.Args) {
+ case 3:
+ if os.Args[2] == "test" {
+ filename = "test.txt"
+ } else {
+ usage()
+ }
+ fallthrough
+ case 2:
+ switch os.Args[1] {
+ case "1":
+ part = part1
+ case "2":
+ part = part2
+ default:
+ usage()
+ }
+ case 1:
+ usage()
+ }
+ file, err := os.Open(filename)
+ if err != nil {
+ fmt.Printf("Unable to open %v\n", filename)
+ os.Exit(1)
+ }
+ defer file.Close()
+ part(bufio.NewScanner(file))
+}
--- /dev/null
+// https://adventofcode.com/2025/day/3
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "slices"
+)
+
+func part1(scanner *bufio.Scanner) {
+ total := 0
+ for scanner.Scan() {
+ digits := scanner.Bytes()
+ left, right := getMaxIndex(digits), 0
+ if left == len(digits)-1 {
+ right = left
+ left = getMaxIndex(digits[:right])
+ } else {
+ right = getMaxIndex(digits[left+1:]) + left + 1
+ }
+ total += 10*int(digits[left]-byte('0')) + int(digits[right]-'0')
+ }
+ println(total)
+}
+
+func getMaxIndex(digits []byte) int {
+ if len(digits) == 0 {
+ return -1
+ }
+ var maxDigit byte = '0'
+ maxIndex := 0
+ for i := 0; i < len(digits); i++ {
+ if digits[i] > maxDigit {
+ maxDigit = digits[i]
+ maxIndex = i
+ }
+ }
+ return maxIndex
+}
+
+func part2(scanner *bufio.Scanner) {
+ total := 0
+ for scanner.Scan() {
+ numLeft = 12
+ digits := scanner.Bytes()
+ indices := getMaxIndices(digits)
+ slices.Sort(indices)
+ subtotal := 0
+ for _, i := range indices {
+ subtotal *= 10
+ subtotal += int(digits[i] - '0')
+ }
+ total += subtotal
+ }
+ println(total)
+}
+
+var numLeft int
+
+func getMaxIndices(digits []byte) []int {
+ if numLeft == 0 {
+ return nil
+ }
+ i := getMaxIndex(digits)
+ if i == -1 {
+ return nil
+ }
+ numLeft--
+ right := getMaxIndices(digits[i+1:])
+ for j := range right {
+ right[j] += i + 1
+ }
+ var left []int
+ if numLeft != 0 {
+ left = getMaxIndices(digits[:i])
+ }
+ left = append(left, i)
+ return append(left, right...)
+}
+
+func main() {
+ var part func(*bufio.Scanner)
+ filename := "input.txt"
+ usage := func() {
+ fmt.Printf("usage: %v {1|2} [test]\n", os.Args[0])
+ os.Exit(1)
+ }
+ switch len(os.Args) {
+ case 3:
+ if os.Args[2] == "test" {
+ filename = "test.txt"
+ } else {
+ usage()
+ }
+ fallthrough
+ case 2:
+ switch os.Args[1] {
+ case "1":
+ part = part1
+ case "2":
+ part = part2
+ default:
+ usage()
+ }
+ case 1:
+ usage()
+ }
+ file, err := os.Open(filename)
+ if err != nil {
+ fmt.Printf("Unable to open %v\n", filename)
+ os.Exit(1)
+ }
+ defer file.Close()
+ part(bufio.NewScanner(file))
+}
--- /dev/null
+// https://adventofcode.com/2025/day/4
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+)
+
+func part1(scanner *bufio.Scanner) {
+ var grid [][]byte
+ for scanner.Scan() {
+ line := scanner.Bytes()
+ row := make([]byte, len(line))
+ copy(row, line)
+ grid = append(grid, row)
+ }
+
+ println(len(getAccessableRolls(grid)))
+}
+
+func part2(scanner *bufio.Scanner) {
+ var grid [][]byte
+ for scanner.Scan() {
+ line := scanner.Bytes()
+ row := make([]byte, len(line))
+ copy(row, line)
+ grid = append(grid, row)
+ }
+
+ total := 0
+ for rolls := getAccessableRolls(grid); len(rolls) != 0; rolls = getAccessableRolls(grid) {
+ total += len(rolls)
+ for _, roll := range rolls {
+ grid[roll[0]][roll[1]] = byte('.')
+ }
+ }
+ println(total)
+}
+
+func getAccessableRolls(grid [][]byte) (result [][]int) {
+ numRows, numCols, roll := len(grid), len(grid[0]), byte('@')
+ for row, gridRow := range grid {
+ for col, spot := range gridRow {
+ if spot != roll {
+ continue
+ }
+ numNeighbors := 0
+ for i := -1; i <= 1; i++ {
+ if row+i == -1 || row+i == numRows {
+ continue
+ }
+ for j := -1; j <= 1; j++ {
+ if col+j == -1 || col+j == numCols {
+ continue
+ }
+ if grid[row+i][col+j] == roll {
+ numNeighbors++
+ }
+ }
+ }
+ numNeighbors--
+ if numNeighbors < 4 {
+ result = append(result, []int{row, col})
+ }
+ }
+ }
+ return result
+}
+
+func main() {
+ var part func(*bufio.Scanner)
+ filename := "input.txt"
+ usage := func() {
+ fmt.Printf("usage: %v {1|2} [test]\n", os.Args[0])
+ os.Exit(1)
+ }
+ switch len(os.Args) {
+ case 3:
+ if os.Args[2] == "test" {
+ filename = "test.txt"
+ } else {
+ usage()
+ }
+ fallthrough
+ case 2:
+ switch os.Args[1] {
+ case "1":
+ part = part1
+ case "2":
+ part = part2
+ default:
+ usage()
+ }
+ case 1:
+ usage()
+ }
+ file, err := os.Open(filename)
+ if err != nil {
+ fmt.Printf("Unable to open %v\n", filename)
+ os.Exit(1)
+ }
+ defer file.Close()
+ part(bufio.NewScanner(file))
+}
--- /dev/null
+// https://adventofcode.com/2025/day/5
+
+package main
+
+import (
+ "bufio"
+ "cmp"
+ "fmt"
+ "os"
+ "slices"
+ "strconv"
+ "strings"
+)
+
+func part1(scanner *bufio.Scanner) {
+ var fresh [][2]int
+
+ scanner.Scan()
+ for line := scanner.Text(); line != ""; line = scanner.Text() {
+ idRange := strings.Split(line, "-")
+ start, _ := strconv.Atoi(idRange[0])
+ end, _ := strconv.Atoi(idRange[1])
+ fresh = append(fresh, [2]int{start, end})
+ scanner.Scan()
+ }
+
+ total := 0
+ for scanner.Scan() {
+ id, _ := strconv.Atoi(scanner.Text())
+ for _, idRange := range fresh {
+ if id >= idRange[0] && id <= idRange[1] {
+ total++
+ break
+ }
+ }
+ }
+ println(total)
+}
+
+func part2(scanner *bufio.Scanner) {
+ var fresh [][2]int
+
+ scanner.Scan()
+ for line := scanner.Text(); line != ""; line = scanner.Text() {
+ idRange := strings.Split(line, "-")
+ start, _ := strconv.Atoi(idRange[0])
+ end, _ := strconv.Atoi(idRange[1])
+ fresh = append(fresh, [2]int{start, end})
+ scanner.Scan()
+ }
+
+ slices.SortFunc(fresh, func(a, b [2]int) int {
+ return cmp.Compare(a[0], b[0])
+ })
+
+ for i := 0; i < len(fresh)-1; i++ {
+ if fresh[i+1][0] <= fresh[i][1] {
+ fresh[i+1][0] = fresh[i][0]
+ if fresh[i+1][1] < fresh[i][1] {
+ fresh[i+1][1] = fresh[i][1]
+ }
+ fresh[i] = [2]int{1, 0}
+ }
+ }
+
+ total := 0
+ for _, idRange := range fresh {
+ total += idRange[1] - idRange[0] + 1
+ }
+ println(total)
+}
+
+func main() {
+ var part func(*bufio.Scanner)
+ filename := "input.txt"
+ usage := func() {
+ fmt.Printf("usage: %v {1|2} [test]\n", os.Args[0])
+ os.Exit(1)
+ }
+ switch len(os.Args) {
+ case 3:
+ if os.Args[2] == "test" {
+ filename = "test.txt"
+ } else {
+ usage()
+ }
+ fallthrough
+ case 2:
+ switch os.Args[1] {
+ case "1":
+ part = part1
+ case "2":
+ part = part2
+ default:
+ usage()
+ }
+ case 1:
+ usage()
+ }
+ file, err := os.Open(filename)
+ if err != nil {
+ fmt.Printf("Unable to open %v\n", filename)
+ os.Exit(1)
+ }
+ defer file.Close()
+ part(bufio.NewScanner(file))
+}
--- /dev/null
+// https://adventofcode.com/2025/day/6
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+func part1(scanner *bufio.Scanner) {
+ var lines [][]string
+ for scanner.Scan() {
+ lines = append(lines, strings.Fields(scanner.Text()))
+ }
+
+ ops, total := lines[len(lines)-1], 0
+ for j, op := range ops {
+ var (
+ opFunc func(int, int) int
+ subtotal int
+ )
+ switch op {
+ case "+":
+ opFunc = func(a, b int) int { return a + b }
+ subtotal = 0
+ case "*":
+ opFunc = func(a, b int) int { return a * b }
+ subtotal = 1
+ }
+
+ for i := 0; i < len(lines)-1; i++ {
+ num, _ := strconv.Atoi(lines[i][j])
+ subtotal = opFunc(subtotal, num)
+ }
+ total += subtotal
+ }
+ println(total)
+}
+
+func part2(scanner *bufio.Scanner) {
+ var lines [][]byte
+ for scanner.Scan() {
+ line := scanner.Bytes()
+ row := make([]byte, len(line))
+ copy(row, line)
+ lines = append(lines, row)
+ }
+
+ nums, index := [][]int{[]int{}}, 0
+ for j := 0; j < len(lines[0]); j++ {
+ num := 0
+ for i := 0; i < len(lines)-1; i++ {
+ if lines[i][j] != byte(' ') {
+ num *= 10
+ num += int(lines[i][j] - byte('0'))
+ }
+ }
+ if num == 0 {
+ nums = append(nums, []int{})
+ index++
+ continue
+ }
+ nums[index] = append(nums[index], num)
+ }
+
+ ops, total := strings.Fields(string(lines[len(lines)-1])), 0
+ for j, op := range ops {
+ var (
+ opFunc func(int, int) int
+ subtotal int
+ )
+ switch op {
+ case "+":
+ opFunc = func(a, b int) int { return a + b }
+ subtotal = 0
+ case "*":
+ opFunc = func(a, b int) int { return a * b }
+ subtotal = 1
+ }
+
+ for _, num := range nums[j] {
+ subtotal = opFunc(subtotal, num)
+ }
+ total += subtotal
+ }
+ println(total)
+}
+
+func main() {
+ var part func(*bufio.Scanner)
+ filename := "input.txt"
+ usage := func() {
+ fmt.Printf("usage: %v {1|2} [test]\n", os.Args[0])
+ os.Exit(1)
+ }
+ switch len(os.Args) {
+ case 3:
+ if os.Args[2] == "test" {
+ filename = "test.txt"
+ } else {
+ usage()
+ }
+ fallthrough
+ case 2:
+ switch os.Args[1] {
+ case "1":
+ part = part1
+ case "2":
+ part = part2
+ default:
+ usage()
+ }
+ case 1:
+ usage()
+ }
+ file, err := os.Open(filename)
+ if err != nil {
+ fmt.Printf("Unable to open %v\n", filename)
+ os.Exit(1)
+ }
+ defer file.Close()
+ part(bufio.NewScanner(file))
+}
--- /dev/null
+// https://adventofcode.com/2025/day/7
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "os"
+)
+
+func part1(scanner *bufio.Scanner) {
+ for scanner.Scan() {
+ line := scanner.Bytes()
+ row := make([]byte, len(line))
+ copy(row, line)
+ grid = append(grid, row)
+ }
+
+ println(countSpliters(1, bytes.Index(grid[0], []byte{byte('S')})))
+}
+
+var grid [][]byte
+
+func countSpliters(i, j int) int {
+ for ; i < len(grid); i++ {
+ if grid[i][j] == byte('|') {
+ return 0
+ }
+ if grid[i][j] == byte('^') {
+ return countSpliters(i, j-1) + countSpliters(i, j+1) + 1
+ }
+ grid[i][j] = byte('|')
+ }
+ return 0
+}
+
+func part2(scanner *bufio.Scanner) {
+ for scanner.Scan() {
+ line := scanner.Bytes()
+ row := make([]byte, len(line))
+ copy(row, line)
+ grid = append(grid, row)
+ }
+ cache = make([][]int, len(grid))
+ for i := range cache {
+ cache[i] = make([]int, len(grid[0]))
+ }
+
+ println(countTimelines(1, bytes.Index(grid[0], []byte{byte('S')})))
+}
+
+var cache [][]int
+
+func countTimelines(i, j int) int {
+ for ; i < len(grid); i++ {
+ if grid[i][j] == byte('^') {
+ if cache[i][j] == 0 {
+ cache[i][j] = countTimelines(i, j-1) + countTimelines(i, j+1)
+ }
+ return cache[i][j]
+ }
+ }
+ return 1
+}
+
+func main() {
+ var part func(*bufio.Scanner)
+ filename := "input.txt"
+ usage := func() {
+ fmt.Printf("usage: %v {1|2} [test]\n", os.Args[0])
+ os.Exit(1)
+ }
+ switch len(os.Args) {
+ case 3:
+ if os.Args[2] == "test" {
+ filename = "test.txt"
+ } else {
+ usage()
+ }
+ fallthrough
+ case 2:
+ switch os.Args[1] {
+ case "1":
+ part = part1
+ case "2":
+ part = part2
+ default:
+ usage()
+ }
+ case 1:
+ usage()
+ }
+ file, err := os.Open(filename)
+ if err != nil {
+ fmt.Printf("Unable to open %v\n", filename)
+ os.Exit(1)
+ }
+ defer file.Close()
+ part(bufio.NewScanner(file))
+}
--- /dev/null
+// https://adventofcode.com/2025/day/8
+
+package main
+
+import (
+ "bufio"
+ "cmp"
+ "fmt"
+ "os"
+ "slices"
+ "strconv"
+ "strings"
+)
+
+func part1(scanner *bufio.Scanner) {
+ _, cables, adj := getData(scanner)
+
+ for _, c := range cables[:numConnections] {
+ adj[c.i][c.j], adj[c.j][c.i] = 1, 1
+ }
+
+ total := 1
+ for i, sizes := 0, getCompSizes(adj); i < 3; i++ {
+ total *= sizes[i]
+ }
+ println(total)
+}
+
+func part2(scanner *bufio.Scanner) {
+ vecs, cables, adj := getData(scanner)
+
+ c := 0
+ for numComps := len(vecs); c < len(cables); {
+ for n := 0; n < numComps-1; n, c = n+1, c+1 {
+ adj[cables[c].i][cables[c].j], adj[cables[c].j][cables[c].i] = 1, 1
+ }
+ if numComps = len(getCompSizes(adj)); numComps == 1 {
+ break
+ }
+ }
+ println(vecs[cables[c-1].i][0] * vecs[cables[c-1].j][0])
+}
+
+type cable struct {
+ i, j, d int
+}
+
+func getData(scanner *bufio.Scanner) (vecs [][3]int, cables []cable, adj [][]int) {
+ for scanner.Scan() {
+ var vec [3]int
+ for i, num := range strings.Split(scanner.Text(), ",") {
+ vec[i], _ = strconv.Atoi(num)
+ }
+ vecs = append(vecs, vec)
+ }
+
+ for i := 0; i < len(vecs); i++ {
+ for j := i + 1; j < len(vecs); j++ {
+ dx, dy, dz := vecs[j][0]-vecs[i][0], vecs[j][1]-vecs[i][1], vecs[j][2]-vecs[i][2]
+ cables = append(cables, cable{i, j, dx*dx + dy*dy + dz*dz})
+ }
+ }
+ slices.SortFunc(cables, func(a, b cable) int {
+ return cmp.Compare(a.d, b.d)
+ })
+
+ adj = make([][]int, len(vecs))
+ for i := range adj {
+ adj[i] = make([]int, len(vecs))
+ }
+
+ return
+}
+
+func getCompSizes(adj [][]int) (sizes []int) {
+ for i, checklist, queue := 0, make([]int, len(adj)), []int{}; i < len(adj); i++ {
+ if checklist[i] == 1 {
+ continue
+ }
+ checklist[i] = 1
+ queue = append(queue, i)
+ for n := 0; n < len(queue); n++ {
+ for j := 0; j < len(adj); j++ {
+ if adj[queue[n]][j] == 1 && checklist[j] == 0 {
+ checklist[j] = 1
+ queue = append(queue, j)
+ }
+ }
+ }
+ sizes = append(sizes, len(queue))
+ queue = nil
+ }
+ slices.SortFunc(sizes, func(a, b int) int {
+ return cmp.Compare(b, a)
+ })
+ return
+}
+
+var numConnections int
+
+func main() {
+ var part func(*bufio.Scanner)
+ filename := "input.txt"
+ usage := func() {
+ fmt.Printf("usage: %v {1|2} [test]\n", os.Args[0])
+ os.Exit(1)
+ }
+ numConnections = 1000
+ switch len(os.Args) {
+ case 3:
+ if os.Args[2] == "test" {
+ filename = "test.txt"
+ numConnections = 10
+ } else {
+ usage()
+ }
+ fallthrough
+ case 2:
+ switch os.Args[1] {
+ case "1":
+ part = part1
+ case "2":
+ part = part2
+ default:
+ usage()
+ }
+ case 1:
+ usage()
+ }
+ file, err := os.Open(filename)
+ if err != nil {
+ fmt.Printf("Unable to open %v\n", filename)
+ os.Exit(1)
+ }
+ defer file.Close()
+ part(bufio.NewScanner(file))
+}
--- /dev/null
+// https://adventofcode.com/2025/day/9
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+func part1(scanner *bufio.Scanner) {
+ getMax(scanner, func(r rect, tiles []tile) bool {
+ return true
+ })
+}
+
+func part2(scanner *bufio.Scanner) {
+ getMax(scanner, func(r rect, tiles []tile) bool {
+ for i := range tiles {
+ bitcode := func(r rect, p tile) (b byte) {
+ if p.x <= r.min.x {
+ b |= 0b1000
+ } else if p.x >= r.max.x {
+ b |= 0b0100
+ }
+ if p.y <= r.min.y {
+ b |= 0b0010
+ } else if p.y >= r.max.y {
+ b |= 0b0001
+ }
+ return
+ }
+ if bitcode(r, tiles[i])&bitcode(r, tiles[(i+1)%len(tiles)]) == 0 {
+ return false
+ }
+ }
+ return true
+ })
+}
+
+type tile struct {
+ x, y int
+}
+
+type rect struct {
+ min, max tile
+}
+
+func getMax(scanner *bufio.Scanner, valid func(r rect, tiles []tile) bool) {
+ var tiles []tile
+ for scanner.Scan() {
+ coords := strings.Split(scanner.Text(), ",")
+ var t tile
+ t.x, _ = strconv.Atoi(coords[0])
+ t.y, _ = strconv.Atoi(coords[1])
+ tiles = append(tiles, t)
+ }
+
+ max := 0
+ for i := 0; i < len(tiles); i++ {
+ for j := i + 1; j < len(tiles); j++ {
+ r := rect{tiles[i], tiles[j]}
+ if r.min.x > r.max.x {
+ r.min.x, r.max.x = r.max.x, r.min.x
+ }
+ if r.min.y > r.max.y {
+ r.min.y, r.max.y = r.max.y, r.min.y
+ }
+ area := (r.max.x - r.min.x + 1) * (r.max.y - r.min.y + 1)
+ if area > max && valid(r, tiles) {
+ max = area
+ }
+ }
+ }
+ println(max)
+}
+
+func main() {
+ var part func(*bufio.Scanner)
+ filename := "input.txt"
+ usage := func() {
+ fmt.Printf("usage: %v {1|2} [test]\n", os.Args[0])
+ os.Exit(1)
+ }
+ switch len(os.Args) {
+ case 3:
+ if os.Args[2] == "test" {
+ filename = "test.txt"
+ } else {
+ usage()
+ }
+ fallthrough
+ case 2:
+ switch os.Args[1] {
+ case "1":
+ part = part1
+ case "2":
+ part = part2
+ default:
+ usage()
+ }
+ case 1:
+ usage()
+ }
+ file, err := os.Open(filename)
+ if err != nil {
+ fmt.Printf("Unable to open %v\n", filename)
+ os.Exit(1)
+ }
+ defer file.Close()
+ part(bufio.NewScanner(file))
+}
--- /dev/null
+// https://adventofcode.com/2025/day/10
+
+// NOTE: Part 2 runs too slow to check for correctness
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "math"
+ "os"
+ "slices"
+ "strconv"
+ "strings"
+)
+
+func part1(scanner *bufio.Scanner) {
+ total := 0
+ for scanner.Scan() {
+ tokens := strings.Split(scanner.Text(), " ")
+
+ lights := tokens[0][1 : len(tokens[0])-1]
+ var goal uint16
+ for i := range lights {
+ goal <<= 1
+ if lights[len(lights)-i-1] == '#' {
+ goal |= 1
+ }
+ }
+
+ schemes := tokens[1 : len(tokens)-1]
+ buttons := make([]uint16, len(schemes))
+ for i, scheme := range schemes {
+ digits := strings.Split(scheme[1:len(scheme)-1], ",")
+ for _, digit := range digits {
+ n, _ := strconv.Atoi(digit)
+ buttons[i] |= 1 << n
+ }
+ }
+
+ for i := 1; i <= len(buttons); i++ {
+ if configureLights(goal, buttons, i) {
+ total += i
+ break
+ }
+ }
+ }
+ println(total)
+}
+
+func configureLights(goal uint16, buttons []uint16, depth int) bool {
+ if goal == 0 {
+ return true
+ }
+ if depth == 0 {
+ return false
+ }
+ for i := range buttons {
+ temp := make([]uint16, len(buttons))
+ copy(temp, buttons)
+ slices.Delete(temp, i, i+1)
+ temp = temp[:len(temp)-1]
+ if configureLights(goal^buttons[i], temp, depth-1) {
+ return true
+ }
+ }
+ return false
+}
+
+func part2(scanner *bufio.Scanner) {
+ total := 0
+ for scanner.Scan() {
+ tokens := strings.Split(scanner.Text(), " ")
+
+ goalToken := tokens[len(tokens)-1]
+ var goal []int
+ for _, digit := range strings.Split(goalToken[1:len(goalToken)-1], ",") {
+ n, _ := strconv.Atoi(digit)
+ goal = append(goal, n)
+ }
+
+ buttonTokens := tokens[1 : len(tokens)-1]
+ buttons := make([][]int, len(buttonTokens))
+ for i, buttonToken := range buttonTokens {
+ buttons[i] = make([]int, len(goal))
+ for _, digit := range strings.Split(buttonToken[1:len(buttonToken)-1], ",") {
+ n, _ := strconv.Atoi(digit)
+ buttons[i][n] = 1
+ }
+ }
+
+ total += distanceFromOrigin(goal, buttons)
+ }
+ println(total)
+}
+
+func distanceFromOrigin(position []int, buttons [][]int) (distance int) {
+ if len(buttons) == 0 {
+ return -1
+ }
+
+ m := math.MaxInt
+ for i, n := range buttons[0] {
+ if n == 1 && position[i] < m {
+ m = position[i]
+ }
+ }
+ for i := range buttons[0] {
+ position[i] -= buttons[0][i] * m
+ }
+ if slices.ContainsFunc(position, func(a int) bool { return a != 0 }) {
+ distance = -1
+ for i := m; i >= 0; i-- {
+ d := distanceFromOrigin(position, buttons[1:])
+ if d != -1 && (distance == -1 || i+d < distance) {
+ distance = i + d
+ }
+ for j := range buttons[0] {
+ position[j] += buttons[0][j]
+ }
+ }
+ for i := range buttons[0] {
+ position[i] -= buttons[0][i]
+ }
+ } else {
+ distance = m
+ for i := range buttons[0] {
+ position[i] += buttons[0][i] * m
+ }
+ }
+ return
+}
+
+func main() {
+ var part func(*bufio.Scanner)
+ filename := "input.txt"
+ usage := func() {
+ fmt.Printf("usage: %v {1|2} [test]\n", os.Args[0])
+ os.Exit(1)
+ }
+ switch len(os.Args) {
+ case 3:
+ if os.Args[2] == "test" {
+ filename = "test.txt"
+ } else {
+ usage()
+ }
+ fallthrough
+ case 2:
+ switch os.Args[1] {
+ case "1":
+ part = part1
+ case "2":
+ part = part2
+ default:
+ usage()
+ }
+ case 1:
+ usage()
+ }
+ file, err := os.Open(filename)
+ if err != nil {
+ fmt.Printf("Unable to open %v\n", filename)
+ os.Exit(1)
+ }
+ defer file.Close()
+ part(bufio.NewScanner(file))
+}
--- /dev/null
+// https://adventofcode.com/2025/day/11
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strings"
+)
+
+func part1(scanner *bufio.Scanner) {
+ initDevices(scanner)
+
+ println(numPaths("you", "out", make(map[string]int)))
+}
+
+func part2(scanner *bufio.Scanner) {
+ initDevices(scanner)
+
+ a, b := "fft", "dac"
+ middle := numPaths(a, b, make(map[string]int))
+ if middle == 0 {
+ a, b = b, a
+ middle = numPaths(a, b, make(map[string]int))
+ }
+ println(numPaths("svr", a, make(map[string]int)) *
+ middle * numPaths(b, "out", make(map[string]int)))
+}
+
+var devices map[string][]string
+
+func initDevices(scanner *bufio.Scanner) {
+ devices = make(map[string][]string)
+ for scanner.Scan() {
+ names := strings.Split(scanner.Text(), ":")
+ devices[names[0]] = strings.Split(names[1], " ")[1:]
+ }
+}
+
+func numPaths(start, end string, cache map[string]int) int {
+ if start == end {
+ return 1
+ }
+ if _, exists := cache[start]; !exists {
+ for _, output := range devices[start] {
+ cache[start] += numPaths(output, end, cache)
+ }
+ }
+ return cache[start]
+}
+
+func main() {
+ var part func(*bufio.Scanner)
+ filename := "input.txt"
+ usage := func() {
+ fmt.Printf("usage: %v {1|2} [test]\n", os.Args[0])
+ os.Exit(1)
+ }
+ switch len(os.Args) {
+ case 3:
+ if os.Args[2] != "test" {
+ usage()
+ }
+ switch os.Args[1] {
+ case "1":
+ filename = "test1.txt"
+ case "2":
+ filename = "test2.txt"
+ default:
+ usage()
+ }
+ fallthrough
+ case 2:
+ switch os.Args[1] {
+ case "1":
+ part = part1
+ case "2":
+ part = part2
+ default:
+ usage()
+ }
+ case 1:
+ usage()
+ }
+ file, err := os.Open(filename)
+ if err != nil {
+ fmt.Printf("Unable to open %v\n", filename)
+ os.Exit(1)
+ }
+ defer file.Close()
+ part(bufio.NewScanner(file))
+}
--- /dev/null
+// https://adventofcode.com/2025/day/12
+
+// NOTE: Part 1 runs too slow to check for correctness, and so Part 2 remains inaccessable to me.
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+func part1(scanner *bufio.Scanner) {
+ total := 0
+ for scanner.Scan() {
+ line := scanner.Text()
+ if line[len(line)-1] == ':' {
+ var s [3][3]bool
+ for i := 0; ; i++ {
+ scanner.Scan()
+ line = scanner.Text()
+ if len(line) == 0 {
+ break
+ }
+
+ for j, c := range line {
+ if c == '#' {
+ s[i][j] = true
+ }
+ }
+ }
+
+ var syms [8][3][3]bool
+ for rot := 0; rot < 4; rot++ {
+ for refl := 0; refl < 2; refl++ {
+ syms[2*rot+refl] = s
+ for i := range s {
+ s[i][0], s[i][2] = s[i][2], s[i][0]
+ }
+ }
+ temp := s
+ for i := range s {
+ for j := range s[0] {
+ s[i][j] = temp[2-j][i]
+ }
+ }
+ }
+
+ var shape [][3]uint
+ nextShape:
+ for i := 0; i < 8; i++ {
+ nextPair:
+ for j := i + 1; j < 8; j++ {
+ for r := range syms[i] {
+ for c := range syms[i][r] {
+ if syms[i][r][c] != syms[j][r][c] {
+ continue nextPair
+ }
+ }
+ }
+ continue nextShape
+ }
+
+ var data [3]uint
+ for r, row := range syms[i] {
+ for _, item := range row {
+ data[r] <<= 1
+ if item {
+ data[r]++
+ }
+ }
+ temp := data[r]
+ for i := 0; i < 16; i++ {
+ data[r] <<= 3
+ data[r] |= temp
+ }
+ }
+ shape = append(shape, data)
+ }
+ shapes = append(shapes, shape)
+ } else {
+ parts := strings.Split(line, ":")
+ var dimensions, indices []uint8
+ for _, value := range strings.Split(parts[0], "x") {
+ n, _ := strconv.Atoi(value)
+ dimensions = append(dimensions, uint8(n))
+ }
+ data := make([]uint, dimensions[1])
+ for _, value := range strings.Split(parts[1], " ")[1:] {
+ n, _ := strconv.Atoi(value)
+ indices = append(indices, uint8(n))
+ }
+ region := region{dimensions[0], data, indices}
+
+ if canFillRegion(region) {
+ total++
+ }
+ }
+ }
+ println(total)
+}
+
+var shapes [][][3]uint
+
+type region struct {
+ width uint8
+ data []uint
+ indices []uint8
+}
+
+func canFillRegion(r region) bool {
+ var n int
+ for n = 0; n < len(r.indices); n++ {
+ if r.indices[n] != 0 {
+ break
+ }
+ }
+ if n == len(r.indices) {
+ return true
+ }
+
+ r.indices[n]--
+ for h := 0; h <= len(r.data)-3; h++ {
+ for _, shape := range shapes[n] {
+ var invalids [3]uint
+ for s := 0; s < 3; s++ {
+ invalids[s] = shape[0]&r.data[h] | shape[1]&r.data[h+1] | shape[2]&r.data[h+2]
+ shape[0] <<= 1
+ shape[1] <<= 1
+ shape[2] <<= 1
+ }
+ shape[0] >>= 3
+ shape[1] >>= 3
+ shape[2] >>= 3
+
+ mask := uint(7)
+ for w, n := 0, 0; w <= int(r.width)-3; w, n = w+1, n+1 {
+ if mask&invalids[n] == 0 {
+ r.data[h] ^= shape[0] << w & mask
+ r.data[h+1] ^= shape[1] << w & mask
+ r.data[h+2] ^= shape[2] << w & mask
+
+ if canFillRegion(r) {
+ return true
+ }
+
+ r.data[h] ^= shape[0] << w & mask
+ r.data[h+1] ^= shape[1] << w & mask
+ r.data[h+2] ^= shape[2] << w & mask
+ }
+ mask <<= 1
+ if n == 2 {
+ n = -1
+ }
+ }
+ }
+ }
+ r.indices[n]++
+
+ return false
+}
+
+func part2(scanner *bufio.Scanner) {
+ for scanner.Scan() {
+ println(scanner.Text())
+ }
+}
+
+func main() {
+ var part func(*bufio.Scanner)
+ filename := "input.txt"
+ usage := func() {
+ fmt.Printf("usage: %v {1|2} [test]\n", os.Args[0])
+ os.Exit(1)
+ }
+ switch len(os.Args) {
+ case 3:
+ if os.Args[2] == "test" {
+ filename = "test.txt"
+ } else {
+ usage()
+ }
+ fallthrough
+ case 2:
+ switch os.Args[1] {
+ case "1":
+ part = part1
+ case "2":
+ part = part2
+ default:
+ usage()
+ }
+ case 1:
+ usage()
+ }
+ file, err := os.Open(filename)
+ if err != nil {
+ fmt.Printf("Unable to open %v\n", filename)
+ os.Exit(1)
+ }
+ defer file.Close()
+ part(bufio.NewScanner(file))
+}
--- /dev/null
+MIT License
+
+Copyright (c) 2025 Trent Huber
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
--- /dev/null
+# Advent of Go 2025
+
+Completing [this year's Advent of Code](https://adventofcode.com/2025/) to the
+best of my ability entirely in [Go](https://go.dev/doc/). Day 10, Part 2 and Day
+12, Part 1 remain unable to be checked for correctness since my code runs too
+slow. Day 12, Part 2 remains unimplemented since I couldn't complete Part 1 for
+that day.
+
+## Building
+
+To build a specific file, just `go build` it. The resulting executable expects
+to take input from a file named `input.txt` located in the same directory as
+you're running the executable in. To specify whether you'd like to process that
+input according to the first or second part of that day, you have to pass either
+a `1` or a `2` on the command line. Additionally, since each day comes with an
+example input used for testing, you can optionally pass `test` at the end of the
+command line to take input from `test.txt` instead, which is where I would paste
+the test input copied directly from the webpage.
+
+If you find this code at all useful, I've included a template, `template.go`,
+that can be used for any other Advent of Code challenges.
--- /dev/null
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+)
+
+func part1(scanner *bufio.Scanner) {
+ for scanner.Scan() {
+ println(scanner.Text())
+ }
+}
+
+func part2(scanner *bufio.Scanner) {
+ for scanner.Scan() {
+ println(scanner.Text())
+ }
+}
+
+func main() {
+ var part func(*bufio.Scanner)
+ filename := "input.txt"
+ usage := func() {
+ fmt.Printf("usage: %v {1|2} [test]\n", os.Args[0])
+ os.Exit(1)
+ }
+ switch len(os.Args) {
+ case 3:
+ if os.Args[2] == "test" {
+ filename = "test.txt"
+ } else {
+ usage()
+ }
+ fallthrough
+ case 2:
+ switch os.Args[1] {
+ case "1":
+ part = part1
+ case "2":
+ part = part2
+ default:
+ usage()
+ }
+ case 1:
+ usage()
+ }
+ file, err := os.Open(filename)
+ if err != nil {
+ fmt.Printf("Unable to open %v\n", filename)
+ os.Exit(1)
+ }
+ defer file.Close()
+ part(bufio.NewScanner(file))
+}