Now files are installed using the install() command instead of manually copying files to their destinations. This allows automatic recompilation of headers that did not work previously
192 lines
3.8 KiB
C++
192 lines
3.8 KiB
C++
#include <BAN/HashMap.h>
|
|
#include <BAN/Queue.h>
|
|
#include <BAN/String.h>
|
|
#include <BAN/Vector.h>
|
|
#include <BAN/UniqPtr.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 Signal
|
|
{
|
|
BAN::String target;
|
|
BAN::String sender;
|
|
bool high;
|
|
};
|
|
|
|
struct Module
|
|
{
|
|
BAN::String name;
|
|
BAN::Vector<BAN::String> targets;
|
|
|
|
virtual ~Module() {}
|
|
|
|
virtual void handle_signal(const Signal& signal, BAN::Queue<Signal>& signal_queue) = 0;
|
|
};
|
|
|
|
struct BroadcasterModule : public Module
|
|
{
|
|
void handle_signal(const Signal& signal, BAN::Queue<Signal>& signal_queue) override
|
|
{
|
|
for (const auto& target : targets)
|
|
MUST(signal_queue.push({ target, name, signal.high }));
|
|
}
|
|
};
|
|
|
|
struct FlipFlopModule : public Module
|
|
{
|
|
bool is_on { false };
|
|
|
|
void handle_signal(const Signal& signal, BAN::Queue<Signal>& signal_queue) override
|
|
{
|
|
if (signal.high)
|
|
return;
|
|
is_on = !is_on;
|
|
for (const auto& target : targets)
|
|
MUST(signal_queue.push({ target, name, is_on }));
|
|
}
|
|
};
|
|
|
|
struct ConjunctionModule : public Module
|
|
{
|
|
BAN::HashMap<BAN::String, bool> inputs;
|
|
|
|
void handle_signal(const Signal& signal, BAN::Queue<Signal>& signal_queue) override
|
|
{
|
|
inputs[signal.sender] = signal.high;
|
|
bool send_value = false;
|
|
for (const auto& input : inputs)
|
|
if (!input.value)
|
|
send_value = true;
|
|
for (const auto& target : targets)
|
|
MUST(signal_queue.push({ target, name, send_value }));
|
|
}
|
|
};
|
|
|
|
BAN::HashMap<BAN::String, BAN::UniqPtr<Module>> parse_modules(FILE* fp)
|
|
{
|
|
BAN::HashMap<BAN::String, BAN::UniqPtr<Module>> modules;
|
|
|
|
char buffer[128];
|
|
while (fgets(buffer, sizeof(buffer), fp))
|
|
{
|
|
BAN::StringView line(buffer);
|
|
ASSERT(line.back() == '\n');
|
|
line = line.substring(0, line.size() - 1);
|
|
if (line.empty())
|
|
break;
|
|
|
|
BAN::UniqPtr<Module> module;
|
|
if (line.front() == '%')
|
|
{
|
|
module = MUST(BAN::UniqPtr<FlipFlopModule>::create());
|
|
line = line.substring(1);
|
|
}
|
|
else if (line.front() == '&')
|
|
{
|
|
module = MUST(BAN::UniqPtr<ConjunctionModule>::create());
|
|
line = line.substring(1);
|
|
}
|
|
else
|
|
{
|
|
module = MUST(BAN::UniqPtr<BroadcasterModule>::create());
|
|
}
|
|
|
|
auto name_targets = MUST(line.split('>'));
|
|
auto name = name_targets[0].substring(0, name_targets[0].size() - 2);
|
|
auto target_strs = MUST(name_targets[1].split(','));
|
|
|
|
for (auto target : target_strs)
|
|
MUST(module->targets.emplace_back(target.substring(1)));
|
|
|
|
module->name = BAN::String(name);
|
|
MUST(modules.insert(module->name, BAN::move(module)));
|
|
}
|
|
|
|
for (auto& [name, module] : modules)
|
|
{
|
|
for (auto& target : module->targets)
|
|
{
|
|
if (!modules.contains(target))
|
|
continue;
|
|
if (auto* ptr = dynamic_cast<ConjunctionModule*>(modules[target].ptr()))
|
|
MUST(ptr->inputs.insert(name, false));
|
|
}
|
|
}
|
|
|
|
return modules;
|
|
}
|
|
|
|
i64 puzzle1(FILE* fp)
|
|
{
|
|
auto modules = parse_modules(fp);
|
|
|
|
BAN::Queue<Signal> signal_queue;
|
|
|
|
i64 sent_hi = 0;
|
|
i64 sent_lo = 0;
|
|
|
|
for (size_t i = 0; i < 1000; i++)
|
|
{
|
|
MUST(signal_queue.push({ "broadcaster"_sv, ""_sv, false }));
|
|
while (!signal_queue.empty())
|
|
{
|
|
auto signal = signal_queue.front();
|
|
signal_queue.pop();
|
|
|
|
if (signal.high)
|
|
sent_hi++;
|
|
else
|
|
sent_lo++;
|
|
|
|
if (!modules.contains(signal.target))
|
|
continue;
|
|
|
|
auto& module = modules[signal.target];
|
|
module->handle_signal(signal, signal_queue);
|
|
}
|
|
}
|
|
|
|
return sent_hi * sent_lo;
|
|
}
|
|
|
|
i64 puzzle2(FILE* fp)
|
|
{
|
|
(void)fp;
|
|
return -1;
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
const char* file_path = "/usr/share/aoc2023/day20_input.txt";
|
|
|
|
if (argc >= 2)
|
|
file_path = argv[1];
|
|
|
|
FILE* fp = fopen(file_path, "r");
|
|
if (fp == nullptr)
|
|
{
|
|
perror("fopen");
|
|
return 1;
|
|
}
|
|
|
|
printf("puzzle1: %" PRId64 "\n", puzzle1(fp));
|
|
|
|
fseek(fp, 0, SEEK_SET);
|
|
|
|
printf("puzzle2: %" PRId64 "\n", puzzle2(fp));
|
|
|
|
fclose(fp);
|
|
}
|