solve

problem

This week is just sliding window questions. Pretty much the same as the last problem but in go and using a for loop to iterate over the second pointer. Use a hashmap to store existing non-repeating substring.

func lengthOfLongestSubstring(s string) int {
	if len(s) < 2 {
		return len(s)
	}

	word := strings.Split(s, "")
	m := make(map[string]int)
	max_length, curr_length, begin_index := 1, 0, 0

	m[word[0]] = 0
	for end_index, i := range word {

		if begin_index == end_index {
			continue
		}

		_, exists := m[i]
		if exists {
			begin_index = m[i] + 1
			for j, k := range m {
				if k < begin_index {
					delete(m, j)
				}
			}
			m[i] = end_index
			// fmt.Println("begin:", begin_index, ", end:", end_index, ", m:", m)

		} else {
			m[i] = end_index
			// fmt.Println("begin:", begin_index, ", end:", end_index, ", m:", m)
			curr_length = len(m)
			if curr_length > max_length {
				max_length = curr_length
			}
		}

	}
	return max_length
}

question

The next few questions for this week will all be sliding window questions.

class Solution:

    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        pointer_1 = 0
        pointer_2 = 0
        curr_sum = nums[pointer_1]
        num_length = len(nums)
        min_subarray = num_length + 1

        while pointer_2 < num_length:

            # check
            if curr_sum >= target:
                curr_length = pointer_2 - pointer_1 + 1
                if curr_length < min_subarray:
                    min_subarray = curr_length
            
            # move
            if pointer_1 == pointer_2:
                pointer_2 = pointer_2 + 1
                if pointer_2 >= num_length:
                    break
                curr_sum = curr_sum + nums[pointer_2]
            elif curr_sum >= target:
                curr_sum = curr_sum - nums[pointer_1]
                pointer_1 = pointer_1 + 1
            elif curr_sum < target:
                pointer_2 = pointer_2 + 1
                if pointer_2 >= num_length:
                    break
                curr_sum = curr_sum + nums[pointer_2]

        if min_subarray == num_length + 1:
            return 0
        
        return min_subarray

2022 advent day 15

I also spent too long thinking this problem in the wrong way. It's basically just checking values in a row to see if it's observable by a beacon. We mark all values as checked for each observation.

package problems

import (
	"os"
	"strings"

	"github.com/xxxx/advent/internal"
)

type day15 struct {
	lines []string
}

func Day15(part int, file string) int {

	in := day15{
		lines: internal.Read(file),
	}

	switch part {
	case 1:
		return in.part_one()
	case 2:
		return in.part_two()
	default:
		return 0
	}

}

func read_beacon_readings(lines []string) map[coordinate][]coordinate {
	beacon_readings := make(map[coordinate][]coordinate)

	for _, line := range lines {
		split := strings.Split(line, "=")
		sensor_x := internal.StrToInt(strings.Split(split[1], ",")[0])
		sensor_y := internal.StrToInt(strings.Split(split[2], ":")[0])
		beacon_x := internal.StrToInt(strings.Split(split[3], ",")[0])
		beacon_y := internal.StrToInt(split[4])

		beacon_coordinate := coordinate{beacon_x, beacon_y}
		sensor_coordiante := coordinate{sensor_x, sensor_y}

		if _, ok := beacon_readings[beacon_coordinate]; !ok {
			beacon_readings[beacon_coordinate] = []coordinate{}
		}
		beacon_readings[beacon_coordinate] = append(beacon_readings[beacon_coordinate], sensor_coordiante)
	}

	return beacon_readings
}

func get_manhattan_distance(a coordinate, b coordinate) int {
	x_dist := a.x - b.x

	if x_dist < 0 {
		x_dist = x_dist * -1
	}

	y_dist := a.y - b.y

	if y_dist < 0 {
		y_dist = y_dist * -1
	}

	return x_dist + y_dist
}

