start adding doctests

This commit is contained in:
Eric Mertens 2022-11-13 11:42:40 -08:00
parent c3b3de5416
commit e6f19d8ee3
8 changed files with 7155 additions and 12 deletions

View File

@ -5,22 +5,57 @@
#include <iterator> #include <iterator>
#include <vector> #include <vector>
#include <doctest.h>
#include <aocpp/Startup.hpp> #include <aocpp/Startup.hpp>
namespace {
auto fuel1(std::int64_t weight) -> std::int64_t {
return weight / 3 - 2;
}
auto fuel2(std::int64_t weight) -> std::int64_t {
std::int64_t total = 0;
for(;;) {
weight = fuel1(weight);
if (weight <= 0) break;
total += weight;
}
return total;
}
}
TEST_SUITE("documented examples") {
TEST_CASE("part 1") {
REQUIRE(fuel1(12) == 2);
REQUIRE(fuel1(14) == 2);
REQUIRE(fuel1(1969) == 654);
REQUIRE(fuel1(100756) == 33583);
}
TEST_CASE("part 2") {
REQUIRE(fuel2(14) == 2);
REQUIRE(fuel2(1969) == 966);
REQUIRE(fuel2(100756) == 50346);
}
}
auto main(int argc, char** argv) -> int { auto main(int argc, char** argv) -> int {
auto& in = aocpp::Startup(argc, argv); auto& in = aocpp::Startup(argc, argv);
auto fuel = [](std::int64_t& x) { return x=x/3-2; };
std::int64_t x; std::int64_t weight;
std::int64_t part1 = 0; std::int64_t part1 = 0;
std::int64_t part2 = 0; std::int64_t part2 = 0;
while (in >> x) { while (in >> weight) {
part1 += fuel(x); part1 += fuel1(weight);
for (; x > 0; fuel(x)) { part2 += fuel2(weight);
part2 += x;
}
} }
std::cout << "Part 1: " << part1 << std::endl; std::cout << "Part 1: " << part1 << std::endl;
std::cout << "Part 2: " << part2 << std::endl; std::cout << "Part 2: " << part2 << std::endl;
} }

View File

