prettify and lint optimization

This commit is contained in:
WieErWill 2023-12-10 17:24:14 +01:00
parent 274c69d0c4
commit 4cd62ef794
32 changed files with 599 additions and 262 deletions

1
.gitignore vendored
View File

@ -341,3 +341,4 @@ dist
solution solution
helper.md helper.md
*/input.txt */input.txt
Linting.md

View File

@ -2,28 +2,15 @@
## Day01 ## Day01
| Language | Status | Real Time | User Time | Sys Time | | Language | Status | Real Time | User Time | Sys Time |
| ---------- | ------- | --------- | --------- | -------- | | --- | --- | --- | --- | --- |
| Python | Success | 0m0,090s | 0m0,073s | 0m0,017s | | Python | Success | 0m0,090s | 0m0,065s | 0m0,025s |
| Rust | Success | 0m0,057s | 0m0,049s | 0m0,008s | | Rust | Success | 0m0,111s | 0m0,062s | 0m0,048s |
| JavaScript | Success | 0m0,080s | 0m0,068s | 0m0,020s | | JavaScript | Success | 0m0,079s | 0m0,073s | 0m0,013s |
| TypeScript | Failed | - | - | - | | TypeScript | Success | 0m1,300s | 0m2,668s | 0m0,201s |
## Day02 ## Day02
| Language | Status | Real Time | User Time | Sys Time | | Language | Status | Real Time | User Time | Sys Time |
| ---------- | ------- | --------- | --------- | -------- | | --- | --- | --- | --- | --- |
| Python | Success | 0m0,047s | 0m0,039s | 0m0,008s | | Python | Success | 0m0,048s | 0m0,033s | 0m0,012s |
| Rust | Success | 0m0,059s | 0m0,032s | 0m0,028s | | Rust | Success | 0m0,097s | 0m0,062s | 0m0,035s |
| JavaScript | Success | 0m0,046s | 0m0,031s | 0m0,015s | | JavaScript | Success | 0m0,045s | 0m0,041s | 0m0,004s |
| TypeScript | Failed | - | - | - |
## Day03
| Language | Status | Real Time | User Time | Sys Time |
| ---------- | ------- | --------- | --------- | -------- |
| Python | Success | 0m0,042s | 0m0,033s | 0m0,008s |
| Rust | Success | 0m0,066s | 0m0,054s | 0m0,012s |
| JavaScript | Success | 0m0,076s | 0m0,061s | 0m0,016s |
| TypeScript | Failed | - | - | - |
## Day04
| Language | Status | Real Time | User Time | Sys Time |
| -------- | ------ | --------- | --------- | -------- |

View File

@ -27,6 +27,7 @@ def extract_calibration_value(line):
else: else:
return 0 return 0
def sum_calibration_values(filename): def sum_calibration_values(filename):
""" """
Calculate the sum of all calibration values in the document. Calculate the sum of all calibration values in the document.
@ -37,12 +38,13 @@ def sum_calibration_values(filename):
total = 0 total = 0
# Open the file and process each line # Open the file and process each line
with open(filename, 'r') as file: with open(filename, "r") as file:
for line in file: for line in file:
total += extract_calibration_value(line) total += extract_calibration_value(line)
return total return total
# Main execution # Main execution
if __name__ == "__main__": if __name__ == "__main__":
filename = "../input.txt" filename = "../input.txt"

View File

@ -1,8 +1,16 @@
def extract_digits(line): def extract_digits(line):
"""Extracts all digits (as numbers) from the line in the order they appear.""" """Extracts all digits (as numbers) from the line in the order they appear."""
digit_map = { digit_map = {
"zero": "0", "one": "1", "two": "2", "three": "3", "four": "4", "zero": "0",
"five": "5", "six": "6", "seven": "7", "eight": "8", "nine": "9" "one": "1",
"two": "2",
"three": "3",
"four": "4",
"five": "5",
"six": "6",
"seven": "7",
"eight": "8",
"nine": "9",
} }
# Add single digit mappings # Add single digit mappings
@ -11,17 +19,15 @@ def extract_digits(line):
digits_found = [] digits_found = []
i = 0 i = 0
while i < len(line): while i < len(line):
matched = False
for word, digit in digit_map.items(): for word, digit in digit_map.items():
if line.startswith(word, i): if line.startswith(word, i):
digits_found.append(int(digit)) digits_found.append(int(digit))
i += len(word) - 1 # Advance the index i += len(word) - 1 # Advance the index
matched = True
break break
i += 1 # Move to the next character if no match i += 1 # Move to the next character if no match
return digits_found return digits_found
def extract_calibration_value(line): def extract_calibration_value(line):
"""Extracts the calibration value from a line.""" """Extracts the calibration value from a line."""
digits = extract_digits(line) digits = extract_digits(line)
@ -29,10 +35,11 @@ def extract_calibration_value(line):
return int(str(digits[0]) + str(digits[-1])) return int(str(digits[0]) + str(digits[-1]))
return 0 return 0
def sum_calibration_values(file_path): def sum_calibration_values(file_path):
"""Extracts calibration values from each line and sums them up.""" """Extracts calibration values from each line and sums them up."""
total_sum = 0 total_sum = 0
with open(file_path, 'r') as file: with open(file_path, "r") as file:
for line in file: for line in file:
calibration_value = extract_calibration_value(line.strip()) calibration_value = extract_calibration_value(line.strip())
if calibration_value: if calibration_value:
@ -44,9 +51,11 @@ def sum_calibration_values(file_path):
return total_sum return total_sum
# Main execution # Main execution
if __name__ == "__main__": if __name__ == "__main__":
import sys import sys
filename = sys.argv[1] if len(sys.argv) > 1 else "../input.txt" filename = sys.argv[1] if len(sys.argv) > 1 else "../input.txt"
total_calibration_value = sum_calibration_values(filename) total_calibration_value = sum_calibration_values(filename)
print(f"Total Sum of Calibration Values: {total_calibration_value}") print(f"Total Sum of Calibration Values: {total_calibration_value}")

View File

