Skip to content

Commit d7533e5

Browse files
author
bt
committed
Day 24 part 1
1 parent dba243f commit d7533e5

File tree

5 files changed

+183
-96
lines changed

5 files changed

+183
-96
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ add_challenge(day16)
2929
add_challenge(day17)
3030
add_challenge(day18)
3131
add_challenge(day19)
32+
add_challenge(day24)
3233

3334
add_custom_command(TARGET day1
3435
COMMAND ${CMAKE_COMMAND} -E create_symlink "${CMAKE_CURRENT_SOURCE_DIR}/data" "./data"

src/day19.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,6 @@ int main(int argc, char* argv[])
104104

105105
auto [patterns, designs] = parseInput(inputVec);
106106

107-
// for(auto p : patterns) {
108-
// std::cerr << "\np `" << p <<"`";
109-
// }
110-
111-
// for(auto s : designs) {
112-
// std::cerr << "\n" << s;
113-
// }
114-
115107
if(task == "part1") {
116108
std::cout << solveFirstPart(patterns, designs);
117109
}

src/day24.cpp

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
#include "common_headers.hpp"
2+
3+
#include <stack>
4+
#include <string>
5+
#include <regex>
6+
#include <unordered_map>
7+
#include <unordered_set>
8+
#include <vector>
9+
#include <queue>
10+
11+
12+
enum class Operation {AND, OR, XOR};
13+
14+
struct LogicExpression final {
15+
std::string operand1;
16+
Operation operation;
17+
std::string operand2;
18+
std::string output;
19+
};
20+
21+
struct Program final
22+
{
23+
std::unordered_map<std::string, bool> gates;
24+
std::vector<LogicExpression> exprs;
25+
};
26+
27+
[[nodiscard]] bool executeOperation(bool operand1, bool operand2, Operation operation) {
28+
switch (operation)
29+
{
30+
case Operation::AND:
31+
return operand1 && operand2;
32+
case Operation::OR:
33+
return operand1 || operand2;
34+
case Operation::XOR:
35+
return operand1 != operand2;
36+
default:
37+
throw std::runtime_error{"unknown operation type"};
38+
}
39+
return false;
40+
}
41+
42+
[[nodiscard]] Operation toOperation(const std::string_view op) {
43+
if(op == "AND") return Operation::AND;
44+
if(op == "OR") return Operation::OR;
45+
if(op == "XOR") return Operation::XOR;
46+
throw std::runtime_error{"unknown operation type"};
47+
}
48+
49+
[[nodiscard]] std::pair<std::string, bool> parseInitialGate(const std::string& line)
50+
{
51+
const auto pos = line.find(":");
52+
if(pos == std::string::npos) {
53+
throw std::logic_error{"input invalid"};
54+
}
55+
std::string gate{line.substr(0, pos)};
56+
bool value{line.at(pos + 2) == '1'};
57+
return {std::move(gate), value};
58+
}
59+
60+
[[nodiscard]] LogicExpression parseLogicExpression(const std::string& line)
61+
{
62+
std::regex pattern(R"((\w+) (\w+) (\w+) -> (\w+))");
63+
std::smatch match;
64+
if(!std::regex_match(line, match, pattern)) {
65+
throw std::logic_error{"invalid logic expression"};
66+
}
67+
68+
LogicExpression expr{
69+
.operand1 = match[1].str(), // operand1
70+
.operation = toOperation(match[2].str()), // operation
71+
.operand2 = match[3].str(), // operand2
72+
.output = match[4].str() // result
73+
};
74+
75+
return expr;
76+
}
77+
78+
[[nodiscard]] Program parseInput(const std::vector<std::string>& inputVec)
79+
{
80+
Program program;
81+
size_t id{};
82+
for(; id < inputVec.size() && !inputVec[id].empty(); ++id) {
83+
const auto [name, val] = parseInitialGate(inputVec[id]);
84+
program.gates.emplace(name, val);
85+
}
86+
++id;
87+
for(; id < inputVec.size(); ++id) {
88+
program.exprs.push_back(parseLogicExpression(inputVec[id]));
89+
}
90+
return program;
91+
}
92+
93+
[[nodiscard]] size_t solveFirstPart(Program& program)
94+
{
95+
std::unordered_map<std::string, int> preordering;
96+
std::unordered_map<std::string, std::vector<size_t>> operandToExpressionId;
97+
98+
for(size_t id = 0; id < program.exprs.size(); ++id) {
99+
const auto& expr = program.exprs[id];
100+
operandToExpressionId[expr.operand1].push_back(id);
101+
operandToExpressionId[expr.operand2].push_back(id);
102+
103+
preordering[expr.output]++;
104+
}
105+
106+
std::queue<size_t> bfs;
107+
for(size_t id = 0; id < program.exprs.size(); ++id) {
108+
const auto& expr = program.exprs[id];
109+
if(preordering[expr.operand1] == 0 && preordering[expr.operand2] == 0) {
110+
bfs.push(id);
111+
}
112+
}
113+
114+
while(!bfs.empty()) {
115+
const auto exprId = bfs.front();
116+
bfs.pop();
117+
118+
const LogicExpression& expr = program.exprs[exprId];
119+
const bool operationResult = executeOperation(program.gates.at(expr.operand1), program.gates.at(expr.operand2), expr.operation);
120+
program.gates[expr.output] = operationResult;
121+
122+
if(--preordering[expr.output] == 0) {
123+
for(const size_t otherExprId : operandToExpressionId[expr.output]) {
124+
if(otherExprId == exprId) continue;
125+
const LogicExpression& otherExpr = program.exprs[otherExprId];
126+
127+
if(preordering.at(otherExpr.operand1) == 0 && preordering.at(otherExpr.operand2) == 0) {
128+
bfs.emplace(otherExprId);
129+
}
130+
}
131+
operandToExpressionId[expr.output].clear();
132+
}
133+
}
134+
135+
size_t zGateOutput{0};
136+
for(const auto& [gate, result] : program.gates) {
137+
if(gate[0] != 'z' || result == false) continue;
138+
const auto gateNumber = std::stoul(gate.substr(1));
139+
zGateOutput |= (size_t{1} << gateNumber);
140+
}
141+
return zGateOutput;
142+
}
143+
144+
void printHelp()
145+
{
146+
std::cerr << "\nUsage:\n"
147+
<< "The program requires 2 args: (part1, part2) and the path to the file."
148+
<< "\nFor example, ./day7 part1 data/day7.txt";
149+
}
150+
151+
int main(int argc, char* argv[])
152+
{
153+
if(argc != 3) {
154+
printHelp();
155+
return 1;
156+
}
157+
158+
std::string_view task{argv[1]};
159+
if(task != "part1" && task != "part2") {
160+
std::cerr << "\nfirst arg can be either `part1` or `part2`\n";
161+
printHelp();
162+
return 1;
163+
}
164+
165+
std::vector<std::string> inputVec;
166+
readInput(argv[2], std::back_inserter(inputVec));
167+
168+
auto program = parseInput(inputVec);
169+
170+
if(task == "part1") {
171+
std::cout << solveFirstPart(program);
172+
}
173+
else {
174+
// std::cout << solveSecondPart(program);
175+
}
176+
177+
return 0;
178+
}

src/day6.cpp

Lines changed: 3 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,12 @@
11
#include "common_headers.hpp"
2+
#include "Cursor.hpp"
3+
24
#include <vector>
35
#include <set>
46
#include <unordered_set>
5-
using Graph = std::vector<std::string>;
6-
7-
class Cursor final
8-
{
9-
public:
10-
enum class Direction{Up = 0, Right = 1, Down = 2, Left=3, Sentinel=4};
11-
12-
Cursor() = default;
13-
14-
explicit constexpr Cursor(Direction initDirection, int initX, int initY)
15-
: m_direction{initDirection}
16-
, m_x{initX}
17-
, m_y{initY}
18-
{}
19-
20-
[[nodiscard]] constexpr int x() const noexcept {
21-
return m_x;
22-
}
237

24-
[[nodiscard]] constexpr int y() const noexcept {
25-
return m_y;
26-
}
27-
28-
[[nodiscard]] constexpr Direction direction() const noexcept {
29-
return m_direction;
30-
}
31-
32-
constexpr void stepUp() noexcept {
33-
--m_x;
34-
}
35-
36-
constexpr void stepDown() noexcept {
37-
++m_x;
38-
}
398

40-
constexpr void stepLeft() noexcept {
41-
--m_y;
42-
}
43-
44-
constexpr void stepRight() noexcept {
45-
++m_y;
46-
}
47-
48-
49-
constexpr void move() noexcept {
50-
switch (m_direction)
51-
{
52-
case Direction::Up:
53-
stepUp();
54-
break;
55-
case Direction::Down:
56-
stepDown();
57-
break;
58-
case Direction::Left:
59-
stepLeft();
60-
break;
61-
case Direction::Right:
62-
stepRight();
63-
break;
64-
}
65-
}
66-
67-
constexpr void stepBack() noexcept {
68-
switch (m_direction)
69-
{
70-
case Direction::Up:
71-
stepDown();
72-
break;
73-
case Direction::Left:
74-
stepRight();
75-
break;
76-
case Direction::Down:
77-
stepUp();
78-
break;
79-
case Direction::Right:
80-
stepLeft();
81-
break;
82-
}
83-
}
84-
85-
constexpr void turnRight() noexcept {
86-
constexpr auto sentinelInt = static_cast<int>(Direction::Sentinel);
87-
m_direction = static_cast<Direction>((static_cast<int>(m_direction) + 1) % sentinelInt);
88-
}
89-
90-
private:
91-
Direction m_direction{Direction::Up};
92-
int m_x{}, m_y{};
93-
};
9+
using Graph = std::vector<std::string>;
9410

9511

9612
std::tuple<Cursor::Direction, int, int> findInitialPosition(const Graph& graph)

src/day8.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#include "common_headers.hpp"
2-
#include "Point.hpp"
2+
#include "Position.hpp"
33
#include "utils/input_parser.hpp"
44

55

0 commit comments

Comments
 (0)