func populate_x(no_beacons_x map[int]bool, sensor coordinate, beacon coordinate, const_y int) map[int]bool {

	manhattan_distance := get_manhattan_distance(sensor, beacon)

	// sensor.y >= const_y
	y_dist := sensor.y - const_y
	if y_dist >= 0 && y_dist <= manhattan_distance {
		x_dist := manhattan_distance - y_dist
		for i := sensor.x - x_dist; i <= sensor.x+x_dist; i++ {
			no_beacons_x[i] = true
		}
	}

	// sensor.y <= const_y
	y_dist = const_y - sensor.y
	if y_dist >= 0 && y_dist <= manhattan_distance {
		x_dist := manhattan_distance - y_dist
		for i := sensor.x - x_dist; i <= sensor.x+x_dist; i++ {
			no_beacons_x[i] = true
		}
	}

	return no_beacons_x
}

func (input day15) part_one() int {
	beacon_readings := read_beacon_readings((input.lines))
	no_beacons_x := make(map[int]bool)

	const_y := 2000000
	if os.Getenv("ENV") == "test" {
		const_y = 10
	}

	for beacon, sensors := range beacon_readings {
		for _, sensor := range sensors {
			// maps passed as references
			populate_x(no_beacons_x, sensor, beacon, const_y)
		}
	}

	for beacon := range beacon_readings {
		if beacon.y == const_y {
			delete(no_beacons_x, beacon.x)
		}
	}

	return len(no_beacons_x)
}

func get_possible_distress_locations(sensor coordinate, distance int) []coordinate {
	result := []coordinate{}
	d := distance + 1
	for i := 0; i <= d; i++ {

		coordinates := []coordinate{
			{sensor.x - d + i, sensor.y + i},
			{sensor.x - d + i, sensor.y - i},
			{sensor.x + d - i, sensor.y + i},
			{sensor.x + d - i, sensor.y - i},
		}

		for _, c := range coordinates {
			if is_in_bound(c) {
				result = append(result, c)
			}
		}

	}
	return result
}

func is_in_bound(c coordinate) bool {
	if os.Getenv("ENV") == "test" {
		if c.x >= 0 && c.x <= 20 && c.y >= 0 && c.y <= 20 {
			return true
		}
	} else {
		if c.x >= 0 && c.x <= 4000000 && c.y >= 0 && c.y <= 4000000 {
			return true
		}
	}
	return false
}

func is_reachable(sensors map[coordinate]int, target coordinate) bool {
	for sensor, max_distance := range sensors {
		if get_manhattan_distance(sensor, target) <= max_distance {
			return true
		}
	}
	return false
}

func (input day15) part_two() int {
	beacon_readings := read_beacon_readings((input.lines))
	distances := make(map[coordinate]int)

	// check possible locations outside of sensor range

	for beacon, sensors := range beacon_readings {
		for _, sensor := range sensors {
			distance := get_manhattan_distance(sensor, beacon)
			if d, ok := distances[sensor]; ok {
				if d < distance {
					distances[sensor] = distance
				}
			} else {
				distances[sensor] = distance
			}
		}
	}

	for sensor, distance := range distances {
		possible_distress_locations := get_possible_distress_locations(sensor, distance)
		for _, possible_distress_location := range possible_distress_locations {
			if !is_reachable(distances, possible_distress_location) {
				return get_tuning_frequency(possible_distress_location)
			}
		}
	}

	return 0
}

func get_tuning_frequency(c coordinate) int {
	return 4000000*c.x + c.y
}

advent 2022 day 11

Monkeys throwing stuff around and making you worried


package problems

import (
	"fmt"
	"sort"
	"strings"

	"github.com/xxxx/advent/internal"
)

type day11 struct {
	lines []string
}

type monkey struct {
	items         []int
	operation     func(int) int
	test          func(int) bool
	true_monkey   int
	false_monkey  int
	total_inspect int
}

func Day11(part int, file string) int {

	in := day11{
		lines: internal.Read(file),
	}

	switch part {
	case 1:
		return in.part_one()
	case 2:
		return in.part_two()
	default:
		return 0
	}

}

