Manthan

Solving Advent of Code 2024 in Go

· Manthan Gupta

Day 1

Link: Day 1

package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"sort"
	"strconv"
	"strings"
)

func main() {
	fmt.Println(part1())
	fmt.Println(part2())
}

func readInput() ([]int, []int) {
	fi, err := os.Open("day1_input.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer fi.Close()

	scanner := bufio.NewScanner(fi)
	left_list := make([]int, 0, 1000)
	right_list := make([]int, 0, 1000)
	for scanner.Scan() {
		line := scanner.Text()
		nums := strings.Fields(line)
		if len(nums) != 2 {
			log.Fatalf("expected 2 numbers, got %d", len(nums))
		}
		left, err := strconv.Atoi(nums[0])
		if err != nil {
			log.Fatalf("failed to parse left number: %v", err)
		}
		right, err := strconv.Atoi(nums[1])
		if err != nil {
			log.Fatalf("failed to parse right number: %v", err)
		}
		left_list = append(left_list, left)
		right_list = append(right_list, right)
	}
	return left_list, right_list
}

func part1() int {
	left_list, right_list := readInput()

	sort.Ints(left_list)
	sort.Ints(right_list)

	res := 0
	for i := range left_list {
		diff := left_list[i] - right_list[i]
		if diff < 0 {
			diff = -diff
		}
		res += diff
	}
	return res
}

func part2() int {
	left_list, right_list := readInput()

	freq_dict := make(map[int]int)
	for _, num := range right_list {
		freq_dict[num]++
	}

	res := 0
	for _, num := range left_list {
		res += (freq_dict[num] * num)
	}
	return res
}

Day 2

Link: Day 2

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	nums := part1()
	fmt.Println(nums)

	nums2 := part2()
	fmt.Println(nums2)
}

func part1() int {
	fi, err := os.Open("input.txt")
	if err != nil {
		panic(err)
	}
	defer fi.Close()

	scanner := bufio.NewScanner(fi)
	safe := 0
	for scanner.Scan() {
		line := scanner.Text()
		nums := strings.Fields(line)

		intNums, err := convertToIntSlice(nums)
		if err != nil {
			panic(err)
		}

		increasing := intNums[0] <= intNums[1]
		changed := false

		for i := 1; i < len(intNums); i++ {
			diff := intNums[i] - intNums[i-1]

			if (diff < 0 && increasing) || (diff > 0 && !increasing) || abs(diff) > 3 || diff == 0 {
				changed = true
				break
			}
		}

		if !changed {
			safe++
		}
	}
	return safe
}

func part2() int {
	fi, err := os.Open("input.txt")
	if err != nil {
		panic(err)
	}
	defer fi.Close()

	scanner := bufio.NewScanner(fi)
	safe := 0
	for scanner.Scan() {
		line := scanner.Text()
		nums := strings.Fields(line)

		intNums, err := convertToIntSlice(nums)
		if err != nil {
			panic(err)
		}

		increasing := intNums[0] <= intNums[1]
		changed := 0

		for i := 1; i < len(intNums); i++ {
			diff := intNums[i] - intNums[i-1]

			if (diff < 0 && increasing) || (diff > 0 && !increasing) || abs(diff) > 3 || diff == 0 {
				changed++
			}
		}

		if changed <= 1 {
			safe++
		}
	}
	return safe
}

func convertToIntSlice(nums []string) ([]int, error) {
	intNums := make([]int, len(nums))
	for i, num := range nums {
		var err error
		intNums[i], err = strconv.Atoi(num)
		if err != nil {
			return nil, err
		}
	}
	return intNums, nil
}

func abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

Day 3

Link: Day 3

package main

import (
	"bufio"
	"fmt"
	"os"
	"regexp"
	"strconv"
)

func main() {
	part1()
	part2()
}

func readInput() []string {
	fi, err := os.Open("input.txt")
	if err != nil {
		panic(err)
	}
	defer fi.Close()

	scanner := bufio.NewScanner(fi)
	var lines []string
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}
	return lines
}

func part1() {
	lines := readInput()
	re := regexp.MustCompile(`mul\(\s*(\d+)\s*,\s*(\d+)\s*\)`)
	res := 0
	for _, line := range lines {
		matches := re.FindAllStringSubmatch(line, -1)
		for _, match := range matches {
			a, _ := strconv.Atoi(match[1])
			b, _ := strconv.Atoi(match[2])
			res += a * b
		}
	}
	fmt.Println(res)
}

func part2() {
	lines := readInput()
	re := regexp.MustCompile(`do\(\)|don't\(\)|mul\((\d{1,3}),(\d{1,3})\)`)
	res := 0
	switching := true

	for _, line := range lines {
		matches := re.FindAllStringSubmatch(line, -1)
		for _, match := range matches {
			if match[0] == "do()" {
				switching = true
			} else if match[0] == "don't()" {
				switching = false
			} else if len(match) == 3 && switching {
				a, _ := strconv.Atoi(match[1])
				b, _ := strconv.Atoi(match[2])
				res += a * b
			}
		}
	}
	fmt.Println(res)
}

Star the github repo if you liked the solution.