Skip to content

Commit 2719a3a

Browse files
committed
Completed Day 3
1 parent 85c5665 commit 2719a3a

File tree

8 files changed

+172
-16
lines changed

8 files changed

+172
-16
lines changed

.github/workflows/build_test.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,5 @@ jobs:
3636
run: ./build/solutions/day_1 solutions/data/day_1.txt
3737
- name: Run Day 2 Solution
3838
run: ./build/solutions/day_2 solutions/data/day_2.txt
39+
- name: Run Day 3 Solution
40+
run: ./build/solutions/day_3 solutions/data/day_3.txt

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ The solutions have been created in the C++ programming language as a library.
77
| | ||||||
88
|-|-|-|-|-|-|-|
99
||1|2|3|4|5|6|
10-
||:x: | ||| | |
10+
||:x: | |:x:|| | |
1111
|7|8|9|10|11|12|13|
1212
| | | | | | | | |
1313
|14|15|16|17|18|19|20|

include/advent_of_code/day_3.hxx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
#pragma once
2-
3-
#include "spdlog/spdlog.h"
4-
#include <sstream>
52
#include <vector>
63
#include <regex>
4+
#include <filesystem>
5+
#include <fstream>
6+
#include <numeric>
7+
#include <functional>
8+
#include <stdexcept>
9+
#include <optional>
10+
#include <string>
11+
12+
#include "spdlog/spdlog.h"
713

814
namespace AdventOfCode24::Day3 {
9-
std::vector<std::pair<int, int>> parse_line(std::istringstream& line);
15+
typedef std::pair<std::vector<int>, std::vector<int>> logic_set;
16+
bool use_calculation(int operation_index, logic_set logic_indexes);
17+
logic_set get_logic_indexes(const std::string& line);
18+
std::vector<std::pair<int, int>> parse_line(const std::string& line, bool logic_enabled, bool& do_state);
19+
std::vector<int> calculate_file_lines(const std::filesystem::path& input_file, bool logic_enabled);
1020
};

solutions/day_3.cxx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#include <filesystem>
2+
#include <string>
3+
#include "spdlog/spdlog.h"
4+
5+
#include "advent_of_code/day_3.hxx"
6+
7+
using namespace AdventOfCode24::Day3;
8+
9+
int main(int argc, char** argv) {
10+
if(argc != 2) {
11+
spdlog::error("Expected input data file!");
12+
return 1;
13+
}
14+
15+
spdlog::set_level(spdlog::level::debug);
16+
17+
const std::filesystem::path input_file{argv[1]};
18+
const std::vector<int> line_totals{calculate_file_lines(input_file, false)};
19+
const std::vector<int> line_totals_w_logic{calculate_file_lines(input_file, true)};
20+
const int overall_total = std::accumulate(line_totals.begin(), line_totals.end(), 0);
21+
const int overall_total_w_logic = std::accumulate(line_totals_w_logic.begin(), line_totals_w_logic.end(), 0);
22+
23+
spdlog::info("For file '" + input_file.string() + "' the program returned " + std::to_string(overall_total));
24+
spdlog::info("With logic statements enabled, this changes to " + std::to_string(overall_total_w_logic));
25+
26+
return 0;
27+
}

src/day_3.cxx

Lines changed: 88 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,83 @@
11
#include "advent_of_code/day_3.hxx"
2-
#include "spdlog/spdlog.h"
3-
#include <regex>
4-
#include <stdexcept>
2+
#include <algorithm>
3+
#include <iterator>
54
#include <string>
65

