Compare commits

...

2 Commits

Author SHA1 Message Date
d730d3c444 after pull 2025-02-14 15:16:07 +00:00
759b9c9544 work 2025-02-14 15:14:46 +00:00
25 changed files with 11149 additions and 14 deletions

View File

@@ -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()

View File

@@ -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
View 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)}]
}
}

View 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
View File

@@ -0,0 +1,5 @@
480A
965A
140A
341A
285A

9
2024/go/day21/tt Normal file
View 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

Binary file not shown.

91
2024/go/day22/day22.go Normal file
View 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
}

View 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

File diff suppressed because it is too large Load Diff

242
2024/go/day23/day23.go Normal file
View 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
}

View 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

File diff suppressed because it is too large Load Diff

297
2024/go/day24/day24.go Normal file
View 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"
}
}

View 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
View 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
View 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
}

View 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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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=

View File

@@ -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
}

View File

@@ -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]
}

View 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
}

View 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
}