71 lines
2.1 KiB
Python
71 lines
2.1 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
import copy
|
||
|
|
import sys
|
||
|
|
from typing import Sequence
|
||
|
|
|
||
|
|
|
||
|
|
def part1(lines: Sequence[int], bits=12):
|
||
|
|
gamma = 0
|
||
|
|
epsilon = 0
|
||
|
|
for bit in range(bits):
|
||
|
|
mask = 1 << (bits - bit - 1)
|
||
|
|
ones = 0
|
||
|
|
for line in lines:
|
||
|
|
if mask & line:
|
||
|
|
ones += 1
|
||
|
|
zeroes = len(lines) - ones
|
||
|
|
if ones > zeroes:
|
||
|
|
gamma |= mask
|
||
|
|
else:
|
||
|
|
epsilon |= mask
|
||
|
|
# Fun thing - epsilon rate is just the inversion of the gamma rate.
|
||
|
|
# However, python doesn't seem to support signed inversion so we just calculate it above. boo
|
||
|
|
print(f"gamma: {gamma} {bin(gamma)}")
|
||
|
|
print(f"epsilon: {epsilon} {bin(epsilon)}")
|
||
|
|
print(f"product: {gamma * epsilon}")
|
||
|
|
|
||
|
|
|
||
|
|
def part2(lines: Sequence[int], bits=12):
|
||
|
|
oxygen = copy.deepcopy(lines)
|
||
|
|
carbon = copy.deepcopy(lines)
|
||
|
|
for bit in range(bits):
|
||
|
|
# Find the most common bit
|
||
|
|
if len(oxygen) > 1:
|
||
|
|
mask = 1 << (bits - bit - 1)
|
||
|
|
ones = 0
|
||
|
|
for line in oxygen:
|
||
|
|
if mask & line:
|
||
|
|
ones += 1
|
||
|
|
zeroes = len(oxygen) - ones
|
||
|
|
if ones >= zeroes:
|
||
|
|
# Filter out oxygen numbers that don't have a 1 in this position
|
||
|
|
oxygen = [line for line in oxygen if line & mask]
|
||
|
|
else:
|
||
|
|
oxygen = [line for line in oxygen if not (line & mask)]
|
||
|
|
|
||
|
|
# Now do this on the carbon array
|
||
|
|
if len(carbon) > 1:
|
||
|
|
ones = 0
|
||
|
|
for line in carbon:
|
||
|
|
if mask & line:
|
||
|
|
ones += 1
|
||
|
|
zeroes = len(carbon) - ones
|
||
|
|
if ones >= zeroes:
|
||
|
|
# Keep the *least* common
|
||
|
|
carbon = [line for line in carbon if not (line & mask)]
|
||
|
|
else:
|
||
|
|
carbon = [line for line in carbon if line & mask]
|
||
|
|
oxygen, = oxygen
|
||
|
|
carbon, = carbon
|
||
|
|
print(f"Oxygen: {oxygen}")
|
||
|
|
print(f"Carbon: {carbon}")
|
||
|
|
print(f"Product: {oxygen * carbon}")
|
||
|
|
|
||
|
|
|
||
|
|
lines = [int(line, 2) for line in sys.stdin]
|
||
|
|
|
||
|
|
print("Part 1")
|
||
|
|
part1(lines)
|
||
|
|
print("Part 2")
|
||
|
|
part2(lines)
|