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

3
.gitignore vendored
View File

@ -340,4 +340,5 @@ dist
solution
helper.md
*/input.txt
*/input.txt
Linting.md

View File

@ -1,29 +1,16 @@
# Performance Analytics
## Day01
| Language | Status | Real Time | User Time | Sys Time |
| ---------- | ------- | --------- | --------- | -------- |
| Python | Success | 0m0,090s | 0m0,073s | 0m0,017s |
| Rust | Success | 0m0,057s | 0m0,049s | 0m0,008s |
| JavaScript | Success | 0m0,080s | 0m0,068s | 0m0,020s |
| TypeScript | Failed | - | - | - |
| Language | Status | Real Time | User Time | Sys Time |
| --- | --- | --- | --- | --- |
| Python | Success | 0m0,090s | 0m0,065s | 0m0,025s |
| Rust | Success | 0m0,111s | 0m0,062s | 0m0,048s |
| JavaScript | Success | 0m0,079s | 0m0,073s | 0m0,013s |
| TypeScript | Success | 0m1,300s | 0m2,668s | 0m0,201s |
## Day02
| Language | Status | Real Time | User Time | Sys Time |
| ---------- | ------- | --------- | --------- | -------- |
| Python | Success | 0m0,047s | 0m0,039s | 0m0,008s |
| Rust | Success | 0m0,059s | 0m0,032s | 0m0,028s |
| JavaScript | Success | 0m0,046s | 0m0,031s | 0m0,015s |
| 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 |
| -------- | ------ | --------- | --------- | -------- |
| --- | --- | --- | --- | --- |
| Python | Success | 0m0,048s | 0m0,033s | 0m0,012s |
| Rust | Success | 0m0,097s | 0m0,062s | 0m0,035s |
| JavaScript | Success | 0m0,045s | 0m0,041s | 0m0,004s |

View File

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

View File

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

View File

