Compare commits
	
		
			No commits in common. "3e9826acf5203a4e5fa6c48120fa3bf5d2fe58f3" and "a7f3351c0efcd04dcbe11753935a7cb9f21e0e94" have entirely different histories.
		
	
	
		
			3e9826acf5
			...
			a7f3351c0e
		
	
		| 
						 | 
					@ -624,6 +624,16 @@ acpi_release_global_lock:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		ASSERT(!m_namespace);
 | 
							ASSERT(!m_namespace);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							TRY(AML::Namespace::prepare_root_namespace());
 | 
				
			||||||
 | 
							m_namespace = &AML::Namespace::root_namespace();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (auto ret = load_aml_tables("DSDT"_sv, false); ret.is_error())
 | 
				
			||||||
 | 
								dwarnln("Could not load DSDT: {}", ret.error());
 | 
				
			||||||
 | 
							if (auto ret = load_aml_tables("SSDT"_sv, true); ret.is_error())
 | 
				
			||||||
 | 
								dwarnln("Could not load all SSDTs: {}", ret.error());
 | 
				
			||||||
 | 
							if (auto ret = load_aml_tables("PSDT"_sv, true); ret.is_error())
 | 
				
			||||||
 | 
								dwarnln("Could not load all PSDTs: {}", ret.error());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/16_Waking_and_Sleeping/initialization.html#placing-the-system-in-acpi-mode
 | 
							// https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/16_Waking_and_Sleeping/initialization.html#placing-the-system-in-acpi-mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// If not hardware-reduced ACPI and SCI_EN is not set
 | 
							// If not hardware-reduced ACPI and SCI_EN is not set
 | 
				
			||||||
| 
						 | 
					@ -653,18 +663,6 @@ acpi_release_global_lock:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dprintln("Entered ACPI mode");
 | 
							dprintln("Entered ACPI mode");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		TRY(AML::Namespace::prepare_root_namespace());
 | 
					 | 
				
			||||||
		m_namespace = &AML::Namespace::root_namespace();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (auto ret = load_aml_tables("DSDT"_sv, false); ret.is_error())
 | 
					 | 
				
			||||||
			dwarnln("Could not load DSDT: {}", ret.error());
 | 
					 | 
				
			||||||
		if (auto ret = load_aml_tables("SSDT"_sv, true); ret.is_error())
 | 
					 | 
				
			||||||
			dwarnln("Could not load all SSDTs: {}", ret.error());
 | 
					 | 
				
			||||||
		if (auto ret = load_aml_tables("PSDT"_sv, true); ret.is_error())
 | 
					 | 
				
			||||||
			dwarnln("Could not load all PSDTs: {}", ret.error());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		dprintln("Loaded ACPI tables");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (auto ret = m_namespace->post_load_initialize(); ret.is_error())
 | 
							if (auto ret = m_namespace->post_load_initialize(); ret.is_error())
 | 
				
			||||||
			dwarnln("Failed to initialize ACPI namespace: {}", ret.error());
 | 
								dwarnln("Failed to initialize ACPI namespace: {}", ret.error());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,8 +4,8 @@
 | 
				
			||||||
#include <kernel/ACPI/AML/Node.h>
 | 
					#include <kernel/ACPI/AML/Node.h>
 | 
				
			||||||
#include <kernel/ACPI/Headers.h>
 | 
					#include <kernel/ACPI/Headers.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define STA_PRESENT    0x01
 | 
					#define STA_PRESENT  0x01
 | 
				
			||||||