func build_operation(a int, operand string) func(old int) int {
	// anonymous function for monkey to use
	// a is a constant
	switch operand {
	case "+":
		return func(old int) int {
			return old + a
		}
	case "*":
		return func(old int) int {
			return old * a
		}
	case "^":
		return func(old int) int {
			return old * old
		}
	default:
		panic(fmt.Sprintf("unknown operand: %s", operand))
	}
}

func build_test(a int) func(old int) bool {
	// anonymous function for monkey to use
	// a is a constant
	return func(old int) bool {
		return old%a == 0
	}
}

func read_input_into_monkeys(lines []string) map[int]*monkey {

	monkeys := make(map[int]*monkey)

	for i, line := range lines {
		monkey_number := i / 7
		m, found := monkeys[monkey_number]
		if found {
			switch i % 7 {
			case 1: // starting items
				data := strings.Split(line, ":")[1]
				m.items = internal.StrSliceToIntSlice(strings.Split(strings.TrimSpace(data), ","))
			case 2: // operation
				data := strings.Split(line, "=")[1]
				if strings.Contains(data, "+") {
					a := internal.StrToInt(strings.TrimSpace(strings.Split(data, "+")[1]))
					m.operation = build_operation(a, "+")
				} else if strings.Contains(data, "*") {
					constant := strings.TrimSpace(strings.Split(data, "*")[1])
					if constant == "old" {
						m.operation = build_operation(0, "^")
					} else {
						a := internal.StrToInt(strings.TrimSpace(strings.Split(data, "*")[1]))
						m.operation = build_operation(a, "*")
					}
				} else {
					panic(data)
				}
			case 3: // test
				a := internal.StrToInt(strings.TrimSpace(strings.Split(line, "by")[1]))
				m.test = build_test(a)
			case 4: // true monkey
				a := internal.StrToInt(strings.TrimSpace(strings.Split(line, "monkey")[1]))
				m.true_monkey = a
			case 5: // false monkey
				a := internal.StrToInt(strings.TrimSpace(strings.Split(line, "monkey")[1]))
				m.false_monkey = a
			case 6:
			default:
				panic(line)
			}

		} else {
			monkeys[monkey_number] = &monkey{
				items:         nil,
				operation:     nil,
				test:          nil,
				true_monkey:   0,
				total_inspect: 0,
			}
		}
	}

	return monkeys
}

func (input day11) part_one() int {

	monkeys := read_input_into_monkeys(input.lines)

	for round := 0; round < 20; round++ {
		for i := 0; i < len(monkeys); i++ {
			monkey := monkeys[i]
			for _, item := range monkey.items {
				worry_level := monkey.operation(item) / 3
				if monkey.test(worry_level) {
					monkeys[monkey.true_monkey].items = append(monkeys[monkey.true_monkey].items, worry_level)
				} else {
					monkeys[monkey.false_monkey].items = append(monkeys[monkey.false_monkey].items, worry_level)
				}
			}
			monkey.total_inspect = monkey.total_inspect + len(monkey.items)
			monkey.items = []int{}
		}
	}

	monkey_inspect_count := []int{}
	for i := 0; i < len(monkeys); i++ {
		monkey_inspect_count = append(monkey_inspect_count, monkeys[i].total_inspect)
	}

	sort.Sort(sort.Reverse(sort.IntSlice(monkey_inspect_count)))
	return monkey_inspect_count[0] * monkey_inspect_count[1]
}

func (input day11) part_two() int {
	monkeys := read_input_into_monkeys(input.lines)

	for round := 0; round < 10000; round++ {
		fmt.Println(round)
		for i := 0; i < len(monkeys); i++ {
			monkey := monkeys[i]
			for _, item := range monkey.items {
				worry_level := monkey.operation(item)
				if worry_level > 9699690 {
					worry_level = worry_level % 9699690
				}
				if monkey.test(worry_level) {
					monkeys[monkey.true_monkey].items = append(monkeys[monkey.true_monkey].items, worry_level)
				} else {
					monkeys[monkey.false_monkey].items = append(monkeys[monkey.false_monkey].items, worry_level)
				}
			}
			monkey.total_inspect = monkey.total_inspect + len(monkey.items)
			monkey.items = []int{}
		}
	}

	monkey_inspect_count := []int{}
	for i := 0; i < len(monkeys); i++ {
		monkey_inspect_count = append(monkey_inspect_count, monkeys[i].total_inspect)
	}

	sort.Sort(sort.Reverse(sort.IntSlice(monkey_inspect_count)))
	return monkey_inspect_count[0] * monkey_inspect_count[1]
}


