solve Day12 in python

This commit is contained in:
WieErWill 2023-12-12 19:35:31 +01:00
parent 5fe2e22a49
commit 28c7ce3b41
4 changed files with 131 additions and 11 deletions

View File

@ -72,3 +72,32 @@ In this example, the number of possible arrangements for each row is:
Adding all of the possible arrangement counts together produces a total of 21 arrangements.
For each row, count all of the different arrangements of operational and broken springs that meet the given criteria. What is the sum of those counts?
## Part Two
As you look out at the field of springs, you feel like there are way more springs than the condition records list. When you examine the records, you discover that they were actually folded up this whole time!
To unfold the records, on each row, replace the list of spring conditions with five copies of itself (separated by ?) and replace the list of contiguous groups of damaged springs with five copies of itself (separated by ,).
So, this row:
```
.# 1
```
Would become:
```
.#?.#?.#?.#?.# 1,1,1,1,1
```
The first line of the above example would become:
```
???.###????.###????.###????.###????.### 1,1,3,1,1,3,1,1,3,1,1,3,1,1,3
```
In the above example, after unfolding, the number of possible arrangements for some rows is now much larger:
- ???.### 1,1,3 - 1 arrangement
- .??..??...?##. 1,1,3 - 16384 arrangements
- ?#?#?#?#?#?#?#? 1,3,1,6 - 1 arrangement
- ????.#...#... 4,1,1 - 16 arrangements
- ????.######..#####. 1,6,5 - 2500 arrangements
- ?###???????? 3,2,1 - 506250 arrangements
After unfolding, adding all of the possible arrangement counts together produces 525152.
Unfold your condition records; what is the new sum of possible arrangement counts?

View File

@ -5,12 +5,13 @@ def parse_line(line):
try:
parts = line.strip().split()
states = parts[0]
group_sizes = [int(x) for x in parts[1].split(',')]
group_sizes = [int(x) for x in parts[1].split(",")]
return states, group_sizes
except Exception as e:
print(f"Error parsing line '{line}': {e}")
raise
def is_valid_configuration(states, group_sizes):
"""
Check if a given configuration of springs is valid based on group sizes.
@ -18,12 +19,12 @@ def is_valid_configuration(states, group_sizes):
try:
i, size_index = 0, 0
while i < len(states):
if states[i] == '#':
if states[i] == "#":
if size_index >= len(group_sizes):
return False # More broken springs than groups
count = 0
while i < len(states) and states[i] == '#':
while i < len(states) and states[i] == "#":
count += 1
i += 1
@ -38,6 +39,7 @@ def is_valid_configuration(states, group_sizes):
print(f"Error in is_valid_configuration: {e}")
raise
def count_configurations(states, group_sizes, index=0, memo=None):
"""
Count the number of valid configurations using backtracking and memoization.
@ -53,26 +55,27 @@ def count_configurations(states, group_sizes, index=0, memo=None):
memo[key] = 1 if is_valid_configuration(states, group_sizes) else 0
return memo[key]
if states[index] != '?':
if states[index] != "?":
memo[key] = count_configurations(states, group_sizes, index + 1, memo)
return memo[key]
count = 0
for state in ['.', '#']:
for state in [".", "#"]:
states[index] = state
count += count_configurations(states, group_sizes, index + 1, memo)
states[index] = '?'
states[index] = "?"
memo[key] = count
return count
def solve_puzzle(file_path):
"""
Solve the puzzle for each line in the file and return the total count of configurations.
"""
try:
total_count = 0
with open(file_path, 'r') as file:
with open(file_path, "r") as file:
for line in file:
states, group_sizes = parse_line(line)
count = count_configurations(list(states), group_sizes)
@ -83,6 +86,7 @@ def solve_puzzle(file_path):
print(f"Error in solve_puzzle: {e}")
raise
def test():
"""
Test the solution with a test file.
@ -93,6 +97,7 @@ def test():
assert test_result == 21, f"Test failed, expected 21, got {test_result}"
print("Test passed successfully.")
def main():
"""
Main function to run the test and then solve the puzzle.
@ -105,5 +110,6 @@ def main():
print(f"Error in main: {e}")
raise
if __name__ == "__main__":
main()

