From 53818e5bd2ab048e052fefee69ada60fd41d87f9 Mon Sep 17 00:00:00 2001 From: wieerwill Date: Wed, 6 Dec 2023 19:08:52 +0100 Subject: [PATCH] solve Day05 Part2 in Python --- Day05/python/solution2.py | 105 +++++++++++++++++++------------------- README.md | 9 ++-- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/Day05/python/solution2.py b/Day05/python/solution2.py index 0fbfafb..604b62e 100644 --- a/Day05/python/solution2.py +++ b/Day05/python/solution2.py @@ -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: diff --git a/README.md b/README.md index 85636b7..fae3f10 100644 --- a/README.md +++ b/README.md @@ -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) |