Compare commits
No commits in common. "2af6066ee3da9254a5ed6986cb4c300d95d4f3d6" and "9d0990e5e89c4fd7534b2960a7fed789ff468f0a" have entirely different histories.
2af6066ee3
...
9d0990e5e8
|
|
@ -157,19 +157,10 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<long> PseudoTerminalMaster::ioctl_impl(int request, void* argument)
|
||||
{
|
||||
switch (request)
|
||||
{
|
||||
case FIONREAD:
|
||||
*static_cast<int*>(argument) = m_buffer_size;
|
||||
return 0;
|
||||
case TIOCGWINSZ:
|
||||
case TIOCSWINSZ:
|
||||
if (auto slave = m_slave.lock())
|
||||
return slave->ioctl(request, argument);
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
}
|
||||
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
auto slave = m_slave.lock();
|
||||
if (!slave)
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
return slave->ioctl(request, argument);
|
||||
}
|
||||
|
||||
PseudoTerminalSlave::PseudoTerminalSlave(BAN::String&& name, uint32_t number, mode_t mode, uid_t uid, gid_t gid)
|
||||
|
|
|
|||
|
|
@ -202,11 +202,6 @@ namespace Kernel
|
|||
TRY(set_font(BAN::move(new_font)));
|
||||
return 0;
|
||||
}
|
||||
case FIONREAD:
|
||||
{
|
||||
*static_cast<int*>(argument) = m_output.flush ? m_output.bytes : 0;
|
||||
return 0;
|
||||
}
|
||||
case TIOCGWINSZ:
|
||||
{
|
||||
auto* winsize = static_cast<struct winsize*>(argument);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ add_custom_target(userspace)
|
|||
|
||||
#add_subdirectory(aoc2023)
|
||||
#add_subdirectory(aoc2024)
|
||||
#add_subdirectory(aoc2025)
|
||||
add_subdirectory(libraries)
|
||||
add_subdirectory(programs)
|
||||
add_subdirectory(tests)
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
set(AOC2025_PROJECTS
|
||||
day1
|
||||
day2
|
||||
day3
|
||||
day4
|
||||
day5
|
||||
day6
|
||||
day7
|
||||
day8
|
||||
day9
|
||||
day10
|
||||
day11
|
||||
day12
|
||||
full
|
||||
)
|
||||
|
||||
set(BANAN_AOC2025_BIN ${CMAKE_INSTALL_BINDIR}/aoc2025)
|
||||
set(BANAN_AOC2025_INPUT ${BANAN_SHARE}/aoc2025)
|
||||
|
||||
set(CMAKE_INSTALL_BINDIR ${BANAN_AOC2025_BIN})
|
||||
|
||||
add_custom_target(aoc2025)
|
||||
|
||||
file(GLOB_RECURSE input_files "input/*")
|
||||
foreach(file ${input_files})
|
||||
install(FILES ${file} DESTINATION ${BANAN_AOC2025_INPUT})
|
||||
endforeach()
|
||||
|
||||
foreach(AOC2025_PROJECT ${AOC2025_PROJECTS})
|
||||
add_subdirectory(${AOC2025_PROJECT})
|
||||
add_dependencies(aoc2025 aoc2025_${AOC2025_PROJECT})
|
||||
|
||||
target_link_options(aoc2025_${AOC2025_PROJECT} PRIVATE -nolibc)
|
||||
target_compile_options(aoc2025_${AOC2025_PROJECT} PRIVATE -g -O2 -Wall -Wextra -Werror)
|
||||
endforeach()
|
||||
|
||||
add_dependencies(userspace aoc2025)
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(aoc2025_day-template ${SOURCES})
|
||||
banan_include_headers(aoc2025_day-template ban)
|
||||
banan_link_library(aoc2025_day-template libc)
|
||||
|
||||
install(TARGETS aoc2025_day-template OPTIONAL)
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using i8 = int8_t;
|
||||
using i16 = int16_t;
|
||||
using i32 = int32_t;
|
||||
using i64 = int64_t;
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
i64 part1(FILE* fp)
|
||||
{
|
||||
(void)fp;
|
||||
return -1;
|
||||
}
|
||||
|
||||
i64 part2(FILE* fp)
|
||||
{
|
||||
(void)fp;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* file_path = "/usr/share/aoc2025/day-template_input.txt";
|
||||
|
||||
if (argc >= 2)
|
||||
file_path = argv[1];
|
||||
|
||||
FILE* fp = fopen(file_path, "r");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("part1: %" PRId64 "\n", part1(fp));
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
printf("part2: %" PRId64 "\n", part2(fp));
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(aoc2025_day1 ${SOURCES})
|
||||
banan_include_headers(aoc2025_day1 ban)
|
||||
banan_link_library(aoc2025_day1 libc)
|
||||
|
||||
install(TARGETS aoc2025_day1 OPTIONAL)
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using i8 = int8_t;
|
||||
using i16 = int16_t;
|
||||
using i32 = int32_t;
|
||||
using i64 = int64_t;
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
i64 part1(FILE* fp)
|
||||
{
|
||||
int amount;
|
||||
char direction;
|
||||
|
||||
i32 value = 50;
|
||||
i32 result = 0;
|
||||
while (fscanf(fp, "%c%d\n", &direction, &amount) == 2)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case 'L':
|
||||
value = (value - amount) % 100;
|
||||
break;
|
||||
case 'R':
|
||||
value = (value + amount) % 100;
|
||||
break;
|
||||
}
|
||||
|
||||
if (value == 0)
|
||||
result++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i64 part2(FILE* fp)
|
||||
{
|
||||
int amount;
|
||||
char direction;
|
||||
|
||||
i32 value = 50;
|
||||
i32 result = 0;
|
||||
while (fscanf(fp, "%c%d\n", &direction, &amount) == 2)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case 'L':
|
||||
if (amount >= value)
|
||||
result += (value != 0) + (amount - value) / 100;
|
||||
value = (((value - amount) % 100) + 100) % 100;
|
||||
break;
|
||||
case 'R':
|
||||
result += (value + amount) / 100;
|
||||
value = (value + amount) % 100;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* file_path = "/usr/share/aoc2025/day1_input.txt";
|
||||
|
||||
if (argc >= 2)
|
||||
file_path = argv[1];
|
||||
|
||||
FILE* fp = fopen(file_path, "r");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("part1: %" PRId64 "\n", part1(fp));
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
printf("part2: %" PRId64 "\n", part2(fp));
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(aoc2025_day10 ${SOURCES})
|
||||
banan_include_headers(aoc2025_day10 ban)
|
||||
banan_link_library(aoc2025_day10 libc)
|
||||
|
||||
install(TARGETS aoc2025_day10 OPTIONAL)
|
||||
|
|
@ -1,216 +0,0 @@
|
|||
#include <BAN/String.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using i8 = int8_t;
|
||||
using i16 = int16_t;
|
||||
using i32 = int32_t;
|
||||
using i64 = int64_t;
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
struct Machine
|
||||
{
|
||||
u32 indicator;
|
||||
BAN::Vector<u32> buttons;
|
||||
BAN::Vector<u32> joltages;
|
||||
};
|
||||
|
||||
static BAN::Vector<Machine> parse_machines(FILE* fp)
|
||||
{
|
||||
BAN::Vector<Machine> machines;
|
||||
|
||||
BAN::String line;
|
||||
char buffer[128];
|
||||
while (fgets(buffer, sizeof(buffer), fp))
|
||||
{
|
||||
MUST(line.append(buffer));
|
||||
if (line.back() != '\n')
|
||||
continue;
|
||||
if (line.front() != '[')
|
||||
break;
|
||||
|
||||
Machine machine {};
|
||||
|
||||
size_t i = 1;
|
||||
while (line[i] != ']')
|
||||
{
|
||||
if (line[i] == '#')
|
||||
machine.indicator |= 1 << (i - 1);
|
||||
i++;
|
||||
}
|
||||
|
||||
i += 2;
|
||||
|
||||
while (line[i++] == '(')
|
||||
{
|
||||
u32 button = 0;
|
||||
|
||||
while (line[i] != ')')
|
||||
{
|
||||
if (line[i] == ',')
|
||||
i++;
|
||||
|
||||
u32 index = 0;
|
||||
while (isdigit(line[i]))
|
||||
index = (index * 10) + (line[i++] - '0');
|
||||
|
||||
button |= 1 << index;
|
||||
}
|
||||
|
||||
MUST(machine.buttons.push_back(button));
|
||||
|
||||
i += 2;
|
||||
}
|
||||
|
||||
i--;
|
||||
|
||||
ASSERT(line[i] == '{');
|
||||
while (line[i++] != '}')
|
||||
{
|
||||
u32 joltage = 0;
|
||||
while (isdigit(line[i]))
|
||||
joltage = (joltage * 10) + (line[i++] - '0');
|
||||
MUST(machine.joltages.push_back(joltage));
|
||||
}
|
||||
|
||||
MUST(machines.push_back(BAN::move(machine)));
|
||||
|
||||
line.clear();
|
||||
}
|
||||
|
||||
return machines;
|
||||
}
|
||||
|
||||
i64 part1(FILE* fp)
|
||||
{
|
||||
static constexpr bool (*works_with_n_buttons)(const Machine&, size_t, size_t, u32) =
|
||||
[](const Machine& machine, size_t buttons, size_t index, u32 state) -> bool
|
||||
{
|
||||
if (buttons == 0)
|
||||
return state == machine.indicator;
|
||||
for (size_t i = index; i < machine.buttons.size(); i++)
|
||||
if (works_with_n_buttons(machine, buttons - 1, i + 1, state ^ machine.buttons[i]))
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
i64 result = 0;
|
||||
|
||||
auto machines = parse_machines(fp);
|
||||
for (const auto& machine : machines)
|
||||
{
|
||||
for (size_t i = 1; i < machine.buttons.size(); i++)
|
||||
{
|
||||
if (!works_with_n_buttons(machine, i, 0, 0))
|
||||
continue;
|
||||
result += i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// based on https://www.reddit.com/r/adventofcode/comments/1pk87hl/2025_day_10_part_2_bifurcate_your_way_to_victory/
|
||||
|
||||
static u32 minimum_presses(const BAN::Vector<BAN::Vector<u32>>& possible_indicators, const BAN::Vector<u32>& buttons, const BAN::Vector<u32>& joltages)
|
||||
{
|
||||
bool all_zeroes = true;
|
||||
for (u32 joltage : joltages)
|
||||
if (joltage != 0)
|
||||
all_zeroes = false;
|
||||
if (all_zeroes)
|
||||
return 0;
|
||||
|
||||
u32 indicator = 0;
|
||||
for (size_t i = 0; i < joltages.size(); i++)
|
||||
if (joltages[i] % 2)
|
||||
indicator |= 1 << i;
|
||||
|
||||
u32 result = 1'000'000;
|
||||
|
||||
for (u32 button_mask : possible_indicators[indicator])
|
||||
{
|
||||
size_t button_count = 0;
|
||||
BAN::Vector<u32> new_joltages = joltages;
|
||||
for (size_t i = 0; i < buttons.size(); i++)
|
||||
{
|
||||
if (!(button_mask & (1 << i)))
|
||||
continue;
|
||||
button_count++;
|
||||
for (size_t bit = 0; bit < new_joltages.size(); bit++)
|
||||
{
|
||||
if (!(buttons[i] & (1 << bit)))
|
||||
continue;
|
||||
if (new_joltages[bit] == 0)
|
||||
goto unusable;
|
||||
new_joltages[bit]--;
|
||||
}
|
||||
}
|
||||
|
||||
for (u32& joltage : new_joltages)
|
||||
joltage /= 2;
|
||||
result = BAN::Math::min<u32>(result, button_count + 2 * minimum_presses(possible_indicators, buttons, new_joltages));
|
||||
|
||||
unusable:
|
||||
(void)0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i64 part2(FILE* fp)
|
||||
{
|
||||
i64 result = 0;
|
||||
|
||||
auto machines = parse_machines(fp);
|
||||
for (const auto& machine : machines)
|
||||
{
|
||||
const size_t bits = machine.joltages.size();
|
||||
|
||||
BAN::Vector<BAN::Vector<u32>> possible_indicators;
|
||||
MUST(possible_indicators.resize(1u << bits));
|
||||
for (size_t button_mask = 0; button_mask < (1u << machine.buttons.size()); button_mask++)
|
||||
{
|
||||
u32 indicator = 0;
|
||||
for (size_t button = 0; button < machine.buttons.size(); button++)
|
||||
if (button_mask & (1 << button))
|
||||
indicator ^= machine.buttons[button];
|
||||
MUST(possible_indicators[indicator].push_back(button_mask));
|
||||
}
|
||||
|
||||
result += minimum_presses(possible_indicators, machine.buttons, machine.joltages);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* file_path = "/usr/share/aoc2025/day10_input.txt";
|
||||
|
||||
if (argc >= 2)
|
||||
file_path = argv[1];
|
||||
|
||||
FILE* fp = fopen(file_path, "r");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("part1: %" PRId64 "\n", part1(fp));
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
printf("part2: %" PRId64 "\n", part2(fp));
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(aoc2025_day11 ${SOURCES})
|
||||
banan_include_headers(aoc2025_day11 ban)
|
||||
banan_link_library(aoc2025_day11 libc)
|
||||
|
||||
install(TARGETS aoc2025_day11 OPTIONAL)
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
#include <BAN/HashMap.h>
|
||||
#include <BAN/StringView.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using i8 = int8_t;
|
||||
using i16 = int16_t;
|
||||
using i32 = int32_t;
|
||||
using i64 = int64_t;
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
struct Device
|
||||
{
|
||||
u32 distance { 0 };
|
||||
BAN::Vector<u32> outputs;
|
||||
};
|
||||
|
||||
static inline constexpr u32 name_to_u32(BAN::StringView name)
|
||||
{
|
||||
ASSERT(name.size() == 3);
|
||||
return name[0] | (name[1] << 8) | (name[2] << 16);
|
||||
}
|
||||
|
||||
static BAN::HashMap<u32, Device> parse_devices(FILE* fp, const char* first_node)
|
||||
{
|
||||
BAN::HashMap<u32, Device> result;
|
||||
|
||||
char buffer[128];
|
||||
while (fgets(buffer, sizeof(buffer), fp))
|
||||
{
|
||||
auto buffer_sv = BAN::StringView(buffer);
|
||||
ASSERT(buffer_sv.back() == '\n');
|
||||
buffer_sv = buffer_sv.substring(0, buffer_sv.size() - 1);
|
||||
|
||||
const u32 device = name_to_u32(buffer_sv.substring(0, 3));
|
||||
|
||||
auto it = result.find(device);
|
||||
if (it == result.end())
|
||||
it = MUST(result.emplace(device));
|
||||
|
||||
const auto outputs = MUST(buffer_sv.substring(5).split(' '));
|
||||
for (auto name : outputs)
|
||||
MUST(it->value.outputs.push_back(name_to_u32(name)));
|
||||
}
|
||||
|
||||
MUST(result.emplace(name_to_u32("out")));
|
||||
|
||||
BAN::Vector<u32> to_update;
|
||||
MUST(to_update.push_back(name_to_u32(first_node)));
|
||||
|
||||
u32 distance = 1;
|
||||
while (!to_update.empty())
|
||||
{
|
||||
BAN::Vector<u32> next_update;
|
||||
|
||||
for (u32 name : to_update)
|
||||
{
|
||||
auto& device = result[name];
|
||||
if (device.distance >= distance)
|
||||
continue;
|
||||
for (u32 output : device.outputs)
|
||||
MUST(next_update.push_back(output));
|
||||
device.distance = distance;
|
||||
}
|
||||
|
||||
to_update = BAN::move(next_update);
|
||||
distance++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static i64 count_paths(const BAN::HashMap<u32, Device>& devices, BAN::HashMap<u32, u32>& cache, u32 current, u32 destination)
|
||||
{
|
||||
if (current == destination)
|
||||
return 1;
|
||||
if (auto it = cache.find(current); it != cache.end())
|
||||
return it->value;
|
||||
if (devices[current].distance >= devices[destination].distance)
|
||||
return 0;
|
||||
|
||||
i64 result = 0;
|
||||
|
||||
const auto& outputs = devices[current].outputs;
|
||||
for (u32 output : outputs)
|
||||
result += count_paths(devices, cache, output, destination);
|
||||
|
||||
MUST(cache.emplace(current, result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i64 part1(FILE* fp)
|
||||
{
|
||||
auto devices = parse_devices(fp, "you");
|
||||
|
||||
BAN::HashMap<u32, u32> cache;
|
||||
return count_paths(devices, cache, name_to_u32("you"), name_to_u32("out"));
|
||||
}
|
||||
|
||||
i64 part2(FILE* fp)
|
||||
{
|
||||
auto devices = parse_devices(fp, "svr");
|
||||
|
||||
const bool fft_before = devices[name_to_u32("fft")].distance < devices[name_to_u32("dac")].distance;
|
||||
const u32 real_path[] {
|
||||
name_to_u32("svr"),
|
||||
fft_before ? name_to_u32("fft") : name_to_u32("dac"),
|
||||
fft_before ? name_to_u32("dac") : name_to_u32("fft"),
|
||||
name_to_u32("out"),
|
||||
};
|
||||
|
||||
i64 result = 1;
|
||||
|
||||
for (size_t i = 1; i < sizeof(real_path) / sizeof(*real_path); i++)
|
||||
{
|
||||
BAN::HashMap<u32, u32> cache;
|
||||
result *= count_paths(devices, cache, real_path[i - 1], real_path[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* file_path = "/usr/share/aoc2025/day11_input.txt";
|
||||
|
||||
if (argc >= 2)
|
||||
file_path = argv[1];
|
||||
|
||||
FILE* fp = fopen(file_path, "r");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("part1: %" PRId64 "\n", part1(fp));
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
printf("part2: %" PRId64 "\n", part2(fp));
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(aoc2025_day12 ${SOURCES})
|
||||
banan_include_headers(aoc2025_day12 ban)
|
||||
banan_link_library(aoc2025_day12 libc)
|
||||
|
||||
install(TARGETS aoc2025_day12 OPTIONAL)
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using i8 = int8_t;
|
||||
using i16 = int16_t;
|
||||
using i32 = int32_t;
|
||||
using i64 = int64_t;
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
// ehh im not happy about this but all inputs were crafted such that there
|
||||
// is no need to overlap any presents, so a simple 3x3 fitting check works
|
||||
|
||||
i64 part1(FILE* fp)
|
||||
{
|
||||
char chs[2] {};
|
||||
chs[0] = fgetc(fp);
|
||||
chs[1] = fgetc(fp);
|
||||
|
||||
char ch;
|
||||
while ((ch = fgetc(fp)) != 'x')
|
||||
{
|
||||
chs[0] = chs[1];
|
||||
chs[1] = ch;
|
||||
}
|
||||
|
||||
ungetc(ch, fp);
|
||||
ungetc(chs[0], fp);
|
||||
ungetc(chs[1], fp);
|
||||
|
||||
i64 result = 0;
|
||||
|
||||
u32 w, h;
|
||||
while (fscanf(fp, "%" SCNu32 "x%" SCNu32 ":", &w, &h) == 2)
|
||||
{
|
||||
u32 blocks = 0;
|
||||
|
||||
u32 count;
|
||||
while (fscanf(fp, "%" SCNu32 "%c", &count, &ch) == 2 && ch != '\n')
|
||||
blocks += count;
|
||||
blocks += count;
|
||||
|
||||
if ((w / 3) * (h / 3) >= blocks)
|
||||
result++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i64 part2(FILE* fp)
|
||||
{
|
||||
(void)fp;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* file_path = "/usr/share/aoc2025/day12_input.txt";
|
||||
|
||||
if (argc >= 2)
|
||||
file_path = argv[1];
|
||||
|
||||
FILE* fp = fopen(file_path, "r");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("part1: %" PRId64 "\n", part1(fp));
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
printf("part2: %" PRId64 "\n", part2(fp));
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(aoc2025_day2 ${SOURCES})
|
||||
banan_include_headers(aoc2025_day2 ban)
|
||||
banan_link_library(aoc2025_day2 libc)
|
||||
|
||||
install(TARGETS aoc2025_day2 OPTIONAL)
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using i8 = int8_t;
|
||||
using i16 = int16_t;
|
||||
using i32 = int32_t;
|
||||
using i64 = int64_t;
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
i64 part1(FILE* fp)
|
||||
{
|
||||
const auto is_invalid_id =
|
||||
[](u64 id) -> bool
|
||||
{
|
||||
u64 temp_id = id;
|
||||
u64 repeat = 0;
|
||||
u64 mult = 1;
|
||||
|
||||
while (repeat * mult + repeat < id)
|
||||
{
|
||||
repeat += (temp_id % 10) * mult;
|
||||
temp_id /= 10;
|
||||
mult *= 10;
|
||||
}
|
||||
|
||||
if (temp_id < mult / 10)
|
||||
return false;
|
||||
return repeat * mult + repeat == id;
|
||||
};
|
||||
|
||||
u64 result = 0;
|
||||
|
||||
u64 start, end;
|
||||
while (fscanf(fp, "%" SCNu64 "-%" SCNu64 ",", &start, &end) >= 2)
|
||||
for (u64 id = start; id <= end; id++)
|
||||
if (is_invalid_id(id))
|
||||
result += id;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i64 part2(FILE* fp)
|
||||
{
|
||||
const auto is_invalid_id =
|
||||
[](u64 id) -> bool
|
||||
{
|
||||
u64 temp_id = id;
|
||||
u64 repeat = 0;
|
||||
u64 mult = 1;
|
||||
|
||||
while (repeat * mult + repeat < id)
|
||||
{
|
||||
repeat += (temp_id % 10) * mult;
|
||||
temp_id /= 10;
|
||||
mult *= 10;
|
||||
|
||||
if (repeat < mult / 10)
|
||||
continue;
|
||||
|
||||
u64 attempt = repeat * mult + repeat;
|
||||
while (attempt < id)
|
||||
attempt = attempt * mult + repeat;
|
||||
if (attempt == id)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
u64 result = 0;
|
||||
|
||||
u64 start, end;
|
||||
while (fscanf(fp, "%" SCNu64 "-%" SCNu64 ",", &start, &end) >= 2)
|
||||
for (u64 id = start; id <= end; id++)
|
||||
if (is_invalid_id(id))
|
||||
result += id;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* file_path = "/usr/share/aoc2025/day2_input.txt";
|
||||
|
||||
if (argc >= 2)
|
||||
file_path = argv[1];
|
||||
|
||||
FILE* fp = fopen(file_path, "r");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("part1: %" PRId64 "\n", part1(fp));
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
printf("part2: %" PRId64 "\n", part2(fp));
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(aoc2025_day3 ${SOURCES})
|
||||
banan_include_headers(aoc2025_day3 ban)
|
||||
banan_link_library(aoc2025_day3 libc)
|
||||
|
||||
install(TARGETS aoc2025_day3 OPTIONAL)
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
#include <BAN/Math.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using i8 = int8_t;
|
||||
using i16 = int16_t;
|
||||
using i32 = int32_t;
|
||||
using i64 = int64_t;
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
i64 get_max_joltage(const char* line, size_t batteries)
|
||||
{
|
||||
size_t line_len = 0;
|
||||
while (isdigit(line[line_len]))
|
||||
line_len++;
|
||||
if (line_len < batteries)
|
||||
return 0;
|
||||
|
||||
i64 result = 0;
|
||||
|
||||
size_t max_i = -1;
|
||||
for (size_t battery = 0; battery < batteries; battery++)
|
||||
{
|
||||
i32 value = 0;
|
||||
for (size_t i = max_i + 1; i < line_len - batteries + battery + 1; i++)
|
||||
{
|
||||
if (line[i] - '0' <= value)
|
||||
continue;
|
||||
value = line[i] - '0';
|
||||
max_i = i;
|
||||
|
||||
if (value == 9)
|
||||
break;
|
||||
}
|
||||
result = (result * 10) + value;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i64 part1(FILE* fp)
|
||||
{
|
||||
i64 result = 0;
|
||||
|
||||
char buffer[128];
|
||||
while (fgets(buffer, sizeof(buffer), fp))
|
||||
result += get_max_joltage(buffer, 2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i64 part2(FILE* fp)
|
||||
{
|
||||
i64 result = 0;
|
||||
|
||||
char buffer[128];
|
||||
while (fgets(buffer, sizeof(buffer), fp))
|
||||
result += get_max_joltage(buffer, 12);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* file_path = "/usr/share/aoc2025/day3_input.txt";
|
||||
|
||||
if (argc >= 2)
|
||||
file_path = argv[1];
|
||||
|
||||
FILE* fp = fopen(file_path, "r");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("part1: %" PRId64 "\n", part1(fp));
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
printf("part2: %" PRId64 "\n", part2(fp));
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(aoc2025_day4 ${SOURCES})
|
||||
banan_include_headers(aoc2025_day4 ban)
|
||||
banan_link_library(aoc2025_day4 libc)
|
||||
|
||||
install(TARGETS aoc2025_day4 OPTIONAL)
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
#include <BAN/Vector.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using i8 = int8_t;
|
||||
using i16 = int16_t;
|
||||
using i32 = int32_t;
|
||||
using i64 = int64_t;
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
using Grid = BAN::Vector<BAN::Vector<bool>>;
|
||||
|
||||
static Grid parse_grid(FILE* fp)
|
||||
{
|
||||
Grid grid;
|
||||
MUST(grid.emplace_back());
|
||||
|
||||
char ch;
|
||||
while ((ch = fgetc(fp)) != EOF)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case '.':
|
||||
case '@':
|
||||
MUST(grid.back().push_back(ch == '@'));
|
||||
break;
|
||||
case '\n':
|
||||
MUST(grid.emplace_back());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (grid.back().empty())
|
||||
grid.pop_back();
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
static i32 count_neighborgs(const Grid& grid, size_t x, size_t y)
|
||||
{
|
||||
i32 count = 0;
|
||||
for (i32 yoff = -1; yoff <= 1; yoff++)
|
||||
{
|
||||
for (i32 xoff = -1; xoff <= 1; xoff++)
|
||||
{
|
||||
if (yoff == 0 && xoff == 0)
|
||||
continue;
|
||||
if (y + yoff >= grid.size())
|
||||
continue;
|
||||
if (x + xoff >= grid[y + yoff].size())
|
||||
continue;
|
||||
count += grid[y + yoff][x + xoff];
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
i64 part1(FILE* fp)
|
||||
{
|
||||
i32 result = 0;
|
||||
|
||||
auto grid = parse_grid(fp);
|
||||
for (size_t y = 0; y < grid.size(); y++)
|
||||
for (size_t x = 0; x < grid[y].size(); x++)
|
||||
if (grid[y][x] && count_neighborgs(grid, x, y) < 4)
|
||||
result++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i64 part2(FILE* fp)
|
||||
{
|
||||
i32 result = 0;
|
||||
|
||||
auto grid = parse_grid(fp);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const auto old_result = result;
|
||||
|
||||
for (size_t y = 0; y < grid.size(); y++)
|
||||
{
|
||||
for (size_t x = 0; x < grid[y].size(); x++)
|
||||
{
|
||||
if (!grid[y][x] || count_neighborgs(grid, x, y) >= 4)
|
||||
continue;
|
||||
grid[y][x] = false;
|
||||
result++;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == old_result)
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* file_path = "/usr/share/aoc2025/day4_input.txt";
|
||||
|
||||
if (argc >= 2)
|
||||
file_path = argv[1];
|
||||
|
||||
FILE* fp = fopen(file_path, "r");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("part1: %" PRId64 "\n", part1(fp));
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
printf("part2: %" PRId64 "\n", part2(fp));
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(aoc2025_day5 ${SOURCES})
|
||||
banan_include_headers(aoc2025_day5 ban)
|
||||
banan_link_library(aoc2025_day5 libc)
|
||||
|
||||
install(TARGETS aoc2025_day5 OPTIONAL)
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
#include <BAN/Vector.h>
|
||||
#include <BAN/Sort.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using i8 = int8_t;
|
||||
using i16 = int16_t;
|
||||
using i32 = int32_t;
|
||||
using i64 = int64_t;
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
struct Range
|
||||
{
|
||||
u64 min;
|
||||
u64 max;
|
||||
};
|
||||
|
||||
static BAN::Vector<Range> parse_ranges(FILE* fp)
|
||||
{
|
||||
BAN::Vector<Range> ranges;
|
||||
|
||||
u64 min, max;
|
||||
ungetc('\n', fp);
|
||||
while (fscanf(fp, "\n%" SCNu64 "-%" SCNu64, &min, &max) == 2)
|
||||
MUST(ranges.emplace_back(min, max));
|
||||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
i64 part1(FILE* fp)
|
||||
{
|
||||
auto ranges = parse_ranges(fp);
|
||||
|
||||
i64 result = 0;
|
||||
|
||||
u64 value;
|
||||
while (fscanf(fp, "%" SCNu64, &value) == 1)
|
||||
{
|
||||
bool is_fresh = false;
|
||||
for (const auto range : ranges)
|
||||
if (range.min <= value && value <= range.max)
|
||||
is_fresh = true;
|
||||
result += is_fresh;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i64 part2(FILE* fp)
|
||||
{
|
||||
auto ranges = parse_ranges(fp);
|
||||
|
||||
BAN::sort::sort(ranges.begin(), ranges.end(),
|
||||
[](auto lhs, auto rhs) -> bool
|
||||
{
|
||||
return lhs.min < rhs.min;
|
||||
}
|
||||
);
|
||||
|
||||
for (size_t i = 0; i < ranges.size() - 1; i++)
|
||||
{
|
||||
auto& lhs = ranges[i];
|
||||
auto& rhs = ranges[i + 1];
|
||||
if (lhs.min > rhs.max || rhs.min > lhs.max)
|
||||
continue;
|
||||
|
||||
lhs.min = BAN::Math::min(lhs.min, rhs.min);
|
||||
lhs.max = BAN::Math::max(lhs.max, rhs.max);
|
||||
ranges.remove(i + 1);
|
||||
|
||||
i--;
|
||||
}
|
||||
|
||||
i64 result = 0;
|
||||
for (auto range : ranges)
|
||||
result += range.max - range.min + 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* file_path = "/usr/share/aoc2025/day5_input.txt";
|
||||
|
||||
if (argc >= 2)
|
||||
file_path = argv[1];
|
||||
|
||||
FILE* fp = fopen(file_path, "r");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("part1: %" PRId64 "\n", part1(fp));
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
printf("part2: %" PRId64 "\n", part2(fp));
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(aoc2025_day6 ${SOURCES})
|
||||
banan_include_headers(aoc2025_day6 ban)
|
||||
banan_link_library(aoc2025_day6 libc)
|
||||
|
||||
install(TARGETS aoc2025_day6 OPTIONAL)
|
||||
|
|
@ -1,152 +0,0 @@
|
|||
#include <BAN/String.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using i8 = int8_t;
|
||||
using i16 = int16_t;
|
||||
using i32 = int32_t;
|
||||
using i64 = int64_t;
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
i64 part1(FILE* fp)
|
||||
{
|
||||
struct Operation
|
||||
{
|
||||
BAN::Vector<i64> values;
|
||||
char op;
|
||||
};
|
||||
|
||||
BAN::Vector<Operation> operations;
|
||||
|
||||
BAN::String line;
|
||||
char line_buffer[128];
|
||||
while (fgets(line_buffer, sizeof(line_buffer), fp))
|
||||
{
|
||||
MUST(line.append(line_buffer));
|
||||
if (line.back() != '\n')
|
||||
continue;
|
||||
line.pop_back();
|
||||
|
||||
auto parts = MUST(line.sv().split(' '));
|
||||
if (operations.size() < parts.size())
|
||||
MUST(operations.resize(parts.size()));
|
||||
|
||||
if (isdigit(parts[0][0]))
|
||||
{
|
||||
for (size_t i = 0; i < parts.size(); i++)
|
||||
MUST(operations[i].values.push_back(atoll(parts[i].data())));
|
||||
line.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < parts.size(); i++)
|
||||
operations[i].op = parts[i][0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i64 result = 0;
|
||||
|
||||
for (const auto& operation : operations)
|
||||
{
|
||||
i64 value;
|
||||
switch (operation.op)
|
||||
{
|
||||
case '+':
|
||||
value = 0;
|
||||
for (auto val : operation.values)
|
||||
value += val;
|
||||
break;
|
||||
case '*':
|
||||
value = 1;
|
||||
for (auto val : operation.values)
|
||||
value *= val;
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
result += value;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i64 part2(FILE* fp)
|
||||
{
|
||||
BAN::Vector<BAN::String> lines;
|
||||
MUST(lines.emplace_back());
|
||||
|
||||
char line_buffer[128];
|
||||
while (fgets(line_buffer, sizeof(line_buffer), fp))
|
||||
{
|
||||
MUST(lines.back().append(line_buffer));
|
||||
if (lines.back().back() != '\n')
|
||||
continue;
|
||||
lines.back().pop_back();
|
||||
MUST(lines.emplace_back());
|
||||
}
|
||||
|
||||
while (lines.back().empty())
|
||||
lines.pop_back();
|
||||
|
||||
i64 result = 0;
|
||||
|
||||
char op = 0;
|
||||
i64 current = 0;
|
||||
for (size_t i = 0; i < lines.front().size(); i++)
|
||||
{
|
||||
if (lines.back()[i] != ' ')
|
||||
{
|
||||
result += current;
|
||||
|
||||
op = lines.back()[i];
|
||||
current = (op == '+') ? 0 : 1;
|
||||
}
|
||||
|
||||
i64 value = 0;
|
||||
bool all_space = true;
|
||||
for (size_t j = 0; j < lines.size() - 1; j++)
|
||||
{
|
||||
if (isdigit(lines[j][i]))
|
||||
value = (value * 10) + (lines[j][i] - '0');
|
||||
all_space = all_space && lines[j][i] == ' ';
|
||||
}
|
||||
|
||||
if (all_space)
|
||||
continue;
|
||||
|
||||
current = (op == '+') ? current + value : current * value;
|
||||
}
|
||||
|
||||
return result + current;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* file_path = "/usr/share/aoc2025/day6_input.txt";
|
||||
|
||||
if (argc >= 2)
|
||||
file_path = argv[1];
|
||||
|
||||
FILE* fp = fopen(file_path, "r");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("part1: %" PRId64 "\n", part1(fp));
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
printf("part2: %" PRId64 "\n", part2(fp));
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(aoc2025_day7 ${SOURCES})
|
||||
banan_include_headers(aoc2025_day7 ban)
|
||||
banan_link_library(aoc2025_day7 libc)
|
||||
|
||||
install(TARGETS aoc2025_day7 OPTIONAL)
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
#include <BAN/String.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using i8 = int8_t;
|
||||
using i16 = int16_t;
|
||||
using i32 = int32_t;
|
||||
using i64 = int64_t;
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
static BAN::Vector<BAN::String> parse_lines(FILE* fp)
|
||||
{
|
||||
BAN::Vector<BAN::String> lines;
|
||||
MUST(lines.emplace_back());
|
||||
|
||||
char line_buffer[128];
|
||||
while (fgets(line_buffer, sizeof(line_buffer), fp))
|
||||
{
|
||||
MUST(lines.back().append(line_buffer));
|
||||
if (lines.back().back() != '\n')
|
||||
continue;
|
||||
lines.back().pop_back();
|
||||
MUST(lines.emplace_back());
|
||||
}
|
||||
|
||||
while (lines.back().empty())
|
||||
lines.pop_back();
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
i64 part1(FILE* fp)
|
||||
{
|
||||
i32 result = 0;
|
||||
|
||||
auto lines = parse_lines(fp);
|
||||
|
||||
for (char& ch : lines.front())
|
||||
if (ch == 'S')
|
||||
ch = '|';
|
||||
|
||||
for (size_t y = 0; y < lines.size() - 1; y++)
|
||||
{
|
||||
for (size_t x = 0; x < lines[y].size(); x++)
|
||||
{
|
||||
if (lines[y][x] != '|')
|
||||
continue;
|
||||
|
||||
switch (lines[y + 1][x])
|
||||
{
|
||||
case '.':
|
||||
lines[y + 1][x] = '|';
|
||||
break;
|
||||
case '^':
|
||||
lines[y + 1][x - 1] = '|';
|
||||
lines[y + 1][x + 1] = '|';
|
||||
result++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i64 part2(FILE* fp)
|
||||
{
|
||||
auto lines = parse_lines(fp);
|
||||
|
||||
const size_t h = lines.size();
|
||||
const size_t w = lines.front().size();
|
||||
|
||||
BAN::Vector<i64> timelines;
|
||||
MUST(timelines.resize(w * h));
|
||||
|
||||
const auto get_char_value = [](char ch) { return ch == '.' ? 0 : ch == 'S' ? 1 : -1; };
|
||||
for (size_t y = 0; y < h; y++)
|
||||
for (size_t x = 0; x < w; x++)
|
||||
timelines[y * w + x] = get_char_value(lines[y][x]);
|
||||
|
||||
for (size_t y = 1; y < h; y++)
|
||||
{
|
||||
for (size_t x = 0; x < w; x++)
|
||||
{
|
||||
if (timelines[(y - 1) * w + x] < 0)
|
||||
;
|
||||
else if (timelines[y * w + x] >= 0)
|
||||
timelines[y * w + x] += timelines[(y - 1) * w + x];
|
||||
else
|
||||
{
|
||||
timelines[y * w + x - 1] += timelines[(y - 1) * w + x];
|
||||
timelines[y * w + x + 1] += timelines[(y - 1) * w + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i64 result = 0;
|
||||
for (size_t x = 0; x < w; x++)
|
||||
if (auto value = timelines[(h - 1) * w + x]; value > 0)
|
||||
result += value;
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* file_path = "/usr/share/aoc2025/day7_input.txt";
|
||||
|
||||
if (argc >= 2)
|
||||
file_path = argv[1];
|
||||
|
||||
FILE* fp = fopen(file_path, "r");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("part1: %" PRId64 "\n", part1(fp));
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
printf("part2: %" PRId64 "\n", part2(fp));
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(aoc2025_day8 ${SOURCES})
|
||||
banan_include_headers(aoc2025_day8 ban)
|
||||
banan_link_library(aoc2025_day8 libc)
|
||||
|
||||
install(TARGETS aoc2025_day8 OPTIONAL)
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
#include <BAN/HashSet.h>
|
||||
#include <BAN/Heap.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using i8 = int8_t;
|
||||
using i16 = int16_t;
|
||||
using i32 = int32_t;
|
||||
using i64 = int64_t;
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
struct Point
|
||||
{
|
||||
i64 x, y, z;
|
||||
|
||||
constexpr bool operator==(const Point& other) const
|
||||
{
|
||||
return x == other.x && y == other.y && z == other.z;
|
||||
}
|
||||
};
|
||||
|
||||
static BAN::Vector<Point> parse_points(FILE* fp)
|
||||
{
|
||||
BAN::Vector<Point> points;
|
||||
|
||||
i64 x, y, z;
|
||||
while (fscanf(fp, "%" SCNi64 ",%" SCNi64 ",%" SCNi64, &x, &y, &z) == 3)
|
||||
MUST(points.emplace_back(x, y, z));
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
struct PointPair
|
||||
{
|
||||
Point a, b;
|
||||
|
||||
constexpr i64 dist() const
|
||||
{
|
||||
return (a.x - b.x) * (a.x - b.x)
|
||||
+ (a.y - b.y) * (a.y - b.y)
|
||||
+ (a.z - b.z) * (a.z - b.z);
|
||||
}
|
||||
|
||||
constexpr bool operator>(const PointPair& other) const
|
||||
{
|
||||
return dist() > other.dist();
|
||||
}
|
||||
};
|
||||
|
||||
static BAN::Vector<PointPair> build_point_pair_heap(const BAN::Vector<Point>& points)
|
||||
{
|
||||
BAN::Vector<PointPair> pairs;
|
||||
MUST(pairs.reserve(points.size() * (points.size() + 1) / 2));
|
||||
|
||||
for (size_t i = 0; i < points.size(); i++)
|
||||
for (size_t j = i + 1; j < points.size(); j++)
|
||||
MUST(pairs.push_back({ points[i], points[j] }));
|
||||
|
||||
BAN::make_heap(pairs.begin(), pairs.end(), BAN::greater<PointPair> {});
|
||||
|
||||
return pairs;
|
||||
}
|
||||
|
||||
using Circuit = BAN::Vector<Point>;
|
||||
|
||||
static BAN::Vector<Circuit> build_circuits(const BAN::Vector<Point>& points)
|
||||
{
|
||||
BAN::Vector<Circuit> circuits;
|
||||
MUST(circuits.reserve(points.size()));
|
||||
|
||||
for (size_t i = 0; i < points.size(); i++)
|
||||
MUST(circuits.emplace_back(1, points[i]));
|
||||
|
||||
return circuits;
|
||||
}
|
||||
|
||||
static void combine_circuits_with_points(BAN::Vector<Circuit>& circuits, const Point& a, const Point& b)
|
||||
{
|
||||
size_t a_index = SIZE_MAX;
|
||||
size_t b_index = SIZE_MAX;
|
||||
|
||||
for (size_t i = 0; i < circuits.size(); i++)
|
||||
{
|
||||
if (circuits[i].contains(a))
|
||||
a_index = i;
|
||||
if (circuits[i].contains(b))
|
||||
b_index = i;
|
||||
}
|
||||
|
||||
if (a_index == b_index)
|
||||
return;
|
||||
|
||||
MUST(circuits[a_index].reserve(circuits[a_index].size() + circuits[b_index].size()));
|
||||
for (auto point : circuits[b_index])
|
||||
MUST(circuits[a_index].push_back(point));
|
||||
|
||||
circuits.remove(b_index);
|
||||
}
|
||||
|
||||
i64 part1(FILE* fp)
|
||||
{
|
||||
auto points = parse_points(fp);
|
||||
auto pairs = build_point_pair_heap(points);
|
||||
auto circuits = build_circuits(points);
|
||||
|
||||
for (size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto [a, b] = pairs.front();
|
||||
BAN::pop_heap(pairs.begin(), pairs.end() - i, BAN::greater<PointPair> {});
|
||||
|
||||
combine_circuits_with_points(circuits, a, b);
|
||||
}
|
||||
|
||||
const auto size_comp =
|
||||
[](const auto& a, const auto& b)
|
||||
{
|
||||
return a.size() < b.size();
|
||||
};
|
||||
|
||||
BAN::make_heap(circuits.begin(), circuits.end(), size_comp);
|
||||
|
||||
i64 result = 1;
|
||||
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
{
|
||||
result *= circuits.front().size();
|
||||
BAN::pop_heap(circuits.begin(), circuits.end() - i, size_comp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i64 part2(FILE* fp)
|
||||
{
|
||||
auto points = parse_points(fp);
|
||||
auto pairs = build_point_pair_heap(points);
|
||||
auto circuits = build_circuits(points);
|
||||
|
||||
for (size_t i = 0; i < pairs.size(); i++)
|
||||
{
|
||||
const auto [a, b] = pairs.front();
|
||||
BAN::pop_heap(pairs.begin(), pairs.end() - i, BAN::greater<PointPair> {});
|
||||
|
||||
combine_circuits_with_points(circuits, a, b);
|
||||
if (circuits.size() == 1)
|
||||
return a.x * b.x;
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* file_path = "/usr/share/aoc2025/day8_input.txt";
|
||||
|
||||
if (argc >= 2)
|
||||
file_path = argv[1];
|
||||
|
||||
FILE* fp = fopen(file_path, "r");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("part1: %" PRId64 "\n", part1(fp));
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
printf("part2: %" PRId64 "\n", part2(fp));
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(aoc2025_day9 ${SOURCES})
|
||||
banan_include_headers(aoc2025_day9 ban)
|
||||
banan_link_library(aoc2025_day9 libc)
|
||||
|
||||
install(TARGETS aoc2025_day9 OPTIONAL)
|
||||
|
|
@ -1,188 +0,0 @@
|
|||
#include <BAN/HashMap.h>
|
||||
#include <BAN/Sort.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using i8 = int8_t;
|
||||
using i16 = int16_t;
|
||||
using i32 = int32_t;
|
||||
using i64 = int64_t;
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
struct Point
|
||||
{
|
||||
i64 x, y;
|
||||
};
|
||||
|
||||
static BAN::Vector<Point> parse_points(FILE* fp)
|
||||
{
|
||||
BAN::Vector<Point> points;
|
||||
|
||||
i64 x, y;
|
||||
while (fscanf(fp, "%" SCNi64 ",%" SCNi64, &x, &y) == 2)
|
||||
MUST(points.emplace_back(x, y));
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
i64 part1(FILE* fp)
|
||||
{
|
||||
auto points = parse_points(fp);
|
||||
|
||||
i64 result = 0;
|
||||
|
||||
for (size_t i = 0; i < points.size(); i++)
|
||||
{
|
||||
for (size_t j = i + 1; j < points.size(); j++)
|
||||
{
|
||||
const i64 w = BAN::Math::abs(points[i].x - points[j].x) + 1;
|
||||
const i64 h = BAN::Math::abs(points[i].y - points[j].y) + 1;
|
||||
result = BAN::Math::max(result, w * h);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static BAN::Vector<i64> compress_coordinates(BAN::Vector<Point>& points)
|
||||
{
|
||||
BAN::HashMap<i64, i64> coord_map;
|
||||
MUST(coord_map.reserve(points.size() * 4));
|
||||
for (size_t i = 0; i < points.size(); i++)
|
||||
{
|
||||
MUST(coord_map.emplace_or_assign(points[i].x));
|
||||
MUST(coord_map.emplace_or_assign(points[i].y));
|
||||
}
|
||||
|
||||
BAN::Vector<i64> coords;
|
||||
MUST(coords.reserve(coord_map.size()));
|
||||
for (auto [coord, _] : coord_map)
|
||||
MUST(coords.push_back(coord));
|
||||
BAN::sort::sort(coords.begin(), coords.end());
|
||||
|
||||
for (size_t i = 0; i < coords.size(); i++)
|
||||
coord_map[coords[i]] = i;
|
||||
|
||||
for (auto& point : points)
|
||||
{
|
||||
point.x = coord_map[point.x];
|
||||
point.y = coord_map[point.y];
|
||||
}
|
||||
|
||||
return coords;
|
||||
}
|
||||
|
||||
i64 part2(FILE* fp)
|
||||
{
|
||||
auto points = parse_points(fp);
|
||||
auto index2coord = compress_coordinates(points);
|
||||
|
||||
const size_t grid_size = index2coord.size();
|
||||
|
||||
BAN::Vector<bool> grid;
|
||||
MUST(grid.resize(grid_size * grid_size, false));
|
||||
|
||||
for (size_t i = 0; i < points.size(); i++)
|
||||
{
|
||||
const auto curr = points[i];
|
||||
const auto next = points[(i + 1) % points.size()];
|
||||
ASSERT((curr.x == next.x) != (curr.y == next.y));
|
||||
|
||||
const i64 minx = BAN::Math::min(curr.x, next.x);
|
||||
const i64 maxx = BAN::Math::max(curr.x, next.x);
|
||||
const i64 miny = BAN::Math::min(curr.y, next.y);
|
||||
const i64 maxy = BAN::Math::max(curr.y, next.y);
|
||||
|
||||
const i64 dx = (minx != maxx);
|
||||
const i64 dy = (miny != maxy);
|
||||
|
||||
for (i64 x = minx, y = miny; x <= maxx && y <= maxy; x += dx, y += dy)
|
||||
grid[y * grid_size + x] = true;
|
||||
}
|
||||
|
||||
for (size_t y = 0; y < grid_size; y++)
|
||||
{
|
||||
bool is_inside = false;
|
||||
for (size_t x = 0; x < grid_size; x++)
|
||||
{
|
||||
if (!grid[y * grid_size + x])
|
||||
grid[y * grid_size + x] = is_inside;
|
||||
else if (x + 1 >= grid_size || !grid[y * grid_size + x + 1])
|
||||
is_inside = !is_inside;
|
||||
else
|
||||
{
|
||||
const bool from_below1 = (y + 1 < grid_size) && grid[(y + 1) * grid_size + x];
|
||||
while (x + 1 < grid_size && grid[y * grid_size + x + 1])
|
||||
x++;
|
||||
const bool from_below2 = (y + 1 < grid_size) && grid[(y + 1) * grid_size + x];
|
||||
|
||||
if (from_below1 != from_below2)
|
||||
is_inside = !is_inside;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto is_usable_area =
|
||||
[&grid, grid_size](const Point& a, const Point& b) -> bool
|
||||
{
|
||||
const i64 minx = BAN::Math::min(a.x, b.x);
|
||||
const i64 maxx = BAN::Math::max(a.x, b.x);
|
||||
const i64 miny = BAN::Math::min(a.y, b.y);
|
||||
const i64 maxy = BAN::Math::max(a.y, b.y);
|
||||
for (i64 x = minx; x <= maxx; x++)
|
||||
if (!grid[miny * grid_size + x] || !grid[maxy * grid_size + x])
|
||||
return false;
|
||||
for (i64 y = miny; y <= maxy; y++)
|
||||
if (!grid[y * grid_size + minx] || !grid[y * grid_size + maxy])
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
i64 result = 0;
|
||||
|
||||
for (size_t i = 0; i < points.size(); i++)
|
||||
{
|
||||
for (size_t j = i + 1; j < points.size(); j++)
|
||||
{
|
||||
const auto& a = points[i];
|
||||
const auto& b = points[j];
|
||||
if (!is_usable_area(a, b))
|
||||
continue;
|
||||
|
||||
const i64 w = BAN::Math::abs(index2coord[a.x] - index2coord[b.x]) + 1;
|
||||
const i64 h = BAN::Math::abs(index2coord[a.y] - index2coord[b.y]) + 1;
|
||||
result = BAN::Math::max(result, w * h);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* file_path = "/usr/share/aoc2025/day9_input.txt";
|
||||
|
||||
if (argc >= 2)
|
||||
file_path = argv[1];
|
||||
|
||||
FILE* fp = fopen(file_path, "r");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("part1: %" PRId64 "\n", part1(fp));
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
printf("part2: %" PRId64 "\n", part2(fp));
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(aoc2025_full ${SOURCES})
|
||||
banan_include_headers(aoc2025_full ban)
|
||||
banan_link_library(aoc2025_full libc)
|
||||
|
||||
install(TARGETS aoc2025_full OPTIONAL)
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
for (int i = 1; i <= 25; i++)
|
||||
{
|
||||
char command[128];
|
||||
sprintf(command, "/bin/aoc2025/aoc2025_day%d", i);
|
||||
|
||||
struct stat st;
|
||||
if (stat(command, &st) == -1)
|
||||
continue;
|
||||
|
||||
printf("day%d\n", i);
|
||||
|
||||
system(command);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [[ -z $1 ]]; then
|
||||
echo Please specify day number >& 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d day$1 ]]; then
|
||||
cp -r day-template day$1
|
||||
sed -i "s/day-template/day$1/g" day$1/*
|
||||
fi
|
||||
|
||||
if [[ ! -f input/day$1_input.txt ]]; then
|
||||
wget --no-cookies --header "Cookie: session=$AOC_SESSION" https://adventofcode.com/2025/day/$1/input -O input/day$1_input.txt
|
||||
fi
|
||||
|
|
@ -1 +0,0 @@
|
|||
day*_input.txt
|
||||
|
|
@ -32,11 +32,6 @@ struct init_funcs_t
|
|||
extern "C" char** environ;
|
||||
|
||||
#define DUMP_BACKTRACE 1
|
||||
#define DEMANGLE_BACKTRACE 0
|
||||
|
||||
#if DEMANGLE_BACKTRACE
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
static void __dump_backtrace(int, siginfo_t*, void*);
|
||||
|
||||
|
|
@ -141,20 +136,8 @@ static void __dump_symbol(int fd, const void* address)
|
|||
return;
|
||||
}
|
||||
|
||||
#if DEMANGLE_BACKTRACE
|
||||
int status;
|
||||
char* demangled = abi::__cxa_demangle(dli.dli_sname, nullptr, nullptr, &status);
|
||||
const char* symbol_name = status ? dli.dli_sname : demangled;
|
||||
#else
|
||||
const char* symbol_name = dli.dli_sname;
|
||||
#endif
|
||||
|
||||
const uintptr_t uptr_saddr = reinterpret_cast<uintptr_t>(dli.dli_saddr);
|
||||
dprintf(fd, " 0x%08" PRIxPTR " (%s) %s+0x%" PRIxPTR "\n", uptr_addr - uptr_fbase, dli.dli_fname, symbol_name, uptr_addr - uptr_saddr);
|
||||
|
||||
#if DEMANGLE_BACKTRACE
|
||||
free(demangled);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __dump_backtrace(int sig, siginfo_t* info, void* context)
|
||||
|
|
@ -163,7 +146,6 @@ static void __dump_backtrace(int sig, siginfo_t* info, void* context)
|
|||
[](int signal) -> const char*
|
||||
{
|
||||
switch (signal) {
|
||||
case SIGABRT: return "SIGABRT";
|
||||
case SIGBUS: return "SIGBUS";
|
||||
case SIGFPE: return "SIGFPE";
|
||||
case SIGILL: return "SIGILL";
|
||||
|
|
@ -1016,6 +998,7 @@ long sysconf(int name)
|
|||
POSIX_CASE(MQ_OPEN_MAX)
|
||||
POSIX_CASE(MQ_PRIO_MAX)
|
||||
POSIX_CASE(NGROUPS_MAX)
|
||||
POSIX_CASE(OPEN_MAX)
|
||||
POSIX_CASE(PRIORITIZED_IO)
|
||||
POSIX_CASE(PRIORITY_SCHEDULING)
|
||||
POSIX_CASE(RAW_SOCKETS)
|
||||
|
|
@ -1103,8 +1086,6 @@ long sysconf(int name)
|
|||
XOPEN_CASE(VERSION)
|
||||
#undef XOPEN_CASE
|
||||
|
||||
case _SC_OPEN_MAX: return OPEN_MAX;
|
||||
|
||||
case _SC_PAGE_SIZE:
|
||||
case _SC_PAGESIZE: return getpagesize();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue