Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/advent_of_code/year_2024/day_04.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import numpy as np

from advent_of_code.utils.input_handling import read_input

STRING_TO_FIND = "XMAS"
Expand Down
19 changes: 14 additions & 5 deletions src/advent_of_code/year_2025/day_02.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from advent_of_code.utils.input_handling import read_input

VALID_PARTS = (1,2)
VALID_PARTS = (1, 2)


def parse_input(raw):
raw_split = raw[0].split(",")
Expand All @@ -25,17 +26,23 @@ def check_id_valid(id):
else:
return True


def check_id_valid_v2(id):
id_len = len(str(id))
half_len = id_len // 2
for sub_str_len in range(1,half_len+1):
for sub_str_len in range(1, half_len + 1):
sub_str = id[:sub_str_len]
str_to_search = id[sub_str_len:]
if (len(str_to_search) % sub_str_len == 0): # substr divisible by search str length
if (sub_str * (id_len // sub_str_len) == id): # substr matches N * search string
if (
len(str_to_search) % sub_str_len == 0
): # substr divisible by search str length
if (
sub_str * (id_len // sub_str_len) == id
): # substr matches N * search string
return False
return True


def get_invalid_ids_in_range(range_pair, part):
full_range = range(range_pair[0], range_pair[1] + 1)

Expand All @@ -45,7 +52,7 @@ def get_invalid_ids_in_range(range_pair, part):
id_checker_function = check_id_valid_v2
else:
raise ValueError("Specify a valid part number")

invalid_ids = []
for x in full_range:
if not id_checker_function(str(x)):
Expand Down Expand Up @@ -74,10 +81,12 @@ def solve_part(parsed_input, part):
invalid_ids = find_all_invalid_ids(parsed_input, part)
return sum_invalid_ids(invalid_ids)


def solve_part_2(parsed_input):
invalid_ids = find_all_invalid_ids(parsed_input)
return sum_invalid_ids(invalid_ids)


def solve(parsed_input):
part_1_solution = solve_part(parsed_input, part=1)
part_2_solution = solve_part(parsed_input, part=2)
Expand Down
59 changes: 35 additions & 24 deletions src/advent_of_code/year_2025/day_03.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,58 @@
from advent_of_code.utils.input_handling import read_input


def parse_battery_bank_to_ints_list(battery_bank_str):
return [int(x) for x in battery_bank_str]


def combine_joltages(j1, j2):
return int(f"{j1}{j2}")
def combine_joltages(list_of_joltages):
return int("".join([str(x) for x in list_of_joltages]))


def find_max_and_leftmost_index(input_list):
max_value = max(input_list)
leftmost_index = input_list.index(max_value)
return max_value, leftmost_index


def calculate_largest_joltage(battery_bank_as_ints, n_batteries):

def calculate_largest_joltage(battery_bank_as_ints):
largest_joltage_1 = 0

batteries_remaining = n_batteries
bank_len = len(battery_bank_as_ints)
list_of_joltages = []
start_ix = 0

print(f"Calculating largest joltage for battery bank: {battery_bank_as_ints}")
while batteries_remaining > 0:
end_ix = bank_len - batteries_remaining + 1
window_to_check = battery_bank_as_ints[start_ix:end_ix]

for battery_index, battery_value in enumerate(battery_bank_as_ints):
print(f"battery_value={battery_value}, battery_index={battery_index}")
if (battery_value > largest_joltage_1) and (battery_index < len(battery_bank_as_ints) - 1):
largest_joltage_1 = battery_value
largest_joltage_2 = 0
print(f"Larger value found! Setting largest_joltage_1 to {largest_joltage_1}")
for second_battery_value in battery_bank_as_ints[battery_index+1:]:
print(f"second_battery_value={second_battery_value}")
if second_battery_value > largest_joltage_2:
largest_joltage_2 = second_battery_value
print(f"Larger value found! Setting largest_joltage_2 to {largest_joltage_2}")
# find largest value in window and the left-most index for dupes
max_value, leftmost_index_window = find_max_and_leftmost_index(window_to_check)
leftmost_index = leftmost_index_window + start_ix
list_of_joltages.append(max_value)

print(f"Largest joltage combination: {largest_joltage_1}, {largest_joltage_2}")

return combine_joltages(largest_joltage_1, largest_joltage_2)
# reassign start_ix and update remaining batteries
start_ix = leftmost_index + 1
batteries_remaining -= 1

def solve_part_1(input):
print(f"list_of_joltages={list_of_joltages}")
return combine_joltages(list_of_joltages)


def solve_part(input, n_batteries):
joltage_list = []

for battery_bank_str in input:
battery_bank_as_ints = parse_battery_bank_to_ints_list(battery_bank_str)
largest_joltage = calculate_largest_joltage(battery_bank_as_ints)
largest_joltage = calculate_largest_joltage(battery_bank_as_ints, n_batteries)
joltage_list.append(largest_joltage)

return sum(joltage_list)


def solve(input):
part_1_solution = solve_part_1(input)
part_2_solution = None
part_1_solution = solve_part(input, n_batteries=2)
part_2_solution = solve_part(input, n_batteries=12)
return (part_1_solution, part_2_solution)


Expand Down
1 change: 0 additions & 1 deletion tests/year_2023/test_day_01.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import pytest

from advent_of_code.year_2023.day_01 import (
convert_first_last_patterns_to_calibration_value,
convert_str_to_numerical,
Expand Down
1 change: 0 additions & 1 deletion tests/year_2023/test_day_02.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import pytest

from advent_of_code.year_2023.day_02 import (
check_game_is_possible,
find_max_shown_for_colour,
Expand Down
1 change: 0 additions & 1 deletion tests/year_2023/test_day_03.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import pytest

from advent_of_code.year_2023.day_03 import (
Part,
Symbol,
Expand Down
1 change: 0 additions & 1 deletion tests/year_2023/test_day_04.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import pytest

from advent_of_code.year_2023.day_04 import (
compute_copies,
compute_total_score,
Expand Down
1 change: 0 additions & 1 deletion tests/year_2023/test_day_06.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import math

import pytest

from advent_of_code.year_2023.day_06 import (
Race,
Races,
Expand Down
1 change: 0 additions & 1 deletion tests/year_2024/test_day_01.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import pytest

from advent_of_code.year_2024.day_01 import (
solve,
)
Expand Down
1 change: 0 additions & 1 deletion tests/year_2024/test_day_02.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import pytest

from advent_of_code.year_2024.day_02 import (
parse_input,
solve,
Expand Down
1 change: 0 additions & 1 deletion tests/year_2024/test_day_03.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import pytest

from advent_of_code.year_2024.day_03 import (
instruction_compute,
)
Expand Down
1 change: 0 additions & 1 deletion tests/year_2024/test_day_04.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import pytest

from advent_of_code.year_2024.day_04 import (
check_direction_safety,
solve,
Expand Down
1 change: 0 additions & 1 deletion tests/year_2025/test_day_01.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import pytest

from advent_of_code.year_2025.day_01 import (
points_at_zero_counter,
solve,
Expand Down
25 changes: 18 additions & 7 deletions tests/year_2025/test_day_02.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import pytest

from advent_of_code.year_2025.day_02 import (
check_id_valid,
check_id_valid_v2,
Expand Down Expand Up @@ -29,6 +28,7 @@ def test_solver(input, expected_output):
result = solve(input_parsed)
assert result == expected_output


# 11-22 still has two invalid IDs, 11 and 22.
# 95-115 now has two invalid IDs, 99 and 111.
# 998-1012 now has two invalid IDs, 999 and 1010.
Expand All @@ -41,6 +41,7 @@ def test_solver(input, expected_output):
# 824824821-824824827 now has one invalid ID, 824824824.
# 2121212118-2121212124 now has one invalid ID, 2121212121.


@pytest.mark.parametrize(
"input, expected_invalid_ids",
[
Expand All @@ -60,6 +61,7 @@ def test_solver(input, expected_output):
def test_find_invalid_ids_in_range_string_part_2(input, expected_invalid_ids):
assert expected_invalid_ids == find_invalid_ids_in_range_string(input, part=2)


@pytest.mark.parametrize(
"input, expected_invalid_ids",
[
Expand Down Expand Up @@ -105,19 +107,28 @@ def test_convert_range_string_to_pair(input, expected_pair):

@pytest.mark.parametrize(
"input, is_valid",
[("11", False), ("12", True), ("22", False), ("998", True), ("999", True), ("1010", False), ("565656", True)],
[
("11", False),
("12", True),
("22", False),
("998", True),
("999", True),
("1010", False),
("565656", True),
],
)
def test_check_id_valid(input, is_valid):
assert is_valid == check_id_valid(input)


@pytest.mark.parametrize(
"input, is_valid",
[
("11", False),
("12", True),
("22", False),
("998", True),
("999", False),
("11", False),
("12", True),
("22", False),
("998", True),
("999", False),
("1010", False),
("565656", False),
],
Expand Down
51 changes: 37 additions & 14 deletions tests/year_2025/test_day_03.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import pytest

from advent_of_code.year_2025.day_03 import (
solve,
calculate_largest_joltage,
parse_battery_bank_to_ints_list,
combine_joltages,
parse_battery_bank_to_ints_list,
solve,
)


Expand All @@ -20,29 +19,53 @@ def day_03_test_input():

@pytest.fixture
def day_03_expected_output():
return (357, None)
return (357, 3121910778619)


def test_solver(day_03_test_input, day_03_expected_output):
result = solve(day_03_test_input)
assert result == day_03_expected_output


@pytest.mark.parametrize(
"input, expected_output",
"input_str, expected_output_part_1, expected_output_part_2",
[
[[9,8,7,6,5,4,3,2,1,1,1,1,1,1,1],98],
[[8,1,1,1,1,1,1,1,1,1,1,1,1,1,9],89],
[[2,3,4,2,3,4,2,3,4,2,3,4,2,7,8],78],
[[8,1,8,1,8,1,9,1,1,1,1,2,1,1,1],92],
("987654321111111", 98, 987654321111),
("811111111111119", 89, 811111111119),
("234234234234278", 78, 434234234278),
("818181911112111", 92, 888911112111),
],
)
def test_calculate_largest_joltage(input, expected_output):
parsed_inputs = parse_battery_bank_to_ints_list(input)
assert expected_output == calculate_largest_joltage(parsed_inputs)
def test_calculate_largest_joltage(
input_str, expected_output_part_1, expected_output_part_2
):
parsed_inputs = parse_battery_bank_to_ints_list(input_str)
assert expected_output_part_1 == calculate_largest_joltage(
parsed_inputs, n_batteries=2
)
assert expected_output_part_2 == calculate_largest_joltage(
parsed_inputs, n_batteries=12
)


def test_parse_battery_bank_to_ints_list():
assert parse_battery_bank_to_ints_list("98765") == [9,8,7,6,5]
assert parse_battery_bank_to_ints_list("98765") == [9, 8, 7, 6, 5]


def test_combine_joltages():
assert combine_joltages(9, 8) == 98
assert combine_joltages([9, 8, 7]) == 987


@pytest.mark.parametrize(
"input_str, n_batteries, expected_output",
[
("987", 2, 98),
("6781", 2, 81),
("19181", 2, 98),
("19182", 3, 982),
("191821", 3, 982),
],
)
def test_calculate_largest_joltage_extra_cases(input_str, expected_output, n_batteries):
parsed_inputs = parse_battery_bank_to_ints_list(input_str)
assert expected_output == calculate_largest_joltage(parsed_inputs, n_batteries)