Compare commits
2 Commits
a529516bab
...
d730d3c444
| Author | SHA1 | Date | |
|---|---|---|---|
| d730d3c444 | |||
| 759b9c9544 |
@@ -52,14 +52,54 @@ func Part1(input string) int {
|
|||||||
return dist
|
return dist
|
||||||
}
|
}
|
||||||
func Part2(input string) int {
|
func Part2(input string) int {
|
||||||
|
const saves int = 100
|
||||||
|
count := 0
|
||||||
maze := Maze{}.Parse(input)
|
maze := Maze{}.Parse(input)
|
||||||
fmt.Println(maze)
|
// fmt.Println(maze)
|
||||||
data := inputGraph(*maze)
|
data := inputGraph(*maze)
|
||||||
graph := dijkstra.CreateGraph(data)
|
graph := dijkstra.CreateGraph(data)
|
||||||
_, count := dijkstra.GetShortestPath(data.From, data.To, graph)
|
path, dist := dijkstra.GetShortestPath(data.From, data.To, graph)
|
||||||
|
cost := make(map[Vec]int)
|
||||||
|
cheats := []Cheat{}
|
||||||
|
|
||||||
|
for i, p := range path {
|
||||||
|
cost[Vec{p.X, p.Y}] = i
|
||||||
|
}
|
||||||
|
cheat_data := cheatGraph(*maze)
|
||||||
|
|
||||||
|
for _, s := range path[:len(path)-saves] {
|
||||||
|
fmt.Println("Checking start:", s)
|
||||||
|
for _, e := range path[saves:] {
|
||||||
|
fmt.Println("\tChecking end", e)
|
||||||
|
cheat_data_1 := cheatGraphAdd(maze, cheat_data, s)
|
||||||
|
cheat_data_2 := cheatGraphAdd(maze, cheat_data_1, e)
|
||||||
|
cheat_graph := dijkstra.CreateGraph(cheat_data_2)
|
||||||
|
_, cheat_dist := dijkstra.GetShortestPath(dijkstra.Point{X: s.X, Y: s.Y}, dijkstra.Point{X: e.X, Y: e.Y}, cheat_graph)
|
||||||
|
fmt.Println("\t\tcheat distance:", cheat_dist)
|
||||||
|
if cheat_dist <= 20 {
|
||||||
|
cheat := Cheat{start: Vec{s.X, s.Y}, end: Vec{e.X, e.Y}, cost: cost[Vec{s.X, s.Y}] + cheat_dist + dist - cost[Vec{e.X, e.Y}]}
|
||||||
|
fmt.Println("\t\tSaving cheat:", cheat)
|
||||||
|
cheats = append(cheats, cheat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, cheat := range cheats {
|
||||||
|
save := dist - cheat.cost
|
||||||
|
// fmt.Println("[", i, "]", "save", save)
|
||||||
|
if save >= saves {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func abs(in int) int {
|
||||||
|
if in < 0 {
|
||||||
|
return in * -1
|
||||||
|
}
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
|
||||||
func inputGraph(maze Maze) dijkstra.InputGraph {
|
func inputGraph(maze Maze) dijkstra.InputGraph {
|
||||||
data := dijkstra.InputGraph{}
|
data := dijkstra.InputGraph{}
|
||||||
data.From = dijkstra.Point{X: maze.start.x, Y: maze.start.y}
|
data.From = dijkstra.Point{X: maze.start.x, Y: maze.start.y}
|
||||||
@@ -89,6 +129,58 @@ func inputGraph(maze Maze) dijkstra.InputGraph {
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cheatGraph(maze Maze) dijkstra.InputGraph {
|
||||||
|
data := dijkstra.InputGraph{}
|
||||||
|
for y := 0; y < maze.height; y++ {
|
||||||
|
for x := 0; x < maze.width; x++ {
|
||||||
|
if maze.grid.Get(x, y) == CORRIDOR {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, dir := range DIRECTIONS {
|
||||||
|
nx, ny := x+dir.x, y+dir.y
|
||||||
|
if nx < 0 || ny < 0 || nx >= maze.width || ny >= maze.height {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if maze.grid.Get(nx, ny) == CORRIDOR {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data.Graph = append(data.Graph, dijkstra.InputData{
|
||||||
|
Source: dijkstra.Point{X: x, Y: y},
|
||||||
|
Destination: dijkstra.Point{X: nx, Y: ny},
|
||||||
|
Weight: 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func cheatGraphAdd(maze *Maze, in dijkstra.InputGraph, s dijkstra.Point) dijkstra.InputGraph {
|
||||||
|
x := s.X
|
||||||
|
y := s.Y
|
||||||
|
out := dijkstra.InputGraph{}
|
||||||
|
out.From = in.From
|
||||||
|
out.To = in.To
|
||||||
|
out.Graph = append([]dijkstra.InputData{}, in.Graph...)
|
||||||
|
|
||||||
|
for _, dir := range DIRECTIONS {
|
||||||
|
nx, ny := x+dir.x, y+dir.y
|
||||||
|
if nx < 0 || ny < 0 || nx >= maze.width || ny >= maze.height {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if maze.grid.Get(nx, ny) == CORRIDOR {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out.Graph = append(out.Graph, dijkstra.InputData{
|
||||||
|
Source: dijkstra.Point{X: x, Y: y},
|
||||||
|
Destination: dijkstra.Point{X: nx, Y: ny},
|
||||||
|
Weight: 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
func (m Maze) Parse(input string) *Maze {
|
func (m Maze) Parse(input string) *Maze {
|
||||||
m.grid = inputs.ToGrid2D(input, "\n", "", '?', func(c string) Cell { return Cell(c[0]) })
|
m.grid = inputs.ToGrid2D(input, "\n", "", '?', func(c string) Cell { return Cell(c[0]) })
|
||||||
m.height, m.width = m.grid.SizeY(), m.grid.SizeX()
|
m.height, m.width = m.grid.SizeY(), m.grid.SizeX()
|
||||||
|
|||||||
@@ -26,6 +26,20 @@ func TestPart1(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPart2(t *testing.T) {
|
func TestPart2(t *testing.T) {
|
||||||
r := Part2("")
|
r := Part2(`###############
|
||||||
|
#...#...#.....#
|
||||||
|
#.#.#.#.#.###.#
|
||||||
|
#S#...#.#.#...#
|
||||||
|
#######.#.#.###
|
||||||
|
#######.#.#...#
|
||||||
|
#######.#.###.#
|
||||||
|
###..E#...#...#
|
||||||
|
###.#######.###
|
||||||
|
#...###...#...#
|
||||||
|
#.#####.#.###.#
|
||||||
|
#.#...#.#.#...#
|
||||||
|
#.#.#.#.#.#.###
|
||||||
|
#...#...#...###
|
||||||
|
###############`)
|
||||||
require.Equal(t, 0, r)
|
require.Equal(t, 0, r)
|
||||||
}
|
}
|
||||||
|
|||||||
181
2024/go/day21/day21.go
Normal file
181
2024/go/day21/day21.go
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
package day21
|
||||||
|
|
||||||
|
import (
|
||||||
|
"adventofcode2024/utils"
|
||||||
|
"adventofcode2024/utils/dijkstra"
|
||||||
|
"adventofcode2024/utils/memo"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Pair struct {
|
||||||
|
s dijkstra.Point
|
||||||
|
d dijkstra.Point
|
||||||
|
}
|
||||||
|
|
||||||
|
type Path struct {
|
||||||
|
path []dijkstra.Point
|
||||||
|
path_str string
|
||||||
|
cost int
|
||||||
|
}
|
||||||
|
|
||||||
|
type State struct {
|
||||||
|
code string
|
||||||
|
depth int
|
||||||
|
isNumericPad bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var numericPad = map[dijkstra.Point]string{
|
||||||
|
{X: 0, Y: 0}: "7", {X: 1, Y: 0}: "8", {X: 2, Y: 0}: "9",
|
||||||
|
{X: 0, Y: 1}: "4", {X: 1, Y: 1}: "5", {X: 2, Y: 1}: "6",
|
||||||
|
{X: 0, Y: 2}: "1", {X: 1, Y: 2}: "2", {X: 2, Y: 2}: "3",
|
||||||
|
{X: 1, Y: 3}: "0", {X: 2, Y: 3}: "A",
|
||||||
|
}
|
||||||
|
|
||||||
|
var directionPad = map[dijkstra.Point]string{
|
||||||
|
{X: 1, Y: 0}: "^", {X: 2, Y: 0}: "A",
|
||||||
|
{X: 0, Y: 1}: "<", {X: 1, Y: 1}: "v", {X: 2, Y: 1}: ">",
|
||||||
|
}
|
||||||
|
|
||||||
|
var directions = []dijkstra.Point{{X: 0, Y: 1}, {X: 0, Y: -1}, {X: 1, Y: 0}, {X: -1, Y: 0}}
|
||||||
|
|
||||||
|
var lookup_np = get_paths(numericPad)
|
||||||
|
var lookup_dp = get_paths(directionPad)
|
||||||
|
|
||||||
|
var m *memo.Memo
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m = memo.New(get_shortest_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Part1(input string) int {
|
||||||
|
codes := strings.Split(input, "\n")
|
||||||
|
cost := 0
|
||||||
|
for _, code := range codes {
|
||||||
|
initialState := State{
|
||||||
|
code: code,
|
||||||
|
depth: 2,
|
||||||
|
isNumericPad: true,
|
||||||
|
}
|
||||||
|
result := m.Get(initialState).(int)
|
||||||
|
cost += result * utils.MustAtoi(code[:len(code)-1])
|
||||||
|
}
|
||||||
|
return cost
|
||||||
|
}
|
||||||
|
|
||||||
|
func Part2(input string) int {
|
||||||
|
codes := strings.Split(input, "\n")
|
||||||
|
cost := 0
|
||||||
|
for _, code := range codes {
|
||||||
|
initialState := State{
|
||||||
|
code: code,
|
||||||
|
depth: 25,
|
||||||
|
isNumericPad: true,
|
||||||
|
}
|
||||||
|
result := m.Get(initialState).(int)
|
||||||
|
cost += result * utils.MustAtoi(code[:len(code)-1])
|
||||||
|
}
|
||||||
|
return cost
|
||||||
|
}
|
||||||
|
|
||||||
|
func get_paths(in map[dijkstra.Point]string) map[Pair][]Path {
|
||||||
|
lookup := make(map[Pair][]Path)
|
||||||
|
data := dijkstra.InputGraph{}
|
||||||
|
for p := range in {
|
||||||
|
for _, dir := range directions {
|
||||||
|
np := dijkstra.Point{X: p.X + dir.X, Y: p.Y + dir.Y}
|
||||||
|
if in[np] != "" {
|
||||||
|
data.Graph = append(data.Graph, dijkstra.InputData{
|
||||||
|
Source: p,
|
||||||
|
Destination: np,
|
||||||
|
Weight: 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
graph := dijkstra.CreateGraph(data)
|
||||||
|
for s := range in {
|
||||||
|
for d := range in {
|
||||||
|
paths, cost := dijkstra.GetAllShortestPaths(s, d, graph)
|
||||||
|
|
||||||
|
for _, path := range paths {
|
||||||
|
path_str := ""
|
||||||
|
for x := 1; x < len(path); x++ {
|
||||||
|
f := path[x-1]
|
||||||
|
t := path[x]
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case f.X == t.X && f.Y < t.Y:
|
||||||
|
// Moving verticallY down
|
||||||
|
path_str += "v"
|
||||||
|
case f.X == t.X && f.Y > t.Y:
|
||||||
|
// Moving verticallY up
|
||||||
|
path_str += "^"
|
||||||
|
case f.Y == t.Y && f.X < t.X:
|
||||||
|
// Moving horizontallY right
|
||||||
|
path_str += ">"
|
||||||
|
case f.Y == t.Y && f.X > t.X:
|
||||||
|
// Moving horizontally left
|
||||||
|
path_str += "<"
|
||||||
|
default:
|
||||||
|
// No matching case or invalid input
|
||||||
|
fmt.Println("Invalid direction")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
lookup[Pair{s, d}] = append(lookup[Pair{s, d}], Path{path, path_str, cost})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lookup
|
||||||
|
}
|
||||||
|
|
||||||
|
func find_point(in string, lookup map[dijkstra.Point]string) dijkstra.Point {
|
||||||
|
for k, v := range lookup {
|
||||||
|
if v == in {
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dijkstra.Point{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func get_shortest_path(key interface{}) interface{} {
|
||||||
|
state := key.(State)
|
||||||
|
|
||||||
|
if state.depth < 0 {
|
||||||
|
return len(state.code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// (Optional) If you need to modify the state, work on a copy.
|
||||||
|
newState := state
|
||||||
|
newState.code = "A" + state.code
|
||||||
|
|
||||||
|
cost := 0
|
||||||
|
for x := 0; x<len(newState.code)-1; x++ {
|
||||||
|
pps := shortest_paths(string(newState.code[x]), string(newState.code[x+1]), newState.isNumericPad)
|
||||||
|
min := math.MaxInt // Start with a very high number not just 65535
|
||||||
|
for _, pp := range pps {
|
||||||
|
nextState := State{
|
||||||
|
code: pp.path_str + "A",
|
||||||
|
depth: newState.depth - 1,
|
||||||
|
isNumericPad: false,
|
||||||
|
}
|
||||||
|
mm := m.Get(nextState).(int)
|
||||||
|
if mm < min {
|
||||||
|
min = mm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cost += min
|
||||||
|
}
|
||||||
|
return cost
|
||||||
|
}
|
||||||
|
|
||||||
|
func shortest_paths(s, d string, isNumericPad bool) []Path {
|
||||||
|
if isNumericPad {
|
||||||
|
return lookup_np[Pair{s: find_point(s, numericPad), d: find_point(d, numericPad)}]
|
||||||
|
} else {
|
||||||
|
return lookup_dp[Pair{s: find_point(s, directionPad), d: find_point(d, directionPad)}]
|
||||||
|
}
|
||||||
|
}
|
||||||
25
2024/go/day21/day21_test.go
Normal file
25
2024/go/day21/day21_test.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package day21
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPart1(t *testing.T) {
|
||||||
|
r := Part1(`029A
|
||||||
|
980A
|
||||||
|
179A
|
||||||
|
456A
|
||||||
|
379A`)
|
||||||
|
require.Equal(t, 126384, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPart2(t *testing.T) {
|
||||||
|
r := Part2(`029A
|
||||||
|
980A
|
||||||
|
179A
|
||||||
|
456A
|
||||||
|
379A`)
|
||||||
|
require.Equal(t, 126384, r)
|
||||||
|
}
|
||||||
5
2024/go/day21/input.txt
Normal file
5
2024/go/day21/input.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
480A
|
||||||
|
965A
|
||||||
|
140A
|
||||||
|
341A
|
||||||
|
285A
|
||||||
9
2024/go/day21/tt
Normal file
9
2024/go/day21/tt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
v<A <A A >>^A v<<A>A<A>>^AvAA<^A>AvA<^A>vA^A
|
||||||
|
<vA <A A >>^A vA A <^A >A <v<A>>^AvA^A<vA>^A<v<A>^A>AAvA^A<v<A>A>^AAAvA<^A>A
|
||||||
|
v < < A > > ^ A <A>AvA<^AA>A<vAAA>^A
|
||||||
|
< A ^A>^^AvvvA
|
||||||
|
0 29A
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BIN
2024/go/day22/__debug_bin1539271134
Executable file
BIN
2024/go/day22/__debug_bin1539271134
Executable file
Binary file not shown.
91
2024/go/day22/day22.go
Normal file
91
2024/go/day22/day22.go
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
package day22
|
||||||
|
|
||||||
|
import (
|
||||||
|
"adventofcode2024/utils"
|
||||||
|
rb "adventofcode2024/utils/ringbuffer"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Part1(input string) int {
|
||||||
|
var secret uint
|
||||||
|
total := 0
|
||||||
|
secrets := strings.Split(input, "\n")
|
||||||
|
for _, secret_str := range secrets {
|
||||||
|
secret = uint(utils.MustAtoi(secret_str))
|
||||||
|
for i := 0; i < 2000; i++ {
|
||||||
|
secret ^= secret * 64
|
||||||
|
secret %= 16777216
|
||||||
|
secret ^= secret / 32
|
||||||
|
secret %= 16777216
|
||||||
|
secret ^= secret * 2048
|
||||||
|
secret %= 16777216
|
||||||
|
}
|
||||||
|
total += int(secret)
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
func Part2(input string) int {
|
||||||
|
var secret uint
|
||||||
|
var banannas0, banannas1, banannas2, banannas3, banannas4 int
|
||||||
|
seq_map := make(map[string]int)
|
||||||
|
total := 0
|
||||||
|
ringBuffer := rb.NewRingBuffer[uint](5)
|
||||||
|
|
||||||
|
secrets := strings.Split(input, "\n")
|
||||||
|
for _, secret_str := range secrets {
|
||||||
|
found_map := make(map[string]bool)
|
||||||
|
secret = uint(utils.MustAtoi(secret_str))
|
||||||
|
for i := 0; i < 2000; i++ {
|
||||||
|
secret = get_next_secret(secret)
|
||||||
|
ringBuffer.Add(secret)
|
||||||
|
if ringBuffer.Len() < 5 { continue }
|
||||||
|
ring := ringBuffer.Get()
|
||||||
|
banannas0 = get_bannnas(ring[0])
|
||||||
|
banannas1 = get_bannnas(ring[1])
|
||||||
|
banannas2 = get_bannnas(ring[2])
|
||||||
|
banannas3 = get_bannnas(ring[3])
|
||||||
|
banannas4 = get_bannnas(ring[4])
|
||||||
|
map_str := diff_bannanas(banannas1, banannas0) +
|
||||||
|
diff_bannanas(banannas2, banannas1) +
|
||||||
|
diff_bannanas(banannas3, banannas2) +
|
||||||
|
diff_bannanas(banannas4, banannas3)
|
||||||
|
if _, ok := found_map[map_str]; !ok {
|
||||||
|
seq_map[map_str] += banannas4
|
||||||
|
found_map[map_str] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, v := range seq_map {
|
||||||
|
if v > total {
|
||||||
|
total = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
func get_next_secret(in uint) uint {
|
||||||
|
in ^= in * 64
|
||||||
|
in %= 16777216
|
||||||
|
in ^= in / 32
|
||||||
|
in %= 16777216
|
||||||
|
in ^= in * 2048
|
||||||
|
in %= 16777216
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
|
||||||
|
func get_bannnas(secret uint) int {
|
||||||
|
return int(secret) % 10
|
||||||
|
}
|
||||||
|
|
||||||
|
func diff_bannanas(a, b int) string {
|
||||||
|
ret := ""
|
||||||
|
diff := a - b
|
||||||
|
if diff >= 0 {
|
||||||
|
ret = "+" + strconv.Itoa(diff)
|
||||||
|
} else {
|
||||||
|
ret = strconv.Itoa(diff)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
20
2024/go/day22/day22_test.go
Normal file
20
2024/go/day22/day22_test.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package day22
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPart1(t *testing.T) {
|
||||||
|
r := Part1("1")
|
||||||
|
require.Equal(t, 8685429, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPart2(t *testing.T) {
|
||||||
|
r := Part2(`1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
2024`)
|
||||||
|
require.Equal(t, 23, r)
|
||||||
|
}
|
||||||
2154
2024/go/day22/input.txt
Normal file
2154
2024/go/day22/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
242
2024/go/day23/day23.go
Normal file
242
2024/go/day23/day23.go
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
package day23
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Lan struct {
|
||||||
|
nodes []*Node
|
||||||
|
}
|
||||||
|
|
||||||
|
type Node struct {
|
||||||
|
key string
|
||||||
|
adjacent []*Node
|
||||||
|
loops [][]*Node
|
||||||
|
}
|
||||||
|
|
||||||
|
func Part1(input string) int {
|
||||||
|
total := 0
|
||||||
|
|
||||||
|
lan := &Lan{}
|
||||||
|
|
||||||
|
pattern := `^([a-z]{2})-([a-z]{2})$`
|
||||||
|
re := regexp.MustCompile(pattern)
|
||||||
|
lines := strings.Split(input, "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
matches := re.FindAllStringSubmatch(line, -1)
|
||||||
|
for _, match := range matches {
|
||||||
|
lan.AddNode(match[1])
|
||||||
|
lan.AddNode(match[2])
|
||||||
|
lan.AddConnection(match[1], match[2])
|
||||||
|
lan.AddConnection(match[2], match[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, node := range lan.nodes {
|
||||||
|
if node.key[0] == 't' {
|
||||||
|
connections := node.adjacent
|
||||||
|
for _, connection := range connections {
|
||||||
|
c := lan.getNode(connection.key)
|
||||||
|
for _, n1 := range c.adjacent {
|
||||||
|
for _, n2 := range connections {
|
||||||
|
if n1.key == n2.key {
|
||||||
|
already_found := false
|
||||||
|
for _, loop := range node.loops {
|
||||||
|
if contains(loop, c.key) && contains(loop, n2.key) {
|
||||||
|
already_found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, loop := range c.loops {
|
||||||
|
if contains(loop, node.key) && contains(loop, n2.key) {
|
||||||
|
already_found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, loop := range n2.loops {
|
||||||
|
if contains(loop, c.key) && contains(loop, node.key) {
|
||||||
|
already_found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !already_found {
|
||||||
|
already_found = true
|
||||||
|
total++
|
||||||
|
loop := make([]*Node, 0)
|
||||||
|
loop = append(loop, node)
|
||||||
|
loop = append(loop, c)
|
||||||
|
loop = append(loop, n2)
|
||||||
|
node.loops = append(node.loops, loop)
|
||||||
|
fmt.Printf("%v,%v,%v\n", node.key, c.key, n2.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lan.Print()
|
||||||
|
t := 0
|
||||||
|
for _, node := range lan.nodes {
|
||||||
|
if node.key[0] == 't' {
|
||||||
|
t += len(node.loops)
|
||||||
|
fmt.Printf("Node: %v\n", node.key)
|
||||||
|
for _, loop := range node.loops {
|
||||||
|
for _, n := range loop {
|
||||||
|
fmt.Printf(" %v ", n.key)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Printf("Total: %d\n", t)
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
func Part2(input string) int {
|
||||||
|
total := 0
|
||||||
|
|
||||||
|
lan := &Lan{}
|
||||||
|
|
||||||
|
pattern := `^([a-z]{2})-([a-z]{2})$`
|
||||||
|
re := regexp.MustCompile(pattern)
|
||||||
|
lines := strings.Split(input, "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
matches := re.FindAllStringSubmatch(line, -1)
|
||||||
|
for _, match := range matches {
|
||||||
|
lan.AddNode(match[1])
|
||||||
|
lan.AddNode(match[2])
|
||||||
|
lan.AddConnection(match[1], match[2])
|
||||||
|
lan.AddConnection(match[2], match[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, node := range lan.nodes {
|
||||||
|
connections := node.adjacent
|
||||||
|
for _, connection := range connections {
|
||||||
|
c := lan.getNode(connection.key)
|
||||||
|
for _, n1 := range c.adjacent {
|
||||||
|
for _, n2 := range connections {
|
||||||
|
if n1.key == n2.key {
|
||||||
|
already_found := false
|
||||||
|
for _, loop := range node.loops {
|
||||||
|
if contains(loop, c.key) && contains(loop, n2.key) {
|
||||||
|
already_found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, loop := range c.loops {
|
||||||
|
if contains(loop, node.key) && contains(loop, n2.key) {
|
||||||
|
already_found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, loop := range n2.loops {
|
||||||
|
if contains(loop, c.key) && contains(loop, node.key) {
|
||||||
|
already_found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !already_found {
|
||||||
|
already_found = true
|
||||||
|
total++
|
||||||
|
loop := make([]*Node, 0)
|
||||||
|
loop = append(loop, node)
|
||||||
|
loop = append(loop, c)
|
||||||
|
loop = append(loop, n2)
|
||||||
|
node.loops = append(node.loops, loop)
|
||||||
|
fmt.Printf("%v,%v,%v\n", node.key, c.key, n2.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lan.Print()
|
||||||
|
maxLoop := 0
|
||||||
|
var maxNode *Node
|
||||||
|
for _, node := range lan.nodes {
|
||||||
|
if len(node.loops) > maxLoop {
|
||||||
|
maxLoop = len(node.loops)
|
||||||
|
maxNode = node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Printf("Max: %d\n", len(maxNode.loops))
|
||||||
|
nodeList := make([]*Node, 0)
|
||||||
|
keyList := make([]string, 0)
|
||||||
|
for _, loop := range maxNode.loops {
|
||||||
|
for _, l := range loop {
|
||||||
|
if !contains(nodeList, l.key) {
|
||||||
|
nodeList = append(nodeList, l)
|
||||||
|
keyList = append(keyList, l.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(keyList)
|
||||||
|
fmt.Println(strings.Join(keyList, ","))
|
||||||
|
return len(nodeList)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Lan) AddNode(key string) {
|
||||||
|
if !contains(g.nodes, key) {
|
||||||
|
g.nodes = append(g.nodes, &Node{key: key})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Lan) AddConnection(from, to string) {
|
||||||
|
fromNode := g.getNode(from)
|
||||||
|
toNode := g.getNode(to)
|
||||||
|
|
||||||
|
if fromNode == nil || toNode == nil {
|
||||||
|
err := fmt.Errorf("Error: Invalid edge (%v --> %v)", from, to)
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
} else if contains(fromNode.adjacent, to) {
|
||||||
|
err := fmt.Errorf("Error: Existing edge (%v --> %v)", from, to)
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
} else {
|
||||||
|
fromNode.adjacent = append(fromNode.adjacent, toNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Lan) getNode(key string) *Node {
|
||||||
|
for i, v := range g.nodes {
|
||||||
|
if v.key == key {
|
||||||
|
return g.nodes[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Lan) Print() {
|
||||||
|
for _, v := range g.nodes {
|
||||||
|
fmt.Printf("\nNode %v : ", v.key)
|
||||||
|
for _, v := range v.adjacent {
|
||||||
|
fmt.Printf(" %v ", v.key)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
for _, loop := range v.loops {
|
||||||
|
for _, v := range loop {
|
||||||
|
if v != nil {
|
||||||
|
fmt.Printf(" %v ", v.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func contains(list []*Node, key string) bool {
|
||||||
|
for _, v := range list {
|
||||||
|
if key == v.key {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
79
2024/go/day23/day23_test.go
Normal file
79
2024/go/day23/day23_test.go
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package day23
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPart1(t *testing.T) {
|
||||||
|
r := Part1(`kh-tc
|
||||||
|
qp-kh
|
||||||
|
de-cg
|
||||||
|
ka-co
|
||||||
|
yn-aq
|
||||||
|
qp-ub
|
||||||
|
cg-tb
|
||||||
|
vc-aq
|
||||||
|
tb-ka
|
||||||
|
wh-tc
|
||||||
|
yn-cg
|
||||||
|
kh-ub
|
||||||
|
ta-co
|
||||||
|
de-co
|
||||||
|
tc-td
|
||||||
|
tb-wq
|
||||||
|
wh-td
|
||||||
|
ta-ka
|
||||||
|
td-qp
|
||||||
|
aq-cg
|
||||||
|
wq-ub
|
||||||
|
ub-vc
|
||||||
|
de-ta
|
||||||
|
wq-aq
|
||||||
|
wq-vc
|
||||||
|
wh-yn
|
||||||
|
ka-de
|
||||||
|
kh-ta
|
||||||
|
co-tc
|
||||||
|
wh-qp
|
||||||
|
tb-vc
|
||||||
|
td-yn`)
|
||||||
|
require.Equal(t, 7, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPart2(t *testing.T) {
|
||||||
|
r := Part2(`kh-tc
|
||||||
|
qp-kh
|
||||||
|
de-cg
|
||||||
|
ka-co
|
||||||
|
yn-aq
|
||||||
|
qp-ub
|
||||||
|
cg-tb
|
||||||
|
vc-aq
|
||||||
|
tb-ka
|
||||||
|
wh-tc
|
||||||
|
yn-cg
|
||||||
|
kh-ub
|
||||||
|
ta-co
|
||||||
|
de-co
|
||||||
|
tc-td
|
||||||
|
tb-wq
|
||||||
|
wh-td
|
||||||
|
ta-ka
|
||||||
|
td-qp
|
||||||
|
aq-cg
|
||||||
|
wq-ub
|
||||||
|
ub-vc
|
||||||
|
de-ta
|
||||||
|
wq-aq
|
||||||
|
wq-vc
|
||||||
|
wh-yn
|
||||||
|
ka-de
|
||||||
|
kh-ta
|
||||||
|
co-tc
|
||||||
|
wh-qp
|
||||||
|
tb-vc
|
||||||
|
td-yn`)
|
||||||
|
require.Equal(t, "co,de,ka,ta", r)
|
||||||
|
}
|
||||||
3380
2024/go/day23/input.txt
Normal file
3380
2024/go/day23/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
297
2024/go/day24/day24.go
Normal file
297
2024/go/day24/day24.go
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
package day24
|
||||||
|
|
||||||
|
import (
|
||||||
|
"adventofcode2024/utils"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Network struct {
|
||||||
|
gates []*Gate
|
||||||
|
wires []*Wire
|
||||||
|
}
|
||||||
|
|
||||||
|
type State int
|
||||||
|
|
||||||
|
const (
|
||||||
|
NA State = iota - 1
|
||||||
|
ZERO
|
||||||
|
ONE
|
||||||
|
)
|
||||||
|
|
||||||
|
type Wire struct {
|
||||||
|
name string
|
||||||
|
state State
|
||||||
|
}
|
||||||
|
|
||||||
|
type Operation int
|
||||||
|
|
||||||
|
const (
|
||||||
|
AND Operation = iota
|
||||||
|
OR
|
||||||
|
XOR
|
||||||
|
)
|
||||||
|
|
||||||
|
type Gate struct {
|
||||||
|
in [2]*Wire
|
||||||
|
out *Wire
|
||||||
|
op Operation
|
||||||
|
}
|
||||||
|
|
||||||
|
func Part1(input string) int {
|
||||||
|
|
||||||
|
network := &Network{}
|
||||||
|
network.wires = make([]*Wire, 0)
|
||||||
|
|
||||||
|
data := strings.Split(input, "\n\n")
|
||||||
|
|
||||||
|
network.AddWires(data[0])
|
||||||
|
network.AddGates(data[1])
|
||||||
|
for {
|
||||||
|
if network.OutputKnown() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, gate := range network.gates {
|
||||||
|
// fmt.Printf("%d: %v\n", i, gate)
|
||||||
|
if gate.out.state == NA && gate.in[0].state != NA && gate.in[1].state != NA {
|
||||||
|
switch gate.op {
|
||||||
|
case AND:
|
||||||
|
gate.out.state = And(gate.in[0].state, gate.in[1].state)
|
||||||
|
case OR:
|
||||||
|
gate.out.state = Or(gate.in[0].state, gate.in[1].state)
|
||||||
|
case XOR:
|
||||||
|
gate.out.state = Xor(gate.in[0].state, gate.in[1].state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return int(network.Output())
|
||||||
|
}
|
||||||
|
|
||||||
|
func Part2(input string) int64 {
|
||||||
|
|
||||||
|
data := strings.Split(input, "\n\n")
|
||||||
|
|
||||||
|
inputs := strings.Split(data[0], "\n")
|
||||||
|
num_inputs := len(inputs) / 2
|
||||||
|
fmt.Println(num_inputs)
|
||||||
|
var x_value int64
|
||||||
|
var y_value int64
|
||||||
|
var z_value int64
|
||||||
|
y_value = 0
|
||||||
|
for i := 0; i < num_inputs; i++ {
|
||||||
|
// y_value = 1 << i
|
||||||
|
x_value = 1 << i
|
||||||
|
network := &Network{}
|
||||||
|
network.wires = make([]*Wire, 0)
|
||||||
|
network.AddWires2("x", num_inputs, x_value)
|
||||||
|
network.AddWires2("y", num_inputs, y_value)
|
||||||
|
network.AddGates(data[1])
|
||||||
|
// for i, gate := range network.gates {
|
||||||
|
// fmt.Printf("%d: %v\n", i, gate)
|
||||||
|
// }
|
||||||
|
network.SwapOutputs("z07", "rts")
|
||||||
|
network.SwapOutputs("z12", "jpj")
|
||||||
|
network.SwapOutputs("z26", "kgj")
|
||||||
|
network.SwapOutputs("vvw", "chv")
|
||||||
|
|
||||||
|
// for i, gate := range network.gates {
|
||||||
|
// fmt.Printf("%d: %v\n", i, gate)
|
||||||
|
// }
|
||||||
|
for {
|
||||||
|
if network.OutputKnown() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, gate := range network.gates {
|
||||||
|
// fmt.Printf("%d: %v\n", i, gate)
|
||||||
|
if gate.out.state == NA && gate.in[0].state != NA && gate.in[1].state != NA {
|
||||||
|
switch gate.op {
|
||||||
|
case AND:
|
||||||
|
gate.out.state = And(gate.in[0].state, gate.in[1].state)
|
||||||
|
case OR:
|
||||||
|
gate.out.state = Or(gate.in[0].state, gate.in[1].state)
|
||||||
|
case XOR:
|
||||||
|
gate.out.state = Xor(gate.in[0].state, gate.in[1].state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
z_value = network.Output()
|
||||||
|
if x_value + y_value != z_value {
|
||||||
|
fmt.Printf("(%d):\t x:%4d\t: y:%4d z:%4d\n", i, x_value, y_value, z_value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ans := []string{"z07", "rts", "z12", "jpj", "z26", "kgj", "vvw", "chv"}
|
||||||
|
sort.Strings(ans)
|
||||||
|
fmt.Println(strings.Join(ans, ","))
|
||||||
|
return z_value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Network) AddWires(data string) {
|
||||||
|
for _, line := range strings.Split(data, "\n") {
|
||||||
|
v := strings.Split(line, ": ")
|
||||||
|
n.AddWire(&Wire{name: v[0], state: to_state(v[1])})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Network) AddWire(wire *Wire) {
|
||||||
|
n.wires = append(n.wires, wire)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Network) AddWires2(w string, count int, value int64) {
|
||||||
|
for x := 0; x < count; x++ {
|
||||||
|
name := fmt.Sprintf("%s%02d", w, x)
|
||||||
|
v := fmt.Sprintf("%d", (value>>x)&1)
|
||||||
|
n.AddWire(&Wire{name: name, state: to_state(v)})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Network) AddGates(data string) {
|
||||||
|
// ntg XOR fgs -> mjb
|
||||||
|
pattern := `^([a-z0-9]{3}) (AND|OR|XOR) ([a-z0-9]{3}) -> ([a-z[0-9]{3})$`
|
||||||
|
|
||||||
|
re := regexp.MustCompile(pattern)
|
||||||
|
for _, line := range strings.Split(data, "\n") {
|
||||||
|
matches := re.FindAllStringSubmatch(line, -1)
|
||||||
|
for _, match := range matches {
|
||||||
|
n.AddGate(match[1], match[2], match[3], match[4], &n.wires)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Network) SwapOutputs(a, b string) {
|
||||||
|
_, wire1 := to_wire(a, n.wires)
|
||||||
|
_, wire2 := to_wire(b, n.wires)
|
||||||
|
for _, gate := range n.gates {
|
||||||
|
if gate.out.name == a {
|
||||||
|
gate.out = wire2
|
||||||
|
} else if gate.out.name == b {
|
||||||
|
gate.out = wire1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Network) AddGate(in0, op, in1, out string, wires *[]*Wire) {
|
||||||
|
var in [2]*Wire
|
||||||
|
var outw *Wire
|
||||||
|
*wires, in[0] = to_wire(in0, *wires)
|
||||||
|
*wires, in[1] = to_wire(in1, *wires)
|
||||||
|
*wires, outw = to_wire(out, *wires)
|
||||||
|
n.gates = append(n.gates, &Gate{in: in,
|
||||||
|
op: to_operation(op),
|
||||||
|
out: outw})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Network) OutputKnown() bool {
|
||||||
|
for _, gate := range n.gates {
|
||||||
|
if gate.out.name[0] != 'z' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if gate.out.state == NA {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Network) Output() int64 {
|
||||||
|
var ret int64
|
||||||
|
ret = 0
|
||||||
|
for _, gate := range n.gates {
|
||||||
|
if gate.out.name[0] != 'z' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addr := utils.MustAtoi(gate.out.name[1:])
|
||||||
|
if gate.out.state == ONE {
|
||||||
|
ret += 1 << addr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n Gate) String() string {
|
||||||
|
return n.in[0].name + "(" + n.in[0].state.String() + ")\t" + n.op.String() + " " + n.in[1].name + "(" + n.in[1].state.String() + ")\t ->\t" + n.out.name + " (" + n.out.state.String() + ")"
|
||||||
|
}
|
||||||
|
func to_state(in string) State {
|
||||||
|
switch in {
|
||||||
|
case "1":
|
||||||
|
return ONE
|
||||||
|
case "0":
|
||||||
|
return ZERO
|
||||||
|
}
|
||||||
|
return NA
|
||||||
|
}
|
||||||
|
|
||||||
|
func to_operation(in string) Operation {
|
||||||
|
var val Operation
|
||||||
|
switch in {
|
||||||
|
case "AND":
|
||||||
|
val = AND
|
||||||
|
case "OR":
|
||||||
|
val = OR
|
||||||
|
case "XOR":
|
||||||
|
val = XOR
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
func to_wire(in string, wires []*Wire) ([]*Wire, *Wire) {
|
||||||
|
for _, v := range wires {
|
||||||
|
if in == v.name {
|
||||||
|
return wires, v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wire := Wire{name: in, state: NA}
|
||||||
|
wires = append(wires, &wire)
|
||||||
|
return wires, &wire
|
||||||
|
}
|
||||||
|
|
||||||
|
func And(a, b State) State {
|
||||||
|
if a == ONE && b == ONE {
|
||||||
|
return ONE
|
||||||
|
}
|
||||||
|
return ZERO
|
||||||
|
}
|
||||||
|
|
||||||
|
func Or(a, b State) State {
|
||||||
|
if a == ONE || b == ONE {
|
||||||
|
return ONE
|
||||||
|
}
|
||||||
|
return ZERO
|
||||||
|
}
|
||||||
|
|
||||||
|
func Xor(a, b State) State {
|
||||||
|
if (a == ONE && b == ZERO) || (a == ZERO && b == ONE) {
|
||||||
|
return ONE
|
||||||
|
}
|
||||||
|
return ZERO
|
||||||
|
}
|
||||||
|
|
||||||
|
func (state State) String() string {
|
||||||
|
switch state {
|
||||||
|
case NA:
|
||||||
|
return "NA"
|
||||||
|
case ZERO:
|
||||||
|
return "0"
|
||||||
|
case ONE:
|
||||||
|
return "1"
|
||||||
|
default:
|
||||||
|
return "Invalid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (op Operation) String() string {
|
||||||
|
switch op {
|
||||||
|
case OR:
|
||||||
|
return "OR"
|
||||||
|
case AND:
|
||||||
|
return "AND"
|
||||||
|
case XOR:
|
||||||
|
return "XOR"
|
||||||
|
default:
|
||||||
|
return "Invalid"
|
||||||
|
}
|
||||||
|
}
|
||||||
17
2024/go/day24/day24_test.go
Normal file
17
2024/go/day24/day24_test.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package day24
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPart1(t *testing.T) {
|
||||||
|
r := Part1("")
|
||||||
|
require.Equal(t, 0, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPart2(t *testing.T) {
|
||||||
|
r := Part2("")
|
||||||
|
require.Equal(t, 0, r)
|
||||||
|
}
|
||||||
313
2024/go/day24/input.txt
Normal file
313
2024/go/day24/input.txt
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
x00: 1
|
||||||
|
x01: 0
|
||||||
|
x02: 1
|
||||||
|
x03: 1
|
||||||
|
x04: 0
|
||||||
|
x05: 0
|
||||||
|
x06: 1
|
||||||
|
x07: 1
|
||||||
|
x08: 0
|
||||||
|
x09: 1
|
||||||
|
x10: 1
|
||||||
|
x11: 1
|
||||||
|
x12: 1
|
||||||
|
x13: 0
|
||||||
|
x14: 1
|
||||||
|
x15: 1
|
||||||
|
x16: 1
|
||||||
|
x17: 1
|
||||||
|
x18: 1
|
||||||
|
x19: 1
|
||||||
|
x20: 0
|
||||||
|
x21: 1
|
||||||
|
x22: 0
|
||||||
|
x23: 1
|
||||||
|
x24: 0
|
||||||
|
x25: 1
|
||||||
|
x26: 1
|
||||||
|
x27: 1
|
||||||
|
x28: 1
|
||||||
|
x29: 0
|
||||||
|
x30: 0
|
||||||
|
x31: 1
|
||||||
|
x32: 0
|
||||||
|
x33: 1
|
||||||
|
x34: 1
|
||||||
|
x35: 0
|
||||||
|
x36: 0
|
||||||
|
x37: 1
|
||||||
|
x38: 0
|
||||||
|
x39: 1
|
||||||
|
x40: 1
|
||||||
|
x41: 1
|
||||||
|
x42: 1
|
||||||
|
x43: 0
|
||||||
|
x44: 1
|
||||||
|
y00: 1
|
||||||
|
y01: 0
|
||||||
|
y02: 0
|
||||||
|
y03: 1
|
||||||
|
y04: 1
|
||||||
|
y05: 0
|
||||||
|
y06: 0
|
||||||
|
y07: 0
|
||||||
|
y08: 0
|
||||||
|
y09: 0
|
||||||
|
y10: 0
|
||||||
|
y11: 1
|
||||||
|
y12: 0
|
||||||
|
y13: 1
|
||||||
|
y14: 0
|
||||||
|
y15: 1
|
||||||
|
y16: 1
|
||||||
|
y17: 1
|
||||||
|
y18: 1
|
||||||
|
y19: 0
|
||||||
|
y20: 0
|
||||||
|
y21: 1
|
||||||
|
y22: 1
|
||||||
|
y23: 1
|
||||||
|
y24: 1
|
||||||
|
y25: 0
|
||||||
|
y26: 0
|
||||||
|
y27: 1
|
||||||
|
y28: 1
|
||||||
|
y29: 1
|
||||||
|
y30: 1
|
||||||
|
y31: 0
|
||||||
|
y32: 0
|
||||||
|
y33: 0
|
||||||
|
y34: 1
|
||||||
|
y35: 1
|
||||||
|
y36: 1
|
||||||
|
y37: 0
|
||||||
|
y38: 1
|
||||||
|
y39: 1
|
||||||
|
y40: 1
|
||||||
|
y41: 1
|
||||||
|
y42: 0
|
||||||
|
y43: 1
|
||||||
|
y44: 1
|
||||||
|
|
||||||
|
x03 AND y03 -> htr
|
||||||
|
gwb AND kvf -> pkd
|
||||||
|
x04 AND y04 -> jjm
|
||||||
|
qcm XOR twv -> z21
|
||||||
|
rrq XOR bmp -> z44
|
||||||
|
x43 AND y43 -> pnn
|
||||||
|
x06 XOR y06 -> qmt
|
||||||
|
x26 AND y26 -> z26
|
||||||
|
y00 AND x00 -> whb
|
||||||
|
jfq XOR fbb -> z36
|
||||||
|
y33 AND x33 -> mmb
|
||||||
|
x38 AND y38 -> vqt
|
||||||
|
bbh OR qtd -> jfq
|
||||||
|
cbs AND ttb -> qtd
|
||||||
|
wqs OR cmf -> tpf
|
||||||
|
x10 AND y10 -> bfm
|
||||||
|
djp OR pfb -> qvr
|
||||||
|
x20 XOR y20 -> vhb
|
||||||
|
kkd XOR cjg -> z32
|
||||||
|
qpp XOR stg -> z41
|
||||||
|
kkd AND cjg -> mdv
|
||||||
|
tpp OR pfj -> twv
|
||||||
|
www AND qdf -> vjf
|
||||||
|
y15 XOR x15 -> hmr
|
||||||
|
mtg XOR sqm -> z09
|
||||||
|
x33 XOR y33 -> chc
|
||||||
|
x41 AND y41 -> pkj
|
||||||
|
x31 AND y31 -> cvn
|
||||||
|
x09 AND y09 -> nvw
|
||||||
|
mtg AND sqm -> chg
|
||||||
|
pkr AND kcv -> thc
|
||||||
|
x07 XOR y07 -> cds
|
||||||
|
x15 AND y15 -> fpr
|
||||||
|
mwv AND jsg -> wdw
|
||||||
|
mwv XOR jsg -> z38
|
||||||
|
y16 XOR x16 -> svs
|
||||||
|
y14 XOR x14 -> fnq
|
||||||
|
wth OR vjf -> btv
|
||||||
|
bvp AND gdb -> stc
|
||||||
|
cjb XOR rjc -> z04
|
||||||
|
x13 AND y13 -> pfb
|
||||||
|
x30 AND y30 -> qgf
|
||||||
|
htq AND rtk -> dsm
|
||||||
|
x18 XOR y18 -> kvf
|
||||||
|
y12 AND x12 -> mqn
|
||||||
|
bcj XOR bkh -> z03
|
||||||
|
x07 AND y07 -> sdj
|
||||||
|
bdf OR wbw -> qkf
|
||||||
|
y30 XOR x30 -> kbn
|
||||||
|
tpf AND vhb -> tpp
|
||||||
|
hqd OR fpr -> hgh
|
||||||
|
vfm XOR hbw -> z23
|
||||||
|
x01 AND y01 -> bdf
|
||||||
|
nvw OR chg -> vgp
|
||||||
|
x21 XOR y21 -> qcm
|
||||||
|
bwg AND mfn -> djp
|
||||||
|
dnf OR pkj -> ksp
|
||||||
|
y44 AND x44 -> gqr
|
||||||
|
y11 AND x11 -> smr
|
||||||
|
smr OR dsm -> ksn
|
||||||
|
jkm OR pkd -> rjf
|
||||||
|
thc OR sqt -> rbd
|
||||||
|
qvr XOR fnq -> z14
|
||||||
|
cjb AND rjc -> fsb
|
||||||
|
svg XOR fmt -> z31
|
||||||
|
x06 AND y06 -> ssv
|
||||||
|
dtj OR vvq -> jvp
|
||||||
|
chv XOR fqf -> z34
|
||||||
|
cvr AND hck -> pjd
|
||||||
|
dqp AND nbm -> hvv
|
||||||
|
x29 AND y29 -> vvq
|
||||||
|
y13 XOR x13 -> mfn
|
||||||
|
ksn AND nft -> z12
|
||||||
|
jjd XOR whb -> z01
|
||||||
|
chc AND rnq -> vjh
|
||||||
|
y36 AND x36 -> kfn
|
||||||
|
cwh OR vvw -> ttb
|
||||||
|
qkf AND wsv -> pqc
|
||||||
|
rdj OR kfv -> gdb
|
||||||
|
x08 AND y08 -> jrr
|
||||||
|
x02 AND y02 -> vdf
|
||||||
|
x12 XOR y12 -> nft
|
||||||
|
ptf OR jrr -> sqm
|
||||||
|
tdv OR wjp -> cjw
|
||||||
|
qvr AND fnq -> mch
|
||||||
|
x28 XOR y28 -> cfj
|
||||||
|
gtn XOR qmt -> z06
|
||||||
|
mqn OR jpj -> bwg
|
||||||
|
x36 XOR y36 -> fbb
|
||||||
|
qht OR bfm -> htq
|
||||||
|
y42 AND x42 -> mkg
|
||||||
|
ksn XOR nft -> jpj
|
||||||
|
x20 AND y20 -> pfj
|
||||||
|
cmt AND nbq -> gmc
|
||||||
|
rbd XOR knm -> z25
|
||||||
|
pvj XOR ksp -> z42
|
||||||
|
kgj OR stc -> www
|
||||||
|
tpf XOR vhb -> z20
|
||||||
|
pjd OR dsg -> mwv
|
||||||
|
cbs XOR ttb -> z35
|
||||||
|
bfk OR jvm -> gwb
|
||||||
|
ffj XOR rpg -> z17
|
||||||
|
vjr OR kwg -> pkr
|
||||||
|
pvj AND ksp -> dkc
|
||||||
|
y37 XOR x37 -> cvr
|
||||||
|
btv XOR cfj -> z28
|
||||||
|
gtq OR qgf -> fmt
|
||||||
|
nbq XOR cmt -> z39
|
||||||
|
wgq AND dqj -> tws
|
||||||
|
x24 AND y24 -> sqt
|
||||||
|
whj OR pnn -> bmp
|
||||||
|
x02 XOR y02 -> wsv
|
||||||
|
stg AND qpp -> dnf
|
||||||
|
kbn XOR jvp -> z30
|
||||||
|
y39 AND x39 -> gwq
|
||||||
|
cds AND rkv -> nph
|
||||||
|
kvf XOR gwb -> z18
|
||||||
|
mkg OR dkc -> sch
|
||||||
|
bqh XOR rjf -> z19
|
||||||
|
hck XOR cvr -> z37
|
||||||
|
jmk OR ssv -> rkv
|
||||||
|
x21 AND y21 -> cgd
|
||||||
|
pqc OR vdf -> bkh
|
||||||
|
rff OR mts -> rpg
|
||||||
|
bkh AND bcj -> rhq
|
||||||
|
bnv OR bst -> stg
|
||||||
|
bwg XOR mfn -> z13
|
||||||
|
sgt AND scc -> bnv
|
||||||
|
btv AND cfj -> tdv
|
||||||
|
svs AND hgh -> rff
|
||||||
|
hbw AND vfm -> kwg
|
||||||
|
x40 XOR y40 -> scc
|
||||||
|
y17 AND x17 -> jvm
|
||||||
|
y34 AND x34 -> chv
|
||||||
|
y35 AND x35 -> bbh
|
||||||
|
mdv OR rft -> rnq
|
||||||
|
fqf AND chv -> cwh
|
||||||
|
y28 AND x28 -> wjp
|
||||||
|
sch AND srj -> whj
|
||||||
|
htr OR rhq -> rjc
|
||||||
|
x05 XOR y05 -> dqp
|
||||||
|
cvn OR qnk -> cjg
|
||||||
|
y14 AND x14 -> tfr
|
||||||
|
y11 XOR x11 -> rtk
|
||||||
|
jfq AND fbb -> trr
|
||||||
|
ppb AND hmr -> hqd
|
||||||
|
gtb OR hvv -> gtn
|
||||||
|
y44 XOR x44 -> rrq
|
||||||
|
rtk XOR htq -> z11
|
||||||
|
x01 XOR y01 -> jjd
|
||||||
|
hmv XOR rts -> z08
|
||||||
|
y10 XOR x10 -> vpc
|
||||||
|
jvp AND kbn -> gtq
|
||||||
|
cjw AND ntj -> dtj
|
||||||
|
x22 AND y22 -> prp
|
||||||
|
ppb XOR hmr -> z15
|
||||||
|
y18 AND x18 -> jkm
|
||||||
|
x39 XOR y39 -> nbq
|
||||||
|
jjd AND whb -> wbw
|
||||||
|
x34 XOR y34 -> vvw
|
||||||
|
x19 AND y19 -> wqs
|
||||||
|
gwq OR gmc -> sgt
|
||||||
|
rbd AND knm -> rdj
|
||||||
|
srj XOR sch -> z43
|
||||||
|
y05 AND x05 -> gtb
|
||||||
|
x08 XOR y08 -> hmv
|
||||||
|
y25 AND x25 -> kfv
|
||||||
|
cgd OR jth -> dqj
|
||||||
|
vpc XOR vgp -> z10
|
||||||
|
tws OR prp -> hbw
|
||||||
|
jjm OR fsb -> nbm
|
||||||
|
wdw OR vqt -> cmt
|
||||||
|
rrq AND bmp -> cbv
|
||||||
|
rts AND hmv -> ptf
|
||||||
|
svs XOR hgh -> z16
|
||||||
|
y41 XOR x41 -> qpp
|
||||||
|
ntj XOR cjw -> z29
|
||||||
|
ffj AND rpg -> bfk
|
||||||
|
gqr OR cbv -> z45
|
||||||
|
x25 XOR y25 -> knm
|
||||||
|
chc XOR rnq -> z33
|
||||||
|
y43 XOR x43 -> srj
|
||||||
|
vgp AND vpc -> qht
|
||||||
|
x00 XOR y00 -> z00
|
||||||
|
cds XOR rkv -> rts
|
||||||
|
x24 XOR y24 -> kcv
|
||||||
|
x32 AND y32 -> rft
|
||||||
|
nbm XOR dqp -> z05
|
||||||
|
x35 XOR y35 -> cbs
|
||||||
|
mch OR tfr -> ppb
|
||||||
|
x16 AND y16 -> mts
|
||||||
|
www XOR qdf -> z27
|
||||||
|
x23 AND y23 -> vjr
|
||||||
|
x26 XOR y26 -> bvp
|
||||||
|
gtn AND qmt -> jmk
|
||||||
|
x29 XOR y29 -> ntj
|
||||||
|
y19 XOR x19 -> bqh
|
||||||
|
rjf AND bqh -> cmf
|
||||||
|
y38 XOR x38 -> jsg
|
||||||
|
x32 XOR y32 -> kkd
|
||||||
|
y03 XOR x03 -> bcj
|
||||||
|
y31 XOR x31 -> svg
|
||||||
|
y22 XOR x22 -> wgq
|
||||||
|
qkf XOR wsv -> z02
|
||||||
|
bvp XOR gdb -> kgj
|
||||||
|
x04 XOR y04 -> cjb
|
||||||
|
x17 XOR y17 -> ffj
|
||||||
|
y37 AND x37 -> dsg
|
||||||
|
y27 AND x27 -> wth
|
||||||
|
y23 XOR x23 -> vfm
|
||||||
|
sgt XOR scc -> z40
|
||||||
|
mmb OR vjh -> fqf
|
||||||
|
qcm AND twv -> jth
|
||||||
|
y09 XOR x09 -> mtg
|
||||||
|
sdj OR nph -> z07
|
||||||
|
wgq XOR dqj -> z22
|
||||||
|
trr OR kfn -> hck
|
||||||
|
y27 XOR x27 -> qdf
|
||||||
|
kcv XOR pkr -> z24
|
||||||
|
x42 XOR y42 -> pvj
|
||||||
|
x40 AND y40 -> bst
|
||||||
|
svg AND fmt -> qnk
|
||||||
76
2024/go/day25/day25.go
Normal file
76
2024/go/day25/day25.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package day25
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Lock struct {
|
||||||
|
diagram string
|
||||||
|
combination int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Key struct {
|
||||||
|
diagram string
|
||||||
|
combination int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Pair struct {
|
||||||
|
l Lock
|
||||||
|
k Key
|
||||||
|
}
|
||||||
|
|
||||||
|
func Part1(input string) int {
|
||||||
|
data := strings.Split(input, "\n\n")
|
||||||
|
locks := make([]Lock, 0)
|
||||||
|
keys := make([]Key, 0)
|
||||||
|
pairs := make([]Pair, 0)
|
||||||
|
|
||||||
|
for _, in := range data {
|
||||||
|
if in[0] == '#' {
|
||||||
|
locks = append(locks, Lock{diagram: in, combination: combination(in, '.') })
|
||||||
|
} else {
|
||||||
|
keys = append(keys, Key{diagram: in, combination: combination(in, '#')})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, l := range locks {
|
||||||
|
for _, k := range keys {
|
||||||
|
if key_fits(l.combination, k.combination) {
|
||||||
|
pairs = append(pairs, Pair{l: l, k: k})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Printf("locks: %d, keys: %d\n", len(locks), len(keys))
|
||||||
|
fmt.Printf("pair0 lock\n%s\n%d\n", pairs[0].l.diagram , pairs[0].l.combination)
|
||||||
|
fmt.Printf("pair0 key\n%s\n%d\n",pairs[0].k.diagram, pairs[0].k.combination)
|
||||||
|
return len(pairs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Part2(input string) int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func combination(d string, k rune) int {
|
||||||
|
comb := 0
|
||||||
|
rows := strings.Split(d, "\n")
|
||||||
|
columns := len(rows[0])
|
||||||
|
for _, r := range rows {
|
||||||
|
for i, c := range r {
|
||||||
|
if c == k {
|
||||||
|
comb += 1 * int(math.Pow10(columns - i - 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return comb
|
||||||
|
}
|
||||||
|
|
||||||
|
func key_fits(l int, k int) bool {
|
||||||
|
for i:=1;i<6;i++ {
|
||||||
|
ll := l % int(math.Pow10(i))
|
||||||
|
kk := k % int(math.Pow10(i))
|
||||||
|
if ll < kk { return false }
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
24
2024/go/day25/day25_test.go
Normal file
24
2024/go/day25/day25_test.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package day25
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPart1(t *testing.T) {
|
||||||
|
data, err := os.ReadFile("input.txt")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to read file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := Part1(string(data))
|
||||||
|
require.Equal(t, 0, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPart2(t *testing.T) {
|
||||||
|
r := Part2("")
|
||||||
|
require.Equal(t, 0, r)
|
||||||
|
}
|
||||||
3999
2024/go/day25/input.txt
Normal file
3999
2024/go/day25/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,14 @@
|
|||||||
module adventofcode2024
|
module adventofcode2024
|
||||||
|
|
||||||
go 1.19
|
go 1.23.2
|
||||||
|
|
||||||
|
toolchain go1.23.5
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/deckarep/golang-set/v2 v2.7.0
|
github.com/deckarep/golang-set/v2 v2.7.0
|
||||||
github.com/luxedo/esb_fireplace-go v0.3.0
|
|
||||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
|
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
|
||||||
)
|
)
|
||||||
|
|
||||||
require github.com/spf13/pflag v1.0.5 // indirect
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
|||||||
@@ -2,12 +2,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
|||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/deckarep/golang-set/v2 v2.7.0 h1:gIloKvD7yH2oip4VLhsv3JyLLFnC0Y2mlusgcvJYW5k=
|
github.com/deckarep/golang-set/v2 v2.7.0 h1:gIloKvD7yH2oip4VLhsv3JyLLFnC0Y2mlusgcvJYW5k=
|
||||||
github.com/deckarep/golang-set/v2 v2.7.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
github.com/deckarep/golang-set/v2 v2.7.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
||||||
github.com/luxedo/esb_fireplace-go v0.3.0 h1:zhpWG9AJfWEzqiaYsPjlBAwIMa1IF1gWoQoM4zvdLxI=
|
|
||||||
github.com/luxedo/esb_fireplace-go v0.3.0/go.mod h1:L8zIvYDHIKTHc3g3VACvjS0qBHvKmt31KRjWLP5ftkU=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ import (
|
|||||||
"adventofcode2024/day17"
|
"adventofcode2024/day17"
|
||||||
"adventofcode2024/day18"
|
"adventofcode2024/day18"
|
||||||
"adventofcode2024/day19"
|
"adventofcode2024/day19"
|
||||||
|
"adventofcode2024/day21"
|
||||||
|
"adventofcode2024/day22"
|
||||||
|
"adventofcode2024/day23"
|
||||||
|
"adventofcode2024/day24"
|
||||||
|
"adventofcode2024/day25"
|
||||||
"adventofcode2024/utils"
|
"adventofcode2024/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -90,6 +95,21 @@ func main() {
|
|||||||
case 19:
|
case 19:
|
||||||
fmt.Printf("part 1: %d\n", day19.Part1(utils.Readfile(d)))
|
fmt.Printf("part 1: %d\n", day19.Part1(utils.Readfile(d)))
|
||||||
fmt.Printf("part 2: %d\n", day19.Part2(utils.Readfile(d)))
|
fmt.Printf("part 2: %d\n", day19.Part2(utils.Readfile(d)))
|
||||||
|
case 21:
|
||||||
|
fmt.Printf("part 1: %d\n", day21.Part1(utils.Readfile(d)))
|
||||||
|
fmt.Printf("part 2: %d\n", day21.Part2(utils.Readfile(d)))
|
||||||
|
case 22:
|
||||||
|
fmt.Printf("part 1: %d\n", day22.Part1(utils.Readfile(d)))
|
||||||
|
fmt.Printf("part 2: %d\n", day22.Part2(utils.Readfile(d)))
|
||||||
|
case 23:
|
||||||
|
fmt.Printf("part 1: %d\n", day23.Part1(utils.Readfile(d)))
|
||||||
|
fmt.Printf("part 2: %d\n", day23.Part2(utils.Readfile(d)))
|
||||||
|
case 24:
|
||||||
|
fmt.Printf("part 1: %d\n", day24.Part1(utils.Readfile(d)))
|
||||||
|
fmt.Printf("part 2: %d\n", day24.Part2(utils.Readfile(d)))
|
||||||
|
case 25:
|
||||||
|
fmt.Printf("part 1: %d\n", day25.Part1(utils.Readfile(d)))
|
||||||
|
fmt.Printf("part 2: %d\n", day25.Part2(utils.Readfile(d)))
|
||||||
default:
|
default:
|
||||||
panic(fmt.Errorf("no such day: %d", d))
|
panic(fmt.Errorf("no such day: %d", d))
|
||||||
}
|
}
|
||||||
@@ -99,7 +119,7 @@ func main() {
|
|||||||
|
|
||||||
// Reads day from os.Args.
|
// Reads day from os.Args.
|
||||||
func day() int {
|
func day() int {
|
||||||
latest := 19
|
latest := 24
|
||||||
if len(os.Args) == 1 {
|
if len(os.Args) == 1 {
|
||||||
return latest
|
return latest
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package dijkstra
|
package dijkstra
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math"
|
"math"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
@@ -92,7 +91,7 @@ func getShortestPath(startNode *Node, endNode *Node, g *ItemGraph) ([]Point, int
|
|||||||
pathval = prev[pathval]
|
pathval = prev[pathval]
|
||||||
}
|
}
|
||||||
finalArr = append(finalArr, pathval)
|
finalArr = append(finalArr, pathval)
|
||||||
fmt.Println(finalArr)
|
// fmt.Println(finalArr)
|
||||||
for i, j := 0, len(finalArr)-1; i < j; i, j = i+1, j-1 {
|
for i, j := 0, len(finalArr)-1; i < j; i, j = i+1, j-1 {
|
||||||
finalArr[i], finalArr[j] = finalArr[j], finalArr[i]
|
finalArr[i], finalArr[j] = finalArr[j], finalArr[i]
|
||||||
}
|
}
|
||||||
|
|||||||
47
2024/go/utils/memo/memo.go
Normal file
47
2024/go/utils/memo/memo.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package memo
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
type Func func(key interface{}) interface{}
|
||||||
|
|
||||||
|
type result struct {
|
||||||
|
value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Memo struct {
|
||||||
|
f Func
|
||||||
|
cache map[interface{}]result
|
||||||
|
mu sync.RWMutex // Allows concurrent reads.
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(f Func) *Memo {
|
||||||
|
return &Memo{
|
||||||
|
f: f,
|
||||||
|
cache: make(map[interface{}]result),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (memo *Memo) Get(key interface{}) interface{} {
|
||||||
|
// First, try to read the cache using a read lock.
|
||||||
|
memo.mu.RLock()
|
||||||
|
res, ok := memo.cache[key]
|
||||||
|
memo.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return res.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the result without holding the lock.
|
||||||
|
computed := memo.f(key)
|
||||||
|
|
||||||
|
// Now acquire a write lock to update the cache.
|
||||||
|
memo.mu.Lock()
|
||||||
|
// Double-check: another goroutine may have stored the result in the meantime.
|
||||||
|
res, ok = memo.cache[key]
|
||||||
|
if !ok {
|
||||||
|
res.value = computed
|
||||||
|
memo.cache[key] = res
|
||||||
|
}
|
||||||
|
memo.mu.Unlock()
|
||||||
|
|
||||||
|
return res.value
|
||||||
|
}
|
||||||
56
2024/go/utils/ringbuffer/ringbuffer.go
Normal file
56
2024/go/utils/ringbuffer/ringbuffer.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package ringbuffer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RingBuffer[T any] struct {
|
||||||
|
buffer []T
|
||||||
|
size int
|
||||||
|
mu sync.Mutex
|
||||||
|
write int
|
||||||
|
count int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRingBuffer creates a new ring buffer with a fixed size.
|
||||||
|
func NewRingBuffer[T any](size int) *RingBuffer[T] {
|
||||||
|
return &RingBuffer[T]{
|
||||||
|
buffer: make([]T, size),
|
||||||
|
size: size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add inserts a new element into the buffer, overwriting the oldest if full.
|
||||||
|
func (rb *RingBuffer[T]) Add(value T) {
|
||||||
|
rb.mu.Lock()
|
||||||
|
defer rb.mu.Unlock()
|
||||||
|
|
||||||
|
rb.buffer[rb.write] = value
|
||||||
|
rb.write = (rb.write + 1) % rb.size
|
||||||
|
|
||||||
|
if rb.count < rb.size {
|
||||||
|
rb.count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the contents of the buffer in FIFO order.
|
||||||
|
func (rb *RingBuffer[T]) Get() []T {
|
||||||
|
rb.mu.Lock()
|
||||||
|
defer rb.mu.Unlock()
|
||||||
|
|
||||||
|
result := make([]T, 0, rb.count)
|
||||||
|
|
||||||
|
for i := 0; i < rb.count; i++ {
|
||||||
|
index := (rb.write + rb.size - rb.count + i) % rb.size
|
||||||
|
result = append(result, rb.buffer[index])
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the current number of elements in the buffer.
|
||||||
|
func (rb *RingBuffer[T]) Len() int {
|
||||||
|
rb.mu.Lock()
|
||||||
|
defer rb.mu.Unlock()
|
||||||
|
return rb.count
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user