1
+ #pragma once
2
+
3
+ #include < algorithm>
4
+ #include < regex>
5
+ #include < string>
6
+ #include < string_view>
7
+ #include < unordered_map>
8
+ #include < vector>
9
+
10
+ namespace aoc ::day_19 {
11
+
12
+ // / @brief State object for pattern matching operations containing caches
13
+ struct pattern_matcher_state {
14
+ std::unordered_map<std::string_view, bool > m_match_cache; // /< Cache for match results
15
+ std::unordered_map<std::string_view, size_t > m_count_cache; // /< Cache for count results
16
+ };
17
+
18
+ class count_processing_strategy ;
19
+ class match_processing_strategy ;
20
+
21
+ // / @brief Class for matching patterns against designs and counting possible combinations
22
+ class pattern_matcher {
23
+ friend class count_processing_strategy ;
24
+ friend class match_processing_strategy ;
25
+
26
+ public:
27
+ // / @brief Constructs a pattern matcher with given patterns
28
+ // / @param patterns Vector of pattern strings to match against
29
+ explicit pattern_matcher (std::vector<std::string> patterns);
30
+
31
+ // / @brief Checks if a design can be constructed using the patterns
32
+ // / @param design The design string to check
33
+ // / @return True if the design can be constructed, false otherwise
34
+ [[nodiscard]] bool can_construct (std::string_view design);
35
+
36
+ // / @brief Counts unique ways to construct a design using the patterns
37
+ // / @param design The design string to analyze
38
+ // / @return Number of unique ways to construct the design
39
+ [[nodiscard]] size_t count_unique_ways_to_construct (std::string_view design);
40
+
41
+ private:
42
+ static constexpr size_t MAX_RECURSION_DEPTH = 100 ; // /< Maximum recursion depth to prevent stack overflow
43
+ std::vector<std::regex> m_patterns; // /< Compiled regex patterns
44
+
45
+ // / @brief Template method for processing patterns with different strategies
46
+ // / @tparam Func Strategy type for processing
47
+ // / @param remaining_design Remaining design to process
48
+ // / @param depth Current recursion depth
49
+ // / @param processing_strategy Strategy object for processing
50
+ // / @param state Current matcher state
51
+ // / @return Result of processing based on strategy type
52
+ template <typename Func>
53
+ [[nodiscard]] auto process_patterns (std::string_view remaining_design, size_t depth, Func && processing_strategy,
54
+ pattern_matcher_state & state) {
55
+ if (depth >= MAX_RECURSION_DEPTH) {
56
+ return processing_strategy.handle_max_depth ();
57
+ }
58
+ if (remaining_design.empty ()) {
59
+ return processing_strategy.handle_empty ();
60
+ }
61
+
62
+ if (auto cached = processing_strategy.check_cache (remaining_design, state)) {
63
+ return *cached;
64
+ }
65
+
66
+ auto result = processing_strategy.initial_value ();
67
+ for (auto const & pattern : m_patterns) {
68
+ std::match_results<std::string_view::const_iterator> match;
69
+ if (std::regex_search (remaining_design.begin (), remaining_design.end (), match, pattern,
70
+ std::regex_constants::match_continuous)) {
71
+ result = processing_strategy.process_match (remaining_design.substr (match.length ()), depth + 1 , result,
72
+ state);
73
+ if (processing_strategy.should_break (result)) {
74
+ break ;
75
+ }
76
+ }
77
+ }
78
+
79
+ processing_strategy.update_cache (remaining_design, result, state);
80
+ return result;
81
+ }
82
+
83
+ // / @brief Recursive counting implementation
84
+ [[nodiscard]] size_t count_recursive (std::string_view remaining_design, size_t depth,
85
+ pattern_matcher_state & state);
86
+
87
+ // / @brief Recursive matching implementation
88
+ [[nodiscard]] bool match_recursive (std::string_view remaining_design, size_t depth, pattern_matcher_state & state);
89
+ };
90
+
91
+ } // namespace aoc::day_19
0 commit comments