From 4cd62ef794e846d935bc7eda9fbf1c419d775567 Mon Sep 17 00:00:00 2001 From: wieerwill Date: Sun, 10 Dec 2023 17:24:14 +0100 Subject: [PATCH] prettify and lint optimization --- .gitignore | 3 +- Analytics.md | 33 +++++----------- Day01/python/solution1.py | 6 ++- Day01/python/solution2.py | 21 ++++++++--- Day01/rust/src/main.rs | 33 ++++++++++------ Day02/python/solution1.py | 38 +++++++++++-------- Day02/python/solution2.py | 36 +++++++++++------- Day02/rust/src/main.rs | 29 +++++++++++--- Day03/python/solution1.py | 27 ++++++++----- Day03/python/solution2.py | 22 +++++++---- Day03/rust/src/main.rs | 18 +++++++-- Day04/python/solution1.py | 25 +++++++++---- Day04/python/solution2.py | 24 +++++++----- Day05/python/solution1.py | 24 +++++++----- Day05/python/solution2.py | 14 +++++-- Day05/rust/src/main.rs | 44 ++++++++++++++++------ Day06/python/solution1.py | 15 ++++++-- Day06/python/solution2.py | 18 ++++++--- Day06/rust/src/main.rs | 28 +++++++++++--- Day07/python/solution1.py | 25 +++++++++---- Day07/python/solution2.py | 45 ++++++++++++++-------- Day07/rust/src/main.rs | 60 ++++++++++++++++++----------- Day08/python/solution1.py | 23 ++++++++---- Day08/python/solution2.py | 35 ++++++++++------- Day08/rust/src/main.rs | 49 +++++++++++++++--------- Day08/ts/solution.ts | 8 ++-- Day09/python/solution1.py | 17 ++++++--- Day09/python/solution2.py | 15 ++++++-- Day09/rust/src/main.rs | 11 +++++- Day09/ts/solution.ts | 4 +- Day10/python/solution1.py | 32 +++++++++++----- lint.sh | 79 +++++++++++++++++++++++++++++++++++++++ 32 files changed, 599 insertions(+), 262 deletions(-) create mode 100755 lint.sh diff --git a/.gitignore b/.gitignore index ca3bc70..65461ec 100644 --- a/.gitignore +++ b/.gitignore @@ -340,4 +340,5 @@ dist solution helper.md -*/input.txt \ No newline at end of file +*/input.txt +Linting.md \ No newline at end of file diff --git a/Analytics.md b/Analytics.md index f591e0b..effade0 100644 --- a/Analytics.md +++ b/Analytics.md @@ -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 | diff --git a/Day01/python/solution1.py b/Day01/python/solution1.py index a787991..b847fc2 100644 --- a/Day01/python/solution1.py +++ b/Day01/python/solution1.py @@ -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" diff --git a/Day01/python/solution2.py b/Day01/python/solution2.py index 2c810be..3e26481 100644 --- a/Day01/python/solution2.py +++ b/Day01/python/solution2.py @@ -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}") diff --git a/Day01/rust/src/main.rs b/Day01/rust/src/main.rs index b005cf2..5e80409 100644 --- a/Day01/rust/src/main.rs +++ b/Day01/rust/src/main.rs @@ -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 { 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 { } } - // 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 + ); } } } diff --git a/Day02/python/solution1.py b/Day02/python/solution1.py index 6ee40bd..0ede0c4 100644 --- a/Day02/python/solution1.py +++ b/Day02/python/solution1.py @@ -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}") diff --git a/Day02/python/solution2.py b/Day02/python/solution2.py index 2f6f3a0..f2e8a60 100644 --- a/Day02/python/solution2.py +++ b/Day02/python/solution2.py @@ -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}") diff --git a/Day02/rust/src/main.rs b/Day02/rust/src/main.rs index c4f65ea..bdf6f96 100644 --- a/Day02/rust/src/main.rs +++ b/Day02/rust/src/main.rs @@ -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) { let parts: Vec<&str> = line.split(": ").collect(); - let game_id = parts[0].split_whitespace().nth(1).unwrap().parse::().unwrap(); + let game_id = parts[0] + .split_whitespace() + .nth(1) + .unwrap() + .parse::() + .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) { } fn calculate_power_of_set(game_data: &HashMap) -> 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 + ); } diff --git a/Day03/python/solution1.py b/Day03/python/solution1.py index 6ab5d22..447d51b 100644 --- a/Day03/python/solution1.py +++ b/Day03/python/solution1.py @@ -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() diff --git a/Day03/python/solution2.py b/Day03/python/solution2.py index f974ddb..41f3baa 100644 --- a/Day03/python/solution2.py +++ b/Day03/python/solution2.py @@ -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() diff --git a/Day03/rust/src/main.rs b/Day03/rust/src/main.rs index 6e8df12..d45693c 100644 --- a/Day03/rust/src/main.rs +++ b/Day03/rust/src/main.rs @@ -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) -> 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); diff --git a/Day04/python/solution1.py b/Day04/python/solution1.py index 0cf3073..c22e5b0 100644 --- a/Day04/python/solution1.py +++ b/Day04/python/solution1.py @@ -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() diff --git a/Day04/python/solution2.py b/Day04/python/solution2.py index 396affd..7e0e50b 100644 --- a/Day04/python/solution2.py +++ b/Day04/python/solution2.py @@ -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() diff --git a/Day05/python/solution1.py b/Day05/python/solution1.py index 7c519f0..4ab1187 100644 --- a/Day05/python/solution1.py +++ b/Day05/python/solution1.py @@ -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() diff --git a/Day05/python/solution2.py b/Day05/python/solution2.py index 604b62e..3a55817 100644 --- a/Day05/python/solution2.py +++ b/Day05/python/solution2.py @@ -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() diff --git a/Day05/rust/src/main.rs b/Day05/rust/src/main.rs index cf6fb36..fa0efe2 100644 --- a/Day05/rust/src/main.rs +++ b/Day05/rust/src/main.rs @@ -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; +type Category = Vec; +type Categories = Vec; + fn read_lines

