Compare commits
2 Commits
a529516bab
...
d730d3c444
| Author | SHA1 | Date | |
|---|---|---|---|
| d730d3c444 | |||
| 759b9c9544 |
@@ -52,14 +52,54 @@ func Part1(input string) int {
|
||||
return dist
|
||||
}
|
||||
func Part2(input string) int {
|
||||
const saves int = 100
|
||||
count := 0
|
||||
maze := Maze{}.Parse(input)
|
||||
fmt.Println(maze)
|
||||
// fmt.Println(maze)
|
||||
data := inputGraph(*maze)
|
||||
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
|
||||
}
|
||||
|
||||
func abs(in int) int {
|
||||
if in < 0 {
|
||||
return in * -1
|
||||
}
|
||||
return in
|
||||
}
|
||||
|
||||
func inputGraph(maze Maze) dijkstra.InputGraph {
|
||||
data := dijkstra.InputGraph{}
|
||||
data.From = dijkstra.Point{X: maze.start.x, Y: maze.start.y}
|
||||
@@ -89,6 +129,58 @@ func inputGraph(maze Maze) dijkstra.InputGraph {
|
||||
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 {
|
||||
m.grid = inputs.ToGrid2D(input, "\n", "", '?', func(c string) Cell { return Cell(c[0]) })
|
||||
m.height, m.width = m.grid.SizeY(), m.grid.SizeX()
|
||||
|
||||
@@ -26,6 +26,20 @@ func TestPart1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPart2(t *testing.T) {
|
||||
r := Part2("")
|
||||
r := Part2(`###############
|
||||
#...#...#.....#
|
||||
#.#.#.#.#.###.#
|
||||
#S#...#.#.#...#
|
||||
#######.#.#.###
|
||||
#######.#.#...#
|
||||
#######.#.###.#
|
||||
###..E#...#...#
|
||||
###.#######.###
|
||||
#...###...#...#
|
||||
#.#####.#.###.#
|
||||
#.#...#.#.#...#
|
||||
#.#.#.#.#.#.###
|
||||
#...#...#...###
|
||||
###############`)
|
||||
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
|
||||
|
||||
go 1.19
|
||||
go 1.23.2
|
||||
|
||||
toolchain go1.23.5
|
||||
|
||||
require (
|
||||
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
|
||||
)
|
||||
|
||||
require github.com/spf13/pflag v1.0.5 // indirect
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // 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/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/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/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/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
||||
|
||||
@@ -26,6 +26,11 @@ import (
|
||||
"adventofcode2024/day17"
|
||||
"adventofcode2024/day18"
|
||||
"adventofcode2024/day19"
|
||||
"adventofcode2024/day21"
|
||||
"adventofcode2024/day22"
|
||||
"adventofcode2024/day23"
|
||||
"adventofcode2024/day24"
|
||||
"adventofcode2024/day25"
|
||||
"adventofcode2024/utils"
|
||||
)
|
||||
|
||||
@@ -90,6 +95,21 @@ func main() {
|
||||
case 19:
|
||||
fmt.Printf("part 1: %d\n", day19.Part1(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:
|
||||
panic(fmt.Errorf("no such day: %d", d))
|
||||
}
|
||||
@@ -99,7 +119,7 @@ func main() {
|
||||
|
||||
// Reads day from os.Args.
|
||||
func day() int {
|
||||
latest := 19
|
||||
latest := 24
|
||||
if len(os.Args) == 1 {
|
||||
return latest
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package dijkstra
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
)
|
||||
@@ -92,7 +91,7 @@ func getShortestPath(startNode *Node, endNode *Node, g *ItemGraph) ([]Point, int
|
||||
pathval = prev[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 {
|
||||
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