#define STA_FUNCTIONAL 0x08
 | 
					#define STA_FUNCTION 0x08
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,10 +150,6 @@ namespace Kernel::ACPI::AML
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BAN::ErrorOr<void> Namespace::post_load_initialize()
 | 
						BAN::ErrorOr<void> Namespace::post_load_initialize()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		auto [sb_path, sb_ref] = TRY(find_named_object({}, TRY(NameString::from_string("\\_SB_"_sv))));
 | 
					 | 
				
			||||||
		if (sb_ref != nullptr)
 | 
					 | 
				
			||||||
			TRY(evaluate_ini(sb_path));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		BAN::Vector<Scope> to_init;
 | 
							BAN::Vector<Scope> to_init;
 | 
				
			||||||
		TRY(to_init.push_back({}));
 | 
							TRY(to_init.push_back({}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -180,6 +176,20 @@ namespace Kernel::ACPI::AML
 | 
				
			||||||
								return BAN::Iteration::Continue;
 | 
													return BAN::Iteration::Continue;
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											auto sta_ret = evaluate_sta(child_path);
 | 
				
			||||||
 | 
											if (sta_ret.is_error())
 | 
				
			||||||
 | 
												return BAN::Iteration::Continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											if (sta_ret.value() & STA_PRESENT)
 | 
				
			||||||
 | 
												(void)evaluate_ini(child_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											if ((sta_ret.value() & STA_PRESENT) || (sta_ret.value() & STA_FUNCTION))
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												auto child_path_copy = child_path.copy();
 | 
				
			||||||
 | 
												if (!child_path_copy.is_error())
 | 
				
			||||||
 | 
													(void)to_init_next.push_back(child_path_copy.release_value());
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						(void)for_each_child(current,
 | 
											(void)for_each_child(current,
 | 
				
			||||||
							[&](const Scope& opregion_path, Reference* opregion_ref) -> BAN::Iteration
 | 
												[&](const Scope& opregion_path, Reference* opregion_ref) -> BAN::Iteration
 | 
				
			||||||
							{
 | 
												{
 | 
				
			||||||
| 
						 | 
					@ -189,20 +199,6 @@ namespace Kernel::ACPI::AML
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
						);
 | 
											);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						auto sta_ret = evaluate_sta(child_path);
 | 
					 | 
				
			||||||
						if (sta_ret.is_error())
 | 
					 | 
				
			||||||
							return BAN::Iteration::Continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
						if (sta_ret.value() & STA_PRESENT)
 | 
					 | 
				
			||||||
							(void)evaluate_ini(child_path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
						if ((sta_ret.value() & STA_PRESENT) || (sta_ret.value() & STA_FUNCTIONAL))
 | 
					 | 
				
			||||||
						{
 | 
					 | 
				
			||||||
							auto child_path_copy = child_path.copy();
 | 
					 | 
				
			||||||
							if (!child_path_copy.is_error())
 | 
					 | 
				
			||||||
								(void)to_init_next.push_back(child_path_copy.release_value());
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
						return BAN::Iteration::Continue;
 | 
											return BAN::Iteration::Continue;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				));
 | 
									));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1020,81 +1020,6 @@ namespace Kernel::ACPI::AML
 | 
				
			||||||
		return result;
 | 
							return result;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static bool match_compare(const Package::Element& element, uint8_t opcode, uint64_t target)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (!element.resolved || element.value.node == nullptr)
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto element_copy = element.value.node->copy();
 | 
					 | 
				
			||||||
		if (element_copy.is_error())
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto element_conv = convert_node(element_copy.release_value(), ConvInteger, sizeof(uint64_t));
 | 
					 | 
				
			||||||
		if (element_conv.is_error())
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		switch (opcode)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			case 0: return true;
 | 
					 | 
				
			||||||
			case 1: return element_conv.value().as.integer.value == target;
 | 
					 | 
				
			||||||
			case 2: return element_conv.value().as.integer.value <= target;
 | 
					 | 
				
			||||||
			case 3: return element_conv.value().as.integer.value <  target;
 | 
					 | 
				
			||||||
			case 4: return element_conv.value().as.integer.value >= target;
 | 
					 | 
				
			||||||
			case 5: return element_conv.value().as.integer.value >  target;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static BAN::ErrorOr<Node> parse_match_op(ParseContext& context)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_match_op");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ASSERT(!context.aml_data.empty());
 | 
					 | 
				
			||||||
		ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::MatchOp);
 | 
					 | 
				
			||||||
		context.aml_data = context.aml_data.slice(1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto search = TRY(parse_node(context));
 | 
					 | 
				
			||||||
		if (search.type != Node::Type::Package)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			dwarnln("Match search package is {}", search);
 | 
					 | 
				
			||||||
			return BAN::Error::from_errno(EINVAL);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (context.aml_data.empty())
 | 
					 | 
				
			||||||
			return BAN::Error::from_errno(ENODATA);
 | 
					 | 
				
			||||||
		const uint8_t opcode1 = context.aml_data[0];
 | 
					 | 
				
			||||||
		const uint64_t operand1 = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))).as.integer.value;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (context.aml_data.empty())
 | 
					 | 
				
			||||||
			return BAN::Error::from_errno(ENODATA);
 | 
					 | 
				
			||||||
		const uint8_t opcode2 = context.aml_data[0];
 | 
					 | 
				
			||||||
		const uint64_t operand2 = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))).as.integer.value;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const uint64_t start_idx = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))).as.integer.value;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Node result;
 | 
					 | 
				
			||||||
		result.type = Node::Type::Integer;
 | 
					 | 
				
			||||||
		result.as.integer.value = ONES;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (uint64_t i = start_idx; i < search.as.package->num_elements; i++)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			auto& element = search.as.package->elements[i];
 | 
					 | 
				
			||||||
			if (!element.resolved)
 | 
					 | 
				
			||||||
				TRY(resolve_package_element(element, false));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (!match_compare(element, opcode1, operand1))
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			if (!match_compare(element, opcode2, operand2))
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			result.as.integer.value = i;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return result;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static BAN::ErrorOr<Node> sizeof_impl(const Node& node)
 | 
						static BAN::ErrorOr<Node> sizeof_impl(const Node& node)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Node result {};
 | 
							Node result {};
 | 
				
			||||||
