Skip to content
Snippets Groups Projects
Verified Commit 0e9fa0fd authored by Christopher Bohn's avatar Christopher Bohn :thinking:
Browse files

2023 Day 5

parent 8c738249
No related branches found
No related tags found
No related merge requests found
from typing import List, Dict, Tuple, Optional, Set
from ImportData import import_data
day: int = 5
sample_data: List[str] = '''
seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4
'''.split('\n')[1:-1]
class AlmanacMap:
almanac_maps: Dict[Tuple[str, str], List["AlmanacMap"]] = {}
def __init__(self, source_category: str, destination_category: str,
source_start: int, destination_start: int, range_length: int):
self.source_category: str = source_category
self.destination_category: str = destination_category
# self.sources: List[int] = [i for i in range(source_start, source_start + range_length)]
# self.destinations: List[int] = [i for i in range(destination_start, destination_start + range_length)]
self.source_start = source_start
self.destination_start = destination_start
self.range_length = range_length
if (source_category, destination_category) not in AlmanacMap.almanac_maps:
AlmanacMap.almanac_maps[(source_category, destination_category)] = []
AlmanacMap.almanac_maps[(source_category, destination_category)].append(self)
@staticmethod
def map(source_category: str, destination_category: str, source: int) -> int:
destination: Optional[int] = None
for almanacMap in AlmanacMap.almanac_maps[(source_category, destination_category)]:
# if source in almanacMap.sources:
# destination = almanacMap.destinations[almanacMap.sources.index(source)]
if almanacMap.source_start <= source < almanacMap.source_start + almanacMap.range_length:
destination = almanacMap.destination_start + (source - almanacMap.source_start)
return source if destination is None else destination
data_structure: type = Tuple[List[int], Dict[str, List[AlmanacMap]]]
def parse_data(data: List[str]) -> data_structure:
mappings: Dict[str, List[AlmanacMap]] = {}
assert data[0].split(':')[0] == 'seeds'
seeds: List[int] = [int(number) for number in data[0].split(':')[1].strip().split()]
map_name: Optional[str] = None
for row in data[2:]:
if not row:
map_name = None
elif row[-4:] == 'map:':
map_name = row[:-5]
mappings[map_name] = []
else:
mappings[map_name].append(AlmanacMap(map_name.split('-')[0], map_name.split('-')[2],
int(row.split()[1]), int(row.split()[0]), int(row.split()[2])))
return seeds, mappings
def part1(data: data_structure) -> int:
nearest_location: Optional[int] = None
seeds: List[int] = data[0]
for seed in seeds:
soil: int = AlmanacMap.map('seed', 'soil', seed)
fertilizer: int = AlmanacMap.map('soil', 'fertilizer', soil)
water: int = AlmanacMap.map('fertilizer', 'water', fertilizer)
light: int = AlmanacMap.map('water', 'light', water)
temperature: int = AlmanacMap.map('light', 'temperature', light)
humidity: int = AlmanacMap.map('temperature', 'humidity', temperature)
location: int = AlmanacMap.map('humidity', 'location', humidity)
if nearest_location is None or location < nearest_location:
nearest_location = location
return nearest_location
def reverse_map(destination: Optional[int], source_name: str, destination_name: str) -> Optional[int]:
if destination is None:
return None
source: Optional[int] = None
almanac_maps = AlmanacMap.almanac_maps[(source_name, destination_name)]
for almanac_map in almanac_maps:
if almanac_map.destination_start <= destination <= almanac_map.destination_start + almanac_map.range_length:
source = almanac_map.source_start + (destination - almanac_map.destination_start)
if source is None:
direct_map = True
for almanac_map in almanac_maps:
if almanac_map.source_start <= destination <= almanac_map.source_start + almanac_map.range_length:
direct_map = False
if direct_map:
source = destination
return source
def validate_seed(seed: int, seeds: List[int]) -> Optional[int]:
seed_exists = False
for i in range(0, len(seeds), 2):
if seeds[i] <= seed <= seeds[i] + seeds[i + 1]:
seed_exists = True
return seed if seed_exists else None
def part2(data: data_structure) -> int:
location: int = -1
seed: Optional[int] = None
seeds: List[int] = data[0]
while seed is None:
location += 1
humidity = reverse_map(location, 'humidity', 'location')
temperature = reverse_map(humidity, 'temperature', 'humidity')
light = reverse_map(temperature, 'light', 'temperature')
water = reverse_map(light, 'water', 'light')
fertilizer = reverse_map(water, 'fertilizer', 'water')
soil = reverse_map(fertilizer, 'soil', 'fertilizer')
seed = validate_seed(reverse_map(soil, 'seed', 'soil'), seeds)
return location
if __name__ == '__main__':
production_ready = True
raw_data = import_data(day) if production_ready else sample_data
print(part1(parse_data(raw_data)))
print(part2(parse_data(raw_data)))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment