prettify and lint optimization
This commit is contained in:
parent
274c69d0c4
commit
4cd62ef794
3
.gitignore
vendored
3
.gitignore
vendored
@ -340,4 +340,5 @@ dist
|
||||
|
||||
solution
|
||||
helper.md
|
||||
*/input.txt
|
||||
*/input.txt
|
||||
Linting.md
|
33
Analytics.md
33
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 |
|
||||
|
@ -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"
|
||||
|
@ -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}")
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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}")
|
||||
|
@ -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}")
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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");
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
|
@ -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}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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
79
lint.sh
Executable 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
|
Loading…
Reference in New Issue
Block a user