Skip to content

Commit f93f477

Browse files
blackteabt
andauthored
day7 compile time evaluation
* github: added token * github: updated secrets * disable some targets * Disable some targets * Fix day1 build * Added cstdint * day4: fix build * day14: fix build * day7: Added tuggle to enable compile time evaluation --------- Co-authored-by: bt <bt@gh.com>
1 parent b204aef commit f93f477

File tree

12 files changed

+302
-82
lines changed

12 files changed

+302
-82
lines changed

.github/workflows/cmake-single-platform.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ jobs:
2222
steps:
2323
- uses: actions/checkout@v4
2424
with:
25+
token: ${{ secrets.DATA_PAT }}
2526
submodules: recursive
2627

2728
- name: Configure CMake

CMakeLists.txt

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
cmake_minimum_required(VERSION 3.20)
22
project(advent2024 LANGUAGES CXX)
33

4+
option(DAY7_CONSTEXPR "Enables computing solution at compile-time" OFF)
5+
46
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
57
add_compile_options(-Wall -Wextra -Wpedantic -O2)
68

@@ -20,6 +22,9 @@ add_challenge(day5)
2022
### Day 7
2123
add_challenge(day7)
2224
target_compile_options(day7 PRIVATE -fconstexpr-ops-limit=3355443200)
25+
if(DAY7_CONSTEXPR)
26+
target_compile_options(day7 PRIVATE -DDAY7_CONSTEXPR)
27+
endif()
2328

