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
|
||||
reduce these to a list of only `16` numbers called the *dense hash*. To
|
||||
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
|
||||
`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
|
||||
|
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
|
||||
|
||||
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:
|
||||
"""
|
||||
Perform a flood fill/dfs starting from the given position in the grid.
|
||||
|
Loading…
Reference in New Issue
Block a user