| 
						 | 
					@ -2736,8 +2661,6 @@ namespace Kernel::ACPI::AML
 | 
				
			||||||
				return TRY(parse_index_op(context));
 | 
									return TRY(parse_index_op(context));
 | 
				
			||||||
			case AML::Byte::ObjectTypeOp:
 | 
								case AML::Byte::ObjectTypeOp:
 | 
				
			||||||
				return TRY(parse_object_type_op(context));
 | 
									return TRY(parse_object_type_op(context));
 | 
				
			||||||
			case AML::Byte::MatchOp:
 | 
					 | 
				
			||||||
				return TRY(parse_match_op(context));
 | 
					 | 
				
			||||||
			case AML::Byte::ToBufferOp:
 | 
								case AML::Byte::ToBufferOp:
 | 
				
			||||||
			case AML::Byte::ToDecimalStringOp:
 | 
								case AML::Byte::ToDecimalStringOp:
 | 
				
			||||||
			case AML::Byte::ToHexStringOp:
 | 
								case AML::Byte::ToHexStringOp:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -119,17 +119,6 @@ namespace Kernel::ACPI
 | 
				
			||||||
		auto batteries = TRY(m_acpi_namespace.find_device_with_eisa_id("PNP0C0A"_sv));
 | 
							auto batteries = TRY(m_acpi_namespace.find_device_with_eisa_id("PNP0C0A"_sv));
 | 
				
			||||||
		for (const auto& battery : batteries)
 | 
							for (const auto& battery : batteries)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			auto [_0, sta_ref] = TRY(m_acpi_namespace.find_named_object(battery, TRY(AML::NameString::from_string("_STA"_sv))));
 | 
					 | 
				
			||||||
			if (sta_ref != nullptr)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				auto sta_result = AML::evaluate_node(_0, sta_ref->node);
 | 
					 | 
				
			||||||
				if (sta_result.is_error() || sta_result.value().type != AML::Node::Type::Integer)
 | 
					 | 
				
			||||||
					continue;
 | 
					 | 
				
			||||||
				// "battery is present"
 | 
					 | 
				
			||||||
				if (!(sta_result.value().as.integer.value & 0x10))
 | 
					 | 
				
			||||||
					continue;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			auto [_1, bif_ref] = TRY(m_acpi_namespace.find_named_object(battery, TRY(AML::NameString::from_string("_BIF"_sv))));
 | 
								auto [_1, bif_ref] = TRY(m_acpi_namespace.find_named_object(battery, TRY(AML::NameString::from_string("_BIF"_sv))));
 | 
				
			||||||
			if (!bif_ref || bif_ref->node.type != AML::Node::Type::Method || bif_ref->node.as.method.arg_count != 0)
 | 
								if (!bif_ref || bif_ref->node.type != AML::Node::Type::Method || bif_ref->node.as.method.arg_count != 0)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,6 @@ set(AOC2024_PROJECTS
 | 
				
			||||||
	day16
 | 
						day16
 | 
				
			||||||
	day17
 | 
						day17
 | 
				
			||||||
	day18
 | 
						day18
 | 
				
			||||||
	day19
 | 
					 | 
				
			||||||
	full
 | 
						full
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +0,0 @@
 | 
				
			||||||
set(SOURCES
 | 
					 | 
				
			||||||
	main.cpp
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
add_executable(aoc2024_day19 ${SOURCES})
 | 
					 | 
				
			||||||
banan_link_library(aoc2024_day19 ban)
 | 
					 | 
				
			||||||
banan_link_library(aoc2024_day19 libc)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
install(TARGETS aoc2024_day19 OPTIONAL)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,162 +0,0 @@
 | 
				
			||||||
#include <BAN/HashMap.h>
 | 
					 | 
				
			||||||
#include <BAN/HashSet.h>
 | 
					 | 
				
			||||||
#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 isize = ssize_t;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using u8  = uint8_t;
 | 
					 | 
				
			||||||
using u16 = uint16_t;
 | 
					 | 
				
			||||||
using u32 = uint32_t;
 | 
					 | 
				
			||||||
using u64 = uint64_t;
 | 
					 | 
				
			||||||
using usize = size_t;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct ParseInputResult
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	BAN::Vector<BAN::String> available_towels;
 | 
					 | 
				
			||||||
	BAN::Vector<BAN::String> target_patterns;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ParseInputResult parse_input(FILE* fp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	char buffer[128];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	BAN::String first_line;
 | 
					 | 
				
			||||||
	while (fgets(buffer, sizeof(buffer), fp))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		MUST(first_line.append(buffer));
 | 
					 | 
				
			||||||
		if (first_line.back() != '\n')
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		first_line.pop_back();
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	BAN::Vector<BAN::String> available_towels;
 | 
					 | 
				
			||||||
	auto first_line_split = MUST(first_line.sv().split(','));
 | 
					 | 
				
			||||||
	for (auto splitted : first_line_split)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (splitted.starts_with(" "_sv))
 | 
					 | 
				
			||||||
			splitted = splitted.substring(1);
 | 
					 | 
				
			||||||
		MUST(available_towels.emplace_back(splitted));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ASSERT(fgets(buffer, sizeof(buffer), fp) && buffer[0] == '\n');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	BAN::Vector<BAN::String> target_patterns;
 | 
					 | 
				
			||||||
	while (fgets(buffer, sizeof(buffer), fp))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		usize len = strlen(buffer);
 | 
					 | 
				
			||||||
		if (len == 0 || buffer[0] == '\n')
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		ASSERT(buffer[len - 1] == '\n');
 | 
					 | 
				
			||||||
		buffer[len - 1] = '\0';
 | 
					 | 
				
			||||||
		MUST(target_patterns.emplace_back(BAN::StringView(buffer, len - 1)));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ParseInputResult {
 | 
					 | 
				
			||||||
		.available_towels = BAN::move(available_towels),
 | 
					 | 
				
			||||||
		.target_patterns = BAN::move(target_patterns),
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool recurse_part1(BAN::StringView target, const BAN::Vector<BAN::String>& available, usize index, BAN::HashSet<BAN::StringView>& not_possible)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (index >= target.size())
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	if (not_possible.contains(target.substring(index)))
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (const auto& towel : available)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (!target.substring(index).starts_with(towel))
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		if (recurse_part1(target, available, index + towel.size(), not_possible))
 | 
					 | 
				
			||||||
			return true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MUST(not_possible.insert(target.substring(index)));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
i64 part1(FILE* fp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	auto [available, targets] = parse_input(fp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	BAN::HashSet<BAN::StringView> not_possible;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	usize result = 0;
 | 
					 | 
				
			||||||
	for (const auto& target : targets)
 | 
					 | 
				
			||||||
		result += recurse_part1(target, available, 0, not_possible);
 | 
					 | 
				
			||||||
	return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static u64 recurse_part2(BAN::StringView target, const BAN::Vector<BAN::String>& available, usize index, BAN::HashSet<BAN::StringView>& not_possible, BAN::HashMap<BAN::StringView, u64>& possible)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (index >= target.size())
 | 
					 | 
				
			||||||
		return 1;
 | 
					 | 
				
			||||||
	if (not_possible.contains(target.substring(index)))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto it = possible.find(target.substring(index));
 | 
					 | 
				
			||||||
	if (it != possible.end())
 | 
					 | 
				
			||||||
		return it->value;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	usize ret = 0;
 | 
					 | 
				
			||||||
	for (const auto& towel : available)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (!target.substring(index).starts_with(towel))
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		ret += recurse_part2(target, available, index + towel.size(), not_possible, possible);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ret == 0)
 | 
					 | 
				
			||||||
		MUST(not_possible.insert(target.substring(index)));
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		MUST(possible.insert_or_assign(target.substring(index), ret));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
i64 part2(FILE* fp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	auto [available, targets] = parse_input(fp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	BAN::HashSet<BAN::StringView> not_possible;
 | 
					 | 
				
			||||||
	BAN::HashMap<BAN::StringView, u64> possible;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	u64 result = 0;
 | 
					 | 
				
			||||||
	for (const auto& target : targets)
 | 
					 | 
				
			||||||
		result += recurse_part2(target, available, 0, not_possible, possible);
 | 
					 | 
				
			||||||
	return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main(int argc, char** argv)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const char* file_path = "/usr/share/aoc2024/day19_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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Loading…
	
		Reference in New Issue