85
Day12/python/solution2.py Normal file
View File

@ -0,0 +1,85 @@
import sys
def read_data(filepath):
"""Reads the data from the given file."""
try:
with open(filepath, "r") as file:
return file.read().strip().split("\n")
except IOError as e:
print(f"Error reading file '{filepath}': {e}")
sys.exit(1)
def unfold_record(record):
"""Unfolds the record according to the puzzle rules."""
dots, blocks = record.split()
dots = "?".join([dots] * 5)
blocks = ",".join([blocks] * 5)
return dots, [int(x) for x in blocks.split(",")]
def count_arrangements(dots, blocks, i=0, bi=0, current=0, memo=None):
"""Counts valid arrangements using dynamic programming."""
if memo is None:
memo = {}
key = (i, bi, current)
if key in memo:
return memo[key]
if i == len(dots):
if bi == len(blocks) and current == 0:
return 1
elif bi == len(blocks) - 1 and blocks[bi] == current:
return 1
else:
return 0
ans = 0
for c in [".", "#"]:
if dots[i] == c or dots[i] == "?":
if c == ".":
if current == 0:
ans += count_arrangements(dots, blocks, i + 1, bi, 0, memo)
elif current > 0 and bi < len(blocks) and blocks[bi] == current:
ans += count_arrangements(dots, blocks, i + 1, bi + 1, 0, memo)
elif c == "#":
ans += count_arrangements(dots, blocks, i + 1, bi, current + 1, memo)
memo[key] = ans
return ans
def solve_puzzle(lines):
"""Solves the puzzle for the given input lines."""
total = 0
for line in lines:
print(f"Processing: {line}")
dots, blocks = unfold_record(line)
total += count_arrangements(dots, blocks)
return total
def test_puzzle():
"""Runs the puzzle solution on test data."""
test_data = read_data("../test.txt")
print("Running tests...")
test_result = solve_puzzle(test_data)
print(f"Test result: {test_result}")
assert test_result == 525152, "Test failed!"
print("Test passed.")
def main():
"""Main function to run the puzzle solution."""
test_puzzle()
input_data = read_data("../input.txt")
print("Processing input data...")
result = solve_puzzle(input_data)
print(f"Final result: {result}")
if __name__ == "__main__":
main()

View File

@ -3,8 +3,8 @@
<div><img src="title_image.png" style="margin: 0 auto;" height="300" width="300" ></div>
![Build Status](https://github.com/wieerwill/advent_of_code_2023/actions/workflows/lint.yml/badge.svg)
![Completed](https://img.shields.io/badge/days%20completed-11-red)
![Stars](https://img.shields.io/badge/stars%20⭐-22-yellow)
![Completed](https://img.shields.io/badge/days%20completed-12-red)
![Stars](https://img.shields.io/badge/stars%20⭐-24-yellow)
![License](https://img.shields.io/github/license/wieerwill/advent_of_code_2023.svg)
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.
@ -39,13 +39,13 @@ I aim to complete each day's puzzle on the same day, but as with any challenge,
| 03 | ✅ | ✅ | [Day03 README](/Day03/README.md) |
| 04 | ✅ | ✅ | [Day04 README](/Day04/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) |
| 08 | ✅ | ✅ | [Day08 README](/Day08/README.md) |
| 09 | ✅ | ✅ | [Day09 README](/Day09/README.md) |
| 10 | ✅ | ✅ | [Day10 README](/Day10/README.md) |
| 11 | ✅ | ✅ | [Day11 README](/Day11/README.md) |
| 12 | ✅ | | [Day12 README](/Day12/README.md) |
| 12 | ✅ | | [Day12 README](/Day12/README.md) |
| 13 | ❓ | ❓ | [Day13 README](/Day13/README.md) |
| 14 | ❓ | ❓ | [Day14 README](/Day14/README.md) |
| 15 | ❓ | ❓ | [Day15 README](/Day15/README.md) |