Initial commit with solutions from 2024
This commit is contained in:
@@ -0,0 +1,304 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "common/lib/Array2D.h"
|
||||
#include "common/lib/Array3D.h"
|
||||
#include "common/lib/Array4D.h"
|
||||
#include "common/lib/Graph.h"
|
||||
#include "common/lib/Helper.h"
|
||||
#include "common/lib/Input.h"
|
||||
#include "common/lib/Json.h"
|
||||
#include "common/lib/Mapper.h"
|
||||
#include "common/lib/Math.h"
|
||||
#include "common/lib/Timer.h"
|
||||
|
||||
#define TERM_RED "\x1B[31m"
|
||||
#define TERM_GREEN "\x1B[32m"
|
||||
#define TERM_CLEAR "\033[0m"
|
||||
|
||||
namespace aoc
|
||||
{
|
||||
template <typename InputType, typename OutputType>
|
||||
class Test
|
||||
{
|
||||
private:
|
||||
std::string name;
|
||||
std::string inputFile;
|
||||
OutputType expectedOutput;
|
||||
bool isExample = false;
|
||||
int part = 0;
|
||||
|
||||
public:
|
||||
Test(
|
||||
const std::string& name, const std::string& inputFile, const OutputType& expectedOutput, bool isExample, int part)
|
||||
: name{name},
|
||||
inputFile{inputFile},
|
||||
expectedOutput{expectedOutput},
|
||||
isExample{isExample},
|
||||
part{part}
|
||||
{
|
||||
std::transform(this->inputFile.begin(),
|
||||
this->inputFile.end(),
|
||||
this->inputFile.begin(),
|
||||
[](char c) { return std::tolower(c); });
|
||||
}
|
||||
|
||||
const std::string& GetInputFile() const
|
||||
{
|
||||
return inputFile;
|
||||
}
|
||||
|
||||
const std::string& GetName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
const OutputType& GetExpectedOutput() const
|
||||
{
|
||||
return expectedOutput;
|
||||
}
|
||||
|
||||
bool IsExample() const
|
||||
{
|
||||
return isExample;
|
||||
}
|
||||
|
||||
int GetPart() const
|
||||
{
|
||||
return part;
|
||||
}
|
||||
};
|
||||
|
||||
class Day
|
||||
{
|
||||
public:
|
||||
virtual bool AocRunTestCases() = 0;
|
||||
virtual const std::string& GetName() const = 0;
|
||||
};
|
||||
|
||||
template <typename InputType, typename OutputType>
|
||||
class DayT : public Day
|
||||
{
|
||||
protected:
|
||||
std::vector<Test<InputType, OutputType>*> tests;
|
||||
|
||||
std::string name;
|
||||
bool isExample = true;
|
||||
|
||||
public:
|
||||
DayT(const std::string& name)
|
||||
: name{name}
|
||||
{
|
||||
}
|
||||
|
||||
void AddTest(Test<InputType, OutputType>* test)
|
||||
{
|
||||
tests.emplace_back(test);
|
||||
}
|
||||
|
||||
bool AocRunTestCases() override
|
||||
{
|
||||
for (const auto& test : tests)
|
||||
{
|
||||
isExample = test->IsExample();
|
||||
std::ifstream inputStream{test->GetInputFile()};
|
||||
if (!inputStream.is_open())
|
||||
{
|
||||
std::cout << TERM_RED << "Could not find input file: " << test->GetInputFile() << TERM_CLEAR << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::string testName = name + ".P" + std::to_string(test->GetPart()) + "." + test->GetName();
|
||||
std::cout << TERM_GREEN << "[ RUN ] " << TERM_CLEAR << testName << std::endl;
|
||||
InputType input = ReadInput(inputStream);
|
||||
OutputType output = test->GetPart() == 1 ? Output1(input) : Output2(input);
|
||||
|
||||
if (!Check(test->GetExpectedOutput(), output, testName))
|
||||
{
|
||||
return false;
|
||||
};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::string& GetName() const override
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
virtual InputType ReadInput(std::istream& input) = 0;
|
||||
virtual OutputType Output1(const InputType& input) = 0;
|
||||
virtual OutputType Output2(const InputType& input) = 0;
|
||||
|
||||
private:
|
||||
bool Check(const OutputType& expected, const OutputType& actual, const std::string& name) const
|
||||
{
|
||||
if (expected == actual)
|
||||
{
|
||||
std::cout << TERM_GREEN << "[ OK ] " << TERM_CLEAR << " Result: " << actual << std::endl;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << TERM_RED << "[ ] " << TERM_CLEAR << "Unexpected value in " << name << std::endl;
|
||||
std::cout << TERM_RED << "[ ] " << TERM_CLEAR << " expect: " << expected << std::endl;
|
||||
std::cout << TERM_RED << "[ FAILED ] " << TERM_CLEAR << " actual: " << actual << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ptr_compare
|
||||
{
|
||||
using is_transparent = void;
|
||||
|
||||
bool operator()(const Day* lhs, const Day* rhs) const
|
||||
{
|
||||
return lhs->GetName() < rhs->GetName();
|
||||
};
|
||||
|
||||
bool operator()(const Day* lhs, const std::string& rhs) const
|
||||
{
|
||||
return lhs->GetName() < rhs;
|
||||
};
|
||||
|
||||
bool operator()(const std::string& lhs, const Day* rhs) const
|
||||
{
|
||||
return lhs < rhs->GetName();
|
||||
};
|
||||
};
|
||||
|
||||
class Registry
|
||||
{
|
||||
private:
|
||||
using Days = std::set<Day*, ptr_compare>;
|
||||
Days days;
|
||||
|
||||
Day* AddDay(Day* day)
|
||||
{
|
||||
days.emplace(day);
|
||||
return day;
|
||||
}
|
||||
|
||||
template <typename InputType, typename OutputType>
|
||||
Test<InputType, OutputType>* AddTest(std::string year, std::string day, Test<InputType, OutputType>* test)
|
||||
{
|
||||
std::string name = year + "." + day;
|
||||
auto it = days.find(name);
|
||||
if (it == days.end())
|
||||
{
|
||||
std::cout << TERM_RED << "Could not find Day: " << name << TERM_CLEAR << std::endl;
|
||||
return test;
|
||||
}
|
||||
DayT<InputType, OutputType>* dayT = dynamic_cast<DayT<InputType, OutputType>*>(*it);
|
||||
if (!dayT)
|
||||
{
|
||||
std::cout << TERM_RED << "Failed to cast day: " << name << TERM_CLEAR << std::endl;
|
||||
return test;
|
||||
}
|
||||
dayT->AddTest(test);
|
||||
return test;
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename DayImpl>
|
||||
static DayImpl* RegisterDay(DayImpl* day)
|
||||
{
|
||||
return (DayImpl*)GetInstance()->AddDay(day);
|
||||
}
|
||||
|
||||
template <typename InputType, typename OutputType>
|
||||
static Test<InputType, OutputType>* RegisterTest(std::string year,
|
||||
std::string day,
|
||||
Test<InputType, OutputType>* test)
|
||||
{
|
||||
return GetInstance()->AddTest(year, day, test);
|
||||
}
|
||||
|
||||
static Registry* GetInstance();
|
||||
|
||||
static Days& GetDays()
|
||||
{
|
||||
return GetInstance()->days;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#define DAY_STR(year, day) #year "." #day
|
||||
|
||||
#define REGISTER_DAY(year, day, InputTypeType, OutputTypeType) \
|
||||
using InputType = InputTypeType; \
|
||||
using OutputType = OutputTypeType; \
|
||||
class DayImpl : public aoc::DayT<InputType, OutputType> \
|
||||
{ \
|
||||
public: \
|
||||
DayImpl() \
|
||||
: DayT(DAY_STR(year, day)) \
|
||||
{ \
|
||||
} \
|
||||
InputType ReadInput(std::istream& input) override; \
|
||||
OutputType Output1(const InputType& input) override; \
|
||||
OutputType Output2(const InputType& input) override; \
|
||||
static DayImpl* test; \
|
||||
}; \
|
||||
DayImpl* DayImpl::test = aoc::Registry::RegisterDay(new DayImpl())
|
||||
|
||||
#define READ_INPUT(x) InputType DayImpl::ReadInput(std::istream& x)
|
||||
#define OUTPUT1(x) OutputType DayImpl::Output1(const InputType& x)
|
||||
#define OUTPUT2(x) OutputType DayImpl::Output2(const InputType& x)
|
||||
|
||||
#define TEST_NAME_EXAMPLE(year, day, name, part) y##year##day##name##part
|
||||
#define TEST_NAME(year, day, name, part) y##year##day##name##part
|
||||
#define _INTERNAL_REGISTER_TEST_FULL(year, day, name, part, val, testName, inputFile, isExample) \
|
||||
static aoc::Test<InputType, OutputType>* testName = aoc::Registry::RegisterTest( \
|
||||
#year, #day, new aoc::Test<InputType, OutputType>(#name, inputFile, val, isExample, part))
|
||||
|
||||
#define REGISTER_TEST_EXAMPLE(year, day, name, part, val) \
|
||||
_INTERNAL_REGISTER_TEST_FULL(year, \
|
||||
day, \
|
||||
name, \
|
||||
part, \
|
||||
val, \
|
||||
TEST_NAME_EXAMPLE(year, day, name, part), \
|
||||
"res/" #year "/" #day "/test_input.txt", \
|
||||
true)
|
||||
#define REGISTER_TEST_EXAMPLE_FILE(year, day, name, part, val, inputFileName) \
|
||||
_INTERNAL_REGISTER_TEST_FULL(year, \
|
||||
day, \
|
||||
name, \
|
||||
part, \
|
||||
val, \
|
||||
TEST_NAME_EXAMPLE(year, day, name, part), \
|
||||
"res/" #year "/" #day "/" + std::string(inputFileName), \
|
||||
true)
|
||||
|
||||
#define REGISTER_TEST(year, day, name, part, val) \
|
||||
_INTERNAL_REGISTER_TEST_FULL( \
|
||||
year, day, name, part, val, TEST_NAME(year, day, name, part), "res/" #year "/" #day "/input.txt", false)
|
||||
#define REGISTER_TEST_FILE(year, day, name, part, val, inputFileName) \
|
||||
_INTERNAL_REGISTER_TEST_FULL(year, \
|
||||
day, \
|
||||
name, \
|
||||
part, \
|
||||
val, \
|
||||
TEST_NAME(year, day, name, part), \
|
||||
"res/" #year "/" #day "/" + std::string(inputFileName), \
|
||||
false)
|
||||
Reference in New Issue
Block a user