Support tests. Pretty self explanatory.

Also, this is pretty tiring, I may continue tweak out future tests at a future date but not tomorrow.

Tests for day 12

package problems

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func Test_Day12(t *testing.T) {
	test_cases := []struct {
		input           []string
		part_one_assert int
		part_two_assert int
	}{
		{
			input: []string{
				"Sabqponm",
				"abcryxxl",
				"accszExk",
				"acctuvwj",
				"abdefghi",
			},
			part_one_assert: 31,
			part_two_assert: 29,
		},
	}

	for _, test := range test_cases {
		in := day12{
			lines: test.input,
		}
		assert.Equal(t, test.part_one_assert, in.part_one())
		assert.Equal(t, test.part_two_assert, in.part_two())
	}
}

tests for day 13

package problems

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func Test_Day13(t *testing.T) {
	test_cases := []struct {
		input           []string
		part_one_assert int
		part_two_assert int
	}{
		{
			input: []string{
				"[1,1,3,1,1]",
				"[1,1,5,1,1]",
				"",
				"[[1],[2,3,4]]",
				"[[1],4]",
				"",
				"[9]",
				"[[8,7,6]]",
				"",
				"[[4,4],4,4]",
				"[[4,4],4,4,4]",
				"",
				"[7,7,7,7]",
				"[7,7,7]",
				"",
				"[]",
				"[3]",
				"",
				"[[[]]]",
				"[[]]",
				"",
				"[1,[2,[3,[4,[5,6,7]]]],8,9]",
				"[1,[2,[3,[4,[5,6,0]]]],8,9]",
			},
			part_one_assert: 13,
			part_two_assert: 140,
		},
	}

	for _, test := range test_cases {
		in := day13{
			lines: test.input,
		}
		assert.Equal(t, test.part_one_assert, in.part_one())
		assert.Equal(t, test.part_two_assert, in.part_two())
	}
}

tests for day 14

package problems

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func Test_Day14(t *testing.T) {
	test_cases := []struct {
		input           []string
		part_one_assert int
		part_two_assert int
	}{
		{
			input: []string{
				"498,4 -> 498,6 -> 496,6",
				"503,4 -> 502,4 -> 502,9 -> 494,9",
			},
			part_one_assert: 24,
			part_two_assert: 93,
		},
	}

	for _, test := range test_cases {
		in := day14{
			lines: test.input,
		}
		assert.Equal(t, test.part_one_assert, in.part_one())
		assert.Equal(t, test.part_two_assert, in.part_two())
	}
}

tests for day 15

package problems

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func Test_Day15(t *testing.T) {
	test_cases := []struct {
		input           []string
		part_one_assert int
		part_two_assert int
	}{
		{
			input: []string{
				"Sensor at x=2, y=18: closest beacon is at x=-2, y=15",
				"Sensor at x=9, y=16: closest beacon is at x=10, y=16",
				"Sensor at x=13, y=2: closest beacon is at x=15, y=3",
				"Sensor at x=12, y=14: closest beacon is at x=10, y=16",
				"Sensor at x=10, y=20: closest beacon is at x=10, y=16",
				"Sensor at x=14, y=17: closest beacon is at x=10, y=16",
				"Sensor at x=8, y=7: closest beacon is at x=2, y=10",
				"Sensor at x=2, y=0: closest beacon is at x=2, y=10",
				"Sensor at x=0, y=11: closest beacon is at x=2, y=10",
				"Sensor at x=20, y=14: closest beacon is at x=25, y=17",
				"Sensor at x=17, y=20: closest beacon is at x=21, y=22",
				"Sensor at x=16, y=7: closest beacon is at x=15, y=3",
				"Sensor at x=14, y=3: closest beacon is at x=15, y=3",
				"Sensor at x=20, y=1: closest beacon is at x=15, y=3",
			},
			part_one_assert: 26,
			part_two_assert: 56000011,
		},
	}

	t.Setenv("ENV", "test")

	for _, test := range test_cases {
		in := day15{
			lines: test.input,
		}

		assert.Equal(t, test.part_one_assert, in.part_one())
		assert.Equal(t, test.part_two_assert, in.part_two())
	}
}

