solve Day05 Part2 in Python
This commit is contained in:
parent
39280b7906
commit
53818e5bd2
@ -1,61 +1,67 @@
|
|||||||
import os
|
import os
|
||||||
import gc
|
import gc
|
||||||
|
from itertools import groupby
|
||||||
|
|
||||||
def free_up_memory():
|
def free_up_memory():
|
||||||
"""Explicitly frees up memory."""
|
"""Explicitly frees up memory."""
|
||||||
gc.collect()
|
gc.collect()
|
||||||
|
|
||||||
def parse_ranges(line):
|
def parse_input(file_path):
|
||||||
"""Parses a line containing seed ranges."""
|
"""Parses the input file into seeds and categories."""
|
||||||
numbers = list(map(int, line.split()))
|
with open(file_path) as file:
|
||||||
return [(numbers[i], numbers[i + 1]) for i in range(0, len(numbers), 2)]
|
lines = file.read().splitlines()
|
||||||
|
|
||||||
def map_single_seed_through_category(seed, category_map):
|
groups = [tuple(group) for not_empty, group in groupby(lines, bool) if not_empty]
|
||||||
"""Maps a single seed through a category based on the mapping."""
|
seeds, *categories = groups
|
||||||
print(f"map seed {seed} in category map")
|
seeds_ranges = tuple(map(int, seeds[0].split()[1:]))
|
||||||
for source_start, (dest_start, range_length) in category_map.items():
|
seeds_numbers = [
|
||||||
if source_start <= seed < source_start + range_length:
|
(seeds_ranges[i], seeds_ranges[i] + seeds_ranges[i + 1])
|
||||||
return dest_start + (seed - source_start)
|
for i in range(0, len(seeds_ranges), 2)
|
||||||
return seed
|
]
|
||||||
|
return seeds_numbers, categories
|
||||||
|
|
||||||
def process_category(file, ranges):
|
def process_categories(seeds_numbers, categories):
|
||||||
"""Processes seed ranges through a single category based on the file lines."""
|
"""Processes the seed ranges through all categories."""
|
||||||
category_map = {}
|
for category in categories:
|
||||||
for i, line in file:
|
ranges = [tuple(map(int, numbers.split())) for numbers in category[1:]]
|
||||||
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")
|
|
||||||
|
|
||||||
# Process each seed through the category map
|
sources = []
|
||||||
mapped_seeds = set()
|
while seeds_numbers:
|
||||||
for start, length in ranges:
|
start, end = seeds_numbers.pop()
|
||||||
print(f"process range {start} with length {length}")
|
for destination, source, length in ranges:
|
||||||
for i in range(length):
|
overlap_start = max(start, source)
|
||||||
seed = start + i
|
overlap_end = min(end, source + length)
|
||||||
mapped_seed = map_single_seed_through_category(seed, category_map)
|
if overlap_start < overlap_end:
|
||||||
mapped_seeds.add(mapped_seed)
|
sources.append(
|
||||||
|
(
|
||||||
return mapped_seeds
|
overlap_start - source + destination,
|
||||||
|
overlap_end - source + destination,
|
||||||
def process_file(file_path):
|
)
|
||||||
"""Processes the file to find the lowest location number for the seed ranges."""
|
)
|
||||||
try:
|
if overlap_start > start:
|
||||||
with open(file_path, 'r') as file:
|
seeds_numbers.append((start, overlap_start))
|
||||||
ranges = parse_ranges(file.readline().split(':')[1])
|
if end > overlap_end:
|
||||||
|
seeds_numbers.append((overlap_end, end))
|
||||||
while True:
|
|
||||||
line = file.readline()
|
|
||||||
if not line: # End of file
|
|
||||||
break
|
break
|
||||||
if ':' in line: # Start of a new category map
|
else:
|
||||||
ranges = {(seed, 1) for seed in process_category(file, ranges)}
|
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:
|
except FileNotFoundError:
|
||||||
print(f"Error: File '{file_path}' not found.")
|
print(f"Error: File '{file_path}' not found.")
|
||||||
@ -66,21 +72,16 @@ def test():
|
|||||||
"""Run tests using the test.txt file."""
|
"""Run tests using the test.txt file."""
|
||||||
print("Starting test")
|
print("Starting test")
|
||||||
expected_result = 46 # Updated expected result for the new puzzle
|
expected_result = 46 # Updated expected result for the new puzzle
|
||||||
result = process_file('../test.txt')
|
find_lowest_location('../test.txt', is_test=True, expected_result=expected_result)
|
||||||
assert result == expected_result, f"Test failed, expected 46 but got {result}"
|
|
||||||
print(f"Test passed: {result}")
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Main function to process the input file and display results."""
|
"""Main function to process the input file and display results."""
|
||||||
try:
|
try:
|
||||||
# Run tests first
|
|
||||||
test()
|
test()
|
||||||
free_up_memory() # Free memory after testing
|
free_up_memory() # Free memory after testing
|
||||||
|
|
||||||
# Process actual input
|
|
||||||
print("Starting input.txt")
|
print("Starting input.txt")
|
||||||
result = process_file("../input.txt")
|
find_lowest_location("../input.txt")
|
||||||
print(f"Total result from input.txt: {result}")
|
|
||||||
free_up_memory()
|
free_up_memory()
|
||||||
|
|
||||||
except Exception as e:
|
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.
|
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
|
## Structure
|
||||||
@ -16,13 +15,13 @@ Within each folder, you'll find:
|
|||||||
|
|
||||||
- `README.md`: A brief description of the day's problem.
|
- `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
|
- 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.
|
- Additional resources or notes if applicable.
|
||||||
|
|
||||||
## My Approach
|
## 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.
|
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.
|
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.
|
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) |
|
| 02 | ✅ | ✅ | [Day02 README](/Day02/README.md) |
|
||||||
| 03 | ✅ | ✅ | [Day03 README](/Day03/README.md) |
|
| 03 | ✅ | ✅ | [Day03 README](/Day03/README.md) |
|
||||||
| 04 | ✅ | ✅ | [Day04 README](/Day04/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) |
|
| 06 | ❓ | ❓ | [Day06 README](/Day06/README.md) |
|
||||||
| 07 | ❓ | ❓ | [Day07 README](/Day07/README.md) |
|
| 07 | ❓ | ❓ | [Day07 README](/Day07/README.md) |
|
||||||
| 08 | ❓ | ❓ | [Day08 README](/Day08/README.md) |
|
| 08 | ❓ | ❓ | [Day08 README](/Day08/README.md) |
|
||||||
|
Loading…
Reference in New Issue
Block a user