Add solution for "Day 24: Crossed Wires", part 1
This commit is contained in:
parent
958adde4a2
commit
4788a1b5ab
45
include/aoc/CrossedWires.hpp
Normal file
45
include/aoc/CrossedWires.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
// Solutions to the Advent Of Code 2024.
|
||||
// Copyright (C) 2025 Stefan Müller
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation, either version 3 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <bitset>
|
||||
#include <forward_list>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <aoc/common/LogicGate.hpp>
|
||||
#include <aoc/framework/Solver-types.hpp>
|
||||
|
||||
class CrossedWires
|
||||
: public Solver<int64_t, std::string>
|
||||
{
|
||||
public:
|
||||
CrossedWires(const int inputFileNameSuffix = 0);
|
||||
virtual const std::string getPuzzleName() const override;
|
||||
virtual const int getPuzzleDay() const override;
|
||||
virtual void processDataLine(const std::string& line) override;
|
||||
virtual void finish() override;
|
||||
private:
|
||||
static constexpr char getInputWireDelimiter();
|
||||
static constexpr char getOutputWiresChar();
|
||||
bool isProcessingInputWires_;
|
||||
std::unordered_map<std::string, bool> wires_;
|
||||
std::forward_list<LogicGate> unevaluatedGates_;
|
||||
std::bitset<64> z_;
|
||||
void processInputWire(const std::string& line);
|
||||
void processLogicGate(const std::string& line);
|
||||
bool tryEvaluateLogicGate(const LogicGate& gate);
|
||||
void setOutputWire(const std::string& wire, const bool value);
|
||||
};
|
33
include/aoc/common/LogicGate.hpp
Normal file
33
include/aoc/common/LogicGate.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
// Solutions to the Advent Of Code 2024.
|
||||
// Copyright (C) 2025 Stefan Müller
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation, either version 3 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
class LogicGate
|
||||
{
|
||||
public:
|
||||
enum class Kind { And, Or, Xor, Unknown };
|
||||
|
||||
std::string inputWire1;
|
||||
std::string inputWire2;
|
||||
std::string outputWire;
|
||||
Kind kind{ Kind::Unknown };
|
||||
};
|
||||
|
||||
std::istream& operator>>(std::istream& is, LogicGate& logicGate);
|
||||
std::istream& operator>>(std::istream& is, LogicGate::Kind& kind);
|
160
src/CrossedWires.cpp
Normal file
160
src/CrossedWires.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
// Solutions to the Advent Of Code 2024.
|
||||
// Copyright (C) 2025 Stefan Müller
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation, either version 3 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <aoc/CrossedWires.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
CrossedWires::CrossedWires(const int inputFileNameSuffix)
|
||||
: Solver(inputFileNameSuffix), isProcessingInputWires_{ true }, wires_{}, unevaluatedGates_{}, z_{ 0 }
|
||||
{
|
||||
}
|
||||
|
||||
const std::string CrossedWires::getPuzzleName() const
|
||||
{
|
||||
return "Crossed Wires";
|
||||
}
|
||||
|
||||
const int CrossedWires::getPuzzleDay() const
|
||||
{
|
||||
return 24;
|
||||
}
|
||||
|
||||
void CrossedWires::processDataLine(const std::string& line)
|
||||
{
|
||||
if (isProcessingInputWires_)
|
||||
{
|
||||
if (line.empty())
|
||||
{
|
||||
isProcessingInputWires_ = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
processInputWire(line);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
processLogicGate(line);
|
||||
}
|
||||
}
|
||||
|
||||
void CrossedWires::finish()
|
||||
{
|
||||
while (!unevaluatedGates_.empty())
|
||||
{
|
||||
unevaluatedGates_.remove_if([this](const LogicGate& gate) { return tryEvaluateLogicGate(gate); });
|
||||
}
|
||||
part1 = z_.to_ullong();
|
||||
}
|
||||
|
||||
constexpr char CrossedWires::getInputWireDelimiter()
|
||||
{
|
||||
return ':';
|
||||
}
|
||||
|
||||
constexpr char CrossedWires::getOutputWiresChar()
|
||||
{
|
||||
return 'z';
|
||||
}
|
||||
|
||||
void CrossedWires::processInputWire(const std::string& line)
|
||||
{
|
||||
std::istringstream stream{ line };
|
||||
std::string wire;
|
||||
int value;
|
||||
std::getline(stream, wire, getInputWireDelimiter());
|
||||
stream >> value;
|
||||
|
||||
wires_.insert({ wire, value == 1 });
|
||||
}
|
||||
|
||||
void CrossedWires::processLogicGate(const std::string& line)
|
||||
{
|
||||
std::istringstream stream{ line };
|
||||
LogicGate gate;
|
||||
stream >> gate;
|
||||
|
||||
if (!tryEvaluateLogicGate(gate))
|
||||
{
|
||||
unevaluatedGates_.push_front(gate);
|
||||
}
|
||||
}
|
||||
|
||||
bool CrossedWires::tryEvaluateLogicGate(const LogicGate& gate)
|
||||
{
|
||||
auto in1 = wires_.find(gate.inputWire1);
|
||||
if (in1 != wires_.end())
|
||||
{
|
||||
if (in1->second)
|
||||
{
|
||||
if (gate.kind == LogicGate::Kind::Or)
|
||||
{
|
||||
setOutputWire(gate.outputWire, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (gate.kind == LogicGate::Kind::And)
|
||||
{
|
||||
setOutputWire(gate.outputWire, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
auto in2 = wires_.find(gate.inputWire2);
|
||||
if (in2 != wires_.end())
|
||||
{
|
||||
if (in2->second)
|
||||
{
|
||||
if (gate.kind == LogicGate::Kind::Or)
|
||||
{
|
||||
setOutputWire(gate.outputWire, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (gate.kind == LogicGate::Kind::And)
|
||||
{
|
||||
setOutputWire(gate.outputWire, false);
|
||||
return true;
|
||||
}
|
||||
if (in1 != wires_.end())
|
||||
{
|
||||
switch (gate.kind)
|
||||
{
|
||||
case LogicGate ::Kind ::And :
|
||||
setOutputWire(gate.outputWire, true);
|
||||
return true;
|
||||
case LogicGate ::Kind ::Or :
|
||||
setOutputWire(gate.outputWire, false);
|
||||
return true;
|
||||
case LogicGate ::Kind ::Xor :
|
||||
setOutputWire(gate.outputWire, in1->second != in2->second);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CrossedWires::setOutputWire(const std::string& wire, const bool value)
|
||||
{
|
||||
if (wire[0] == getOutputWiresChar())
|
||||
{
|
||||
size_t index = std::stoull(wire.substr(1, 2));
|
||||
z_[index] = value;
|
||||
}
|
||||
wires_.insert({ wire, value });
|
||||
}
|
@ -44,6 +44,7 @@
|
||||
#include <aoc/KeypadConundrum.hpp>
|
||||
#include <aoc/MonkeyMarket.hpp>
|
||||
#include <aoc/LanParty.hpp>
|
||||
#include <aoc/CrossedWires.hpp>
|
||||
|
||||
void Program::run()
|
||||
{
|
||||
@ -84,6 +85,7 @@ void Program::runSolvers()
|
||||
runSolver<KeypadConundrum>(solverEngine);
|
||||
runSolver<MonkeyMarket>(solverEngine);
|
||||
runSolver<LanParty>(solverEngine);
|
||||
runSolver<CrossedWires>(solverEngine);
|
||||
}
|
||||
|
||||
std::vector<std::string> Program::getInputPaths() const
|
||||
|
45
src/common/LogicGate.cpp
Normal file
45
src/common/LogicGate.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
// Solutions to the Advent Of Code 2024.
|
||||
// Copyright (C) 2025 Stefan Müller
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation, either version 3 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <aoc/common/LogicGate.hpp>
|
||||
|
||||
std::istream& operator>>(std::istream& is, LogicGate& logicGate)
|
||||
{
|
||||
std::string token;
|
||||
is >> logicGate.inputWire1 >> logicGate.kind >> logicGate.inputWire2 >> token >> logicGate.outputWire;
|
||||
return is;
|
||||
}
|
||||
|
||||
std::istream& operator>>(std::istream& is, LogicGate::Kind& kind)
|
||||
{
|
||||
std::string s;
|
||||
is >> s;
|
||||
switch (s[0])
|
||||
{
|
||||
case 'A' :
|
||||
kind = LogicGate::Kind::And;
|
||||
break;
|
||||
case 'O' :
|
||||
kind = LogicGate::Kind::Or;
|
||||
break;
|
||||
case 'X' :
|
||||
kind = LogicGate::Kind::Xor;
|
||||
break;
|
||||
default :
|
||||
kind = LogicGate::Kind::Unknown;
|
||||
break;
|
||||
}
|
||||
return is;
|
||||
}
|
@ -38,6 +38,7 @@ class TestContext
|
||||
const std::string& expected2);
|
||||
void runExamplePart1(std::unique_ptr<Solver<int64_t, int64_t>>&& solver, const int64_t expected);
|
||||
void runExamplePart1(std::unique_ptr<Solver<std::string, int64_t>>&& solver, const std::string& expected);
|
||||
void runExamplePart1(std::unique_ptr<Solver<int64_t, std::string>>&& solver, const int64_t expected);
|
||||
void runExamplePart2(std::unique_ptr<Solver<int64_t, int64_t>>&& solver, const int64_t expected);
|
||||
private:
|
||||
template <typename T1, typename T2>
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <aoc/KeypadConundrum.hpp>
|
||||
#include <aoc/MonkeyMarket.hpp>
|
||||
#include <aoc/LanParty.hpp>
|
||||
#include <aoc/CrossedWires.hpp>
|
||||
|
||||
#define REQUIRE_MESSAGE(cond, msg) if (!(cond)) { INFO(msg); REQUIRE(cond); }
|
||||
|
||||
@ -413,3 +414,20 @@ TEST_CASE("[LanPartyTests]")
|
||||
test.runExample(std::make_unique<LanParty>(), 7, "co,de,ka,ta");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("[CrossedWiresTests]")
|
||||
{
|
||||
TestContext test;
|
||||
SECTION("FullData")
|
||||
{
|
||||
test.runFull(std::make_unique<CrossedWires>(), 48508229772400, "");
|
||||
}
|
||||
SECTION("ExampleData")
|
||||
{
|
||||
test.runExamplePart1(std::make_unique<CrossedWires>(), 4);
|
||||
}
|
||||
SECTION("ExampleData2")
|
||||
{
|
||||
test.runExamplePart1(std::make_unique<CrossedWires>(2), 2024);
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,11 @@ void TestContext::runExamplePart1(std::unique_ptr<Solver<std::string, int64_t>>&
|
||||
runPart1Generic(std::move(solver), expected, exampleInputPaths_);
|
||||
}
|
||||
|
||||
void TestContext::runExamplePart1(std::unique_ptr<Solver<int64_t, std::string>>&& solver, const int64_t expected)
|
||||
{
|
||||
runPart1Generic(std::move(solver), expected, exampleInputPaths_);
|
||||
}
|
||||
|
||||
void TestContext::runExamplePart2(std::unique_ptr<Solver<int64_t, int64_t>>&& solver, const int64_t expected)
|
||||
{
|
||||
runPart2Generic(std::move(solver), expected, exampleInputPaths_);
|
||||
|
Loading…
x
Reference in New Issue
Block a user