@ -7,12 +7,11 @@ fn main() {
match read_lines(path) {
Ok(lines) => {
let mut total = 0;
for line in lines {
if let Ok(ip) = line {
let value = extract_calibration_value(&ip);
println!("Line: '{}', Calibration Value: {}", ip, value);
total += value;
}
// Using flatten to directly iterate over Ok values
for ip in lines.flatten() {
let value = extract_calibration_value(&ip);
println!("Line: '{}', Calibration Value: {}", ip, value);
total += value;
}
println!("Total Calibration Value: {}", total);
}
@ -39,18 +38,24 @@ fn extract_calibration_value(line: &str) -> u32 {
fn extract_digits(line: &str) -> Vec<u32> {
let digit_map = vec![
("zero", 0), ("one", 1), ("two", 2), ("three", 3), ("four", 4),
("five", 5), ("six", 6), ("seven", 7), ("eight", 8), ("nine", 9),
("zero", 0),
("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 current_line = line.to_string();
// Iterate over each character in the line
while !current_line.is_empty() {
let mut found = false;
// Check for word representations of digits
for (word, digit) in &digit_map {
if current_line.starts_with(word) {
digits.push(*digit);
@ -60,7 +65,6 @@ fn extract_digits(line: &str) -> Vec<u32> {
}
}
// Check for single digit characters
if !found {
if let Some(first_char) = current_line.chars().next() {
if let Some(digit) = first_char.to_digit(10) {
@ -91,7 +95,12 @@ mod tests {
];
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:
int, dict: Game ID and a dictionary with color counts.
"""
parts = line.split(': ')
game_id = int(parts[0].split(' ')[1])
color_counts = {'red': 0, 'green': 0, 'blue': 0}
subsets = parts[1].split('; ')
parts = line.split(": ")
game_id = int(parts[0].split(" ")[1])
color_counts = {"red": 0, "green": 0, "blue": 0}
subsets = parts[1].split("; ")
for subset in subsets:
colors = subset.split(', ')
colors = subset.split(", ")
for color in colors:
count, color_name = color.split(' ')
color_name = color_name.strip() # Remove any trailing whitespace or newline characters
count, color_name = color.split(" ")
color_name = (
color_name.strip()
) # Remove any trailing whitespace or newline characters
color_counts[color_name] = max(color_counts[color_name], int(count))
return game_id, color_counts
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.
@ -35,9 +38,12 @@ def is_game_possible(game_data, red_cubes, green_cubes, blue_cubes):
Returns:
bool: True if the game is possible, False otherwise.
"""
return (game_data['red'] <= red_cubes and
game_data['green'] <= green_cubes and
game_data['blue'] <= blue_cubes)
return (
game_data["red"] <= red_cubes
and game_data["green"] <= green_cubes
and game_data["blue"] <= 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:
int: Sum of IDs of possible games.
"""
with open(file_path, 'r') as file:
with open(file_path, "r") as file:
lines = file.readlines()
sum_of_ids = 0
@ -63,17 +69,19 @@ def process_games(file_path, red_cubes, green_cubes, blue_cubes):
return sum_of_ids
def test():
print("start testing")
# Test the function
result = process_games('../test.txt', 12, 13, 14)
result = process_games("../test.txt", 12, 13, 14)
# Assertion for testing
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")
# Run the test
test()
# 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}")

View File

@ -8,20 +8,23 @@ def parse_game_data(line):
Returns:
int, dict: Game ID and a dictionary with color counts.
"""
parts = line.split(': ')
game_id = int(parts[0].split(' ')[1])
color_counts = {'red': 0, 'green': 0, 'blue': 0}
subsets = parts[1].split('; ')
parts = line.split(": ")
game_id = int(parts[0].split(" ")[1])
color_counts = {"red": 0, "green": 0, "blue": 0}
subsets = parts[1].split("; ")
for subset in subsets:
colors = subset.split(', ')
colors = subset.split(", ")
for color in colors:
count, color_name = color.split(' ')
color_name = color_name.strip() # Remove any trailing whitespace or newline characters
count, color_name = color.split(" ")
color_name = (
color_name.strip()
) # Remove any trailing whitespace or newline characters
color_counts[color_name] = max(color_counts[color_name], int(count))
return game_id, color_counts
def calculate_power_of_set(game_data):
"""
Calculates the power of the cube set.
@ -32,7 +35,8 @@ def calculate_power_of_set(game_data):
Returns:
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):
"""
@ -44,7 +48,7 @@ def process_games(file_path):
Returns:
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()
sum_of_powers = 0
@ -55,18 +59,22 @@ def process_games(file_path):
return sum_of_powers
def test():
print("start testing")
sum_of_powers = process_games('../test.txt')
sum_of_powers = process_games("../test.txt")
# 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")
# Run the test
test()
# 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}")

View File

@ -1,11 +1,16 @@
use std::collections::HashMap;
use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;
use std::collections::HashMap;
fn parse_game_data(line: &str) -> (i32, HashMap<String, i32>) {
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();
color_counts.insert("red".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 {
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 {
@ -48,10 +55,20 @@ fn process_games(file_path: &Path) -> i32 {
fn main() {
// Test the function with test data
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);
println!("Test Passed: Sum of powers for the minimum cube sets is {}\n", test_result);
assert_eq!(
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
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):
"""Reads the engine schematic from a file and returns it as a list of strings."""
try:
with open(file_path, 'r') as file:
with open(file_path, "r") as file:
return [line.strip() for line in file.readlines()]
except FileNotFoundError:
raise Exception(f"File not found: {file_path}")
def is_symbol(char):
"""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):
"""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:
yield i, j
def find_start_of_number(schematic, row, col):
"""Finds the start position of the number that includes the given digit."""
while col > 0 and schematic[row][col - 1].isdigit():
col -= 1
return row, col
def extract_full_number(schematic, start_row, start_col):
"""Extracts the full number starting from the given digit coordinates."""
start_row, start_col = find_start_of_number(schematic, start_row, start_col)
number = ''
rows, cols = len(schematic), len(schematic[0])
number = ""
cols = len(schematic[0])
col = start_col
while col < cols and schematic[start_row][col].isdigit():
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
return int(number) if number else 0
def sum_part_numbers(file_path):
"""Calculates the sum of all part numbers in the engine schematic."""
schematic = parse_schematic(file_path)
@ -48,7 +52,9 @@ def sum_part_numbers(file_path):
for row in range(len(schematic)):
for col in range(len(schematic[row])):
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:
visited.add((i, j))
number = extract_full_number(schematic, i, j)
@ -57,12 +63,14 @@ def sum_part_numbers(file_path):
return total_sum
def run_tests():
"""Runs tests on the test file and prints the results."""
test_result = sum_part_numbers("../test.txt")
print(f"Test Result: {test_result}")
assert test_result == 4361, f"Test failed: Expected 4361, got {test_result}"
def main():
"""Main function to run the test and then process the input file."""
try:
@ -73,5 +81,6 @@ def main():
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
main()

View File

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

View File

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

View File

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

View File

@ -1,5 +1,3 @@
import os
def map_seed_through_category(seed, line):
"""Maps a single seed through a category based on a mapping line."""
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 seed
def process_category(file, seeds):
"""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
for line in file:
line = line.strip()
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
dest_start, source_start, range_length = map(int, line.split())
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)
# 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}")
return updated_seeds
def process_file(file_path, is_test=False):
"""Processes the file to find the lowest location number for the seeds."""
try:
with open(file_path, 'r') as file:
seeds = list(map(int, file.readline().split(':')[1].split()))
with open(file_path, "r") as file:
seeds = list(map(int, file.readline().split(":")[1].split()))
print(f"Initial Seeds: {seeds}")
while True:
line = file.readline()
if not line: # End of file
break
if ':' in line: # Start of a new category map
if ":" in line: # Start of a new category map
seeds = process_category(file, seeds)
lowest_location = min(seeds)
@ -54,13 +57,15 @@ def process_file(file_path, is_test=False):
except Exception as e:
print(f"An error occurred processing '{file_path}': {e}")
def test():
"""Run tests using the test.txt file."""
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}"
print(f"Test passed: {result}")
def main():
"""Main function to process the input file and display results."""
try:
@ -74,5 +79,6 @@ def main():
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
main()

View File

@ -1,11 +1,12 @@
import os
import gc
from itertools import groupby
def free_up_memory():
"""Explicitly frees up memory."""
gc.collect()
def parse_input(file_path):
"""Parses the input file into seeds and categories."""
with open(file_path) as file:
@ -20,6 +21,7 @@ def parse_input(file_path):
]
return seeds_numbers, categories
def process_categories(seeds_numbers, categories):
"""Processes the seed ranges through all categories."""
for category in categories:
@ -49,6 +51,7 @@ def process_categories(seeds_numbers, categories):
seeds_numbers = sources
return seeds_numbers
def find_lowest_location(file_path, is_test=False, expected_result=None):
"""Finds the lowest location number from the input file."""
try:
@ -57,7 +60,9 @@ def find_lowest_location(file_path, is_test=False, expected_result=None):
lowest_location = min(seeds_numbers)[0]
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.")
else:
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:
print(f"An error occurred processing '{file_path}': {e}")
def test():
"""Run tests using the test.txt file."""
print("Starting test")
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():
"""Main function to process the input file and display results."""
@ -87,5 +94,6 @@ def main():
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
main()

View File

@ -3,6 +3,13 @@ use std::io::{self, BufRead};
use std::path::Path;
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>>>
where
P: AsRef<Path>,
@ -11,10 +18,10 @@ where
Ok(io::BufReader::new(file).lines())
}
fn parse_input(file_path: &str) -> io::Result<(Vec<(i32, i32)>, Vec<Vec<(i32, i32, i32)>>)> {
let mut seeds_numbers = Vec::new();
let mut categories = Vec::new();
let mut current_category = Vec::new();
fn parse_input(file_path: &str) -> io::Result<(SeedNumbers, Categories)> {
let mut seeds_numbers = SeedNumbers::new();
let mut categories = Categories::new();
let mut current_category = Category::new();
let mut is_seed_line = true;
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 !current_category.is_empty() {
categories.push(current_category);
current_category = Vec::new();
current_category = Category::new();
}
is_seed_line = false;
continue;
}
if is_seed_line {
let seeds_ranges: Vec<i32> = line.split_whitespace()
let seeds_ranges: Vec<i32> = line
.split_whitespace()
.skip(1)
.filter_map(|s| i32::from_str(s).ok())
.collect();
@ -40,7 +48,8 @@ fn parse_input(file_path: &str) -> io::Result<(Vec<(i32, i32)>, Vec<Vec<(i32, i3
}
}
} else {
let numbers: Vec<i32> = line.split_whitespace()
let numbers: Vec<i32> = line
.split_whitespace()
.filter_map(|s| i32::from_str(s).ok())
.collect();
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))
}
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 {
let mut sources = Vec::new();
let mut sources = SeedNumbers::new();
while let Some((start, end)) = seeds_numbers.pop() {
let mut is_mapped = false;
for &(destination, source, length) in &category {
let overlap_start = std::cmp::max(start, source);
let overlap_end = std::cmp::min(end, source + length);
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 {
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> {
let (seeds_numbers, categories) = parse_input(file_path)?;
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)
}
fn main() -> io::Result<()> {
// Test
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.");
// Process actual input

View File

@ -1,12 +1,15 @@
def parse_input(file_path):
"""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()
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}")
return times, distances
def calculate_winning_ways(time, record):
"""Calculate the number of ways to beat the record for a single race."""
print(f"Calculating winning ways for time: {time}, record: {record}")
@ -16,13 +19,16 @@ def calculate_winning_ways(time, record):
speed = hold_time
remaining_time = time - hold_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
if distance > record:
winning_ways += 1
print(f"Winning ways for this race: {winning_ways}")
return winning_ways
def total_winning_combinations(times, distances):
"""Calculate the total number of winning combinations for all races."""
print("Calculating total winning combinations.")
@ -36,6 +42,7 @@ def total_winning_combinations(times, distances):
print(f"Total winning combinations: {total_combinations}")
return total_combinations
def run_test(file_path):
"""Run the test with assertions to verify the functionality."""
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}"
print("Test passed successfully.")
def main():
"""Main function to run the test and then process the input file."""
try:
@ -64,5 +72,6 @@ def main():
except Exception as e:
print(f"An unexpected error occurred: {e}")
if __name__ == "__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.
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()
time = int(''.join(filter(str.isdigit, lines[0].strip())))
distance = int(''.join(filter(str.isdigit, lines[1].strip())))
time = int("".join(filter(str.isdigit, lines[0].strip())))
distance = int("".join(filter(str.isdigit, lines[1].strip())))
print(f"Parsed input from {file_path} - Time: {time}, Distance: {distance}")
return time, distance
def calculate_winning_ways(time, record):
"""
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
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
def run_test(file_path, 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)
result = calculate_winning_ways(time, record)
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.")
def main():
"""
Main function to run the test and then process the actual input file.
@ -61,5 +68,6 @@ def main():
except Exception as e:
print(f"An unexpected error occurred: {e}")
if __name__ == "__main__":
main()

View File

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

View File

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

View File

@ -1,41 +1,45 @@
import os
from collections import Counter
def read_hands(file_path):
try:
with open(file_path, 'r') as file:
with open(file_path, "r") as file:
print("Reading hands...")
return [line.strip().split() for line in file]
except Exception as e:
print(f"Error reading file {file_path}: {e}")
raise
def replace_face_cards(hand):
replacements = {'T': 'a', 'J': '1', 'Q': 'c', 'K': 'd', 'A': 'e'}
return ''.join(replacements.get(card, card) for card in hand)
replacements = {"T": "a", "J": "1", "Q": "c", "K": "d", "A": "e"}
return "".join(replacements.get(card, card) for card in hand)
def strength(hand):
hand = replace_face_cards(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':
C[target] += C['1']
del C['1']
if "1" in C and target != "1":
C[target] += C["1"]
del C["1"]
if sorted(C.values()) == [5]:
category = 10
elif sorted(C.values()) == [1,4]:
elif sorted(C.values()) == [1, 4]:
category = 9
elif sorted(C.values()) == [2,3]:
elif sorted(C.values()) == [2, 3]:
category = 8
elif sorted(C.values()) == [1,1,3]:
elif sorted(C.values()) == [1, 1, 3]:
category = 7
elif sorted(C.values()) == [1,2,2]:
elif sorted(C.values()) == [1, 2, 2]:
category = 6
elif sorted(C.values()) == [1,1,1,2]:
elif sorted(C.values()) == [1, 1, 1, 2]:
category = 5
elif sorted(C.values()) == [1,1,1,1,1]:
elif sorted(C.values()) == [1, 1, 1, 1, 1]:
category = 4
else:
raise ValueError(f"Invalid hand: {C} {hand}")
@ -43,27 +47,35 @@ def strength(hand):
print(f"Hand: {hand}, Category: {category}")
return (category, hand)
def hand_key(hand):
return strength(hand[0])
def calculate_total_winnings(file_path):
hands = read_hands(file_path)
print("Sorting hands based on strength...")
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...")
return total_winnings
def test(file_path):
print(f"Running test with {file_path}...")
try:
expected_result = 5905
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}")
except Exception as e:
print(f"Test failed: {e}")
def main():
try:
test("../test.txt")
@ -72,5 +84,6 @@ def main():
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
main()

View File

@ -7,14 +7,12 @@ fn read_hands(filename: &str) -> io::Result<Vec<(String, i32)>> {
let lines = io::BufReader::new(file).lines();
let mut hands = Vec::new();
for line in lines {
if let Ok(line) = line {
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() == 2 {
let hand = parts[0].to_string();
let bid: i32 = parts[1].parse().unwrap();
hands.push((hand, bid));
}
for line in lines.flatten() {
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() == 2 {
let hand = parts[0].to_string();
let bid: i32 = parts[1].parse().unwrap();
hands.push((hand, bid));
}
}
Ok(hands)
@ -22,11 +20,11 @@ fn read_hands(filename: &str) -> io::Result<Vec<(String, i32)>> {
fn replace_face_cards(hand: &str) -> String {
let mut replaced = hand.to_string();
replaced = replaced.replace("T", "a");
replaced = replaced.replace("J", "1");
replaced = replaced.replace("Q", "c");
replaced = replaced.replace("K", "d");
replaced = replaced.replace("A", "e");
replaced = replaced.replace('T', "a");
replaced = replaced.replace('J', "1");
replaced = replaced.replace('Q', "c");
replaced = replaced.replace('K', "d");
replaced = replaced.replace('A', "e");
replaced
}
@ -44,7 +42,11 @@ fn calculate_strength(hand: &str) -> (i32, String) {
let mut best_category = 4; // Default to High card
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 {
5 => 10,
4 => 9,
@ -56,7 +58,10 @@ fn calculate_strength(hand: &str) -> (i32, String) {
// Use original hand for tie-breaking
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)
}
@ -69,17 +74,30 @@ fn calculate_total_winnings(hands: Vec<(String, i32)>) -> i32 {
(strength_b, tie_breaker_b).cmp(&(strength_a, tie_breaker_a))
});
sorted_hands.iter().enumerate().fold(0, |acc, (i, (hand, bid))| {
let winnings = bid * (i as i32 + 1);
println!("Hand: {}, Rank: {}, Bid: {}, Winnings: {}", hand, i + 1, bid, winnings);
acc + winnings
})
sorted_hands
.iter()
.enumerate()
.fold(0, |acc, (i, (hand, bid))| {
let winnings = bid * (i as i32 + 1);
println!(
"Hand: {}, Rank: {}, Bid: {}, Winnings: {}",
hand,
i + 1,
bid,
winnings
);
acc + winnings
})
}
fn main() {
let test_hands = read_hands("../test.txt").expect("Failed to read test file");
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);
let hands = read_hands("../input.txt").expect("Failed to read input file");

View File

@ -1,20 +1,21 @@
def parse_file(file_path):
"""Parse the input file to extract instructions and the node map."""
try:
with open(file_path, 'r') as file:
with open(file_path, "r") as file:
lines = file.readlines()
instructions = lines[0].strip()
node_map = {}
for line in lines[2:]:
node, neighbors = line.strip().split(' = ')
node_map[node] = tuple(neighbors[1:-1].split(', '))
node, neighbors = line.strip().split(" = ")
node_map[node] = tuple(neighbors[1:-1].split(", "))
return instructions, node_map
except Exception as e:
print(f"Error parsing file {file_path}: {e}")
raise
def find_repeating_unit(sequence):
"""Find the repeating unit in a sequence."""
for i in range(1, len(sequence) + 1):
@ -23,7 +24,8 @@ def find_repeating_unit(sequence):
return unit
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."""
current_node = start_node
steps = 0
@ -33,28 +35,34 @@ def navigate_network(instructions, node_map, start_node='AAA', end_node='ZZZ'):
while current_node != end_node:
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
visited.add((current_node, instruction_index))
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
steps += 1
return steps
def run_test():
"""Run the test with the provided file path."""
try:
expected_result = 6
instructions, node_map = parse_file("../test.txt")
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.")
except AssertionError as error:
print(error)
def main():
print("Start Tests")
run_test()
@ -70,5 +78,6 @@ def main():
except Exception as e:
print(f"Error during main execution: {e}")
if __name__ == "__main__":
main()

View File

@ -1,18 +1,19 @@
import sys
from math import gcd
def parse_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()
steps, rule = D.split('\n\n')
GO = {'L': {}, 'R': {}}
for line in rule.split('\n'):
st, lr = line.split('=')
left, right = lr.split(',')
GO['L'][st.strip()] = left.strip()[1:].strip()
GO['R'][st.strip()] = right[:-1].strip()
return [0 if char == 'L' else 1 for char in steps], GO
steps, rule = D.split("\n\n")
GO = {"L": {}, "R": {}}
for line in rule.split("\n"):
st, lr = line.split("=")
left, right = lr.split(",")
GO["L"][st.strip()] = left.strip()[1:].strip()
GO["R"][st.strip()] = right[:-1].strip()
return [0 if char == "L" else 1 for char in steps], GO
def lcm(xs):
ans = 1
@ -20,16 +21,17 @@ def lcm(xs):
ans = (x * ans) // gcd(x, ans)
return ans
def navigate_network_simultaneously(steps, GO):
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 = 0
while True:
NP = []
for i, p in enumerate(POS):
p = GO['L' if steps[t % len(steps)] == 0 else 'R'][p]
if p.endswith('Z'):
p = GO["L" if steps[t % len(steps)] == 0 else "R"][p]
if p.endswith("Z"):
T[i] = t + 1
if len(T) == len(POS):
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}")
assert False
def run_test():
print("Running test...")
expected_result = 6
steps, GO = parse_file("../test2.txt")
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.")
def main():
run_test()
steps, GO = parse_file("../input.txt")
result = navigate_network_simultaneously(steps, GO)
print(f"All paths reached 'Z' nodes simultaneously in {result} steps.")
if __name__ == "__main__":
main()

View File

@ -1,7 +1,10 @@
use std::fs;
use std::collections::HashMap;
use std::fs;
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 {
if b == 0 {
a
@ -14,10 +17,12 @@ fn lcm(a: u64, b: u64) -> u64 {
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 mut sections = data.trim().split("\n\n");
let steps = sections.next().unwrap()
let steps = sections
.next()
.unwrap()
.chars()
.map(|c| if c == 'L' { 0 } else { 1 })
.collect();
@ -27,7 +32,9 @@ fn parse_file(file_path: &Path) -> Result<(Vec<u8>, HashMap<String, (String, Str
for line in rules_section.lines() {
let mut parts = line.split('=').map(str::trim);
let state = parts.next().unwrap().to_string();
let directions = parts.next().unwrap()
let directions = parts
.next()
.unwrap()
.split(',')
.map(str::trim)
.map(|s| s.trim_matches(|c: char| c == '(' || c == ')').to_string())
@ -40,20 +47,25 @@ 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 {
let start_nodes: Vec<String> = rules.keys()
.filter(|k| k.ends_with('A'))
.cloned()
.collect();
let start_nodes: Vec<String> = rules.keys().filter(|k| k.ends_with('A')).cloned().collect();
let mut current_nodes = start_nodes.clone();
let mut step_count = 0;
let mut time_to_z = HashMap::new();
while time_to_z.len() < start_nodes.len() {
for (i, node) in current_nodes.iter_mut().enumerate() {
let direction = if steps[step_count % steps.len()] == 0 { 'L' } else { 'R' };
let next_node = if direction == 'L' { &rules[node].0 } else { &rules[node].1 };
let direction = if steps[step_count % steps.len()] == 0 {
'L'
} else {
'R'
};
let next_node = if direction == 'L' {
&rules[node].0
} else {
&rules[node].1
};
*node = next_node.clone();
if next_node.ends_with('Z') && !time_to_z.contains_key(&i) {
time_to_z.insert(i, step_count + 1);
}
@ -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))
}
fn run_test(test_file: &Path) {
fn run_test(test_path: &Path) {
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);
assert_eq!(result, 6, "Test failed: expected 6, got {}", result);
println!("Test passed with {} steps.", result);
@ -80,10 +92,13 @@ fn run_test(test_file: &Path) {
fn main() {
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 (steps, rules) = parse_file(&input_path).expect("Failed to parse input file");
let result = navigate_network_simultaneously(&steps, &rules);
println!("All paths reached 'Z' nodes simultaneously in {} steps.", result);
let (steps, rules) = parse_file(input_path).expect("Failed to parse input file"); // Removed needless borrow
let result = navigate_network_simultaneously(&steps, &rules); // Calculate result for input file
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 {
while (b !== 0) {
let t = b;
const t = b;
b = a % b;
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 {
console.log("Starting navigation of network.");
const startNodes = Object.keys(rules['L']).filter((node: string) => node.endsWith('A'));
let currentNodes = startNodes;
const currentNodes = startNodes;
let stepCount = 0;
const timeToZ: { [key: number]: number } = {};
@ -74,8 +74,8 @@ function main(): void {
const { steps, rules } = parseFile(inputPath);
const result = navigateNetworkSimultaneously(steps, rules);
console.log(`All paths reached 'Z' nodes simultaneously in ${result} steps.`);
} catch (error: any) {
console.error(`Error: ${error.message}`);
} catch (error) {
console.error(`Error: ${(error as Error).message}`);
}
}

View File

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

View File

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

View File

@ -38,7 +38,10 @@ fn solve_puzzle(filename: &str) -> Result<i32, io::Error> {
if line.trim().is_empty() {
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 prev_value = extrapolate_previous_value(&mut diff_table);
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
let expected = 2; // Expected result from the test data for the second part
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.");
Ok(())
}

View File

@ -2,9 +2,9 @@ import fs from 'fs';
function generateDifferenceTable(history: number[]): number[][] {
// 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)) {
let nextRow: number[] = [];
const nextRow: number[] = [];
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]);
}

View File

@ -1,15 +1,16 @@
def parse_grid(file_path):
"""Parses the grid from a file and returns it as a 2D list."""
try:
with open(file_path, 'r') as file:
with open(file_path, "r") as file:
grid = [list(line.strip()) for line in file]
print(f"Grid parsed from {file_path}:")
[print(''.join(row)) for row in grid]
[print("".join(row)) for row in grid]
return grid
except Exception as e:
print(f"Error reading file {file_path}: {e}")
raise
def create_graph(grid):
"""Creates a graph from the grid."""
graph = {}
@ -22,31 +23,38 @@ def create_graph(grid):
print(graph)
return graph
def get_neighbors(grid, r, c):
"""Finds the neighbors of a cell in the grid."""
neighbors = []
rows, cols = len(grid), len(grid[0])
# 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 = {
"|": [0, 2], "-": [1, 3],
"L": [0, 1], "J": [0, 3],
"7": [2, 3], "F": [1, 2],
"S": [0, 1, 2, 3] # 'S' connects in all directions for initial identification
"|": [0, 2],
"-": [1, 3],
"L": [0, 1],
"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):
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]
# Check if there is a valid connection
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))
print(f"Neighbors for ({r}, {c}): {neighbors}")
return neighbors
def bfs(graph, start):
"""Performs BFS on the graph and returns the maximum distance from the start."""
visited = set()
@ -64,15 +72,17 @@ def bfs(graph, start):
print(f"Maximum distance from start: {max_distance}")
return max_distance
def find_start(grid):
"""Finds the starting position 'S' in the grid."""
for r, row in enumerate(grid):
for c, cell in enumerate(row):
if cell == 'S':
if cell == "S":
print(f"Starting position found at: ({r}, {c})")
return r, c
raise ValueError("Starting position 'S' not found in the grid")
def run_test(file_path):
"""Runs the algorithm on a test file and asserts the result."""
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}")
return max_distance
def main(file_path):
"""Main function to run the algorithm on the input file."""
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}")
return max_distance
if __name__ == "__main__":
test_result = run_test("../test.txt")
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