76
namespace AdventOfCode24::Day3 {
8-
std::vector<std::pair<int, int>> parse_line(std::istringstream& line) {
9-
std::vector<std::pair<int, int>> operations;
7+
bool use_calculation(int operation_index, logic_set logic_indexes, const bool& current_state) {
8+
auto last_do_before_val = std::find_if(
9+
logic_indexes.first.rbegin(),
10+
logic_indexes.first.rend(),
11+
[operation_index](int value){return value < operation_index;}
12+
);
13+
14+
auto last_dont_before_val = std::find_if(
15+
logic_indexes.second.rbegin(),
16+
logic_indexes.second.rend(),
17+
[operation_index](int value){return value < operation_index;}
18+
);
1019

11-
const std::string line_str{line.str()};
20+
// If we have not yet encountered any logic statements enable by default
21+
if(last_do_before_val == logic_indexes.first.rend() && last_dont_before_val == logic_indexes.second.rend()) return current_state;
22+
23+
return (*last_do_before_val) > (*last_dont_before_val);
24+
}
25+
logic_set get_logic_indexes(const std::string& line) {
26+
const std::regex find_dos("do\\(\\)");
27+
const std::regex find_donts("don't\\(\\)");
28+
29+
logic_set logic_indexes;
30+
31+
auto dos_begin{std::sregex_iterator(line.begin(), line.end(), find_dos)};
32+
auto dos_end {std::sregex_iterator()};
33+
auto donts_begin{std::sregex_iterator(line.begin(), line.end(), find_donts)};
34+
auto donts_end {std::sregex_iterator()};
35+
36+
for(std::sregex_iterator iter{dos_begin}; iter != dos_end; ++iter) {
37+
const std::smatch do_match{*iter};
38+
const size_t index = std::distance(line.begin(), line.begin() + do_match.position());
39+
logic_indexes.first.push_back(static_cast<int>(index));
40+
}
41+
42+
for(std::sregex_iterator iter{donts_begin}; iter != donts_end; ++iter) {
43+
const std::smatch dont_match{*iter};
44+
const size_t index = std::distance(line.begin(), line.begin() + dont_match.position());
45+
logic_indexes.second.push_back(static_cast<int>(index));
46+
}
47+
48+
return logic_indexes;
49+
}
50+
51+
std::vector<std::pair<int, int>> parse_line(const std::string& line, bool logic_enabled, bool& do_state) {
52+
std::vector<std::pair<int, int>> operations;
1253

1354
const std::regex find_valid_mul_statements{"mul\\(-?\\d+,-?\\d+\\)"};
1455
const std::regex find_numbers{"-?\\d+"};
1556

16-
auto results_begin{std::sregex_iterator(line_str.begin(), line_str.end(), find_valid_mul_statements)};
57+
auto results_begin{std::sregex_iterator(line.begin(), line.end(), find_valid_mul_statements)};
1758
auto results_end {std::sregex_iterator()};
1859

60+
std::optional<std::pair<std::vector<int>, std::vector<int>>> logic_indexes = {};
61+
62+
if(logic_enabled) logic_indexes = get_logic_indexes(line);
63+
1964
for(std::sregex_iterator iter{results_begin}; iter != results_end; ++iter) {
2065
const std::smatch match{*iter};
2166
const std::string match_str{match.str()};
67+
bool calculation_active{true};
2268

2369
auto numbers_begin{std::sregex_iterator(match_str.begin(), match_str.end(), find_numbers)};
2470
auto numbers_end {std::sregex_iterator()};
2571

2672
std::pair<int, int> arguments{-1000, -1000};
73+
const size_t match_position = std::distance(line.begin(), line.begin() + match.position());
2774

2875
for(std::sregex_iterator n_iter{numbers_begin}; n_iter != numbers_end; ++n_iter) {
2976
const std::smatch n_match{*n_iter};
3077
int n_match_int{0};
3178

3279
try {
33-
n_match_int = std::stoi(match.str());
80+
n_match_int = std::stoi(n_match.str());
3481
} catch(std::invalid_argument& e) {
3582
spdlog::error("Could not parse " + n_match.str());
3683
return operations;
@@ -40,8 +87,40 @@ namespace AdventOfCode24::Day3 {
4087
else arguments.second = n_match_int;
4188
}
4289

43-
operations.push_back(arguments);
90+
bool state_result{do_state};
91+
92+
if(logic_enabled) state_result = use_calculation(match_position, logic_indexes.value(), do_state);
93+
94+
if(!logic_enabled || state_result) operations.push_back(arguments);
95+
96+
// Update global state with latest state result
97+
do_state = state_result;
4498
}
4599
return operations;
46100
}
101+
102+
std::vector<int> calculate_file_lines(const std::filesystem::path& input_file, bool logic_enabled) {
103+
std::vector<int> calculation_results;
104+
105+
std::ifstream read_in(input_file, std::ios::in);
106+
std::string line;
107+
bool do_state{true};
108+
109+
while (std::getline(read_in, line)) {
110+
const std::vector<std::pair<int, int>> line_calculations{parse_line(line, logic_enabled, do_state)};
111+
112+
const int line_total = std::accumulate(
113+
line_calculations.begin(),
114+
line_calculations.end(),
115+
0,
116+
[](int total, std::pair<int, int> couplet){
117+
spdlog::debug("\t" + std::to_string(couplet.first) + " * " + std::to_string(couplet.second));
118+
return total + (couplet.first * couplet.second);
119+
}
120+
);
121+
calculation_results.push_back(line_total);
122+
}
123+
124+
return calculation_results;
125+
}
47126
};

tests/data/day_3_2.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))

tests/data/day_3_3.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
do(asd"kj*£"!)mul(1,2)don't()(uhj£3Q"Emul(3,4)
2+
mul(3,4)mul(do()(3jmul(3,5)3

tests/test_day_3.cxx

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,52 @@
66
#include <sstream>
77
#include <utility>
88
#include <vector>
9+
#include <numeric>
910

1011
#ifndef ADVENT_OF_CODE_DATA
1112
#error "ADVENT_OF_CODE_DATA is not defined!"
1213
#endif
1314

1415
TEST(TestAOC, TestDay3pt1_line_parse) {
15-
std::istringstream sstr(std::string("Gmul(4,5)L3£9mul(34,)&3yMul(3,4)?"), std::ios::in);
16-
const std::vector<std::pair<int,int>> parsed{AdventOfCode24::Day3::parse_line(sstr)};
16+
const std::string line("Gmul(4,5)L3£9mul(34,)&3yMul(3,4)?");
17+
bool do_state{true};
18+
const std::vector<std::pair<int,int>> parsed{AdventOfCode24::Day3::parse_line(line, false, do_state)};
1719

1820
ASSERT_EQ(parsed.size(), 1);
1921

2022
ASSERT_EQ(parsed[0].first, 4);
2123
ASSERT_EQ(parsed[0].second, 5);
24+
}
25+
26+
TEST(TestAOC, TestDay3pt1) {
27+
spdlog::set_level(spdlog::level::debug);
28+
const std::filesystem::path input_file = std::filesystem::path(ADVENT_OF_CODE_DATA) / "day_3_1.txt";
29+
const std::vector<int> line_totals{AdventOfCode24::Day3::calculate_file_lines(input_file, false)};
30+
31+
const int overall_total = std::accumulate(line_totals.begin(), line_totals.end(), 0);
32+
33+
ASSERT_EQ(line_totals.size(), 1);
34+
ASSERT_EQ(overall_total, 161);
35+
}
36+
37+
TEST(TestAOC, TestDay3pt2) {
38+
spdlog::set_level(spdlog::level::debug);
39+
const std::filesystem::path input_file = std::filesystem::path(ADVENT_OF_CODE_DATA) / "day_3_2.txt";
40+
const std::vector<int> line_totals{AdventOfCode24::Day3::calculate_file_lines(input_file, true)};
41+
42+
const int overall_total = std::accumulate(line_totals.begin(), line_totals.end(), 0);
43+
44+
ASSERT_EQ(line_totals.size(), 1);
45+
ASSERT_EQ(overall_total, 48);
46+
}
47+
48+
TEST(TestAOC, TestDay3pt2_scenario_1) {
49+
spdlog::set_level(spdlog::level::debug);
50+
const std::filesystem::path input_file = std::filesystem::path(ADVENT_OF_CODE_DATA) / "day_3_3.txt";
51+
const std::vector<int> line_totals{AdventOfCode24::Day3::calculate_file_lines(input_file, true)};
52+
53+
const int overall_total = std::accumulate(line_totals.begin(), line_totals.end(), 0);
54+
55+
ASSERT_EQ(line_totals.size(), 2);
56+
ASSERT_EQ(overall_total, 17);
2257
}

0 commit comments

Comments
 (0)