Add 2021-03 in Python

Signed-off-by: AKU <tom@tdpain.net>
This commit is contained in:
akp 2021-12-03 14:27:39 +00:00
parent e6847a3fdc
commit 020cf34fa2
No known key found for this signature in database
GPG key ID: AA5726202C8879B7
4 changed files with 122 additions and 4 deletions

View file

@ -0,0 +1,2 @@
# [Day 3: Binary Diagnostic](https://adventofcode.com/2021/day/3)

View file

@ -0,0 +1,17 @@
{
"inputFile": "input.txt",
"testCases": {
"one": [
{
"input": "00100\n11110\n10110\n10111\n10101\n01111\n00111\n11100\n10000\n11001\n00010\n01010\n",
"expected": "198"
}
],
"two": [
{
"input": "00100\n11110\n10110\n10111\n10101\n01111\n00111\n11100\n10000\n11001\n00010\n01010\n",
"expected": "230"
}
]
}
}

View file

@ -0,0 +1,98 @@
from typing import List, Tuple
from aocpy import BaseChallenge
def parse(instr: str) -> Tuple[List[int], int]:
# parse returns a list of integers and the original length of the first of
# those integers in the binary representation in the input.
y = instr.strip().splitlines()
return [int(x, base=2) for x in y], len(y[0])
def get_bit(number: int, n: int) -> int:
# get_bit returns a given bit from the binary representation of `number`.
#
# In the number 111001011110, n=4 would refer to this bit:
# ^
return (number >> n) & 0b1
def analyse_bits(numbers: List[int], n: int) -> Tuple[int, int]:
# analyse_bits returns a tuple containing the most common bit (either 1 or
# 0) and the least common bit (either 1 or 0) in position `n` of each
# number in `numbers`.
#
# If the most common bit and least common bit occur the same amount of
# times, both return values are -1.
#
# Returns: most common bit, least common bit
zeros = 0
ones = 0
for number in numbers:
sel = get_bit(number, n)
if sel == 0:
zeros += 1
elif sel == 1:
ones += 1
if zeros > ones:
return 0, 1
elif ones > zeros:
return 1, 0
return -1, -1
class Challenge(BaseChallenge):
@staticmethod
def one(instr: str) -> int:
numbers, bit_length = parse(instr)
gamma = ""
epsilon = ""
for bit_number in reversed(range(bit_length)):
most_common, least_common = analyse_bits(numbers, bit_number)
gamma += str(most_common)
epsilon += str(least_common)
return int(gamma, 2) * int(epsilon, 2)
@staticmethod
def two(instr: str) -> int:
numbers, bit_length = parse(instr)
def find(inp: List[int], use_most_common: bool, n: int = bit_length-1) -> int:
# find implements the bit criteria-based filtering as defined in
# AoC 2021 day 3 part 2. If `use_most_common` is True, the bit
# criteria for the oxygen generator rating is used, else, the bit
# criteria for the CO2 scrubber rating is used.
if len(inp) == 1:
return inp[0]
most_common, least_common = analyse_bits(inp, n)
target = None
if most_common == -1 or least_common == -1:
target = 1 if use_most_common else 0
else:
target = most_common if use_most_common else least_common
# oooo, accidental tail recursion!
return find(
list(filter(
lambda x: get_bit(x, n) == target,
inp,
)),
use_most_common,
n - 1,
)
o2_rating = find(numbers, True)
co2_rating = find(numbers, False)
return o2_rating * co2_rating

View file

@ -8,9 +8,10 @@ Solutions to the [2021 Advent of Code](https://adventofcode.com/2021).
<!-- PARSE START -->
| Day | Status | Solutions | Notes |
| ----------------------------------- | ------------------ | ---------------------------------------------------------------------------- | -------------------- |
| 01 - Sonar Sweep | Complete | [Python](01-sonarSweep/py), [Go](01-sonarSweep/go), [Nim](01-sonarSweep/nim) | |
| 02 - Dive! | Complete | [Python](02-dive/py), [Go](02-dive/go) | |
| Day | Status | Solutions | Notes |
| ----------------------------------- | ------------------ | ---------------------------------------------------------------------------- | ---------------------------- |
| 01 - Sonar Sweep | Complete | [Python](01-sonarSweep/py), [Go](01-sonarSweep/go), [Nim](01-sonarSweep/nim) | |
| 02 - Dive! | Complete | [Python](02-dive/py), [Go](02-dive/go) | |
| 02 - Binary Diagnostic | Complete | [Python](03-binaryDiagnostic/py) | Bit twiddling, my favourite! |
<!-- PARSE END -->