(filename: P) -> io::Result>> where P: AsRef, @@ -11,10 +18,10 @@ where Ok(io::BufReader::new(file).lines()) } -fn parse_input(file_path: &str) -> io::Result<(Vec<(i32, i32)>, Vec>)> { - 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 = line.split_whitespace() + let seeds_ranges: Vec = 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 = line.split_whitespace() + let numbers: Vec = 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, categories: Vec>) -> 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 io::Result { 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 diff --git a/Day06/python/solution1.py b/Day06/python/solution1.py index ba039cc..2a85681 100644 --- a/Day06/python/solution1.py +++ b/Day06/python/solution1.py @@ -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() diff --git a/Day06/python/solution2.py b/Day06/python/solution2.py index 41a9e4a..0cc85f1 100644 --- a/Day06/python/solution2.py +++ b/Day06/python/solution2.py @@ -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() diff --git a/Day06/rust/src/main.rs b/Day06/rust/src/main.rs index b537658..a05cfc7 100644 --- a/Day06/rust/src/main.rs +++ b/Day06/rust/src/main.rs @@ -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::().parse::().unwrap_or(0); - let distance = distance_line.chars().filter(|c| c.is_digit(10)).collect::().parse::().unwrap_or(0); + let time = time_line + .chars() + .filter(|c| c.is_ascii_digit()) + .collect::() + .parse::() + .unwrap_or(0); + let distance = distance_line + .chars() + .filter(|c| c.is_ascii_digit()) + .collect::() + .parse::() + .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(()) } diff --git a/Day07/python/solution1.py b/Day07/python/solution1.py index 855b471..3d083bd 100644 --- a/Day07/python/solution1.py +++ b/Day07/python/solution1.py @@ -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() diff --git a/Day07/python/solution2.py b/Day07/python/solution2.py index d869261..bd7120d 100644 --- a/Day07/python/solution2.py +++ b/Day07/python/solution2.py @@ -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() diff --git a/Day07/rust/src/main.rs b/Day07/rust/src/main.rs index bd5841d..4ac7c6c 100644 --- a/Day07/rust/src/main.rs +++ b/Day07/rust/src/main.rs @@ -7,14 +7,12 @@ fn read_hands(filename: &str) -> io::Result> { 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> { 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::(); - 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"); diff --git a/Day08/python/solution1.py b/Day08/python/solution1.py index 9a2bda0..4b74b30 100644 --- a/Day08/python/solution1.py +++ b/Day08/python/solution1.py @@ -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() diff --git a/Day08/python/solution2.py b/Day08/python/solution2.py index 262fdc5..3453d05 100644 --- a/Day08/python/solution2.py +++ b/Day08/python/solution2.py @@ -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() diff --git a/Day08/rust/src/main.rs b/Day08/rust/src/main.rs index 0905e18..f128753 100644 --- a/Day08/rust/src/main.rs +++ b/Day08/rust/src/main.rs @@ -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, HashMap); + 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, HashMap), String> { +fn parse_file(file_path: &Path) -> Result { 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, HashMap Result<(Vec, HashMap) -> u64 { - let start_nodes: Vec = rules.keys() - .filter(|k| k.ends_with('A')) - .cloned() - .collect(); + let start_nodes: Vec = 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 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}`); } } diff --git a/Day09/python/solution1.py b/Day09/python/solution1.py index d08421b..f5a4299 100644 --- a/Day09/python/solution1.py +++ b/Day09/python/solution1.py @@ -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() diff --git a/Day09/python/solution2.py b/Day09/python/solution2.py index ac873bf..21f5623 100644 --- a/Day09/python/solution2.py +++ b/Day09/python/solution2.py @@ -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() diff --git a/Day09/rust/src/main.rs b/Day09/rust/src/main.rs index 4a62f54..6b030e7 100644 --- a/Day09/rust/src/main.rs +++ b/Day09/rust/src/main.rs @@ -38,7 +38,10 @@ fn solve_puzzle(filename: &str) -> Result { if line.trim().is_empty() { continue; } - let history: Vec = line.split_whitespace().map(|s| s.parse().unwrap()).collect(); + let history: Vec = 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(()) } diff --git a/Day09/ts/solution.ts b/Day09/ts/solution.ts index 1ddb532..d628c14 100644 --- a/Day09/ts/solution.ts +++ b/Day09/ts/solution.ts @@ -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]); } diff --git a/Day10/python/solution1.py b/Day10/python/solution1.py index cf5e4fc..e348c9a 100644 --- a/Day10/python/solution1.py +++ b/Day10/python/solution1.py @@ -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}" diff --git a/lint.sh b/lint.sh new file mode 100755 index 0000000..38354f0 --- /dev/null +++ b/lint.sh @@ -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 \ No newline at end of file