2429
# Read the content of the input file
2530
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/data/2024/day7.txt FILE_CONTENT)
@@ -32,16 +37,16 @@ file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/data/2024/day7_constexpr.txt ${FILE_CONTE
3237

3338

3439
add_challenge(day8)
35-
add_challenge(day9)
40+
# add_challenge(day9)
3641
add_challenge(day10)
3742
add_challenge(day11)
3843
add_challenge(day12)
3944
add_challenge(day13)
4045
add_challenge(day14)
41-
add_challenge(day15)
42-
add_challenge(day16)
43-
add_challenge(day17)
44-
add_challenge(day18)
46+
# add_challenge(day15)
47+
# add_challenge(day16)
48+
# add_challenge(day17)
49+
# add_challenge(day18)
4550
add_challenge(day19)
4651
add_challenge(day24)
4752
add_challenge(day25)

include/common_headers.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
#include "utils/input_parser.hpp"
33

44
#include <algorithm>
5+
#include <array>
6+
#include <cstdint>
57
#include <iostream>
68
#include <fstream>
79
#include <charconv>
810
#include <vector>
11+
#include <string>
912
#include <stdexcept>
1013
#include <numeric>
1114
#include <unordered_map>

include/utils/numeric_algorithm.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#pragma once
22

3-
#include <stdint.h>
3+
#include <cstdint>
44
#include <cmath>
55

66
[[nodiscard]] constexpr size_t numOfDigits(uint64_t num) noexcept {

src/day1.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <algorithm>
2+
#include <cstdint>
23
#include <iostream>
34
#include <fstream>
45
#include <vector>

src/day11.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "utils/numeric_algorithm.hpp"
33

44
#include <cmath>
5+
#include <cstdint>
56
#include <sstream>
67

78

src/day13.cpp

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
#include "common_headers.hpp"
2+
#include <cmath>
3+
#include <regex>
4+
5+
void printHelp()
6+
{
7+
std::cerr << "\nUsage:\n"
8+
<< "The program requires 2 args: (part1, part2) and the path to the file."
9+
<< "\nFor example, ./day7 part1 data/day7.txt";
10+
}
11+
12+
using Matrix = std::vector<std::vector<long double>>;
13+
using Vector = std::vector<long double>;
14+
15+
struct EquationParams final
16+
{
17+
Matrix coords;
18+
Vector result;
19+
20+
void appendXY(std::pair<int64_t, int64_t> xy) {
21+
coords.resize(2);
22+
coords[0].push_back(xy.first);
23+
coords[1].push_back(xy.second);
24+
}
25+
26+
void setResult(std::pair<int64_t, int64_t> resultXY) {
27+
result.push_back(resultXY.first);
28+
result.push_back(resultXY.second);
29+
}
30+
};
31+
32+
33+
void gaussianElimination(Matrix& A, Vector& b) {
34+
int n = A.size();
35+
36+
for (int i = 0; i < n; ++i) {
37+
// Partial pivoting
38+
int maxRow = i;
39+
for (int k = i + 1; k < n; ++k) {
40+
if (std::abs(A[k][i]) > std::abs(A[maxRow][i])) {
41+
maxRow = k;
42+
}
43+
}
44+
45+
// Swap rows in A and b
46+
std::swap(A[i], A[maxRow]);
47+
std::swap(b[i], b[maxRow]);
48+
49+
// Check for singularity
50+
if (std::abs(A[i][i]) < 1e-10) {
51+
throw std::runtime_error("Matrix is singular or nearly singular");
52+
}
53+
54+
// Eliminate column i below the pivot
55+
for (int k = i + 1; k < n; ++k) {
56+
double factor = A[k][i] / A[i][i];
57+
for (int j = i; j < n; ++j) {
58+
A[k][j] -= factor * A[i][j];
59+
}
60+
b[k] -= factor * b[i];
61+
}
62+
}
63+
}
64+
65+
Vector backSubstitution(const Matrix& A, const Vector& b) {
66+
int n = A.size();
67+
Vector x(n);
68+
69+
for (int i = n - 1; i >= 0; --i) {
70+
x[i] = b[i];
71+
for (int j = i + 1; j < n; ++j) {
72+
x[i] -= A[i][j] * x[j];
73+
}
74+
x[i] /= A[i][i];
75+
}
76+
77+
return x;
78+
}
79+
80+
Vector solveLinearSystem(Matrix A, Vector b) {
81+
gaussianElimination(A, b);
82+
return backSubstitution(A, b);
83+
}
84+
85+
bool checkResultCorrectness(const Vector& result, double upperBoundValue) {
86+
for(auto r : result) {
87+
if(!std::isfinite(r) || std::abs(std::trunc(std::round(r)) - r) > 0.0003 || r > upperBoundValue) {
88+
if(r > 100) {
89+
}
90+
std::cerr << "\nsolution incorrect: " << r ;
91+
return false;
92+
}
93+
}
94+
return true;
95+
}
96+
97+
size_t solveFirstPart(const std::vector<EquationParams>& equationParams) {
98+
constexpr size_t costButtonA{3};
99+
constexpr size_t costButtonB{1};
100+
size_t tokens{};
101+
102+
for(const auto& equation : equationParams) {
103+
Vector result = solveLinearSystem(equation.coords, equation.result);
104+
if(checkResultCorrectness(result, 100)) {
105+
tokens += static_cast<size_t>(std::round(result.at(0))) * costButtonA + static_cast<size_t>(std::round(result.at(1)) * costButtonB);
106+
}
107+
}
108+
return tokens;
109+
}
110+
111+
size_t solveSecondPart(const std::vector<EquationParams>& equationParams) {
112+
constexpr size_t costButtonA{3};
113+
constexpr size_t costButtonB{1};
114+
size_t tokens{};
115+
116+
for(const auto& equation : equationParams) {
117+
Vector result = solveLinearSystem(equation.coords, equation.result);
118+
if(checkResultCorrectness(result, 10000000000000)) {
119+
tokens += static_cast<size_t>(std::round(result.at(0))) * costButtonA + static_cast<size_t>(std::round(result.at(1)) * costButtonB);
120+
}
121+
}
122+
return tokens;
123+
}
124+
125+
126+
[[nodiscard]] std::pair<int64_t, int64_t> parseXY(const std::string& input) {
127+
std::pair<int64_t, int64_t> values{};
128+
129+
// Regular expression to match the input pattern
130+
std::regex pattern(R"((\w+ \w+|\w+): X[+=](\-?\d+), Y[+=](\-?\d+))");
131+
std::smatch matches;
132+
133+
std::string::const_iterator searchStart(input.cbegin());
134+
std::regex_search(searchStart, input.cend(), matches, pattern);
135+
// std::cerr << "\nx " << matches[2] << " y " << matches[3];
136+
return std::pair{std::stoll(matches[2]), std::stoll(matches[3])};
137+
}
138+
139+
[[nodiscard]] EquationParams parse(const std::string& buttonA, const std::string& buttonB, const std::string& result) {
140+
EquationParams params;
141+
params.appendXY(parseXY(buttonA));
142+
params.appendXY(parseXY(buttonB));
143+
params.setResult(parseXY(result));
144+
return params;
145+
}
146+
147+
[[nodiscard]] std::vector<EquationParams> parseEquationParams(const std::vector<std::string>& inputLines) {
148+
std::vector<EquationParams> equationParams;
149+
for(size_t i = 0; i + 3 <= inputLines.size();) {
150+
if(inputLines[i].empty()) {
151+
++i;
152+
}
153+
else {
154+
equationParams.emplace_back(parse(inputLines[i], inputLines[i + 1], inputLines[i + 2]));
155+
i += 3;
156+
}
157+
}
158+
return equationParams;
159+
}
160+
161+
int main(int argc, char* argv[])
162+
{
163+
if(argc != 3) {
164+
printHelp();
165+
return 1;
166+
}
167+
168+
std::string_view task{argv[1]};
169+
if(task != "part1" && task != "part2") {
170+
std::cerr << "\nfirst arg can be either `part1` or `part2`\n";
171+
printHelp();
172+
return 1;
173+
}
174+
175+
std::vector<std::string> inputVec;
176+
readInput(argv[2], std::back_inserter(inputVec));
177+
std::vector<EquationParams> equationParams = parseEquationParams(inputVec);
178+
179+
180+
if(task == "part1") {
181+
std::cout << solveFirstPart(equationParams);
182+
}
183+
else {
184+
for(auto& param : equationParams) {
185+
param.result[0] += 10000000000000;
186+
param.result[1] += 10000000000000;
187+
}
188+
std::cout << solveSecondPart(equationParams);
189+
}
190+
191+
return 0;
192+
}

src/day1_part2.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <algorithm>
2+
#include <cstdint>
23
#include <iostream>
34
#include <fstream>
45
#include <unordered_map>

src/day2_part1.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#include <algorithm>
2+
#include <iostream>
3+
#include <fstream>
4+
#include <charconv>
5+
#include <vector>
6+
#include <stdexcept>
7+
8+
namespace {
9+
void parseLevels(const std::string& report, std::vector<int>& out)
10+
{
11+
if(report.empty()) return;
12+
13+
const char *begin = &report[0];
14+
const char * const end = &report[report.size()];
15+
std::from_chars_result result{};
16+
int val{};
17+
while(begin != end) {
18+
result = std::from_chars(begin, end, val);
19+
if(result.ec != std::errc()) {
20+
std::cerr << "\nreport: " << report;
21+
throw std::logic_error{"Invalid report input string"};
22+
}
23+
begin = std::min(result.ptr + 1, end);
24+
out.push_back(val);
25+
}
26+
}
27+
28+
[[nodiscard]] constexpr bool isLevelsSafe(int largelLevel, int smallerLevel) noexcept
29+
{
30+
const auto diff{largelLevel - smallerLevel};
31+
return 1 <= diff && diff <= 3;
32+
}
33+
34+
35+
[[nodiscard]] bool isAscendingSafe(const std::vector<int>& levels) noexcept
36+
{
37+
return std::adjacent_find(levels.begin(), levels.end(), [](int smallerLevel, int largerLevel) {
38+
return !isLevelsSafe(largerLevel, smallerLevel);
39+
}) == levels.end();
40+
}
41+
42+
[[nodiscard]] bool isDescendingSafe(const std::vector<int>& levels) noexcept
43+
{
44+
return std::adjacent_find(levels.rbegin(), levels.rend(), [](int smallerLevel, int largerLevel) {
45+
return !isLevelsSafe(largerLevel, smallerLevel);
46+
}) == levels.rend();
47+
}
48+
49+
[[nodiscard]] bool isSafe(const std::vector<int>& levels) noexcept
50+
{
51+
if(levels.front() < levels.back()) {
52+
return isAscendingSafe(levels);
53+
}
54+
return isDescendingSafe(levels);
55+
}
56+
} //< anonymous namespace
57+
58+
int main(int argc, char *argv[]) {
59+
if(argc != 2) {
60+
std::cerr << "\nUsage:\n"
61+
<< "The program requires the path to the file.";
62+
return 1;
63+
}
64+
65+
std::ifstream ifile(argv[1]);
66+
if(!ifile) {
67+
std::cerr << "\nFile cannot be open";
68+
return 1;
69+
}
70+
71+
size_t count{};
72+
std::string report;
73+
std::vector<int> levels;
74+
while(std::getline(ifile, report)) {
75+
// std::cerr << "\nline " << report;
76+
levels.clear();
77+
parseLevels(report, levels);
78+
count += isSafe(levels);
79+
}
80+
std::cout << count;
81+
82+
return 0;
83+
}

src/day4.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#include "common_headers.hpp"
22

3+
#include <array>
4+
5+
36
/*
47
Part 1.
58
The task is to count the word `XMAS` horizontally, vertically, diagonally.

0 commit comments

Comments
 (0)