solve Day05 Part2 in Python
This commit is contained in:
parent
39280b7906
commit
53818e5bd2
@ -1,61 +1,67 @@
|
||||
import os
|
||||
import gc
|
||||
from itertools import groupby
|
||||
|
||||
def free_up_memory():
|
||||
"""Explicitly frees up memory."""
|
||||
gc.collect()
|
||||
|
||||
def parse_ranges(line):
|
||||
"""Parses a line containing seed ranges."""
|
||||
numbers = list(map(int, line.split()))
|
||||
return [(numbers[i], numbers[i + 1]) for i in range(0, len(numbers), 2)]
|
||||
def parse_input(file_path):
|
||||
"""Parses the input file into seeds and categories."""
|
||||
with open(file_path) as file:
|
||||
lines = file.read().splitlines()
|
||||
|
||||
def map_single_seed_through_category(seed, category_map):
|
||||
"""Maps a single seed through a category based on the mapping."""
|
||||
print(f"map seed {seed} in category map")
|
||||
for source_start, (dest_start, range_length) in category_map.items():
|
||||
if source_start <= seed < source_start + range_length:
|
||||
return dest_start + (seed - source_start)
|
||||
return seed
|
||||
groups = [tuple(group) for not_empty, group in groupby(lines, bool) if not_empty]
|
||||
seeds, *categories = groups
|
||||
seeds_ranges = tuple(map(int, seeds[0].split()[1:]))
|
||||
seeds_numbers = [
|
||||
(seeds_ranges[i], seeds_ranges[i] + seeds_ranges[i + 1])
|
||||
for i in range(0, len(seeds_ranges), 2)
|
||||
]
|
||||
return seeds_numbers, categories
|
||||
|
||||
def process_category(file, ranges):
|
||||
"""Processes seed ranges through a single category based on the file lines."""
|
||||
category_map = {}
|
||||
for i, line in file:
|
||||
line = line.strip()
|
||||
if not line or ':' in line: # End of the current category map
|
||||
break
|
||||
dest_start, source_start, range_length = map(int, line.split())
|
||||
category_map[source_start] = (dest_start, range_length)
|
||||
print(f"parsed line {i} in file")
|
||||
def process_categories(seeds_numbers, categories):
|
||||
"""Processes the seed ranges through all categories."""
|
||||
for category in categories:
|
||||
ranges = [tuple(map(int, numbers.split())) for numbers in category[1:]]
|
||||
|
||||
# Process each seed through the category map
|
||||
mapped_seeds = set()
|
||||
for start, length in ranges:
|
||||
print(f"process range {start} with length {length}")
|
||||
for i in range(length):
|
||||
seed = start + i
|
||||
mapped_seed = map_single_seed_through_category(seed, category_map)
|
||||
mapped_seeds.add(mapped_seed)
|
||||
|
||||
return mapped_seeds
|
||||
|
||||
def process_file(file_path):
|
||||
"""Processes the file to find the lowest location number for the seed ranges."""
|
||||
try:
|
||||
with open(file_path, 'r') as file:
|
||||
ranges = parse_ranges(file.readline().split(':')[1])
|
||||
|
||||
while True:
|
||||
line = file.readline()
|
||||
if not line: # End of file
|
||||
sources = []
|
||||
while seeds_numbers:
|
||||
start, end = seeds_numbers.pop()
|
||||
for destination, source, length in ranges:
|
||||
overlap_start = max(start, source)
|
||||
overlap_end = min(end, source + length)
|
||||
if overlap_start < overlap_end:
|
||||
sources.append(
|
||||
(
|
||||
overlap_start - source + destination,
|
||||
overlap_end - source + destination,
|
||||
)
|
||||
)
|
||||
if overlap_start > start:
|
||||
seeds_numbers.append((start, overlap_start))
|
||||
if end > overlap_end:
|
||||
seeds_numbers.append((overlap_end, end))
|
||||
break
|
||||
if ':' in line: # Start of a new category map
|
||||
ranges = {(seed, 1) for seed in process_category(file, ranges)}
|
||||
else:
|
||||
sources.append((start, end))
|
||||
|
||||
lowest_location = min(ranges)[0]
|
||||
seeds_numbers = sources
|
||||
return seeds_numbers
|
||||
|
||||
return lowest_location
|
||||
def find_lowest_location(file_path, is_test=False, expected_result=None):
|
||||
"""Finds the lowest location number from the input file."""
|
||||
try:
|
||||
seeds_numbers, categories = parse_input(file_path)
|
||||
seeds_numbers = process_categories(seeds_numbers, categories)
|
||||
lowest_location = min(seeds_numbers)[0]
|
||||
|
||||
if is_test:
|
||||
assert lowest_location == expected_result, f"Test failed, expected {expected_result} but got {lowest_location}"
|
||||
print("Test passed.")
|
||||
else:
|
||||
print(f"Lowest location from {file_path}: {lowest_location}")
|
||||
return lowest_location
|
||||
|
||||
except FileNotFoundError:
|
||||
print(f"Error: File '{file_path}' not found.")
|
||||
@ -66,21 +72,16 @@ def test():
|
||||
"""Run tests using the test.txt file."""
|
||||
print("Starting test")
|
||||
expected_result = 46 # Updated expected result for the new puzzle
|
||||
result = process_file('../test.txt')
|
||||
assert result == expected_result, f"Test failed, expected 46 but got {result}"
|
||||
print(f"Test passed: {result}")
|
||||
find_lowest_location('../test.txt', is_test=True, expected_result=expected_result)
|
||||
|
||||
def main():
|
||||
"""Main function to process the input file and display results."""
|
||||
try:
|
||||
# Run tests first
|
||||
test()
|
||||
free_up_memory() # Free memory after testing
|
||||
|
||||
# Process actual input
|
||||
print("Starting input.txt")
|
||||
result = process_file("../input.txt")
|
||||
print(f"Total result from input.txt: {result}")
|
||||
find_lowest_location("../input.txt")
|
||||
free_up_memory()
|
||||
|
||||
except Exception as e:
|
||||
|
@ -1,6 +1,5 @@
|
||||
# Advent of Code 2023
|
||||
# 🎄 Advent of Code 2023 🎄
|
||||
|
||||
## Overview
|
||||
Welcome to my repository where I share my solutions for the [Advent of Code 2023](https://adventofcode.com/2023). Advent of Code is an annual online event where participants solve a series of programming puzzles released daily from December 1st until December 25th. Each puzzle is a fun and unique challenge designed to test problem-solving skills.
|
||||
|
||||
## Structure
|
||||
@ -16,13 +15,13 @@ Within each folder, you'll find:
|
||||
|
||||
- `README.md`: A brief description of the day's problem.
|
||||
- Source code files: My solution for the day's puzzle, typically in Python or Rust
|
||||
- `input.txt`: The input data provided for the puzzle.
|
||||
- `input.txt`: The input data provided for the puzzle. (add those yourself as we don't provide those for legal reasons)
|
||||
- Additional resources or notes if applicable.
|
||||
|
||||
## My Approach
|
||||
For Advent of Code 2023, I've decided to primarily use Python due to its readability and the extensive libraries available, which make it an excellent choice for solving diverse and complex problems quickly. In each solution, I focus not only on solving the problem but also on writing clean, efficient, and well-documented code.
|
||||
|
||||
## Progress
|
||||
## 📈 Progress
|
||||
Here I'll track my progress throughout the event.
|
||||
I aim to complete each day's puzzle on the same day, but as with any challenge, there might be some delays.
|
||||
|
||||
@ -32,7 +31,7 @@ I aim to complete each day's puzzle on the same day, but as with any challenge,
|
||||
| 02 | ✅ | ✅ | [Day02 README](/Day02/README.md) |
|
||||
| 03 | ✅ | ✅ | [Day03 README](/Day03/README.md) |
|
||||
| 04 | ✅ | ✅ | [Day04 README](/Day04/README.md) |
|
||||
| 05 | ✅ | ❓ | [Day05 README](/Day05/README.md) |
|
||||
| 05 | ✅ | ✅ | [Day05 README](/Day05/README.md) |
|
||||
| 06 | ❓ | ❓ | [Day06 README](/Day06/README.md) |
|
||||
| 07 | ❓ | ❓ | [Day07 README](/Day07/README.md) |
|
||||
| 08 | ❓ | ❓ | [Day08 README](/Day08/README.md) |
|
||||
|
Loading…
Reference in New Issue
Block a user