@ -1,9 +1,12 @@
#include <iostream> #include <iostream>
#include <utility> #include <utility>
#include <doctest.h>
#include <aocpp/Startup.hpp> #include <aocpp/Startup.hpp>
#include <intcode/intcode.hpp> #include <intcode/intcode.hpp>
using namespace intcode; using namespace intcode;
namespace { namespace {
@ -17,6 +20,22 @@ auto Compute(Machine machine, ValueType x, ValueType y) {
} // namespace } // namespace
TEST_SUITE("documented examples") {
auto eval = [](std::vector<ValueType> program, std::vector<ValueType> output) {
Machine m{program};
REQUIRE(std::holds_alternative<Halt>(Step(m)));
REQUIRE(m.Dump() == output);
};
TEST_CASE("part 1") {
eval({1,0,0,0,99}, {2,0,0,0,99});
eval({2,3,0,3,99}, {2,3,0,6,99});
eval({2,4,4,5,99,0}, {2,4,4,5,99,9801});
eval({1,1,1,4,99,5,6,0,99}, {30,1,1,4,2,5,6,0,99});
}
}
auto main(int argc, char** argv) -> int { auto main(int argc, char** argv) -> int {
auto machine = Machine{ParseStream(aocpp::Startup(argc, argv))}; auto machine = Machine{ParseStream(aocpp::Startup(argc, argv))};

View File

@ -5,6 +5,9 @@
#include <iterator> #include <iterator>
#include <vector> #include <vector>
#include <map> #include <map>
#include <sstream>
#include <doctest.h>
#include <aocpp/Startup.hpp> #include <aocpp/Startup.hpp>
@ -74,6 +77,17 @@ auto Part2(std::map<std::string, std::string> const& parents) {
} // namespace } // namespace
TEST_SUITE("documented examples") {
TEST_CASE("part 1") {
std::istringstream in {"COM)B\nB)C\nC)D\nD)E\nE)F\nB)G\nG)H\nD)I\nE)J\nJ)K\nK)L\n"};
REQUIRE(Part1(Parse(in)) == 42);
}
TEST_CASE("part 2") {
std::istringstream in {"COM)B\nB)C\nC)D\nD)E\nE)F\nB)G\nG)H\nD)I\nE)J\nJ)K\nK)L\nK)YOU\nI)SAN\n"};
REQUIRE(Part2(Parse(in)) == 4);
}
}
auto main(int argc, char** argv) -> int { auto main(int argc, char** argv) -> int {
auto parents = Parse(aocpp::Startup(argc, argv)); auto parents = Parse(aocpp::Startup(argc, argv));
std::cout << "Part 1: " << Part1(parents) << std::endl; std::cout << "Part 1: " << Part1(parents) << std::endl;

View File

@ -5,6 +5,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <doctest.h>
#include <aocpp/Startup.hpp> #include <aocpp/Startup.hpp>
#include <intcode/intcode.hpp> #include <intcode/intcode.hpp>
using namespace intcode; using namespace intcode;
@ -36,11 +38,11 @@ auto Feed(R &&amps, ValueType start) -> std::optional<ValueType> {
return {start}; return {start};
} }
auto compute1(Machine machine, std::vector<ValueType> const &params) auto Compute1(Machine machine, std::vector<ValueType> const &params)
-> ValueType { -> ValueType {
return *Feed(Controller(std::move(machine), params), 0); return *Feed(Controller(std::move(machine), params), 0);
} }
auto compute2(Machine machine, std::vector<ValueType> const &params) auto Compute2(Machine machine, std::vector<ValueType> const &params)
-> ValueType { -> ValueType {
auto amps = Controller(std::move(machine), params); auto amps = Controller(std::move(machine), params);
ValueType last = 0; ValueType last = 0;
@ -51,7 +53,7 @@ auto compute2(Machine machine, std::vector<ValueType> const &params)
} }
template <std::invocable<Machine, std::vector<ValueType> const &> F> template <std::invocable<Machine, std::vector<ValueType> const &> F>
auto optimize(Machine machine, std::vector<ValueType> params, F f) { auto Optimize(Machine machine, std::vector<ValueType> params, F f) {
ValueType best = 0; ValueType best = 0;
do { do {
best = std::max(best, f(machine, params)); best = std::max(best, f(machine, params));
@ -59,10 +61,32 @@ auto optimize(Machine machine, std::vector<ValueType> params, F f) {
return best; return best;
} }
auto Part1(Machine machine) -> ValueType {
return Optimize(std::move(machine), {0, 1, 2, 3, 4}, Compute1);
}
auto Part2(Machine machine) -> ValueType {
return Optimize(std::move(machine), {5, 6, 7, 8, 9}, Compute2);
}
} // namespace } // namespace
TEST_SUITE("documented examples") {
TEST_CASE("part 1") {
auto eval = [](std::vector<ValueType> pgm) { return Part1(Machine{pgm}); };
REQUIRE(eval({3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0}) == 43210);
REQUIRE(eval({3,23,3,24,1002,24,10,24,1002,23,-1,23,101,5,23,23,1,24,23,23,4,23,99,0,0}) == 54321);
REQUIRE(eval({3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0}) == 65210);
}
TEST_CASE("part 2") {
auto eval = [](std::vector<ValueType> pgm) { return Part2(Machine{pgm}); };
REQUIRE(eval({3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26,27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5}) == 139629729);
REQUIRE(eval({3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54,-5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4,53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10})== 18216);
}
}
auto main(int argc, char** argv) -> int { auto main(int argc, char** argv) -> int {
auto machine = Machine{ParseStream(aocpp::Startup(argc, argv))}; auto machine = Machine{ParseStream(aocpp::Startup(argc, argv))};
std::cout << "Part 1: " << optimize(machine, {0, 1, 2, 3, 4}, compute1) << std::endl; std::cout << "Part 1: " << Part1(machine) << std::endl;
std::cout << "Part 2: " << optimize(std::move(machine), {5, 6, 7, 8, 9}, compute2) << std::endl; std::cout << "Part 2: " << Part2(std::move(machine)) << std::endl;
} }

View File

@ -33,10 +33,13 @@ public:
/// @param offset from base pointer /// @param offset from base pointer
/// @return reference to memory at given offset /// @return reference to memory at given offset
auto Rel(std::size_t offset) -> ValueType &; auto Rel(std::size_t offset) -> ValueType &;
auto Rel(std::size_t offset) const -> ValueType;
auto Next() -> ValueType &; auto Next() -> ValueType &;
auto Goto(std::size_t address) -> void; auto Goto(std::size_t address) -> void;
auto Rebase(std::size_t offset) -> void; auto Rebase(std::size_t offset) -> void;
auto Dump() const -> std::vector<ValueType>;
}; };
} // namespace } // namespace

View File

@ -21,6 +21,10 @@ auto Machine::Rel(std::size_t const i) -> ValueType & {
return At(base_ + i); return At(base_ + i);
} }
auto Machine::Rel(std::size_t const i) const -> ValueType {
return At(base_ + i);
}
auto Machine::Rebase(std::size_t const offset) -> void { auto Machine::Rebase(std::size_t const offset) -> void {
base_ += offset; base_ += offset;
} }
@ -33,4 +37,21 @@ auto Machine::Goto(std::size_t const address) -> void {
pc_ = address; pc_ = address;
} }
auto Machine::Dump() const -> std::vector<ValueType> {
if (ram_.empty()) { return rom_; }
std::size_t size = rom_.size();
for (auto const& [k,v] : ram_) {
if (k >= size) { size = k+1; }
}
std::vector<ValueType> result(size);
std::copy(rom_.begin(), rom_.end(), result.begin());
for (auto const& [k,v] : ram_) {
result[k] = v;
}
return result;
}
} // namespace } // namespace

7019
lib/include/doctest.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -5,10 +5,18 @@
#include <optional> #include <optional>
#include <memory> #include <memory>
#include <fstream> #include <fstream>
#include <utility>
#define DOCTEST_CONFIG_IMPLEMENT
#include <doctest.h>
namespace aocpp { namespace aocpp {
auto Startup(int argc, char ** argv) -> std::istream& { auto Startup(int argc, char ** argv) -> std::istream& {
if (std::getenv("DOCTEST")) {
exit(doctest::Context{argc, argv}.run());
}
static std::ifstream fin; static std::ifstream fin;
switch (argc) { switch (argc) {
case 2: fin = std::ifstream{argv[1]}; return fin; case 2: fin = std::ifstream{argv[1]}; return fin;