There's a couple of 'needlessly' cool things I did for advent. The entire project is somewhat production-ized. There's a makefile, tests run in github ci. With the command line, you can generate files for code needed to run, you can run the code against problem input, you can run against tests.

package main

import (
	"flag"
	"fmt"

	"github.com/xxxx/advent/internal"
	"github.com/xxxx/advent/problems"
)

func main() {

	day := flag.Int("day", 1, "day value, default 1")
	part := flag.Int("part", 1, "a part value, default 1")
	generate := flag.Bool("generate", false, "set as true to generate dayxx.go, dayxx.in, dayxx_test.go files, default false")
	flag.Parse()

	if *generate {
		internal.GenerateFiles(*day)
	} else {
		answer, _ := internal.Call(problems.Dailies, internal.GetFunc(*day), *part, "problems/"+internal.GetFile(*day))
		fmt.Println(answer[0])
	}
}

code generation:

package internal

import (
	"fmt"
	"os"
	"text/template"
)

func generate_go(day_int int) {
	day := GetDayString(day_int)
	vars := make(map[string]interface{})
	vars["day"] = day

	go_file := fmt.Sprintf("problems/day%s.go", day)
	go_template, err := template.ParseFiles("templates/go.tmpl")
	if err != nil {
		panic(err)
	}

	file, err := os.Create(go_file)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	go_template.Execute(file, vars)
}

func generate_in(day_int int) {
	day := GetDayString(day_int)
	go_file := fmt.Sprintf("problems/day%s.in", day)
	go_template, err := template.ParseFiles("templates/in.tmpl")
	if err != nil {
		panic(err)
	}

	file, err := os.Create(go_file)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	go_template.Execute(file, nil)
}

func generate_test(day_int int) {
	day := GetDayString(day_int)
	vars := make(map[string]interface{})
	vars["day"] = day

	go_file := fmt.Sprintf("problems/day%s_test.go", day)
	go_template, err := template.ParseFiles("templates/test.tmpl")
	if err != nil {
		panic(err)
	}

	file, err := os.Create(go_file)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	go_template.Execute(file, vars)
}

func GenerateFiles(day_int int) {
	generate_go(day_int)
	generate_in(day_int)
	generate_test(day_int)
}

2022 advent day 10

Problem is basically keeping track of a running sum.

package problems

import (
	"fmt"
	"strings"

	"github.com/sooflee/advent/internal"
)

type day10 struct {
	lines []string
}

func Day10(part int, file string) int {

	in := day10{
		lines: internal.Read(file),
	}

	switch part {
	case 1:
		return in.part_one()
	case 2:
		return in.part_two()
	default:
		return 0
	}

}

func update_signal_strength(signal_strength *int, cycle_number int, curr_X int) {
	if cycle_number%40 == 20 {
		curr_strength := curr_X * cycle_number
		*signal_strength = *signal_strength + curr_strength
	}
}

func (input day10) part_one() int {
	curr_X := 1
	cycle_number := 0
	signal_strength := new(int)
	*signal_strength = 0

	for _, line := range input.lines {

		if line == "noop" {
			cycle_number++
			update_signal_strength(signal_strength, cycle_number, curr_X)

		} else {
			cycle_number++
			update_signal_strength(signal_strength, cycle_number, curr_X)

			cycle_number++
			update_signal_strength(signal_strength, cycle_number, curr_X)

			parsed := strings.Split(line, " ")
			curr_X = curr_X + internal.StrToInt(parsed[1])
		}
	}
	return *signal_strength
}