@ -7,13 +7,12 @@ fn main() {
match read_lines(path) { match read_lines(path) {
Ok(lines) => { Ok(lines) => {
let mut total = 0; let mut total = 0;
for line in lines { // Using flatten to directly iterate over Ok values
if let Ok(ip) = line { for ip in lines.flatten() {
let value = extract_calibration_value(&ip); let value = extract_calibration_value(&ip);
println!("Line: '{}', Calibration Value: {}", ip, value); println!("Line: '{}', Calibration Value: {}", ip, value);
total += value; total += value;
} }
}
println!("Total Calibration Value: {}", total); println!("Total Calibration Value: {}", total);
} }
Err(e) => println!("Error: {}", e), Err(e) => println!("Error: {}", e),
@ -39,18 +38,24 @@ fn extract_calibration_value(line: &str) -> u32 {
fn extract_digits(line: &str) -> Vec<u32> { fn extract_digits(line: &str) -> Vec<u32> {
let digit_map = vec![ let digit_map = vec![
("zero", 0), ("one", 1), ("two", 2), ("three", 3), ("four", 4), ("zero", 0),
("five", 5), ("six", 6), ("seven", 7), ("eight", 8), ("nine", 9), ("one", 1),
("two", 2),
("three", 3),
("four", 4),
("five", 5),
("six", 6),
("seven", 7),
("eight", 8),
("nine", 9),
]; ];
let mut digits = Vec::new(); let mut digits = Vec::new();
let mut current_line = line.to_string(); let mut current_line = line.to_string();
// Iterate over each character in the line
while !current_line.is_empty() { while !current_line.is_empty() {
let mut found = false; let mut found = false;
// Check for word representations of digits
for (word, digit) in &digit_map { for (word, digit) in &digit_map {
if current_line.starts_with(word) { if current_line.starts_with(word) {
digits.push(*digit); digits.push(*digit);
@ -60,7 +65,6 @@ fn extract_digits(line: &str) -> Vec<u32> {
} }
} }
// Check for single digit characters
if !found { if !found {
if let Some(first_char) = current_line.chars().next() { if let Some(first_char) = current_line.chars().next() {
if let Some(digit) = first_char.to_digit(10) { if let Some(digit) = first_char.to_digit(10) {
@ -91,7 +95,12 @@ mod tests {
]; ];
for (input, expected) in test_cases { for (input, expected) in test_cases {
assert_eq!(extract_calibration_value(input), expected, "Failed on input: {}", input); assert_eq!(
extract_calibration_value(input),
expected,
"Failed on input: {}",
input
);
} }
} }
} }

View File

@ -8,20 +8,23 @@ def parse_game_data(line):
Returns: Returns:
int, dict: Game ID and a dictionary with color counts. int, dict: Game ID and a dictionary with color counts.
""" """
parts = line.split(': ') parts = line.split(": ")
game_id = int(parts[0].split(' ')[1]) game_id = int(parts[0].split(" ")[1])
color_counts = {'red': 0, 'green': 0, 'blue': 0} color_counts = {"red": 0, "green": 0, "blue": 0}
subsets = parts[1].split('; ') subsets = parts[1].split("; ")
for subset in subsets: for subset in subsets:
colors = subset.split(', ') colors = subset.split(", ")
for color in colors: for color in colors:
count, color_name = color.split(' ') count, color_name = color.split(" ")
color_name = color_name.strip() # Remove any trailing whitespace or newline characters color_name = (
color_name.strip()
) # Remove any trailing whitespace or newline characters
color_counts[color_name] = max(color_counts[color_name], int(count)) color_counts[color_name] = max(color_counts[color_name], int(count))
return game_id, color_counts return game_id, color_counts
def is_game_possible(game_data, red_cubes, green_cubes, blue_cubes): def is_game_possible(game_data, red_cubes, green_cubes, blue_cubes):
""" """
Determines if a game is possible given the number of each color of cubes. Determines if a game is possible given the number of each color of cubes.
@ -35,9 +38,12 @@ def is_game_possible(game_data, red_cubes, green_cubes, blue_cubes):
Returns: Returns:
bool: True if the game is possible, False otherwise. bool: True if the game is possible, False otherwise.
""" """
return (game_data['red'] <= red_cubes and return (
game_data['green'] <= green_cubes and game_data["red"] <= red_cubes
game_data['blue'] <= blue_cubes) and game_data["green"] <= green_cubes
and game_data["blue"] <= blue_cubes
)
def process_games(file_path, red_cubes, green_cubes, blue_cubes): def process_games(file_path, red_cubes, green_cubes, blue_cubes):
""" """
@ -52,7 +58,7 @@ def process_games(file_path, red_cubes, green_cubes, blue_cubes):
Returns: Returns:
int: Sum of IDs of possible games. int: Sum of IDs of possible games.
""" """
with open(file_path, 'r') as file: with open(file_path, "r") as file:
lines = file.readlines() lines = file.readlines()
sum_of_ids = 0 sum_of_ids = 0
@ -63,17 +69,19 @@ def process_games(file_path, red_cubes, green_cubes, blue_cubes):
return sum_of_ids return sum_of_ids
def test(): def test():
print("start testing") print("start testing")
# Test the function # Test the function
result = process_games('../test.txt', 12, 13, 14) result = process_games("../test.txt", 12, 13, 14)
# Assertion for testing # Assertion for testing
assert result == 8, f"Expected sum of IDs to be 8, but got {result}" assert result == 8, f"Expected sum of IDs to be 8, but got {result}"
print(f"Test Passed: Sum of IDs for possible games is {result}\n") print(f"Test Passed: Sum of IDs for possible games is {result}\n")
# Run the test # Run the test
test() test()
# Process the actual input file # Process the actual input file
result = process_games('../input.txt', 12, 13, 14) result = process_games("../input.txt", 12, 13, 14)
print(f"From input.txt: Sum of IDs for possible games is {result}") print(f"From input.txt: Sum of IDs for possible games is {result}")

View File

@ -8,20 +8,23 @@ def parse_game_data(line):
Returns: Returns:
int, dict: Game ID and a dictionary with color counts. int, dict: Game ID and a dictionary with color counts.
""" """
parts = line.split(': ') parts = line.split(": ")
game_id = int(parts[0].split(' ')[1]) game_id = int(parts[0].split(" ")[1])
color_counts = {'red': 0, 'green': 0, 'blue': 0} color_counts = {"red": 0, "green": 0, "blue": 0}
subsets = parts[1].split('; ') subsets = parts[1].split("; ")
for subset in subsets: for subset in subsets:
colors = subset.split(', ') colors = subset.split(", ")
for color in colors: for color in colors:
count, color_name = color.split(' ') count, color_name = color.split(" ")
color_name = color_name.strip() # Remove any trailing whitespace or newline characters color_name = (
color_name.strip()
) # Remove any trailing whitespace or newline characters
color_counts[color_name] = max(color_counts[color_name], int(count)) color_counts[color_name] = max(color_counts[color_name], int(count))
return game_id, color_counts return game_id, color_counts
def calculate_power_of_set(game_data): def calculate_power_of_set(game_data):
""" """
Calculates the power of the cube set. Calculates the power of the cube set.
@ -32,7 +35,8 @@ def calculate_power_of_set(game_data):
Returns: Returns:
int: The power of the cube set. int: The power of the cube set.
""" """
return game_data['red'] * game_data['green'] * game_data['blue'] return game_data["red"] * game_data["green"] * game_data["blue"]
def process_games(file_path): def process_games(file_path):
""" """
@ -44,7 +48,7 @@ def process_games(file_path):
Returns: Returns:
int: Sum of the power of the minimum cube sets. int: Sum of the power of the minimum cube sets.
""" """
with open(file_path, 'r') as file: with open(file_path, "r") as file:
lines = file.readlines() lines = file.readlines()
sum_of_powers = 0 sum_of_powers = 0
@ -55,18 +59,22 @@ def process_games(file_path):
return sum_of_powers return sum_of_powers
def test(): def test():
print("start testing") print("start testing")
sum_of_powers = process_games('../test.txt') sum_of_powers = process_games("../test.txt")
# Assertion for testing # Assertion for testing
assert sum_of_powers == 2286, f"Expected sum of powers to be 2286, but got {sum_of_powers}" assert (
sum_of_powers == 2286
), f"Expected sum of powers to be 2286, but got {sum_of_powers}"
print(f"Test Passed: Sum of powers for the minimum cube sets is {sum_of_powers}\n") print(f"Test Passed: Sum of powers for the minimum cube sets is {sum_of_powers}\n")
# Run the test # Run the test
test() test()
# Process the actual input file # Process the actual input file
sum_of_powers = process_games('../input.txt') sum_of_powers = process_games("../input.txt")
print(f"From input.txt: Sum of powers for the minimum cube sets is {sum_of_powers}") print(f"From input.txt: Sum of powers for the minimum cube sets is {sum_of_powers}")

View File

@ -1,11 +1,16 @@
use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::io::{self, BufRead}; use std::io::{self, BufRead};
use std::path::Path; use std::path::Path;
use std::collections::HashMap;
fn parse_game_data(line: &str) -> (i32, HashMap<String, i32>) { fn parse_game_data(line: &str) -> (i32, HashMap<String, i32>) {
let parts: Vec<&str> = line.split(": ").collect(); let parts: Vec<&str> = line.split(": ").collect();
let game_id = parts[0].split_whitespace().nth(1).unwrap().parse::<i32>().unwrap(); let game_id = parts[0]
.split_whitespace()
.nth(1)
.unwrap()
.parse::<i32>()
.unwrap();
let mut color_counts = HashMap::new(); let mut color_counts = HashMap::new();
color_counts.insert("red".to_string(), 0); color_counts.insert("red".to_string(), 0);
color_counts.insert("green".to_string(), 0); color_counts.insert("green".to_string(), 0);
@ -27,7 +32,9 @@ fn parse_game_data(line: &str) -> (i32, HashMap<String, i32>) {
} }
fn calculate_power_of_set(game_data: &HashMap<String, i32>) -> i32 { fn calculate_power_of_set(game_data: &HashMap<String, i32>) -> i32 {
game_data.get("red").unwrap_or(&0) * game_data.get("green").unwrap_or(&0) * game_data.get("blue").unwrap_or(&0) game_data.get("red").unwrap_or(&0)
* game_data.get("green").unwrap_or(&0)
* game_data.get("blue").unwrap_or(&0)
} }
fn process_games(file_path: &Path) -> i32 { fn process_games(file_path: &Path) -> i32 {
@ -48,10 +55,20 @@ fn process_games(file_path: &Path) -> i32 {
fn main() { fn main() {
// Test the function with test data // Test the function with test data
let test_result = process_games(Path::new("../test.txt")); let test_result = process_games(Path::new("../test.txt"));
assert_eq!(test_result, 2286, "Test failed: expected sum of powers to be 2286, but got {}", test_result); assert_eq!(
println!("Test Passed: Sum of powers for the minimum cube sets is {}\n", test_result); test_result, 2286,
"Test failed: expected sum of powers to be 2286, but got {}",
test_result
);
println!(
"Test Passed: Sum of powers for the minimum cube sets is {}\n",
test_result
);
// Process the actual input file // Process the actual input file
let result = process_games(Path::new("../input.txt")); let result = process_games(Path::new("../input.txt"));
println!("From input.txt: Sum of powers for the minimum cube sets is {}", result); println!(
"From input.txt: Sum of powers for the minimum cube sets is {}",
result
);
} }

View File

@ -1,16 +1,16 @@
import os
def parse_schematic(file_path): def parse_schematic(file_path):
"""Reads the engine schematic from a file and returns it as a list of strings.""" """Reads the engine schematic from a file and returns it as a list of strings."""
try: try:
with open(file_path, 'r') as file: with open(file_path, "r") as file:
return [line.strip() for line in file.readlines()] return [line.strip() for line in file.readlines()]
except FileNotFoundError: except FileNotFoundError:
raise Exception(f"File not found: {file_path}") raise Exception(f"File not found: {file_path}")
def is_symbol(char): def is_symbol(char):
"""Checks if a character is a symbol (not a digit or a period).""" """Checks if a character is a symbol (not a digit or a period)."""
return not char.isdigit() and char != '.' return not char.isdigit() and char != "."
def get_adjacent_positions(rows, cols, row, col): def get_adjacent_positions(rows, cols, row, col):
"""Generates positions adjacent (including diagonally) to the given coordinates.""" """Generates positions adjacent (including diagonally) to the given coordinates."""
@ -19,26 +19,30 @@ def get_adjacent_positions(rows, cols, row, col):
if i != row or j != col: if i != row or j != col:
yield i, j yield i, j
def find_start_of_number(schematic, row, col): def find_start_of_number(schematic, row, col):
"""Finds the start position of the number that includes the given digit.""" """Finds the start position of the number that includes the given digit."""
while col > 0 and schematic[row][col - 1].isdigit(): while col > 0 and schematic[row][col - 1].isdigit():
col -= 1 col -= 1
return row, col return row, col
def extract_full_number(schematic, start_row, start_col): def extract_full_number(schematic, start_row, start_col):
"""Extracts the full number starting from the given digit coordinates.""" """Extracts the full number starting from the given digit coordinates."""
start_row, start_col = find_start_of_number(schematic, start_row, start_col) start_row, start_col = find_start_of_number(schematic, start_row, start_col)
number = '' number = ""
rows, cols = len(schematic), len(schematic[0]) cols = len(schematic[0])
col = start_col col = start_col
while col < cols and schematic[start_row][col].isdigit(): while col < cols and schematic[start_row][col].isdigit():
number += schematic[start_row][col] number += schematic[start_row][col]
schematic[start_row] = schematic[start_row][:col] + '.' + schematic[start_row][col + 1:] schematic[start_row] = (
schematic[start_row][:col] + "." + schematic[start_row][col + 1 :]
)
col += 1 col += 1
return int(number) if number else 0 return int(number) if number else 0
def sum_part_numbers(file_path): def sum_part_numbers(file_path):
"""Calculates the sum of all part numbers in the engine schematic.""" """Calculates the sum of all part numbers in the engine schematic."""
schematic = parse_schematic(file_path) schematic = parse_schematic(file_path)
@ -48,7 +52,9 @@ def sum_part_numbers(file_path):
for row in range(len(schematic)): for row in range(len(schematic)):
for col in range(len(schematic[row])): for col in range(len(schematic[row])):
if is_symbol(schematic[row][col]): if is_symbol(schematic[row][col]):
for i, j in get_adjacent_positions(len(schematic), len(schematic[row]), row, col): for i, j in get_adjacent_positions(
len(schematic), len(schematic[row]), row, col
):
if schematic[i][j].isdigit() and (i, j) not in visited: if schematic[i][j].isdigit() and (i, j) not in visited:
visited.add((i, j)) visited.add((i, j))
number = extract_full_number(schematic, i, j) number = extract_full_number(schematic, i, j)
@ -57,12 +63,14 @@ def sum_part_numbers(file_path):
return total_sum return total_sum
def run_tests(): def run_tests():
"""Runs tests on the test file and prints the results.""" """Runs tests on the test file and prints the results."""
test_result = sum_part_numbers("../test.txt") test_result = sum_part_numbers("../test.txt")
print(f"Test Result: {test_result}") print(f"Test Result: {test_result}")
assert test_result == 4361, f"Test failed: Expected 4361, got {test_result}" assert test_result == 4361, f"Test failed: Expected 4361, got {test_result}"
def main(): def main():
"""Main function to run the test and then process the input file.""" """Main function to run the test and then process the input file."""
try: try:
@ -73,5 +81,6 @@ def main():
except Exception as e: except Exception as e:
print(f"Error: {e}") print(f"Error: {e}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -1,13 +1,12 @@
import os
def parse_schematic(file_path): def parse_schematic(file_path):
"""Reads the engine schematic from a file and returns it as a list of strings.""" """Reads the engine schematic from a file and returns it as a list of strings."""
try: try:
with open(file_path, 'r') as file: with open(file_path, "r") as file:
return [line.strip() for line in file.readlines()] return [line.strip() for line in file.readlines()]
except FileNotFoundError: except FileNotFoundError:
raise Exception(f"File not found: {file_path}") raise Exception(f"File not found: {file_path}")
def get_adjacent_positions(rows, cols, row, col): def get_adjacent_positions(rows, cols, row, col):
"""Generates positions adjacent (including diagonally) to the given coordinates.""" """Generates positions adjacent (including diagonally) to the given coordinates."""
for i in range(max(0, row - 1), min(row + 2, rows)): for i in range(max(0, row - 1), min(row + 2, rows)):
@ -15,26 +14,30 @@ def get_adjacent_positions(rows, cols, row, col):
if i != row or j != col: if i != row or j != col:
yield i, j yield i, j
def find_start_of_number(schematic, row, col): def find_start_of_number(schematic, row, col):
"""Finds the start position of the number that includes the given digit.""" """Finds the start position of the number that includes the given digit."""
while col > 0 and schematic[row][col - 1].isdigit(): while col > 0 and schematic[row][col - 1].isdigit():
col -= 1 col -= 1
return row, col return row, col
def extract_full_number(schematic, start_row, start_col): def extract_full_number(schematic, start_row, start_col):
"""Extracts the full number starting from the given digit coordinates.""" """Extracts the full number starting from the given digit coordinates."""
start_row, start_col = find_start_of_number(schematic, start_row, start_col) start_row, start_col = find_start_of_number(schematic, start_row, start_col)
number = '' number = ""
rows, cols = len(schematic), len(schematic[0]) cols = len(schematic[0])
col = start_col col = start_col
while col < cols and schematic[start_row][col].isdigit(): while col < cols and schematic[start_row][col].isdigit():
number += schematic[start_row][col] number += schematic[start_row][col]
schematic[start_row] = schematic[start_row][:col] + '.' + schematic[start_row][col + 1:] schematic[start_row] = (
schematic[start_row][:col] + "." + schematic[start_row][col + 1 :]
)
col += 1 col += 1
return int(number) if number else 0 return int(number) if number else 0
def find_gears_and_calculate_ratios(schematic): def find_gears_and_calculate_ratios(schematic):
"""Finds gears in the schematic and calculates their gear ratios.""" """Finds gears in the schematic and calculates their gear ratios."""
total_ratio_sum = 0 total_ratio_sum = 0
@ -42,7 +45,7 @@ def find_gears_and_calculate_ratios(schematic):
for row in range(rows): for row in range(rows):
for col in range(cols): for col in range(cols):
if schematic[row][col] == '*': if schematic[row][col] == "*":
part_numbers = [] part_numbers = []
for i, j in get_adjacent_positions(rows, cols, row, col): for i, j in get_adjacent_positions(rows, cols, row, col):
if schematic[i][j].isdigit(): if schematic[i][j].isdigit():
@ -57,6 +60,7 @@ def find_gears_and_calculate_ratios(schematic):
return total_ratio_sum return total_ratio_sum
def run_tests(): def run_tests():
"""Runs tests on the test file and prints the results.""" """Runs tests on the test file and prints the results."""
test_schematic = parse_schematic("../test.txt") test_schematic = parse_schematic("../test.txt")
@ -64,6 +68,7 @@ def run_tests():
print(f"Test Result: {test_result}") print(f"Test Result: {test_result}")
assert test_result == 467835, "Test failed: Expected 467835" assert test_result == 467835, "Test failed: Expected 467835"
def main(): def main():
"""Main function to process the input file and calculate the sum of gear ratios.""" """Main function to process the input file and calculate the sum of gear ratios."""
try: try:
@ -75,5 +80,6 @@ def main():
except Exception as e: except Exception as e:
print(f"Error: {e}") print(f"Error: {e}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -21,7 +21,13 @@ fn get_adjacent_positions(rows: usize, cols: usize, row: usize, col: usize) -> V
} }
fn find_start_of_number(schematic: &[String], row: usize, mut col: usize) -> usize { fn find_start_of_number(schematic: &[String], row: usize, mut col: usize) -> usize {
while col > 0 && schematic[row].chars().nth(col - 1).unwrap().is_digit(10) { while col > 0
&& schematic[row]
.chars()
.nth(col - 1)
.unwrap()
.is_ascii_digit()
{
col -= 1; col -= 1;
} }
col col
@ -32,7 +38,13 @@ fn extract_full_number(schematic: &mut [String], start_row: usize, start_col: us
let mut number = String::new(); let mut number = String::new();
let mut col = start_col; let mut col = start_col;
while col < schematic[start_row].len() && schematic[start_row].chars().nth(col).unwrap().is_digit(10) { while col < schematic[start_row].len()
&& schematic[start_row]
.chars()
.nth(col)
.unwrap()
.is_ascii_digit()
{
number.push(schematic[start_row].chars().nth(col).unwrap()); number.push(schematic[start_row].chars().nth(col).unwrap());
schematic[start_row].replace_range(col..=col, "."); schematic[start_row].replace_range(col..=col, ".");
col += 1; col += 1;
@ -51,7 +63,7 @@ fn find_gears_and_calculate_ratios(schematic: &mut Vec<String>) -> i32 {
if schematic[row].chars().nth(col).unwrap() == '*' { if schematic[row].chars().nth(col).unwrap() == '*' {
let mut part_numbers = Vec::new(); let mut part_numbers = Vec::new();
for (i, j) in get_adjacent_positions(rows, cols, row, col) { for (i, j) in get_adjacent_positions(rows, cols, row, col) {
if schematic[i].chars().nth(j).unwrap().is_digit(10) { if schematic[i].chars().nth(j).unwrap().is_ascii_digit() {
let part_number = extract_full_number(schematic, i, j); let part_number = extract_full_number(schematic, i, j);
if !part_numbers.contains(&part_number) { if !part_numbers.contains(&part_number) {
part_numbers.push(part_number); part_numbers.push(part_number);

View File

@ -1,21 +1,24 @@
def parse_card_data(line): def parse_card_data(line):
"""Parse a single line of card data into card number, winning numbers, and own numbers.""" """Parse a single line of card data into card number, winning numbers, and own numbers."""
try: try:
card_info, number_parts = line.split(':') card_info, number_parts = line.split(":")
winning_part, own_part = number_parts.split('|') winning_part, own_part = number_parts.split("|")
# Extract card number from card_info # Extract card number from card_info
card_number = ''.join(filter(str.isdigit, card_info)) card_number = "".join(filter(str.isdigit, card_info))
# Convert number strings to integer lists # Convert number strings to integer lists
winning_numbers = set(map(int, winning_part.split())) winning_numbers = set(map(int, winning_part.split()))
own_numbers = list(map(int, own_part.split())) own_numbers = list(map(int, own_part.split()))
print(f"Card {card_number}: Winning Numbers: {winning_numbers}, Own Numbers: {own_numbers}") print(
f"Card {card_number}: Winning Numbers: {winning_numbers}, Own Numbers: {own_numbers}"
)
return winning_numbers, own_numbers return winning_numbers, own_numbers
except ValueError as e: except ValueError as e:
raise ValueError(f"Error parsing line '{line}': {e}") raise ValueError(f"Error parsing line '{line}': {e}")
def calculate_card_points(winning_numbers, own_numbers): def calculate_card_points(winning_numbers, own_numbers):
"""Calculate the points for a single card.""" """Calculate the points for a single card."""
points = 0 points = 0
@ -24,22 +27,27 @@ def calculate_card_points(winning_numbers, own_numbers):
points = 1 if points == 0 else points * 2 points = 1 if points == 0 else points * 2
return points return points
def process_cards(file_path): def process_cards(file_path):
"""Process all cards in the given file and return the total points.""" """Process all cards in the given file and return the total points."""
total_points = 0 total_points = 0
with open(file_path, 'r') as file: with open(file_path, "r") as file:
for line in file: for line in file:
winning_numbers, own_numbers = parse_card_data(line.strip()) winning_numbers, own_numbers = parse_card_data(line.strip())
total_points += calculate_card_points(winning_numbers, own_numbers) total_points += calculate_card_points(winning_numbers, own_numbers)
return total_points return total_points
def test(): def test():
"""Run tests using the test.txt file.""" """Run tests using the test.txt file."""
expected_result = 13 # Based on the given example expected_result = 13 # Based on the given example
result = process_cards('../test.txt') result = process_cards("../test.txt")
assert result == expected_result, f"Test failed: Expected {expected_result}, got {result}" assert (
result == expected_result
), f"Test failed: Expected {expected_result}, got {result}"
print(f"Test passed: {result} points") print(f"Test passed: {result} points")
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:
@ -47,11 +55,12 @@ def main():
test() test()
# Process actual input # Process actual input
total_points = process_cards('../input.txt') total_points = process_cards("../input.txt")
print(f"Total points from input.txt: {total_points}") print(f"Total points from input.txt: {total_points}")
except Exception as e: except Exception as e:
print(f"An error occurred: {e}") print(f"An error occurred: {e}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -1,25 +1,26 @@
def parse_card_data(line): def parse_card_data(line):
"""Parse a single line of card data into card number, winning numbers, and own numbers.""" """Parse a single line of card data into card number, winning numbers, and own numbers."""
try: try:
card_info, number_parts = line.split(':') card_info, number_parts = line.split(":")
winning_part, own_part = number_parts.split('|') winning_part, own_part = number_parts.split("|")
card_number = ''.join(filter(str.isdigit, card_info)) card_number = "".join(filter(str.isdigit, card_info))
winning_numbers = set(map(int, winning_part.split())) winning_numbers = set(map(int, winning_part.split()))
own_numbers = list(map(int, own_part.split())) own_numbers = list(map(int, own_part.split()))
return int(card_number), winning_numbers, own_numbers return int(card_number), winning_numbers, own_numbers
except ValueError as e: except ValueError as e:
raise ValueError(f"Error parsing line '{line}': {e}") raise ValueError(f"Error parsing line '{line}': {e}")
def calculate_matches(winning_numbers, own_numbers): def calculate_matches(winning_numbers, own_numbers):
"""Calculate the number of matches for a single card.""" """Calculate the number of matches for a single card."""
return sum(1 for number in own_numbers if number in winning_numbers) return sum(1 for number in own_numbers if number in winning_numbers)
def process_cards(file_path): def process_cards(file_path):
"""Process all cards in the given file and return the total number of cards.""" """Process all cards in the given file and return the total number of cards."""
with open(file_path, 'r') as file: with open(file_path, "r") as file:
cards = [parse_card_data(line.strip()) for line in file] cards = [parse_card_data(line.strip()) for line in file]
total_cards = len(cards) # Start with original cards
i = 0 i = 0
while i < len(cards): while i < len(cards):
card_number, winning_numbers, own_numbers = cards[i] card_number, winning_numbers, own_numbers = cards[i]
@ -32,13 +33,17 @@ def process_cards(file_path):
return len(cards) return len(cards)
def test(): def test():
"""Run tests using the test.txt file.""" """Run tests using the test.txt file."""
expected_result = 30 # Based on the given example expected_result = 30 # Based on the given example
result = process_cards('../test.txt') result = process_cards("../test.txt")
assert result == expected_result, f"Test failed: Expected {expected_result}, got {result}" assert (
result == expected_result
), f"Test failed: Expected {expected_result}, got {result}"
print(f"Test passed: {result} cards") print(f"Test passed: {result} cards")
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:
@ -46,11 +51,12 @@ def main():
test() test()
# Process actual input # Process actual input
total_cards = process_cards('../input.txt') total_cards = process_cards("../input.txt")
print(f"Total cards from input.txt: {total_cards}") print(f"Total cards from input.txt: {total_cards}")
except Exception as e: except Exception as e:
print(f"An error occurred: {e}") print(f"An error occurred: {e}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -1,5 +1,3 @@
import os
def map_seed_through_category(seed, line): def map_seed_through_category(seed, line):
"""Maps a single seed through a category based on a mapping line.""" """Maps a single seed through a category based on a mapping line."""
dest_start, source_start, range_length = map(int, line.split()) dest_start, source_start, range_length = map(int, line.split())
@ -7,20 +5,24 @@ def map_seed_through_category(seed, line):
return dest_start + (seed - source_start) return dest_start + (seed - source_start)
return seed return seed
def process_category(file, seeds): def process_category(file, seeds):
"""Processes seeds through a single category based on the file lines.""" """Processes seeds through a single category based on the file lines."""
print(f"Starting category processing") print("Starting category processing")
updated_seeds = [-1] * len(seeds) # Initialize with -1 to indicate unmapped seeds updated_seeds = [-1] * len(seeds) # Initialize with -1 to indicate unmapped seeds
for line in file: for line in file:
line = line.strip() line = line.strip()
print(f"Processing category line: {line}") print(f"Processing category line: {line}")
if not line or ':' in line: # End of the current category map if not line or ":" in line: # End of the current category map
break break
dest_start, source_start, range_length = map(int, line.split()) dest_start, source_start, range_length = map(int, line.split())
for i, seed in enumerate(seeds): for i, seed in enumerate(seeds):
if updated_seeds[i] == -1 and source_start <= seed < source_start + range_length: if (
updated_seeds[i] == -1
and source_start <= seed < source_start + range_length
):
updated_seeds[i] = dest_start + (seed - source_start) updated_seeds[i] = dest_start + (seed - source_start)
# For seeds that weren't mapped in this category, keep their original value # For seeds that weren't mapped in this category, keep their original value
@ -31,18 +33,19 @@ def process_category(file, seeds):
print(f"Seeds after category processing: {updated_seeds}") print(f"Seeds after category processing: {updated_seeds}")
return updated_seeds return updated_seeds
def process_file(file_path, is_test=False): def process_file(file_path, is_test=False):
"""Processes the file to find the lowest location number for the seeds.""" """Processes the file to find the lowest location number for the seeds."""
try: try:
with open(file_path, 'r') as file: with open(file_path, "r") as file:
seeds = list(map(int, file.readline().split(':')[1].split())) seeds = list(map(int, file.readline().split(":")[1].split()))
print(f"Initial Seeds: {seeds}") print(f"Initial Seeds: {seeds}")
while True: while True:
line = file.readline() line = file.readline()
if not line: # End of file if not line: # End of file
break break
if ':' in line: # Start of a new category map if ":" in line: # Start of a new category map
seeds = process_category(file, seeds) seeds = process_category(file, seeds)
lowest_location = min(seeds) lowest_location = min(seeds)
@ -54,13 +57,15 @@ def process_file(file_path, is_test=False):
except Exception as e: except Exception as e:
print(f"An error occurred processing '{file_path}': {e}") print(f"An error occurred processing '{file_path}': {e}")
def test(): def test():
"""Run tests using the test.txt file.""" """Run tests using the test.txt file."""
expected_result = 35 # Based on the given example expected_result = 35 # Based on the given example
result = process_file('../test.txt') result = process_file("../test.txt")
assert result == expected_result, f"Test failed, expected 35 but got {result}" assert result == expected_result, f"Test failed, expected 35 but got {result}"
print(f"Test passed: {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:
@ -74,5 +79,6 @@ def main():
except Exception as e: except Exception as e:
print(f"An error occurred: {e}") print(f"An error occurred: {e}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -1,11 +1,12 @@
import os
import gc import gc
from itertools import groupby 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_input(file_path): def parse_input(file_path):
"""Parses the input file into seeds and categories.""" """Parses the input file into seeds and categories."""
with open(file_path) as file: with open(file_path) as file:
@ -20,6 +21,7 @@ def parse_input(file_path):
] ]
return seeds_numbers, categories return seeds_numbers, categories
def process_categories(seeds_numbers, categories): def process_categories(seeds_numbers, categories):
"""Processes the seed ranges through all categories.""" """Processes the seed ranges through all categories."""
for category in categories: for category in categories:
@ -49,6 +51,7 @@ def process_categories(seeds_numbers, categories):
seeds_numbers = sources seeds_numbers = sources
return seeds_numbers return seeds_numbers
def find_lowest_location(file_path, is_test=False, expected_result=None): def find_lowest_location(file_path, is_test=False, expected_result=None):
"""Finds the lowest location number from the input file.""" """Finds the lowest location number from the input file."""
try: try:
@ -57,7 +60,9 @@ def find_lowest_location(file_path, is_test=False, expected_result=None):
lowest_location = min(seeds_numbers)[0] lowest_location = min(seeds_numbers)[0]
if is_test: if is_test:
assert lowest_location == expected_result, f"Test failed, expected {expected_result} but got {lowest_location}" assert (
lowest_location == expected_result
), f"Test failed, expected {expected_result} but got {lowest_location}"
print("Test passed.") print("Test passed.")
else: else:
print(f"Lowest location from {file_path}: {lowest_location}") print(f"Lowest location from {file_path}: {lowest_location}")
@ -68,11 +73,13 @@ def find_lowest_location(file_path, is_test=False, expected_result=None):
except Exception as e: except Exception as e:
print(f"An error occurred processing '{file_path}': {e}") print(f"An error occurred processing '{file_path}': {e}")
def test(): 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
find_lowest_location('../test.txt', is_test=True, expected_result=expected_result) find_lowest_location("../test.txt", is_test=True, expected_result=expected_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."""
@ -87,5 +94,6 @@ def main():
except Exception as e: except Exception as e:
print(f"An error occurred: {e}") print(f"An error occurred: {e}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -3,6 +3,13 @@ use std::io::{self, BufRead};
use std::path::Path; use std::path::Path;
use std::str::FromStr; use std::str::FromStr;
// Define type aliases for clarity
type SeedNumber = (i32, i32);
type CategoryItem = (i32, i32, i32);
type SeedNumbers = Vec<SeedNumber>;
type Category = Vec<CategoryItem>;
type Categories = Vec<Category>;
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where where
P: AsRef<Path>, P: AsRef<Path>,
@ -11,10 +18,10 @@ where
Ok(io::BufReader::new(file).lines()) Ok(io::BufReader::new(file).lines())
} }
fn parse_input(file_path: &str) -> io::Result<(Vec<(i32, i32)>, Vec<Vec<(i32, i32, i32)>>)> { fn parse_input(file_path: &str) -> io::Result<(SeedNumbers, Categories)> {
let mut seeds_numbers = Vec::new(); let mut seeds_numbers = SeedNumbers::new();
let mut categories = Vec::new(); let mut categories = Categories::new();
let mut current_category = Vec::new(); let mut current_category = Category::new();
let mut is_seed_line = true; let mut is_seed_line = true;
for line in read_lines(file_path)? { for line in read_lines(file_path)? {
@ -22,14 +29,15 @@ fn parse_input(file_path: &str) -> io::Result<(Vec<(i32, i32)>, Vec<Vec<(i32, i3
if line.is_empty() { if line.is_empty() {
if !current_category.is_empty() { if !current_category.is_empty() {
categories.push(current_category); categories.push(current_category);
current_category = Vec::new(); current_category = Category::new();
} }
is_seed_line = false; is_seed_line = false;
continue; continue;
} }
if is_seed_line { if is_seed_line {
let seeds_ranges: Vec<i32> = line.split_whitespace() let seeds_ranges: Vec<i32> = line
.split_whitespace()
.skip(1) .skip(1)
.filter_map(|s| i32::from_str(s).ok()) .filter_map(|s| i32::from_str(s).ok())
.collect(); .collect();
@ -40,7 +48,8 @@ fn parse_input(file_path: &str) -> io::Result<(Vec<(i32, i32)>, Vec<Vec<(i32, i3
} }
} }
} else { } else {
let numbers: Vec<i32> = line.split_whitespace() let numbers: Vec<i32> = line
.split_whitespace()
.filter_map(|s| i32::from_str(s).ok()) .filter_map(|s| i32::from_str(s).ok())
.collect(); .collect();
if numbers.len() == 3 { if numbers.len() == 3 {
@ -55,16 +64,19 @@ fn parse_input(file_path: &str) -> io::Result<(Vec<(i32, i32)>, Vec<Vec<(i32, i3
Ok((seeds_numbers, categories)) Ok((seeds_numbers, categories))
} }
fn process_categories(mut seeds_numbers: Vec<(i32, i32)>, categories: Vec<Vec<(i32, i32, i32)>>) -> Vec<(i32, i32)> { fn process_categories(mut seeds_numbers: SeedNumbers, categories: Categories) -> SeedNumbers {
for category in categories { for category in categories {
let mut sources = Vec::new(); let mut sources = SeedNumbers::new();
while let Some((start, end)) = seeds_numbers.pop() { while let Some((start, end)) = seeds_numbers.pop() {
let mut is_mapped = false; let mut is_mapped = false;
for &(destination, source, length) in &category { for &(destination, source, length) in &category {
let overlap_start = std::cmp::max(start, source); let overlap_start = std::cmp::max(start, source);
let overlap_end = std::cmp::min(end, source + length); let overlap_end = std::cmp::min(end, source + length);
if overlap_start < overlap_end { if overlap_start < overlap_end {
sources.push((overlap_start - source + destination, overlap_end - source + destination)); sources.push((
overlap_start - source + destination,
overlap_end - source + destination,
));
if overlap_start > start { if overlap_start > start {
seeds_numbers.push((start, overlap_start)); seeds_numbers.push((start, overlap_start));
} }
@ -87,14 +99,22 @@ fn process_categories(mut seeds_numbers: Vec<(i32, i32)>, categories: Vec<Vec<(i
fn find_lowest_location(file_path: &str) -> io::Result<i32> { fn find_lowest_location(file_path: &str) -> io::Result<i32> {
let (seeds_numbers, categories) = parse_input(file_path)?; let (seeds_numbers, categories) = parse_input(file_path)?;
let processed_seeds = process_categories(seeds_numbers, categories); let processed_seeds = process_categories(seeds_numbers, categories);
let lowest_location = processed_seeds.iter().map(|&(start, _)| start).min().unwrap(); let lowest_location = processed_seeds
.iter()
.map(|&(start, _)| start)
.min()
.unwrap();
Ok(lowest_location) Ok(lowest_location)
} }
fn main() -> io::Result<()> { fn main() -> io::Result<()> {
// Test // Test
let test_result = find_lowest_location("../test.txt")?; let test_result = find_lowest_location("../test.txt")?;
assert_eq!(test_result, 46, "Test failed. Expected 46, got {}", test_result); assert_eq!(
test_result, 46,
"Test failed. Expected 46, got {}",
test_result
);
println!("Test passed."); println!("Test passed.");
// Process actual input // Process actual input

View File

@ -1,12 +1,15 @@
def parse_input(file_path): def parse_input(file_path):
"""Parse the input file into race times and record distances.""" """Parse the input file into race times and record distances."""
with open(file_path, 'r') as file: with open(file_path, "r") as file:
lines = file.readlines() lines = file.readlines()
times = [int(value) for value in lines[0].strip().split() if value.isdigit()] times = [int(value) for value in lines[0].strip().split() if value.isdigit()]
distances = [int(value) for value in lines[1].strip().split() if value.isdigit()] distances = [
int(value) for value in lines[1].strip().split() if value.isdigit()
]
print(f"Input parsed. Times: {times}, Distances: {distances}") print(f"Input parsed. Times: {times}, Distances: {distances}")
return times, distances return times, distances
def calculate_winning_ways(time, record): def calculate_winning_ways(time, record):
"""Calculate the number of ways to beat the record for a single race.""" """Calculate the number of ways to beat the record for a single race."""
print(f"Calculating winning ways for time: {time}, record: {record}") print(f"Calculating winning ways for time: {time}, record: {record}")
@ -16,13 +19,16 @@ def calculate_winning_ways(time, record):
speed = hold_time speed = hold_time
remaining_time = time - hold_time remaining_time = time - hold_time
distance = speed * remaining_time distance = speed * remaining_time
print(f"Hold Time: {hold_time}, Speed: {speed}, Remaining Time: {remaining_time}, Distance: {distance}") print(
f"Hold Time: {hold_time}, Speed: {speed}, Remaining Time: {remaining_time}, Distance: {distance}"
)
# Count as winning way if distance is greater than the record # Count as winning way if distance is greater than the record
if distance > record: if distance > record:
winning_ways += 1 winning_ways += 1
print(f"Winning ways for this race: {winning_ways}") print(f"Winning ways for this race: {winning_ways}")
return winning_ways return winning_ways
def total_winning_combinations(times, distances): def total_winning_combinations(times, distances):
"""Calculate the total number of winning combinations for all races.""" """Calculate the total number of winning combinations for all races."""
print("Calculating total winning combinations.") print("Calculating total winning combinations.")
@ -36,6 +42,7 @@ def total_winning_combinations(times, distances):
print(f"Total winning combinations: {total_combinations}") print(f"Total winning combinations: {total_combinations}")
return total_combinations return total_combinations
def run_test(file_path): def run_test(file_path):
"""Run the test with assertions to verify the functionality.""" """Run the test with assertions to verify the functionality."""
print(f"Running test with file: {file_path}") print(f"Running test with file: {file_path}")
@ -45,6 +52,7 @@ def run_test(file_path):
assert result == 288, f"Test failed! Expected 288, got {result}" assert result == 288, f"Test failed! Expected 288, got {result}"
print("Test passed successfully.") print("Test passed successfully.")
def main(): def main():
"""Main function to run the test and then process the input file.""" """Main function to run the test and then process the input file."""
try: try:
@ -64,5 +72,6 @@ def main():
except Exception as e: except Exception as e:
print(f"An unexpected error occurred: {e}") print(f"An unexpected error occurred: {e}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -3,13 +3,14 @@ def parse_input(file_path):
Parse the input file to extract the race time and record distance. Parse the input file to extract the race time and record distance.
Assumes the file has two lines: first for time, second for distance. Assumes the file has two lines: first for time, second for distance.
""" """
with open(file_path, 'r') as file: with open(file_path, "r") as file:
lines = file.readlines() lines = file.readlines()
time = int(''.join(filter(str.isdigit, lines[0].strip()))) time = int("".join(filter(str.isdigit, lines[0].strip())))
distance = int(''.join(filter(str.isdigit, lines[1].strip()))) distance = int("".join(filter(str.isdigit, lines[1].strip())))
print(f"Parsed input from {file_path} - Time: {time}, Distance: {distance}") print(f"Parsed input from {file_path} - Time: {time}, Distance: {distance}")
return time, distance return time, distance
def calculate_winning_ways(time, record): def calculate_winning_ways(time, record):
""" """
Calculate the number of ways to beat the record for the race. Calculate the number of ways to beat the record for the race.
@ -25,9 +26,12 @@ def calculate_winning_ways(time, record):
max_hold_time -= 1 max_hold_time -= 1
winning_ways = max(0, max_hold_time - min_hold_time + 1) winning_ways = max(0, max_hold_time - min_hold_time + 1)
print(f"Winning ways calculated: {winning_ways} (Min: {min_hold_time}, Max: {max_hold_time})") print(
f"Winning ways calculated: {winning_ways} (Min: {min_hold_time}, Max: {max_hold_time})"
)
return winning_ways return winning_ways
def run_test(file_path, expected_result): def run_test(file_path, expected_result):
""" """
Run a test with the given file and compare the result to the expected result. Run a test with the given file and compare the result to the expected result.
@ -36,9 +40,12 @@ def run_test(file_path, expected_result):
time, record = parse_input(file_path) time, record = parse_input(file_path)
result = calculate_winning_ways(time, record) result = calculate_winning_ways(time, record)
print(f"Test result: {result}") print(f"Test result: {result}")
assert result == expected_result, f"Test failed! Expected {expected_result}, got {result}" assert (
result == expected_result
), f"Test failed! Expected {expected_result}, got {result}"
print("Test passed successfully.") print("Test passed successfully.")
def main(): def main():
""" """
Main function to run the test and then process the actual input file. Main function to run the test and then process the actual input file.
@ -61,5 +68,6 @@ def main():
except Exception as e: except Exception as e:
print(f"An unexpected error occurred: {e}") print(f"An unexpected error occurred: {e}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -6,11 +6,25 @@ fn parse_input(file_path: &str) -> io::Result<(i64, i64)> {
let reader = BufReader::new(file); let reader = BufReader::new(file);
let mut lines = reader.lines(); let mut lines = reader.lines();
let time_line = lines.next().ok_or(io::Error::new(io::ErrorKind::Other, "Missing time line"))??; let time_line = lines
let distance_line = lines.next().ok_or(io::Error::new(io::ErrorKind::Other, "Missing distance line"))??; .next()
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Missing time line"))??;
let distance_line = lines
.next()
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Missing distance line"))??;
let time = time_line.chars().filter(|c| c.is_digit(10)).collect::<String>().parse::<i64>().unwrap_or(0); let time = time_line
let distance = distance_line.chars().filter(|c| c.is_digit(10)).collect::<String>().parse::<i64>().unwrap_or(0); .chars()
.filter(|c| c.is_ascii_digit())
.collect::<String>()
.parse::<i64>()
.unwrap_or(0);
let distance = distance_line
.chars()
.filter(|c| c.is_ascii_digit())
.collect::<String>()
.parse::<i64>()
.unwrap_or(0);
Ok((time, distance)) Ok((time, distance))
} }
@ -30,7 +44,11 @@ fn calculate_winning_ways(time: i64, record: i64) -> i64 {
fn run_test(file_path: &str, expected_result: i64) -> io::Result<()> { fn run_test(file_path: &str, expected_result: i64) -> io::Result<()> {
let (time, distance) = parse_input(file_path)?; let (time, distance) = parse_input(file_path)?;
let result = calculate_winning_ways(time, distance); let result = calculate_winning_ways(time, distance);
assert_eq!(result, expected_result, "Test failed! Expected {}, got {}", expected_result, result); assert_eq!(
result, expected_result,
"Test failed! Expected {}, got {}",
expected_result, result
);
println!("Test passed successfully."); println!("Test passed successfully.");
Ok(()) Ok(())
} }

View File

@ -1,24 +1,26 @@
import os
from collections import Counter from collections import Counter
def read_hands(file_path): def read_hands(file_path):
""" """
Reads hands and their bids from the file. Reads hands and their bids from the file.
Returns a list of tuples (hand, bid). Returns a list of tuples (hand, bid).
""" """
try: try:
with open(file_path, 'r') as file: with open(file_path, "r") as file:
return [line.strip().split() for line in file] return [line.strip().split() for line in file]
except Exception as e: except Exception as e:
print(f"Error reading file {file_path}: {e}") print(f"Error reading file {file_path}: {e}")
raise raise
def replace_face_cards(hand): def replace_face_cards(hand):
""" """
Replaces face cards with characters that maintain the card order. Replaces face cards with characters that maintain the card order.
""" """
replacements = {'T': 'a', 'J': 'b', 'Q': 'c', 'K': 'd', 'A': 'e'} replacements = {"T": "a", "J": "b", "Q": "c", "K": "d", "A": "e"}
return ''.join(replacements.get(card, card) for card in hand) return "".join(replacements.get(card, card) for card in hand)
def categorize_hand(hand): def categorize_hand(hand):
""" """
@ -44,6 +46,7 @@ def categorize_hand(hand):
return (category, hand) return (category, hand)
def hand_key(hand): def hand_key(hand):
""" """
Key function for sorting hands. Key function for sorting hands.
@ -51,25 +54,32 @@ def hand_key(hand):
""" """
return categorize_hand(hand[0]) return categorize_hand(hand[0])
def calculate_total_winnings(file_path): def calculate_total_winnings(file_path):
""" """
Calculates the total winnings from the hands in the file. Calculates the total winnings from the hands in the file.
""" """
hands = read_hands(file_path) hands = read_hands(file_path)
sorted_hands = sorted(hands, key=hand_key, reverse=True) sorted_hands = sorted(hands, key=hand_key, reverse=True)
total_winnings = sum(int(bid) * (len(hands) - index) for index, (_, bid) in enumerate(sorted_hands)) total_winnings = sum(
int(bid) * (len(hands) - index) for index, (_, bid) in enumerate(sorted_hands)
)
return total_winnings return total_winnings
def test(): def test():
print(f"Running test...") print("Running test...")
try: try:
expected_result = 6440 expected_result = 6440
total_winnings = calculate_total_winnings("../test.txt") total_winnings = calculate_total_winnings("../test.txt")
assert total_winnings == expected_result, f"Test failed, expected {expected_result} but got {total_winnings}" assert (
total_winnings == expected_result
), f"Test failed, expected {expected_result} but got {total_winnings}"
print(f"Test passed: {total_winnings}") print(f"Test passed: {total_winnings}")
except Exception as e: except Exception as e:
print(f"Test failed: {e}") print(f"Test failed: {e}")
def main(): def main():
try: try:
test() test()
@ -80,5 +90,6 @@ def main():
except Exception as e: except Exception as e:
print(f"An error occurred: {e}") print(f"An error occurred: {e}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -1,27 +1,31 @@
import os
from collections import Counter from collections import Counter
def read_hands(file_path): def read_hands(file_path):
try: try:
with open(file_path, 'r') as file: with open(file_path, "r") as file:
print("Reading hands...") print("Reading hands...")
return [line.strip().split() for line in file] return [line.strip().split() for line in file]
except Exception as e: except Exception as e:
print(f"Error reading file {file_path}: {e}") print(f"Error reading file {file_path}: {e}")
raise raise
def replace_face_cards(hand): def replace_face_cards(hand):
replacements = {'T': 'a', 'J': '1', 'Q': 'c', 'K': 'd', 'A': 'e'} replacements = {"T": "a", "J": "1", "Q": "c", "K": "d", "A": "e"}
return ''.join(replacements.get(card, card) for card in hand) return "".join(replacements.get(card, card) for card in hand)
def strength(hand): def strength(hand):
hand = replace_face_cards(hand) hand = replace_face_cards(hand)
C = Counter(hand) C = Counter(hand)
target = max(C, key=lambda k: (C[k], k != '1')) # Find the target card, excluding joker target = max(
C, key=lambda k: (C[k], k != "1")
) # Find the target card, excluding joker
if '1' in C and target != '1': if "1" in C and target != "1":
C[target] += C['1'] C[target] += C["1"]
del C['1'] del C["1"]
if sorted(C.values()) == [5]: if sorted(C.values()) == [5]:
category = 10 category = 10
@ -43,27 +47,35 @@ def strength(hand):
print(f"Hand: {hand}, Category: {category}") print(f"Hand: {hand}, Category: {category}")
return (category, hand) return (category, hand)
def hand_key(hand): def hand_key(hand):
return strength(hand[0]) return strength(hand[0])
def calculate_total_winnings(file_path): def calculate_total_winnings(file_path):
hands = read_hands(file_path) hands = read_hands(file_path)
print("Sorting hands based on strength...") print("Sorting hands based on strength...")
sorted_hands = sorted(hands, key=hand_key, reverse=True) sorted_hands = sorted(hands, key=hand_key, reverse=True)
total_winnings = sum(int(bid) * (len(hands) - index) for index, (_, bid) in enumerate(sorted_hands)) total_winnings = sum(
int(bid) * (len(hands) - index) for index, (_, bid) in enumerate(sorted_hands)
)
print("Calculating total winnings...") print("Calculating total winnings...")
return total_winnings return total_winnings
def test(file_path): def test(file_path):
print(f"Running test with {file_path}...") print(f"Running test with {file_path}...")
try: try:
expected_result = 5905 expected_result = 5905
total_winnings = calculate_total_winnings(file_path) total_winnings = calculate_total_winnings(file_path)
assert total_winnings == expected_result, f"Test failed, expected {expected_result} but got {total_winnings}" assert (
total_winnings == expected_result
), f"Test failed, expected {expected_result} but got {total_winnings}"
print(f"Test passed: {total_winnings}") print(f"Test passed: {total_winnings}")
except Exception as e: except Exception as e:
print(f"Test failed: {e}") print(f"Test failed: {e}")
def main(): def main():
try: try:
test("../test.txt") test("../test.txt")
@ -72,5 +84,6 @@ def main():
except Exception as e: except Exception as e:
print(f"An error occurred: {e}") print(f"An error occurred: {e}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -7,8 +7,7 @@ fn read_hands(filename: &str) -> io::Result<Vec<(String, i32)>> {
let lines = io::BufReader::new(file).lines(); let lines = io::BufReader::new(file).lines();
let mut hands = Vec::new(); let mut hands = Vec::new();
for line in lines { for line in lines.flatten() {
if let Ok(line) = line {
let parts: Vec<&str> = line.split_whitespace().collect(); let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() == 2 { if parts.len() == 2 {
let hand = parts[0].to_string(); let hand = parts[0].to_string();
@ -16,17 +15,16 @@ fn read_hands(filename: &str) -> io::Result<Vec<(String, i32)>> {
hands.push((hand, bid)); hands.push((hand, bid));
} }
} }
}
Ok(hands) Ok(hands)
} }
fn replace_face_cards(hand: &str) -> String { fn replace_face_cards(hand: &str) -> String {
let mut replaced = hand.to_string(); let mut replaced = hand.to_string();
replaced = replaced.replace("T", "a"); replaced = replaced.replace('T', "a");
replaced = replaced.replace("J", "1"); replaced = replaced.replace('J', "1");
replaced = replaced.replace("Q", "c"); replaced = replaced.replace('Q', "c");
replaced = replaced.replace("K", "d"); replaced = replaced.replace('K', "d");
replaced = replaced.replace("A", "e"); replaced = replaced.replace('A', "e");
replaced replaced
} }
@ -44,7 +42,11 @@ fn calculate_strength(hand: &str) -> (i32, String) {
let mut best_category = 4; // Default to High card let mut best_category = 4; // Default to High card
for (card, count) in &counts { for (card, count) in &counts {
let adjusted_count = if *card != '1' { count + joker_count } else { *count }; let adjusted_count = if *card != '1' {
count + joker_count
} else {
*count
};
best_category = best_category.max(match adjusted_count { best_category = best_category.max(match adjusted_count {
5 => 10, 5 => 10,
4 => 9, 4 => 9,
@ -56,7 +58,10 @@ fn calculate_strength(hand: &str) -> (i32, String) {
// Use original hand for tie-breaking // Use original hand for tie-breaking
let tie_breaker_hand = hand.chars().collect::<String>(); let tie_breaker_hand = hand.chars().collect::<String>();
println!("Hand: {}, Strength: {}, Tie-breaker hand: {}", hand, best_category, tie_breaker_hand); println!(
"Hand: {}, Strength: {}, Tie-breaker hand: {}",
hand, best_category, tie_breaker_hand
);
(best_category, tie_breaker_hand) (best_category, tie_breaker_hand)
} }
@ -69,9 +74,18 @@ fn calculate_total_winnings(hands: Vec<(String, i32)>) -> i32 {
(strength_b, tie_breaker_b).cmp(&(strength_a, tie_breaker_a)) (strength_b, tie_breaker_b).cmp(&(strength_a, tie_breaker_a))
}); });
sorted_hands.iter().enumerate().fold(0, |acc, (i, (hand, bid))| { sorted_hands
.iter()
.enumerate()
.fold(0, |acc, (i, (hand, bid))| {
let winnings = bid * (i as i32 + 1); let winnings = bid * (i as i32 + 1);
println!("Hand: {}, Rank: {}, Bid: {}, Winnings: {}", hand, i + 1, bid, winnings); println!(
"Hand: {}, Rank: {}, Bid: {}, Winnings: {}",
hand,
i + 1,
bid,
winnings
);
acc + winnings acc + winnings
}) })
} }
@ -79,7 +93,11 @@ fn calculate_total_winnings(hands: Vec<(String, i32)>) -> i32 {
fn main() { fn main() {
let test_hands = read_hands("../test.txt").expect("Failed to read test file"); let test_hands = read_hands("../test.txt").expect("Failed to read test file");
let test_total = calculate_total_winnings(test_hands); let test_total = calculate_total_winnings(test_hands);
assert_eq!(test_total, 5905, "Test failed: expected 5905, got {}", test_total); assert_eq!(
test_total, 5905,
"Test failed: expected 5905, got {}",
test_total
);
println!("Test passed: Total winnings = {}", test_total); println!("Test passed: Total winnings = {}", test_total);
let hands = read_hands("../input.txt").expect("Failed to read input file"); let hands = read_hands("../input.txt").expect("Failed to read input file");

View File

@ -1,20 +1,21 @@
def parse_file(file_path): def parse_file(file_path):
"""Parse the input file to extract instructions and the node map.""" """Parse the input file to extract instructions and the node map."""
try: try:
with open(file_path, 'r') as file: with open(file_path, "r") as file:
lines = file.readlines() lines = file.readlines()
instructions = lines[0].strip() instructions = lines[0].strip()
node_map = {} node_map = {}
for line in lines[2:]: for line in lines[2:]:
node, neighbors = line.strip().split(' = ') node, neighbors = line.strip().split(" = ")
node_map[node] = tuple(neighbors[1:-1].split(', ')) node_map[node] = tuple(neighbors[1:-1].split(", "))
return instructions, node_map return instructions, node_map
except Exception as e: except Exception as e:
print(f"Error parsing file {file_path}: {e}") print(f"Error parsing file {file_path}: {e}")
raise raise
def find_repeating_unit(sequence): def find_repeating_unit(sequence):
"""Find the repeating unit in a sequence.""" """Find the repeating unit in a sequence."""
for i in range(1, len(sequence) + 1): for i in range(1, len(sequence) + 1):
@ -23,7 +24,8 @@ def find_repeating_unit(sequence):
return unit return unit
return sequence return sequence
def navigate_network(instructions, node_map, start_node='AAA', end_node='ZZZ'):
def navigate_network(instructions, node_map, start_node="AAA", end_node="ZZZ"):
"""Navigate the network based on the instructions and return the number of steps.""" """Navigate the network based on the instructions and return the number of steps."""
current_node = start_node current_node = start_node
steps = 0 steps = 0
@ -33,28 +35,34 @@ def navigate_network(instructions, node_map, start_node='AAA', end_node='ZZZ'):
while current_node != end_node: while current_node != end_node:
if (current_node, instruction_index) in visited: if (current_node, instruction_index) in visited:
print(f"Loop detected at {current_node} with instruction index {instruction_index}") print(
f"Loop detected at {current_node} with instruction index {instruction_index}"
)
return -1 # Indicates a loop without reaching the end node return -1 # Indicates a loop without reaching the end node
visited.add((current_node, instruction_index)) visited.add((current_node, instruction_index))
direction = instructions[instruction_index % len(instructions)] direction = instructions[instruction_index % len(instructions)]
current_node = node_map[current_node][0 if direction == 'L' else 1] current_node = node_map[current_node][0 if direction == "L" else 1]
instruction_index += 1 instruction_index += 1
steps += 1 steps += 1
return steps return steps
def run_test(): def run_test():
"""Run the test with the provided file path.""" """Run the test with the provided file path."""
try: try:
expected_result = 6 expected_result = 6
instructions, node_map = parse_file("../test.txt") instructions, node_map = parse_file("../test.txt")
result = navigate_network(instructions, node_map) result = navigate_network(instructions, node_map)
assert result == expected_result, f"Test failed, expected {expected_result} but got {result}" assert (
result == expected_result
), f"Test failed, expected {expected_result} but got {result}"
print(f"Test passed with {result} steps.") print(f"Test passed with {result} steps.")
except AssertionError as error: except AssertionError as error:
print(error) print(error)
def main(): def main():
print("Start Tests") print("Start Tests")
run_test() run_test()
@ -70,5 +78,6 @@ def main():
except Exception as e: except Exception as e:
print(f"Error during main execution: {e}") print(f"Error during main execution: {e}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -1,18 +1,19 @@
import sys
from math import gcd from math import gcd
def parse_file(file_path): def parse_file(file_path):
print(f"Parsing file: {file_path}") print(f"Parsing file: {file_path}")
with open(file_path, 'r') as file: with open(file_path, "r") as file:
D = file.read().strip() D = file.read().strip()
steps, rule = D.split('\n\n') steps, rule = D.split("\n\n")
GO = {'L': {}, 'R': {}} GO = {"L": {}, "R": {}}
for line in rule.split('\n'): for line in rule.split("\n"):
st, lr = line.split('=') st, lr = line.split("=")
left, right = lr.split(',') left, right = lr.split(",")
GO['L'][st.strip()] = left.strip()[1:].strip() GO["L"][st.strip()] = left.strip()[1:].strip()
GO['R'][st.strip()] = right[:-1].strip() GO["R"][st.strip()] = right[:-1].strip()
return [0 if char == 'L' else 1 for char in steps], GO return [0 if char == "L" else 1 for char in steps], GO
def lcm(xs): def lcm(xs):
ans = 1 ans = 1
@ -20,16 +21,17 @@ def lcm(xs):
ans = (x * ans) // gcd(x, ans) ans = (x * ans) // gcd(x, ans)
return ans return ans
def navigate_network_simultaneously(steps, GO): def navigate_network_simultaneously(steps, GO):
print("Starting navigation of network.") print("Starting navigation of network.")
POS = [s for s in GO['L'] if s.endswith('A')] POS = [s for s in GO["L"] if s.endswith("A")]
T = {} T = {}
t = 0 t = 0
while True: while True:
NP = [] NP = []
for i, p in enumerate(POS): for i, p in enumerate(POS):
p = GO['L' if steps[t % len(steps)] == 0 else 'R'][p] p = GO["L" if steps[t % len(steps)] == 0 else "R"][p]
if p.endswith('Z'): if p.endswith("Z"):
T[i] = t + 1 T[i] = t + 1
if len(T) == len(POS): if len(T) == len(POS):
print(f"All paths reached 'Z' nodes at step {t + 1}.") print(f"All paths reached 'Z' nodes at step {t + 1}.")
@ -40,19 +42,24 @@ def navigate_network_simultaneously(steps, GO):
print(f"Step {t}: Current nodes - {POS}") print(f"Step {t}: Current nodes - {POS}")
assert False assert False
def run_test(): def run_test():
print("Running test...") print("Running test...")
expected_result = 6 expected_result = 6
steps, GO = parse_file("../test2.txt") steps, GO = parse_file("../test2.txt")
result = navigate_network_simultaneously(steps, GO) result = navigate_network_simultaneously(steps, GO)
assert result == expected_result, f"Test failed, expected {expected_result} but got {result}" assert (
result == expected_result
), f"Test failed, expected {expected_result} but got {result}"
print(f"Test passed with {result} steps.") print(f"Test passed with {result} steps.")
def main(): def main():
run_test() run_test()
steps, GO = parse_file("../input.txt") steps, GO = parse_file("../input.txt")
result = navigate_network_simultaneously(steps, GO) result = navigate_network_simultaneously(steps, GO)
print(f"All paths reached 'Z' nodes simultaneously in {result} steps.") print(f"All paths reached 'Z' nodes simultaneously in {result} steps.")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -1,7 +1,10 @@
use std::fs;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs;
use std::path::Path; use std::path::Path;
// Type alias to simplify the complex type
type StepsRules = (Vec<u8>, HashMap<String, (String, String)>);
fn gcd(a: u64, b: u64) -> u64 { fn gcd(a: u64, b: u64) -> u64 {
if b == 0 { if b == 0 {
a a
@ -14,10 +17,12 @@ fn lcm(a: u64, b: u64) -> u64 {
a / gcd(a, b) * b a / gcd(a, b) * b
} }
fn parse_file(file_path: &Path) -> Result<(Vec<u8>, HashMap<String, (String, String)>), String> { fn parse_file(file_path: &Path) -> Result<StepsRules, String> {
let data = fs::read_to_string(file_path).map_err(|e| e.to_string())?; let data = fs::read_to_string(file_path).map_err(|e| e.to_string())?;
let mut sections = data.trim().split("\n\n"); let mut sections = data.trim().split("\n\n");
let steps = sections.next().unwrap() let steps = sections
.next()
.unwrap()
.chars() .chars()
.map(|c| if c == 'L' { 0 } else { 1 }) .map(|c| if c == 'L' { 0 } else { 1 })
.collect(); .collect();
@ -27,7 +32,9 @@ fn parse_file(file_path: &Path) -> Result<(Vec<u8>, HashMap<String, (String, Str
for line in rules_section.lines() { for line in rules_section.lines() {
let mut parts = line.split('=').map(str::trim); let mut parts = line.split('=').map(str::trim);
let state = parts.next().unwrap().to_string(); let state = parts.next().unwrap().to_string();
let directions = parts.next().unwrap() let directions = parts
.next()
.unwrap()
.split(',') .split(',')
.map(str::trim) .map(str::trim)
.map(|s| s.trim_matches(|c: char| c == '(' || c == ')').to_string()) .map(|s| s.trim_matches(|c: char| c == '(' || c == ')').to_string())
@ -40,18 +47,23 @@ fn parse_file(file_path: &Path) -> Result<(Vec<u8>, HashMap<String, (String, Str
} }
fn navigate_network_simultaneously(steps: &[u8], rules: &HashMap<String, (String, String)>) -> u64 { fn navigate_network_simultaneously(steps: &[u8], rules: &HashMap<String, (String, String)>) -> u64 {
let start_nodes: Vec<String> = rules.keys() let start_nodes: Vec<String> = rules.keys().filter(|k| k.ends_with('A')).cloned().collect();
.filter(|k| k.ends_with('A'))
.cloned()
.collect();
let mut current_nodes = start_nodes.clone(); let mut current_nodes = start_nodes.clone();
let mut step_count = 0; let mut step_count = 0;
let mut time_to_z = HashMap::new(); let mut time_to_z = HashMap::new();
while time_to_z.len() < start_nodes.len() { while time_to_z.len() < start_nodes.len() {
for (i, node) in current_nodes.iter_mut().enumerate() { for (i, node) in current_nodes.iter_mut().enumerate() {
let direction = if steps[step_count % steps.len()] == 0 { 'L' } else { 'R' }; let direction = if steps[step_count % steps.len()] == 0 {
let next_node = if direction == 'L' { &rules[node].0 } else { &rules[node].1 }; 'L'
} else {
'R'
};
let next_node = if direction == 'L' {
&rules[node].0
} else {
&rules[node].1
};
*node = next_node.clone(); *node = next_node.clone();
if next_node.ends_with('Z') && !time_to_z.contains_key(&i) { if next_node.ends_with('Z') && !time_to_z.contains_key(&i) {
@ -70,9 +82,9 @@ fn navigate_network_simultaneously(steps: &[u8], rules: &HashMap<String, (String
time_to_z.values().fold(1, |acc, &val| lcm(acc, val as u64)) time_to_z.values().fold(1, |acc, &val| lcm(acc, val as u64))
} }
fn run_test(test_file: &Path) { fn run_test(test_path: &Path) {
println!("Running test..."); println!("Running test...");
let (steps, rules) = parse_file(test_file).expect("Failed to parse test file"); let (steps, rules) = parse_file(test_path).expect("Failed to parse test file");
let result = navigate_network_simultaneously(&steps, &rules); let result = navigate_network_simultaneously(&steps, &rules);
assert_eq!(result, 6, "Test failed: expected 6, got {}", result); assert_eq!(result, 6, "Test failed: expected 6, got {}", result);
println!("Test passed with {} steps.", result); println!("Test passed with {} steps.", result);
@ -80,10 +92,13 @@ fn run_test(test_file: &Path) {
fn main() { fn main() {
let test_path = Path::new("../test.txt"); let test_path = Path::new("../test.txt");
run_test(&test_path); run_test(test_path); // Removed needless borrow
let input_path = Path::new("../input.txt"); let input_path = Path::new("../input.txt");
let (steps, rules) = parse_file(&input_path).expect("Failed to parse input file"); let (steps, rules) = parse_file(input_path).expect("Failed to parse input file"); // Removed needless borrow
let result = navigate_network_simultaneously(&steps, &rules); let result = navigate_network_simultaneously(&steps, &rules); // Calculate result for input file
println!("All paths reached 'Z' nodes simultaneously in {} steps.", result); println!(
"All paths reached 'Z' nodes simultaneously in {} steps.",
result
);
} }

View File

@ -3,7 +3,7 @@ import * as path from 'path';
function gcd(a: number, b: number): number { function gcd(a: number, b: number): number {
while (b !== 0) { while (b !== 0) {
let t = b; const t = b;
b = a % b; b = a % b;
a = t; a = t;
} }
@ -33,7 +33,7 @@ function parseFile(filePath: string): { steps: number[], rules: { [key: string]:
function navigateNetworkSimultaneously(steps: number[], rules: { [key: string]: { [key: string]: string } }): number { function navigateNetworkSimultaneously(steps: number[], rules: { [key: string]: { [key: string]: string } }): number {
console.log("Starting navigation of network."); console.log("Starting navigation of network.");
const startNodes = Object.keys(rules['L']).filter((node: string) => node.endsWith('A')); const startNodes = Object.keys(rules['L']).filter((node: string) => node.endsWith('A'));
let currentNodes = startNodes; const currentNodes = startNodes;
let stepCount = 0; let stepCount = 0;
const timeToZ: { [key: number]: number } = {}; const timeToZ: { [key: number]: number } = {};
@ -74,8 +74,8 @@ function main(): void {
const { steps, rules } = parseFile(inputPath); const { steps, rules } = parseFile(inputPath);
const result = navigateNetworkSimultaneously(steps, rules); const result = navigateNetworkSimultaneously(steps, rules);
console.log(`All paths reached 'Z' nodes simultaneously in ${result} steps.`); console.log(`All paths reached 'Z' nodes simultaneously in ${result} steps.`);
} catch (error: any) { } catch (error) {
console.error(`Error: ${error.message}`); console.error(`Error: ${(error as Error).message}`);
} }
} }

View File

@ -3,7 +3,9 @@ def generate_difference_table(history):
table = [history] table = [history]
while not all(value == 0 for value in table[-1]): while not all(value == 0 for value in table[-1]):
try: try:
next_row = [table[-1][i+1] - table[-1][i] for i in range(len(table[-1]) - 1)] next_row = [
table[-1][i + 1] - table[-1][i] for i in range(len(table[-1]) - 1)
]
except IndexError as e: except IndexError as e:
print(f"IndexError in generate_difference_table: {e}") print(f"IndexError in generate_difference_table: {e}")
print(f"Current table: {table}") print(f"Current table: {table}")
@ -11,6 +13,7 @@ def generate_difference_table(history):
table.append(next_row) table.append(next_row)
return table return table
def extrapolate_next_value(table): def extrapolate_next_value(table):
"""Extrapolates the next value from the difference table.""" """Extrapolates the next value from the difference table."""
try: try:
@ -22,11 +25,12 @@ def extrapolate_next_value(table):
raise raise
return table[0][-1] return table[0][-1]
def solve_puzzle(filename): def solve_puzzle(filename):
"""Solves the puzzle by reading histories from the file and summing their extrapolated next values.""" """Solves the puzzle by reading histories from the file and summing their extrapolated next values."""
total = 0 total = 0
try: try:
with open(filename, 'r') as file: with open(filename, "r") as file:
for line in file: for line in file:
try: try:
history = [int(x) for x in line.split()] history = [int(x) for x in line.split()]
@ -37,14 +41,15 @@ def solve_puzzle(filename):
print(f"ValueError processing line '{line}': {e}") print(f"ValueError processing line '{line}': {e}")
except IndexError as e: except IndexError as e:
print(f"IndexError processing line '{line}': {e}") print(f"IndexError processing line '{line}': {e}")
except FileNotFoundError as e: except FileNotFoundError:
print(f"FileNotFoundError: The file {filename} was not found.") print(f"FileNotFoundError: The file {filename} was not found")
raise raise
except Exception as e: except Exception as e:
print(f"Unexpected error processing file {filename}: {e}") print(f"Unexpected error processing file {filename}: {e}")
raise raise
return total return total
def test(): def test():
"""Runs the test using the test.txt file and asserts the expected outcome.""" """Runs the test using the test.txt file and asserts the expected outcome."""
expected = 114 # Expected result from the test data expected = 114 # Expected result from the test data
@ -56,6 +61,7 @@ def test():
print(e) print(e)
raise raise
def main(): def main():
"""Main function to run the test and then solve the puzzle.""" """Main function to run the test and then solve the puzzle."""
print("Running test...") print("Running test...")
@ -64,5 +70,6 @@ def main():
result = solve_puzzle("../input.txt") result = solve_puzzle("../input.txt")
print(f"Puzzle result: {result}") print(f"Puzzle result: {result}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -3,7 +3,9 @@ def generate_difference_table(history):
table = [history] table = [history]
while not all(value == 0 for value in table[-1]): while not all(value == 0 for value in table[-1]):
try: try:
next_row = [table[-1][i+1] - table[-1][i] for i in range(len(table[-1]) - 1)] next_row = [
table[-1][i + 1] - table[-1][i] for i in range(len(table[-1]) - 1)
]
except IndexError as e: except IndexError as e:
print(f"IndexError in generate_difference_table: {e}") print(f"IndexError in generate_difference_table: {e}")
print(f"Current table: {table}") print(f"Current table: {table}")
@ -11,6 +13,7 @@ def generate_difference_table(history):
table.append(next_row) table.append(next_row)
return table return table
def extrapolate_previous_value(table): def extrapolate_previous_value(table):
"""Extrapolates the previous value from the difference table.""" """Extrapolates the previous value from the difference table."""
try: try:
@ -22,11 +25,12 @@ def extrapolate_previous_value(table):
raise raise
return table[0][0] return table[0][0]
def solve_puzzle(filename): def solve_puzzle(filename):
"""Solves the puzzle by reading histories from the file and summing their extrapolated previous values.""" """Solves the puzzle by reading histories from the file and summing their extrapolated previous values."""
total = 0 total = 0
try: try:
with open(filename, 'r') as file: with open(filename, "r") as file:
for line in file: for line in file:
try: try:
history = [int(x) for x in line.split()] history = [int(x) for x in line.split()]
@ -37,7 +41,7 @@ def solve_puzzle(filename):
print(f"ValueError processing line '{line}': {e}") print(f"ValueError processing line '{line}': {e}")
except IndexError as e: except IndexError as e:
print(f"IndexError processing line '{line}': {e}") print(f"IndexError processing line '{line}': {e}")
except FileNotFoundError as e: except FileNotFoundError:
print(f"FileNotFoundError: The file {filename} was not found.") print(f"FileNotFoundError: The file {filename} was not found.")
raise raise
except Exception as e: except Exception as e:
@ -45,6 +49,7 @@ def solve_puzzle(filename):
raise raise
return total return total
def test(): def test():
"""Runs the test using the test.txt file and asserts the expected outcome for the second part of the puzzle.""" """Runs the test using the test.txt file and asserts the expected outcome for the second part of the puzzle."""
expected = 2 # Expected result from the test data for the second part expected = 2 # Expected result from the test data for the second part
@ -56,6 +61,7 @@ def test():
print(e) print(e)
raise raise
def main(): def main():
"""Main function to run the test and then solve the puzzle.""" """Main function to run the test and then solve the puzzle."""
print("Running test for the second part...") print("Running test for the second part...")
@ -64,5 +70,6 @@ def main():
result = solve_puzzle("../input.txt") result = solve_puzzle("../input.txt")
print(f"Puzzle result for the second part: {result}") print(f"Puzzle result for the second part: {result}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -38,7 +38,10 @@ fn solve_puzzle(filename: &str) -> Result<i32, io::Error> {
if line.trim().is_empty() { if line.trim().is_empty() {
continue; continue;
} }
let history: Vec<i32> = line.split_whitespace().map(|s| s.parse().unwrap()).collect(); let history: Vec<i32> = line
.split_whitespace()
.map(|s| s.parse().unwrap())
.collect();
let mut diff_table = generate_difference_table(&history); let mut diff_table = generate_difference_table(&history);
let prev_value = extrapolate_previous_value(&mut diff_table); let prev_value = extrapolate_previous_value(&mut diff_table);
total += prev_value; total += prev_value;
@ -51,7 +54,11 @@ fn test() -> Result<(), io::Error> {
// Runs the test using the test.txt file and asserts the expected outcome // Runs the test using the test.txt file and asserts the expected outcome
let expected = 2; // Expected result from the test data for the second part let expected = 2; // Expected result from the test data for the second part
let result = solve_puzzle("../test.txt")?; let result = solve_puzzle("../test.txt")?;
assert_eq!(result, expected, "Test failed: Expected {}, got {}", expected, result); assert_eq!(
result, expected,
"Test failed: Expected {}, got {}",
expected, result
);
println!("Test passed successfully."); println!("Test passed successfully.");
Ok(()) Ok(())
} }

View File

@ -2,9 +2,9 @@ import fs from 'fs';
function generateDifferenceTable(history: number[]): number[][] { function generateDifferenceTable(history: number[]): number[][] {
// Generates a difference table for a given history // Generates a difference table for a given history
let table: number[][] = [history]; const table: number[][] = [history];
while (!table[table.length - 1].every(value => value === 0)) { while (!table[table.length - 1].every(value => value === 0)) {
let nextRow: number[] = []; const nextRow: number[] = [];
for (let i = 0; i < table[table.length - 1].length - 1; i++) { for (let i = 0; i < table[table.length - 1].length - 1; i++) {
nextRow.push(table[table.length - 1][i + 1] - table[table.length - 1][i]); nextRow.push(table[table.length - 1][i + 1] - table[table.length - 1][i]);
} }

View File

@ -1,15 +1,16 @@
def parse_grid(file_path): def parse_grid(file_path):
"""Parses the grid from a file and returns it as a 2D list.""" """Parses the grid from a file and returns it as a 2D list."""
try: try:
with open(file_path, 'r') as file: with open(file_path, "r") as file:
grid = [list(line.strip()) for line in file] grid = [list(line.strip()) for line in file]
print(f"Grid parsed from {file_path}:") print(f"Grid parsed from {file_path}:")
[print(''.join(row)) for row in grid] [print("".join(row)) for row in grid]
return grid return grid
except Exception as e: except Exception as e:
print(f"Error reading file {file_path}: {e}") print(f"Error reading file {file_path}: {e}")
raise raise
def create_graph(grid): def create_graph(grid):
"""Creates a graph from the grid.""" """Creates a graph from the grid."""
graph = {} graph = {}
@ -22,6 +23,7 @@ def create_graph(grid):
print(graph) print(graph)
return graph return graph
def get_neighbors(grid, r, c): def get_neighbors(grid, r, c):
"""Finds the neighbors of a cell in the grid.""" """Finds the neighbors of a cell in the grid."""
neighbors = [] neighbors = []
@ -30,23 +32,29 @@ def get_neighbors(grid, r, c):
# Directions: North, East, South, West # Directions: North, East, South, West
directions = [(r - 1, c), (r, c + 1), (r + 1, c), (r, c - 1)] directions = [(r - 1, c), (r, c + 1), (r + 1, c), (r, c - 1)]
connected = { connected = {
"|": [0, 2], "-": [1, 3], "|": [0, 2],
"L": [0, 1], "J": [0, 3], "-": [1, 3],
"7": [2, 3], "F": [1, 2], "L": [0, 1],
"S": [0, 1, 2, 3] # 'S' connects in all directions for initial identification "J": [0, 3],
"7": [2, 3],
"F": [1, 2],
"S": [0, 1, 2, 3], # 'S' connects in all directions for initial identification
} }
for i, (dr, dc) in enumerate(directions): for i, (dr, dc) in enumerate(directions):
if 0 <= dr < rows and 0 <= dc < cols and grid[dr][dc] != '.': if 0 <= dr < rows and 0 <= dc < cols and grid[dr][dc] != ".":
neighbor_type = grid[dr][dc] neighbor_type = grid[dr][dc]
# Check if there is a valid connection # Check if there is a valid connection
if neighbor_type in connected: if neighbor_type in connected:
if i in connected[grid[r][c]] and (3-i) in connected[neighbor_type]: # Check reverse direction if (
i in connected[grid[r][c]] and (3 - i) in connected[neighbor_type]
): # Check reverse direction
neighbors.append((dr, dc)) neighbors.append((dr, dc))
print(f"Neighbors for ({r}, {c}): {neighbors}") print(f"Neighbors for ({r}, {c}): {neighbors}")
return neighbors return neighbors
def bfs(graph, start): def bfs(graph, start):
"""Performs BFS on the graph and returns the maximum distance from the start.""" """Performs BFS on the graph and returns the maximum distance from the start."""
visited = set() visited = set()
@ -64,15 +72,17 @@ def bfs(graph, start):
print(f"Maximum distance from start: {max_distance}") print(f"Maximum distance from start: {max_distance}")
return max_distance return max_distance
def find_start(grid): def find_start(grid):
"""Finds the starting position 'S' in the grid.""" """Finds the starting position 'S' in the grid."""
for r, row in enumerate(grid): for r, row in enumerate(grid):
for c, cell in enumerate(row): for c, cell in enumerate(row):
if cell == 'S': if cell == "S":
print(f"Starting position found at: ({r}, {c})") print(f"Starting position found at: ({r}, {c})")
return r, c return r, c
raise ValueError("Starting position 'S' not found in the grid") raise ValueError("Starting position 'S' not found in the grid")
def run_test(file_path): def run_test(file_path):
"""Runs the algorithm on a test file and asserts the result.""" """Runs the algorithm on a test file and asserts the result."""
print(f"Running test with file: {file_path}") print(f"Running test with file: {file_path}")
@ -83,6 +93,7 @@ def run_test(file_path):
print(f"Max distance for test: {max_distance}") print(f"Max distance for test: {max_distance}")
return max_distance return max_distance
def main(file_path): def main(file_path):
"""Main function to run the algorithm on the input file.""" """Main function to run the algorithm on the input file."""
print(f"Running main algorithm with file: {file_path}") print(f"Running main algorithm with file: {file_path}")
@ -93,6 +104,7 @@ def main(file_path):
print(f"Max distance for input: {max_distance}") print(f"Max distance for input: {max_distance}")
return max_distance return max_distance
if __name__ == "__main__": if __name__ == "__main__":
test_result = run_test("../test.txt") test_result = run_test("../test.txt")
assert test_result == 8, f"Test failed: expected 8, got {test_result}" assert test_result == 8, f"Test failed: expected 8, got {test_result}"

79
lint.sh Executable file
View File

@ -0,0 +1,79 @@
#!/bin/bash
# Define paths to the directories for each language
PYTHON_DIRS="Day*/python"
JAVASCRIPT_DIRS="Day*/javascript"
TYPESCRIPT_DIRS="Day*/typescript"
RUST_DIRS="Day*/rust"
# File to store linting results
LINTING_MD="Linting.md"
> "$LINTING_MD" # Clear the file contents
# Prettify and Lint Python files
prettify_lint_python() {
echo "Prettifying and Linting Python files..."
for dir in $PYTHON_DIRS; do
if [ -d "$dir" ]; then
echo "# Prettifying and Linting $dir" >> "$LINTING_MD"
# Prettify
black "$dir" >> "$LINTING_MD" 2>&1
# Lint
flake8 "$dir" --count --select=E9,F63,F7,F82 --show-source --statistics >> "$LINTING_MD" 2>&1
flake8 "$dir" --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics >> "$LINTING_MD" 2>&1
fi
done
}
# Prettify and Lint JavaScript files
prettify_lint_js() {
echo "Prettifying and Linting JavaScript files..."
for dir in $JAVASCRIPT_DIRS; do
if [ -d "$dir" ]; then
echo "# Prettifying and Linting $dir" >> "$LINTING_MD"
# Prettify
(cd "$dir" && npx prettier --write .) >> "$LINTING_MD" 2>&1
# Lint
(cd "$dir" && npm run lint) >> "$LINTING_MD" 2>&1
fi
done
}
# Prettify and Lint TypeScript files
prettify_lint_ts() {
echo "Prettifying and Linting TypeScript files..."
for dir in $TYPESCRIPT_DIRS; do
if [ -d "$dir" ]; then
echo "# Prettifying and Linting $dir" >> "$LINTING_MD"
# Prettify
(cd "$dir" && npx prettier --write .) >> "$LINTING_MD" 2>&1
# Lint
(cd "$dir" && npm run lint) >> "$LINTING_MD" 2>&1
fi
done
}
# Prettify and Lint Rust files
prettify_lint_rust() {
echo "Prettifying and Linting Rust files..."
for dir in $RUST_DIRS; do
if [ -d "$dir" ]; then
echo "# Prettifying and Linting $dir" >> "$LINTING_MD"
# Prettify
(cd "$dir" && cargo fmt) >> "$LINTING_MD" 2>&1
# Lint
(cd "$dir" && cargo clippy -- -D warnings) >> "$LINTING_MD" 2>&1
fi
done
}
# Run the prettifying and linting functions
prettify_lint_python
prettify_lint_js
prettify_lint_ts
prettify_lint_rust
# Run the performance measurement script
echo "Running performance measurement..."
chmod +x ./measure_performance.sh
./measure_performance.sh