Solved 2024/24 P1
This commit is contained in:
parent
1b58a3c6d4
commit
5bed995d01
@ -123,7 +123,7 @@ Once the rounds are complete, you will be left with the numbers from `0`
|
|||||||
to `255` in some order, called the *sparse hash*. Your next task is to
|
to `255` in some order, called the *sparse hash*. Your next task is to
|
||||||
reduce these to a list of only `16` numbers called the *dense hash*. To
|
reduce these to a list of only `16` numbers called the *dense hash*. To
|
||||||
do this, use numeric bitwise
|
do this, use numeric bitwise
|
||||||
[XOR](https://en.wikipedia.org/wiki/Bitwise_operation#XOR) to combine
|
[](https://en.wikipedia.org/wiki/Bitwise_operation#) to combine
|
||||||
each consecutive block of `16` numbers in the sparse hash (there are
|
each consecutive block of `16` numbers in the sparse hash (there are
|
||||||
`16` such blocks in a list of `256` numbers). So, the first element in
|
`16` such blocks in a list of `256` numbers). So, the first element in
|
||||||
the dense hash is the first sixteen elements of the sparse hash XOR\'d
|
the dense hash is the first sixteen elements of the sparse hash XOR\'d
|
||||||
|
158
2024/20/20.md
Normal file
158
2024/20/20.md
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
## \-\-- Day 20: Race Condition \-\--
|
||||||
|
|
||||||
|
The Historians are quite pixelated again. This time, a massive, black
|
||||||
|
building looms over you - you\'re [right outside](/2017/day/24) the CPU!
|
||||||
|
|
||||||
|
While The Historians get to work, a nearby program sees that you\'re
|
||||||
|
idle and challenges you to a *race*. Apparently, you\'ve arrived just in
|
||||||
|
time for the frequently-held *race condition* festival!
|
||||||
|
|
||||||
|
The race takes place on a particularly long and twisting code path;
|
||||||
|
programs compete to see who can finish in the *fewest picoseconds*. The
|
||||||
|
winner
|
||||||
|
even gets their very own
|
||||||
|
[mutex](https://en.wikipedia.org/wiki/Lock_(computer_science))!
|
||||||
|
|
||||||
|
They hand you a *map of the racetrack* (your puzzle input). For example:
|
||||||
|
|
||||||
|
###############
|
||||||
|
#...#...#.....#
|
||||||
|
#.#.#.#.#.###.#
|
||||||
|
#S#...#.#.#...#
|
||||||
|
#######.#.#.###
|
||||||
|
#######.#.#...#
|
||||||
|
#######.#.###.#
|
||||||
|
###..E#...#...#
|
||||||
|
###.#######.###
|
||||||
|
#...###...#...#
|
||||||
|
#.#####.#.###.#
|
||||||
|
#.#...#.#.#...#
|
||||||
|
#.#.#.#.#.#.###
|
||||||
|
#...#...#...###
|
||||||
|
###############
|
||||||
|
|
||||||
|
The map consists of track (`.`) - including the *start* (`S`) and *end*
|
||||||
|
(`E`) positions (both of which also count as track) - and *walls* (`#`).
|
||||||
|
|
||||||
|
When a program runs through the racetrack, it starts at the start
|
||||||
|
position. Then, it is allowed to move up, down, left, or right; each
|
||||||
|
such move takes *1 picosecond*. The goal is to reach the end position as
|
||||||
|
quickly as possible. In this example racetrack, the fastest time is `84`
|
||||||
|
picoseconds.
|
||||||
|
|
||||||
|
Because there is only a single path from the start to the end and the
|
||||||
|
programs all go the same speed, the races used to be pretty boring. To
|
||||||
|
make things more interesting, they introduced a new rule to the races:
|
||||||
|
programs are allowed to *cheat*.
|
||||||
|
|
||||||
|
The rules for cheating are very strict. *Exactly once* during a race, a
|
||||||
|
program may *disable collision* for up to *2 picoseconds*. This allows
|
||||||
|
the program to *pass through walls* as if they were regular track. At
|
||||||
|
the end of the cheat, the program must be back on normal track again;
|
||||||
|
otherwise, it will receive a [segmentation
|
||||||
|
fault](https://en.wikipedia.org/wiki/Segmentation_fault)
|
||||||
|
and get disqualified.
|
||||||
|
|
||||||
|
So, a program could complete the course in 72 picoseconds (saving *12
|
||||||
|
picoseconds*) by cheating for the two moves marked `1` and `2`:
|
||||||
|
|
||||||
|
###############
|
||||||
|
#...#...12....#
|
||||||
|
#.#.#.#.#.###.#
|
||||||
|
#S#...#.#.#...#
|
||||||
|
#######.#.#.###
|
||||||
|
#######.#.#...#
|
||||||
|
#######.#.###.#
|
||||||
|
###..E#...#...#
|
||||||
|
###.#######.###
|
||||||
|
#...###...#...#
|
||||||
|
#.#####.#.###.#
|
||||||
|
#.#...#.#.#...#
|
||||||
|
#.#.#.#.#.#.###
|
||||||
|
#...#...#...###
|
||||||
|
###############
|
||||||
|
|
||||||
|
Or, a program could complete the course in 64 picoseconds (saving *20
|
||||||
|
picoseconds*) by cheating for the two moves marked `1` and `2`:
|
||||||
|
|
||||||
|
###############
|
||||||
|
#...#...#.....#
|
||||||
|
#.#.#.#.#.###.#
|
||||||
|
#S#...#.#.#...#
|
||||||
|
#######.#.#.###
|
||||||
|
#######.#.#...#
|
||||||
|
#######.#.###.#
|
||||||
|
###..E#...12..#
|
||||||
|
###.#######.###
|
||||||
|
#...###...#...#
|
||||||
|
#.#####.#.###.#
|
||||||
|
#.#...#.#.#...#
|
||||||
|
#.#.#.#.#.#.###
|
||||||
|
#...#...#...###
|
||||||
|
###############
|
||||||
|
|
||||||
|
This cheat saves *38 picoseconds*:
|
||||||
|
|
||||||
|
###############
|
||||||
|
#...#...#.....#
|
||||||
|
#.#.#.#.#.###.#
|
||||||
|
#S#...#.#.#...#
|
||||||
|
#######.#.#.###
|
||||||
|
#######.#.#...#
|
||||||
|
#######.#.###.#
|
||||||
|
###..E#...#...#
|
||||||
|
###.####1##.###
|
||||||
|
#...###.2.#...#
|
||||||
|
#.#####.#.###.#
|
||||||
|
#.#...#.#.#...#
|
||||||
|
#.#.#.#.#.#.###
|
||||||
|
#...#...#...###
|
||||||
|
###############
|
||||||
|
|
||||||
|
This cheat saves *64 picoseconds* and takes the program directly to the
|
||||||
|
end:
|
||||||
|
|
||||||
|
###############
|
||||||
|
#...#...#.....#
|
||||||
|
#.#.#.#.#.###.#
|
||||||
|
#S#...#.#.#...#
|
||||||
|
#######.#.#.###
|
||||||
|
#######.#.#...#
|
||||||
|
#######.#.###.#
|
||||||
|
###..21...#...#
|
||||||
|
###.#######.###
|
||||||
|
#...###...#...#
|
||||||
|
#.#####.#.###.#
|
||||||
|
#.#...#.#.#...#
|
||||||
|
#.#.#.#.#.#.###
|
||||||
|
#...#...#...###
|
||||||
|
###############
|
||||||
|
|
||||||
|
Each cheat has a distinct *start position* (the position where the cheat
|
||||||
|
is activated, just before the first move that is allowed to go through
|
||||||
|
walls) and *end position*; cheats are uniquely identified by their start
|
||||||
|
position and end position.
|
||||||
|
|
||||||
|
In this example, the total number of cheats (grouped by the amount of
|
||||||
|
time they save) are as follows:
|
||||||
|
|
||||||
|
- There are 14 cheats that save 2 picoseconds.
|
||||||
|
- There are 14 cheats that save 4 picoseconds.
|
||||||
|
- There are 2 cheats that save 6 picoseconds.
|
||||||
|
- There are 4 cheats that save 8 picoseconds.
|
||||||
|
- There are 2 cheats that save 10 picoseconds.
|
||||||
|
- There are 3 cheats that save 12 picoseconds.
|
||||||
|
- There is one cheat that saves 20 picoseconds.
|
||||||
|
- There is one cheat that saves 36 picoseconds.
|
||||||
|
- There is one cheat that saves 38 picoseconds.
|
||||||
|
- There is one cheat that saves 40 picoseconds.
|
||||||
|
- There is one cheat that saves 64 picoseconds.
|
||||||
|
|
||||||
|
You aren\'t sure what the conditions of the racetrack will be like, so
|
||||||
|
to give yourself as many options as possible, you\'ll need a list of the
|
||||||
|
best cheats. *How many cheats would save you at least 100 picoseconds?*
|
||||||
|
|
||||||
|
To begin, [get your puzzle input](20/input).
|
||||||
|
|
||||||
|
Answer:
|
||||||
|
|
77
2024/20/solution.py
Normal file
77
2024/20/solution.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#!/bin/python3
|
||||||
|
import sys,time,re,copy
|
||||||
|
from pprint import pprint
|
||||||
|
sys.path.insert(0, '../../')
|
||||||
|
from fred import list2int,get_re,nprint,lprint,loadFile,dijkstra,toGrid,findInGrid,create_graph_from_grid,get_value_in_direction,addTuples
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
input_f = 'input'
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 1 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
def part1():
|
||||||
|
grid = toGrid(input_f)
|
||||||
|
start = findInGrid(grid,'S')
|
||||||
|
end = findInGrid(grid,'E')
|
||||||
|
graph = create_graph_from_grid(grid,start,end,'#')
|
||||||
|
#nprint(grid)
|
||||||
|
grid[start[0]][start[1]] = '.'
|
||||||
|
grid[end[0]][end[1]] = '.'
|
||||||
|
|
||||||
|
path, dist = dijkstra(graph,start,end)
|
||||||
|
|
||||||
|
cheatWalls = []
|
||||||
|
|
||||||
|
for r,row in enumerate(grid):
|
||||||
|
for c,pos in enumerate(row):
|
||||||
|
if pos == '.':
|
||||||
|
if get_value_in_direction(grid,(r,c),'up') == '#' and get_value_in_direction(grid,(r,c),'down') == '#':
|
||||||
|
cheatWalls.append(addTuples((r,c),(-1,0)))
|
||||||
|
cheatWalls.append(addTuples((r,c),(1,0)))
|
||||||
|
elif get_value_in_direction(grid,(r,c),'left') == '#' and get_value_in_direction(grid,(r,c),'right') == '#':
|
||||||
|
cheatWalls.append(addTuples((r,c),(0,-1)))
|
||||||
|
cheatWalls.append(addTuples((r,c),(0,1)))
|
||||||
|
if pos == '#':
|
||||||
|
if get_value_in_direction(grid,(r,c),'up') == '.' and get_value_in_direction(grid,(r,c),'down') == '.':
|
||||||
|
cheatWalls.append((r,c))
|
||||||
|
cheatWalls.append((r,c))
|
||||||
|
elif get_value_in_direction(grid,(r,c),'left') == '.' and get_value_in_direction(grid,(r,c),'right') == '.':
|
||||||
|
cheatWalls.append((r,c))
|
||||||
|
cheatWalls.append((r,c))
|
||||||
|
|
||||||
|
|
||||||
|
#print(dist)
|
||||||
|
#nprint(grid,positions=path)
|
||||||
|
|
||||||
|
results = {}
|
||||||
|
startDist = dist
|
||||||
|
#print(cheatWalls)
|
||||||
|
for c in cheatWalls:
|
||||||
|
newGrid = copy.deepcopy(grid)
|
||||||
|
newGrid[c[0]][c[1]] = '.'
|
||||||
|
graph = create_graph_from_grid(newGrid,start,end,'#')
|
||||||
|
path, dist = dijkstra(graph,start,end)
|
||||||
|
dist = startDist-dist
|
||||||
|
if dist not in results:
|
||||||
|
results[dist] = 0
|
||||||
|
results[dist] += 1
|
||||||
|
|
||||||
|
pprint(results)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
print('Part 1:',part1(), '\t\t', round((time.time() - start_time)*1000), 'ms')
|
||||||
|
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 2 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
def part2():
|
||||||
|
return
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
print('Part 2:',part2(), '\t\t', round((time.time() - start_time)*1000), 'ms')
|
92
2024/23/23.md
Normal file
92
2024/23/23.md
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
## \-\-- Day 23: LAN Party \-\--
|
||||||
|
|
||||||
|
As The Historians wander around a secure area at Easter Bunny HQ, you
|
||||||
|
come across posters for a [LAN
|
||||||
|
party](https://en.wikipedia.org/wiki/LAN_party)
|
||||||
|
scheduled for today! Maybe you can find it; you connect to a nearby
|
||||||
|
[datalink port](/2016/day/9) and download a map of the local network
|
||||||
|
(your puzzle input).
|
||||||
|
|
||||||
|
The network map provides a list of every *connection between two
|
||||||
|
computers*. For example:
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Each line of text in the network map represents a single connection; the
|
||||||
|
line `kh-tc` represents a connection between the computer named `kh` and
|
||||||
|
the computer named `tc`. Connections aren\'t directional; `tc-kh` would
|
||||||
|
mean exactly the same thing.
|
||||||
|
|
||||||
|
LAN parties typically involve multiplayer games, so maybe you can locate
|
||||||
|
it by finding groups of connected computers. Start by looking for *sets
|
||||||
|
of three computers* where each computer in the set is connected to the
|
||||||
|
other two computers.
|
||||||
|
|
||||||
|
In this example, there are `12` such sets of three inter-connected
|
||||||
|
computers:
|
||||||
|
|
||||||
|
aq,cg,yn
|
||||||
|
aq,vc,wq
|
||||||
|
co,de,ka
|
||||||
|
co,de,ta
|
||||||
|
co,ka,ta
|
||||||
|
de,ka,ta
|
||||||
|
kh,qp,ub
|
||||||
|
qp,td,wh
|
||||||
|
tb,vc,wq
|
||||||
|
tc,td,wh
|
||||||
|
td,wh,yn
|
||||||
|
ub,vc,wq
|
||||||
|
|
||||||
|
If the Chief Historian is here, *and* he\'s at the LAN party, it would
|
||||||
|
be best to know that right away. You\'re pretty sure his computer\'s
|
||||||
|
name starts with `t`, so consider only sets of three computers where at
|
||||||
|
least one computer\'s name starts with `t`. That narrows the list down
|
||||||
|
to `7` sets of three inter-connected computers:
|
||||||
|
|
||||||
|
co,de,ta
|
||||||
|
co,ka,ta
|
||||||
|
de,ka,ta
|
||||||
|
qp,td,wh
|
||||||
|
tb,vc,wq
|
||||||
|
tc,td,wh
|
||||||
|
td,wh,yn
|
||||||
|
|
||||||
|
Find all the sets of three inter-connected computers. *How many contain
|
||||||
|
at least one computer with a name that starts with `t`?*
|
||||||
|
|
||||||
|
To begin, [get your puzzle input](23/input).
|
||||||
|
|
||||||
|
Answer:
|
||||||
|
|
49
2024/23/solution.py
Normal file
49
2024/23/solution.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/python3
|
||||||
|
import sys,time,re
|
||||||
|
from pprint import pprint
|
||||||
|
sys.path.insert(0, '../../')
|
||||||
|
from fred import list2int,get_re,nprint,lprint,loadFile,dprint,TSP,dfs_graph
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
input_f = 'test'
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 1 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
def part1():
|
||||||
|
graph = {}
|
||||||
|
|
||||||
|
file = loadFile(input_f)
|
||||||
|
for f in file:
|
||||||
|
f = f.split('-')
|
||||||
|
if f[0] not in graph:
|
||||||
|
graph[f[0]] = []
|
||||||
|
if f[1] not in graph:
|
||||||
|
graph[f[1]] = []
|
||||||
|
graph[f[0]].append(f[1])
|
||||||
|
graph[f[1]].append(f[0])
|
||||||
|
dprint(graph)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for key,values in graph.items():
|
||||||
|
print(key)
|
||||||
|
print(dfs_graph(graph,key))
|
||||||
|
input()
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
print('Part 1:',part1(), '\t\t', round((time.time() - start_time)*1000), 'ms')
|
||||||
|
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 2 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
def part2():
|
||||||
|
return
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
print('Part 2:',part2(), '\t\t', round((time.time() - start_time)*1000), 'ms')
|
282
2024/24/24.md
Normal file
282
2024/24/24.md
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
## \-\-- Day 24: Crossed Wires \-\--
|
||||||
|
|
||||||
|
You and The Historians arrive at the edge of a [large
|
||||||
|
grove](/2022/day/23) somewhere in the jungle. After the last incident,
|
||||||
|
the Elves installed a small device that monitors the fruit. While The
|
||||||
|
Historians search the grove, one of them asks if you can take a look at
|
||||||
|
the monitoring device; apparently, it\'s been malfunctioning recently.
|
||||||
|
|
||||||
|
The device seems to be trying to produce a number through some boolean
|
||||||
|
logic gates. Each gate has two inputs and one output. The gates all
|
||||||
|
operate on values that are either *true* (`1`) or *false* (`0`).
|
||||||
|
|
||||||
|
- `AND` gates output `1` if *both* inputs are `1`; if either input is
|
||||||
|
`0`, these gates output `0`.
|
||||||
|
- `OR` gates output `1` if *one or both* inputs is `1`; if both inputs
|
||||||
|
are `0`, these gates output `0`.
|
||||||
|
- `XOR` gates output `1` if the inputs are *different*; if the inputs
|
||||||
|
are the same, these gates output `0`.
|
||||||
|
|
||||||
|
Gates wait until both inputs are received before producing output; wires
|
||||||
|
can carry `0`, `1` or no value at all. There are no loops; once a gate
|
||||||
|
has determined its output, the output will not change until the whole
|
||||||
|
system is reset. Each wire is connected to at most one gate output, but
|
||||||
|
can be connected to many gate inputs.
|
||||||
|
|
||||||
|
Rather than risk getting shocked while tinkering with the live system,
|
||||||
|
you write down all of the gate connections and initial wire values (your
|
||||||
|
puzzle input) so you can consider them in relative safety. For example:
|
||||||
|
|
||||||
|
x00: 1
|
||||||
|
x01: 1
|
||||||
|
x02: 1
|
||||||
|
y00: 0
|
||||||
|
y01: 1
|
||||||
|
y02: 0
|
||||||
|
|
||||||
|
x00 AND y00 -> z00
|
||||||
|
x01 XOR y01 -> z01
|
||||||
|
x02 OR y02 -> z02
|
||||||
|
|
||||||
|
Because gates wait for input, some wires need to start with a value (as
|
||||||
|
inputs to the entire system). The first section specifies these values.
|
||||||
|
For example, `x00: 1` means that the wire named `x00` starts with the
|
||||||
|
value `1` (as if a gate is already outputting that value onto that
|
||||||
|
wire).
|
||||||
|
|
||||||
|
The second section lists all of the gates and the wires connected to
|
||||||
|
them. For example, `x00 AND y00 -> z00` describes an instance of an
|
||||||
|
`AND` gate which has wires `x00` and `y00` connected to its inputs and
|
||||||
|
which will write its output to wire `z00`.
|
||||||
|
|
||||||
|
In this example, simulating these gates eventually causes `0` to appear
|
||||||
|
on wire `z00`, `0` to appear on wire `z01`, and `1` to appear on wire
|
||||||
|
`z02`.
|
||||||
|
|
||||||
|
Ultimately, the system is trying to produce a *number* by combining the
|
||||||
|
bits on all wires starting with `z`. `z00` is the least significant bit,
|
||||||
|
then `z01`, then `z02`, and so on.
|
||||||
|
|
||||||
|
In this example, the three output bits form the binary number `100`
|
||||||
|
which is equal to the decimal number `4`.
|
||||||
|
|
||||||
|
Here\'s a larger example:
|
||||||
|
|
||||||
|
x00: 1
|
||||||
|
x01: 0
|
||||||
|
x02: 1
|
||||||
|
x03: 1
|
||||||
|
x04: 0
|
||||||
|
y00: 1
|
||||||
|
y01: 1
|
||||||
|
y02: 1
|
||||||
|
y03: 1
|
||||||
|
y04: 1
|
||||||
|
|
||||||
|
ntg XOR fgs -> mjb
|
||||||
|
y02 OR x01 -> tnw
|
||||||
|
kwq OR kpj -> z05
|
||||||
|
x00 OR x03 -> fst
|
||||||
|
tgd XOR rvg -> z01
|
||||||
|
vdt OR tnw -> bfw
|
||||||
|
bfw AND frj -> z10
|
||||||
|
ffh OR nrd -> bqk
|
||||||
|
y00 AND y03 -> djm
|
||||||
|
y03 OR y00 -> psh
|
||||||
|
bqk OR frj -> z08
|
||||||
|
tnw OR fst -> frj
|
||||||
|
gnj AND tgd -> z11
|
||||||
|
bfw XOR mjb -> z00
|
||||||
|
x03 OR x00 -> vdt
|
||||||
|
gnj AND wpb -> z02
|
||||||
|
x04 AND y00 -> kjc
|
||||||
|
djm OR pbm -> qhw
|
||||||
|
nrd AND vdt -> hwm
|
||||||
|
kjc AND fst -> rvg
|
||||||
|
y04 OR y02 -> fgs
|
||||||
|
y01 AND x02 -> pbm
|
||||||
|
ntg OR kjc -> kwq
|
||||||
|
psh XOR fgs -> tgd
|
||||||
|
qhw XOR tgd -> z09
|
||||||
|
pbm OR djm -> kpj
|
||||||
|
x03 XOR y03 -> ffh
|
||||||
|
x00 XOR y04 -> ntg
|
||||||
|
bfw OR bqk -> z06
|
||||||
|
nrd XOR fgs -> wpb
|
||||||
|
frj XOR qhw -> z04
|
||||||
|
bqk OR frj -> z07
|
||||||
|
y03 OR x01 -> nrd
|
||||||
|
hwm AND bqk -> z03
|
||||||
|
tgd XOR rvg -> z12
|
||||||
|
tnw OR pbm -> gnj
|
||||||
|
|
||||||
|
After waiting for values on all wires starting with `z`, the wires in
|
||||||
|
this system have the following values:
|
||||||
|
|
||||||
|
bfw: 1
|
||||||
|
bqk: 1
|
||||||
|
djm: 1
|
||||||
|
ffh: 0
|
||||||
|
fgs: 1
|
||||||
|
frj: 1
|
||||||
|
fst: 1
|
||||||
|
gnj: 1
|
||||||
|
hwm: 1
|
||||||
|
kjc: 0
|
||||||
|
kpj: 1
|
||||||
|
kwq: 0
|
||||||
|
mjb: 1
|
||||||
|
nrd: 1
|
||||||
|
ntg: 0
|
||||||
|
pbm: 1
|
||||||
|
psh: 1
|
||||||
|
qhw: 1
|
||||||
|
rvg: 0
|
||||||
|
tgd: 0
|
||||||
|
tnw: 1
|
||||||
|
vdt: 1
|
||||||
|
wpb: 0
|
||||||
|
z00: 0
|
||||||
|
z01: 0
|
||||||
|
z02: 0
|
||||||
|
z03: 1
|
||||||
|
z04: 0
|
||||||
|
z05: 1
|
||||||
|
z06: 1
|
||||||
|
z07: 1
|
||||||
|
z08: 1
|
||||||
|
z09: 1
|
||||||
|
z10: 1
|
||||||
|
z11: 0
|
||||||
|
z12: 0
|
||||||
|
|
||||||
|
Combining the bits from all wires starting with `z` produces the binary
|
||||||
|
number `0011111101000`. Converting this number to decimal produces
|
||||||
|
`2024`.
|
||||||
|
|
||||||
|
Simulate the system of gates and wires. *What decimal number does it
|
||||||
|
output on the wires starting with `z`?*
|
||||||
|
|
||||||
|
Your puzzle answer was `51715173446832`.
|
||||||
|
|
||||||
|
The first half of this puzzle is complete! It provides one gold star: \*
|
||||||
|
|
||||||
|
## \-\-- Part Two \-\-- {#part2}
|
||||||
|
|
||||||
|
After inspecting the monitoring device more closely, you determine that
|
||||||
|
the system you\'re simulating is trying to *add two binary numbers*.
|
||||||
|
|
||||||
|
Specifically, it is treating the bits on wires starting with `x` as one
|
||||||
|
binary number, treating the bits on wires starting with `y` as a second
|
||||||
|
binary number, and then attempting to add those two numbers together.
|
||||||
|
The output of this operation is produced as a binary number on the wires
|
||||||
|
starting with `z`. (In all three cases, wire `00` is the least
|
||||||
|
significant bit, then `01`, then `02`, and so on.)
|
||||||
|
|
||||||
|
The initial values for the wires in your puzzle input represent *just
|
||||||
|
one instance* of a pair of numbers that sum to the wrong value.
|
||||||
|
Ultimately, *any* two binary numbers provided as input should be handled
|
||||||
|
correctly. That is, for any combination of bits on wires starting with
|
||||||
|
`x` and wires starting with `y`, the sum of the two numbers those bits
|
||||||
|
represent should be produced as a binary number on the wires starting
|
||||||
|
with `z`.
|
||||||
|
|
||||||
|
For example, if you have an addition system with four `x` wires, four
|
||||||
|
`y` wires, and five `z` wires, you should be able to supply any four-bit
|
||||||
|
number on the `x` wires, any four-bit number on the `y` numbers, and
|
||||||
|
eventually find the sum of those two numbers as a five-bit number on the
|
||||||
|
`z` wires. One of the many ways you could provide numbers to such a
|
||||||
|
system would be to pass `11` on the `x` wires (`1011` in binary) and
|
||||||
|
`13` on the `y` wires (`1101` in binary):
|
||||||
|
|
||||||
|
x00: 1
|
||||||
|
x01: 1
|
||||||
|
x02: 0
|
||||||
|
x03: 1
|
||||||
|
y00: 1
|
||||||
|
y01: 0
|
||||||
|
y02: 1
|
||||||
|
y03: 1
|
||||||
|
|
||||||
|
If the system were working correctly, then after all gates are finished
|
||||||
|
processing, you should find `24` (`11+13`) on the `z` wires as the
|
||||||
|
five-bit binary number `11000`:
|
||||||
|
|
||||||
|
z00: 0
|
||||||
|
z01: 0
|
||||||
|
z02: 0
|
||||||
|
z03: 1
|
||||||
|
z04: 1
|
||||||
|
|
||||||
|
Unfortunately, your actual system needs to add numbers with many more
|
||||||
|
bits and therefore has many more wires.
|
||||||
|
|
||||||
|
Based on forensic analysis of scuff marks and
|
||||||
|
scratches on the device, you can tell that there are exactly *four*
|
||||||
|
pairs of gates whose output wires have been *swapped*. (A gate can only
|
||||||
|
be in at most one such pair; no gate\'s output was swapped multiple
|
||||||
|
times.)
|
||||||
|
|
||||||
|
For example, the system below is supposed to find the bitwise `AND` of
|
||||||
|
the six-bit number on `x00` through `x05` and the six-bit number on
|
||||||
|
`y00` through `y05` and then write the result as a six-bit number on
|
||||||
|
`z00` through `z05`:
|
||||||
|
|
||||||
|
x00: 0
|
||||||
|
x01: 1
|
||||||
|
x02: 0
|
||||||
|
x03: 1
|
||||||
|
x04: 0
|
||||||
|
x05: 1
|
||||||
|
y00: 0
|
||||||
|
y01: 0
|
||||||
|
y02: 1
|
||||||
|
y03: 1
|
||||||
|
y04: 0
|
||||||
|
y05: 1
|
||||||
|
|
||||||
|
x00 AND y00 -> z05
|
||||||
|
x01 AND y01 -> z02
|
||||||
|
x02 AND y02 -> z01
|
||||||
|
x03 AND y03 -> z03
|
||||||
|
x04 AND y04 -> z04
|
||||||
|
x05 AND y05 -> z00
|
||||||
|
|
||||||
|
However, in this example, two pairs of gates have had their output wires
|
||||||
|
swapped, causing the system to produce wrong answers. The first pair of
|
||||||
|
gates with swapped outputs is `x00 AND y00 -> z05` and
|
||||||
|
`x05 AND y05 -> z00`; the second pair of gates is `x01 AND y01 -> z02`
|
||||||
|
and `x02 AND y02 -> z01`. Correcting these two swaps results in this
|
||||||
|
system that works as intended for any set of initial values on wires
|
||||||
|
that start with `x` or `y`:
|
||||||
|
|
||||||
|
x00 AND y00 -> z00
|
||||||
|
x01 AND y01 -> z01
|
||||||
|
x02 AND y02 -> z02
|
||||||
|
x03 AND y03 -> z03
|
||||||
|
x04 AND y04 -> z04
|
||||||
|
x05 AND y05 -> z05
|
||||||
|
|
||||||
|
In this example, two pairs of gates have outputs that are involved in a
|
||||||
|
swap. By sorting their output wires\' names and joining them with
|
||||||
|
commas, the list of wires involved in swaps is `z00,z01,z02,z05`.
|
||||||
|
|
||||||
|
Of course, your actual system is much more complex than this, and the
|
||||||
|
gates that need their outputs swapped could be *anywhere*, not just
|
||||||
|
attached to a wire starting with `z`. If you were to determine that you
|
||||||
|
need to swap output wires `aaa` with `eee`, `ooo` with `z99`, `bbb` with
|
||||||
|
`ccc`, and `aoc` with `z24`, your answer would be
|
||||||
|
`aaa,aoc,bbb,ccc,eee,ooo,z24,z99`.
|
||||||
|
|
||||||
|
Your system of gates and wires has *four* pairs of gates which need
|
||||||
|
their output wires swapped - *eight* wires in total. Determine which
|
||||||
|
four pairs of gates need their outputs swapped so that your system
|
||||||
|
correctly performs addition; *what do you get if you sort the names of
|
||||||
|
the eight wires involved in a swap and then join those names with
|
||||||
|
commas?*
|
||||||
|
|
||||||
|
Answer:
|
||||||
|
|
||||||
|
Although it hasn\'t changed, you can still [get your puzzle
|
||||||
|
input](24/input).
|
||||||
|
|
125
2024/24/solution.py
Normal file
125
2024/24/solution.py
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
#!/bin/python3
|
||||||
|
import sys,time,re
|
||||||
|
from pprint import pprint
|
||||||
|
sys.path.insert(0, '../../')
|
||||||
|
from fred import list2int,get_re,nprint,lprint,loadFile,dprint
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
input_f = 'input'
|
||||||
|
|
||||||
|
def loadGates(input_f):
|
||||||
|
gates = {}
|
||||||
|
instructions = []
|
||||||
|
with open(input_f) as file:
|
||||||
|
for line in file:
|
||||||
|
if ':' in line:
|
||||||
|
tmp = line.split(': ')
|
||||||
|
gates[tmp[0]] = int(tmp[1])
|
||||||
|
if '->' in line:
|
||||||
|
tmp = line.replace('-> ','').rstrip().split(' ')
|
||||||
|
instructions.append(tmp)
|
||||||
|
return gates, instructions
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 1 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
def part1():
|
||||||
|
gates, instructions = loadGates(input_f)
|
||||||
|
|
||||||
|
#print(gates)
|
||||||
|
#print(instructions)
|
||||||
|
wait_for = []
|
||||||
|
for inst in instructions:
|
||||||
|
|
||||||
|
x,logic,y,z = inst
|
||||||
|
|
||||||
|
if x not in gates or y not in gates:
|
||||||
|
#print(inst)
|
||||||
|
wait_for.append(inst)
|
||||||
|
continue
|
||||||
|
|
||||||
|
for wdx, w in enumerate(wait_for):
|
||||||
|
x,logic,y,z = w
|
||||||
|
if x in gates and y in gates:
|
||||||
|
#print(wait_for,w,wdx)
|
||||||
|
# `AND` gates output `1` if *both* inputs are `1`; if either input is `0`, these gates output `0`.
|
||||||
|
if logic == 'AND':
|
||||||
|
gates[z] = 1 if gates[x] and gates[y] else 0
|
||||||
|
|
||||||
|
# `OR` gates output `1` if *one or both* inputs is `1`; if both inputs are `0`, these gates output `0`.
|
||||||
|
if logic == 'OR':
|
||||||
|
gates[z] = 1 if gates[x] or gates[y] else 0
|
||||||
|
|
||||||
|
# `XOR` gates output `1` if the inputs are *different*; if the inputs are the same, these gates output `0`.
|
||||||
|
if logic == 'XOR':
|
||||||
|
gates[z] = 1 if gates[x] != gates[y] else 0
|
||||||
|
wait_for.pop(wdx)
|
||||||
|
#input()
|
||||||
|
|
||||||
|
x,logic,y,z = inst
|
||||||
|
|
||||||
|
# `AND` gates output `1` if *both* inputs are `1`; if either input is `0`, these gates output `0`.
|
||||||
|
if logic == 'AND':
|
||||||
|
gates[z] = 1 if gates[x] and gates[y] else 0
|
||||||
|
|
||||||
|
# `OR` gates output `1` if *one or both* inputs is `1`; if both inputs are `0`, these gates output `0`.
|
||||||
|
if logic == 'OR':
|
||||||
|
gates[z] = 1 if gates[x] or gates[y] else 0
|
||||||
|
|
||||||
|
# `XOR` gates output `1` if the inputs are *different*; if the inputs are the same, these gates output `0`.
|
||||||
|
if logic == 'XOR':
|
||||||
|
gates[z] = 1 if gates[x] != gates[y] else 0
|
||||||
|
|
||||||
|
while len(wait_for) > 0:
|
||||||
|
for wdx, w in enumerate(wait_for):
|
||||||
|
x,logic,y,z = w
|
||||||
|
if x in gates and y in gates:
|
||||||
|
#print(wait_for,w,wdx)
|
||||||
|
# `AND` gates output `1` if *both* inputs are `1`; if either input is `0`, these gates output `0`.
|
||||||
|
if logic == 'AND':
|
||||||
|
gates[z] = 1 if gates[x] and gates[y] else 0
|
||||||
|
|
||||||
|
# `OR` gates output `1` if *one or both* inputs is `1`; if both inputs are `0`, these gates output `0`.
|
||||||
|
if logic == 'OR':
|
||||||
|
gates[z] = 1 if gates[x] or gates[y] else 0
|
||||||
|
|
||||||
|
# `XOR` gates output `1` if the inputs are *different*; if the inputs are the same, these gates output `0`.
|
||||||
|
if logic == 'XOR':
|
||||||
|
gates[z] = 1 if gates[x] != gates[y] else 0
|
||||||
|
wait_for.pop(wdx)
|
||||||
|
|
||||||
|
#dprint(gates)
|
||||||
|
result = ''
|
||||||
|
|
||||||
|
countZ = 0
|
||||||
|
|
||||||
|
for g in gates.keys():
|
||||||
|
if g[0] == 'z':
|
||||||
|
countZ += 1
|
||||||
|
|
||||||
|
for i in range(countZ-1,-1,-1):
|
||||||
|
#print(i)
|
||||||
|
#print(g,gates[g])
|
||||||
|
if i < 10:
|
||||||
|
result += str(gates['z0'+str(i)])
|
||||||
|
else:
|
||||||
|
result += str(gates['z'+str(i)])
|
||||||
|
print(result)
|
||||||
|
return int(result, 2)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
print('Part 1:',part1(), '\t\t', round((time.time() - start_time)*1000), 'ms')
|
||||||
|
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 2 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
def part2():
|
||||||
|
return
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
print('Part 2:',part2(), '\t\t', round((time.time() - start_time)*1000), 'ms')
|
Binary file not shown.
23
fred.py
23
fred.py
@ -653,6 +653,29 @@ def bfs(start, is_goal, get_neighbors, max_depth=float('inf')):
|
|||||||
|
|
||||||
return goal_nodes, paths_to_goal
|
return goal_nodes, paths_to_goal
|
||||||
|
|
||||||
|
def dfs_graph(graph: dict, start) -> list:
|
||||||
|
"""
|
||||||
|
Perform a DFS starting from the given position in the graph.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
graph (dict): Dictionary representing the graph where keys are nodes (tuples) and values are lists of neighbors.
|
||||||
|
start: Starting node in the graph.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: List of visited nodes.
|
||||||
|
"""
|
||||||
|
visited = set()
|
||||||
|
|
||||||
|
def dfs_graph(node):
|
||||||
|
visited.add(node)
|
||||||
|
for neighbor in graph.get(node, []):
|
||||||
|
if neighbor not in visited:
|
||||||
|
dfs_graph(neighbor)
|
||||||
|
|
||||||
|
dfs_graph(start)
|
||||||
|
return list(visited)
|
||||||
|
|
||||||
|
|
||||||
def dfs(grid:list, pos:set) -> list:
|
def dfs(grid:list, pos:set) -> list:
|
||||||
"""
|
"""
|
||||||
Perform a flood fill/dfs starting from the given position in the grid.
|
Perform a flood fill/dfs starting from the given position in the grid.
|
||||||
|
Loading…
Reference in New Issue
Block a user