func mark_output(output *[240]string, curr_X int, cycle_number int) *[240]string {
	if cycle_number > 239 || cycle_number < 0 {
		return output
	}
	if cycle_number%40 == curr_X-1 || cycle_number%40 == curr_X || cycle_number%40 == curr_X+1 {
		output[cycle_number] = "#"
	} else {
		output[cycle_number] = "."
	}
	return output
}

func print_output(output *[240]string) {
	for i := 0; i < 6; i++ {
		fmt.Println(output[i*40 : (i+1)*40-1])
	}
}

func (input day10) part_two() int {
	curr_X := 1
	cycle_number := 0
	output := new([240]string)
	curr_X_arr := [240]int{}

	for _, line := range input.lines {

		if line == "noop" {
			cycle_number++
			curr_X_arr[cycle_number-1] = curr_X

		} else {
			cycle_number++
			curr_X_arr[cycle_number-1] = curr_X

			cycle_number++
			curr_X_arr[cycle_number-1] = curr_X

			parsed := strings.Split(line, " ")
			curr_X = curr_X + internal.StrToInt(parsed[1])
		}
	}

	for i, curr_X_val := range curr_X_arr {
		output = mark_output(output, curr_X_val, i)
	}

	print_output(output)
	return 0
}

advent day 14

Kind of cool because running the code you can visualize dripping sand across an obstacle course.

package problems

import (
	"fmt"
	"strings"

	"github.com/sooflee/advent/internal"
)

type day14 struct {
	lines []string
}

func Day14(part int, file string) int {

	in := day14{
		lines: internal.Read(file),
	}

	switch part {
	case 1:
		return in.part_one()
	case 2:
		return in.part_two()
	default:
		return 0
	}

}

func create_cavern(lines []string, part2 bool) ([][]string, int, int) {

	sequences := [][]coordinate{}
	max_x := 0
	max_y := 0

	for _, line := range lines {
		sequence := []coordinate{}
		for _, coordinate_str := range strings.Split(line, "->") {
			coordinates := strings.Split(coordinate_str, ",")
			x := internal.StrToInt(coordinates[0])
			y := internal.StrToInt(coordinates[1])
			sequence = append(sequence, coordinate{x, y})

			if x > max_x {
				max_x = x
			}

			if y > max_y {
				max_y = y
			}
		}
		sequences = append(sequences, sequence)
	}

	if part2 {
		max_y = max_y + 2
		max_x = max_x + max_x
	}

	cavern := make([][]string, max_y+1)
	for i := range cavern {
		cavern_row := make([]string, max_x+1)
		for j := range cavern_row {
			cavern_row[j] = "."
		}
		cavern[i] = cavern_row
	}

	if part2 {
		cavern_row := make([]string, max_x+1)
		for j := range cavern_row {
			cavern_row[j] = "#"
		}
		cavern[max_y] = cavern_row
	}

	for _, sequence := range sequences {
		last_c := coordinate{}
		for i, c := range sequence {
			cavern[c.y][c.x] = "#"
			if i != 0 {
				if last_c.x < c.x {
					for x := last_c.x; x <= c.x; x++ {
						cavern[c.y][x] = "#"
					}
				} else if last_c.x > c.x {
					for x := last_c.x; x >= c.x; x-- {
						cavern[c.y][x] = "#"
					}
				} else if last_c.y < c.y {
					for y := last_c.y; y <= c.y; y++ {
						cavern[y][c.x] = "#"
					}
				} else if last_c.y > c.y {
					for y := last_c.y; y >= c.y; y-- {
						cavern[y][c.x] = "#"
					}
				}
			}
			last_c = coordinate{c.x, c.y}
		}
	}

	return cavern, max_x, max_y
}

func draw_cavern(cavern [][]string) {
	for i, cavern_row := range cavern {
		fmt.Println(i, cavern_row)
	}
}

func (input day14) part_one() int {

	cavern, max_x, max_y := create_cavern(input.lines, false)

	sand_count := 0

	for {
		sand_count++
		sand_x := 500
		sand_y := 0

		for {

			if sand_y == max_y || sand_x == max_x {
				break
			}

			if cavern[sand_y+1][sand_x] == "." {
				sand_y++
			} else if cavern[sand_y+1][sand_x-1] == "." {
				sand_x--
				sand_y++
			} else if cavern[sand_y+1][sand_x+1] == "." {
				sand_x++
				sand_y++
			} else {
				break
			}
		}

		if sand_y >= max_y || sand_x >= max_x {
			break
		}

		draw_cavern(cavern)

		if sand_y >= max_y {
			break
		}
		cavern[sand_y][sand_x] = "o"
	}

	return sand_count - 1
}

func (input day14) part_two() int {
	cavern, max_x, max_y := create_cavern(input.lines, true)

	sand_count := 0

	for {
		sand_count++
		sand_x := 500
		sand_y := 0
		not_move := true

		for {

			if sand_y == max_y || sand_x == max_x {
				break
			}

			if cavern[sand_y+1][sand_x] == "." {
				sand_y++
				not_move = false
			} else if cavern[sand_y+1][sand_x-1] == "." {
				sand_x--
				sand_y++
				not_move = false
			} else if cavern[sand_y+1][sand_x+1] == "." {
				sand_x++
				sand_y++
				not_move = false
			} else {
				break
			}
		}

		// if sand_count%50 == 0 {
		// 	draw_cavern(cavern)
		// }

		if not_move {
			break
		}

		if sand_y >= max_y {
			break
		}
		cavern[sand_y][sand_x] = "o"
	}

	return sand_count
}

2022 advent day 13

package problems

import (
	"encoding/json"
	"fmt"
	"sort"

	"github.com/xxxx/advent/internal"
)

type day13 struct {
	lines []string
}

func Day13(part int, file string) int {

	in := day13{
		lines: internal.Read(file),
	}

	switch part {
	case 1:
		return in.part_one()
	case 2:
		return in.part_two()
	default:
		return 0
	}

}

type OrderedResult int

const (
	Unordered OrderedResult = iota
	Equal
	Ordered
)

func is_ordered(left []interface{}, right []interface{}) OrderedResult {

	for i := 0; i < len(left); i++ {
		if i > len(right)-1 {
			return Unordered
		}

		left_int, is_left_int := left[i].(float64)
		right_int, is_right_int := right[i].(float64)

		left_list, _ := left[i].([]interface{})
		right_list, _ := right[i].([]interface{})

		if is_left_int && is_right_int {
			if left_int != right_int {
				if left_int < right_int {
					return Ordered
				}
				if left_int > right_int {
					return Unordered
				}
			}
		} else if is_left_int {
			is_order := is_ordered([]interface{}{left_int}, right_list)
			if is_order == Equal {
				continue
			} else {
				return is_order
			}
		} else if is_right_int {
			is_order := is_ordered(left_list, []interface{}{right_int})
			if is_order == Equal {
				continue
			} else {
				return is_order
			}
		} else {
			is_order := is_ordered(left_list, right_list)
			if is_order == Equal {
				continue
			} else {
				return is_order
			}
		}
	}

	if len(left) == len(right) {
		return Equal
	}
	return Ordered
}

func (input day13) part_one() int {
	total_count := 0
	for i := 0; i <= len(input.lines)/3; i++ {
		left := []interface{}{}
		right := []interface{}{}
		json.Unmarshal([]byte(input.lines[i*3]), &left)
		json.Unmarshal([]byte(input.lines[i*3+1]), &right)
		order := is_ordered(left, right)
		if order == Equal || order == Ordered {
			total_count = total_count + i + 1
		}
	}
	return total_count
}

func (input day13) part_two() int {

	all_rows := [][]interface{}{
		{[]interface{}{float64(2)}},
		{[]interface{}{float64(6)}},
	}

	for i := 0; i <= len(input.lines)/3; i++ {
		left := []interface{}{}
		right := []interface{}{}
		json.Unmarshal([]byte(input.lines[i*3]), &left)
		json.Unmarshal([]byte(input.lines[i*3+1]), &right)
		all_rows = append(all_rows, left, right)
	}

	// https://www.geeksforgeeks.org/how-to-sort-a-slice-in-golang/
	sort.Slice(all_rows, func(i, j int) bool {
		left, right := all_rows[i], all_rows[j]
		order := is_ordered(left, right)
		if order == Equal || order == Ordered {
			return true
		}
		return false
	})

	total := 1
	for i, packet := range all_rows {
		if fmt.Sprint(packet) == "[[2]]" || fmt.Sprint(packet) == "[[6]]" {
			total = total * (i + 1)
		}
	}

	return total
}

My goal for 2024 is to be prolific not meticulous. To the summit we go! I may shift this to more system design posts later on, we will see.

As of right now, these posts will mainly be code snippets of coding problems with comments. Treat them as photos with captions. Some moment being captured to ascertain my daily check-in.

Below code for 2022 advent day 12. It's a fitting problem because it's about using bfs to get to the summit. Written in golang.

package problems

import (
	"github.com/gammazero/deque"
	"github.com/xxxxxxx/advent/internal"
)

type day12 struct {
	lines []string
}

func Day12(part int, file string) int {

	in := day12{
		lines: internal.Read(file),
	}

	switch part {
	case 1:
		return in.part_one()
	case 2:
		return in.part_two()
	default:
		return 0
	}

}

func read_graph(lines []string) [][]int {

	graph := make([][]int, len(lines))

	for i, line := range lines {
		graph[i] = []int{}
		for _, character := range line {
			height := int(character) - 97
			if height == -14 { // S
				height = 0
			}
			if height == -28 {
				height = 25
			}
			graph[i] = append(graph[i], height)
		}
	}

	return graph
}

func get_start_end(lines []string) ([2]int, [2]int) {

	start := [2]int{}
	end := [2]int{}

	for i, line := range lines {
		for j, char := range line {
			if char == 'S' {
				start = [2]int{i, j}
			}
			if char == 'E' {
				end = [2]int{i, j}
			}
		}
	}

	return start, end

}

func (input day12) part_one() int {
	graph := read_graph(input.lines)
	start, end := get_start_end(input.lines)
	rows := len(graph)
	columns := len(graph[0])
	directions := [4][2]int{
		{1, 0}, {-1, 0}, {0, 1}, {0, -1},
	}

	visited := make(map[[2]int]bool)
	visited[start] = true
	var q deque.Deque[[3]int]
	q.PushBack([3]int{start[0], start[1], 0})

	for q.Len() != 0 {
		curr := q.PopFront()
		if curr[0] == end[0] && curr[1] == end[1] {
			return curr[2]
		}

		for _, direction := range directions {
			next := [2]int{}
			next[0], next[1] = curr[0]+direction[0], curr[1]+direction[1]
			_, curr_visited := visited[next]

			if next[0] >= 0 && next[0] < rows &&
				next[1] >= 0 && next[1] < columns &&
				!curr_visited && graph[next[0]][next[1]] <= graph[curr[0]][curr[1]]+1 {
				q.PushBack([3]int{next[0], next[1], curr[2] + 1})
				visited[next] = true
			}
		}

	}

	return 0
}

func (input day12) part_two() int {
	graph := read_graph(input.lines)
	_, start := get_start_end(input.lines)
	rows := len(graph)
	columns := len(graph[0])
	directions := [4][2]int{
		{1, 0}, {-1, 0}, {0, 1}, {0, -1},
	}

	visited := make(map[[2]int]bool)
	visited[start] = true
	var q deque.Deque[[3]int]
	q.PushBack([3]int{start[0], start[1], 0})

	for q.Len() != 0 {
		curr := q.PopFront()
		if graph[curr[0]][curr[1]] == 0 {
			return curr[2]
		}

		for _, direction := range directions {
			next := [2]int{}
			next[0], next[1] = curr[0]+direction[0], curr[1]+direction[1]
			_, curr_visited := visited[next]

			if next[0] >= 0 && next[0] < rows &&
				next[1] >= 0 && next[1] < columns &&
				!curr_visited &&
				graph[next[0]][next[1]] >= graph[curr[0]][curr[1]]-1 {
				q.PushBack([3]int{next[0], next[1], curr[2] + 1})
				visited[next] = true
			}
		}

	}

	return 0
}