├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md └── advent_of_code ├── CMakeLists.txt ├── advent ├── advent_assert.h ├── advent_headers.h ├── advent_logger.h ├── advent_of_code.h ├── advent_setup.h ├── advent_solutions.h ├── advent_test_inputs.h ├── advent_testcase_setup.h ├── advent_types.h └── advent_utils.h ├── advent1 ├── advent1.cpp ├── advent1.h └── advent1.txt ├── advent10 ├── advent10.cpp ├── advent10.h └── advent10.txt ├── advent11 ├── advent11.cpp ├── advent11.h └── advent11.txt ├── advent12 ├── advent12.cpp ├── advent12.h └── advent12.txt ├── advent13 ├── advent13.cpp ├── advent13.h └── advent13.txt ├── advent14 ├── advent14.cpp ├── advent14.h └── advent14.txt ├── advent15 ├── advent15.cpp ├── advent15.h └── advent15.txt ├── advent16 ├── advent16.cpp ├── advent16.h └── advent16.txt ├── advent17 ├── advent17.cpp ├── advent17.h └── advent17.txt ├── advent18 ├── advent18.cpp ├── advent18.h └── advent18.txt ├── advent19 ├── advent19.cpp ├── advent19.h ├── advent19.txt └── testcase_a.txt ├── advent2 ├── advent2.cpp ├── advent2.h └── advent2.txt ├── advent20 ├── advent20.cpp ├── advent20.h └── advent20.txt ├── advent21 ├── advent21.cpp ├── advent21.h └── advent21.txt ├── advent22 ├── advent22.cpp ├── advent22.h └── advent22.txt ├── advent23 ├── advent23.cpp ├── advent23.h └── advent23.txt ├── advent24 ├── advent24.cpp ├── advent24.h └── advent24.txt ├── advent25 ├── advent25.cpp ├── advent25.h └── advent25.txt ├── advent3 ├── advent3.cpp ├── advent3.h └── advent3.txt ├── advent4 ├── advent4.cpp ├── advent4.h └── advent4.txt ├── advent5 ├── advent5.cpp ├── advent5.h └── advent5.txt ├── advent6 ├── advent6.cpp ├── advent6.h └── advent6.txt ├── advent7 ├── advent7.cpp ├── advent7.h └── advent7.txt ├── advent8 ├── advent8.cpp ├── advent8.h └── advent8.txt ├── advent9 ├── advent9.cpp ├── advent9.h └── advent9.txt ├── main.cpp ├── src ├── advent_of_code_testcases.cpp ├── isqrt.cpp ├── md5.cpp └── parse_utils.cpp ├── templates ├── advent_setup.h.in ├── advent_solutions.h.in ├── advent_template.cpp.in ├── advent_template.h.in ├── advent_template.txt.in └── advent_test_inputs.h.in └── utils ├── Coords.h ├── a_star.h ├── advent_utils.h ├── aoc_utils.natvis ├── binary_find.h ├── bit_ops.h ├── brackets.h ├── combine_maps.h ├── comparisons.h ├── conway_simulation.h ├── coords3d.h ├── coords_iterators.h ├── enums.h ├── erase_remove_if.h ├── grid.h ├── has_duplicates.h ├── index_iterator.h ├── index_iterator2.h ├── int_range.h ├── is_sorted.h ├── isqrt.cpp ├── isqrt.h ├── istream_block_iterator.h ├── istream_line_iterator.h ├── md5.cpp ├── md5.h ├── min_transform.h ├── modular_int.h ├── parse_utils.cpp ├── parse_utils.h ├── position3d.h ├── push_back_unique.h ├── range_contains.h ├── ring_buffer.h ├── shared_lock_guard.h ├── small_vector.h ├── sorted_vector.h ├── span.h ├── sparse_array.h ├── split_string.h ├── string_line_iterator.h ├── swap_remove.h ├── to_value.h ├── transform_if.h └── trim_string.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #Ignore puzzle inputs 2 | *.txt 3 | 4 | # Prerequisites 5 | *.d 6 | 7 | # Compiled Object files 8 | *.slo 9 | *.lo 10 | *.o 11 | *.obj 12 | *.iobj 13 | 14 | # Precompiled Headers 15 | *.gch 16 | *.pch 17 | 18 | # Compiled Dynamic libraries 19 | *.so 20 | *.dylib 21 | *.dll 22 | 23 | # Fortran module files 24 | *.mod 25 | *.smod 26 | 27 | # Compiled Static libraries 28 | *.lai 29 | *.la 30 | *.a 31 | *.lib 32 | 33 | # Executables 34 | *.exe 35 | *.out 36 | *.app 37 | 38 | # Files used by the build but not part of it 39 | *.ipch 40 | *.pdb 41 | *.tlog 42 | *.ipdb 43 | *.db 44 | *.db-* 45 | *.opendb 46 | *.log 47 | *.idb 48 | *.ilk 49 | *.enc 50 | *.recipe 51 | 52 | # Visual studio project files 53 | *.vcxproj 54 | *.vcxproj.* 55 | .vs/* 56 | *.sln 57 | 58 | # Files marked as backup 59 | *.bak 60 | 61 | # For Advent of Code, don't accidentally upload puzzle data. 62 | *.txt 63 | *.vsidx 64 | *.lock 65 | *.i 66 | *.json 67 | 68 | # For CMAKE temporaries 69 | advent_of_code/CMakeFiles/* 70 | advent_of_code/.vs/* 71 | *.cmake 72 | !*/cmakelists.txt 73 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /advent_of_code/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | project(advent2024) 4 | 5 | function(reset_solution TXT DIGIT) 6 | foreach(FILESUFFIX IN ITEMS "h" "cpp" "txt") 7 | set(DAYTXT ${TXT}) 8 | set(DAYDIGIT ${DIGIT}) 9 | set(FROM_FILE "templates/advent_template.${FILESUFFIX}.in") 10 | set(TO_FILE "advent${DAYDIGIT}/advent${DAYDIGIT}.${FILESUFFIX}") 11 | message("Copying ${FROM_FILE} to ${TO_FILE}") 12 | configure_file(${FROM_FILE} ${TO_FILE} @ONLY) 13 | endforeach() 14 | endfunction() 15 | 16 | message("RESET_ALL_SOLUTIONS=${RESET_ALL_SOLUTIONS}") 17 | if(${RESET_ALL_SOLUTIONS}) 18 | message("Resetting all solutions") 19 | reset_solution("one" 1) 20 | reset_solution("two" 2) 21 | reset_solution("three" 3) 22 | reset_solution("four" 4) 23 | reset_solution("five" 5) 24 | reset_solution("six" 6) 25 | reset_solution("seven" 7) 26 | reset_solution("eight" 8) 27 | reset_solution("nine" 9) 28 | reset_solution("ten" 10) 29 | reset_solution("eleven" 11) 30 | reset_solution("twelve" 12) 31 | reset_solution("thirteen" 13) 32 | reset_solution("fourteen" 14) 33 | reset_solution("fifteen" 15) 34 | reset_solution("sixteen" 16) 35 | reset_solution("seventeen" 17) 36 | reset_solution("eighteen" 18) 37 | reset_solution("nineteen" 19) 38 | reset_solution("twenty" 20) 39 | reset_solution("twentyone" 21) 40 | reset_solution("twentytwo" 22) 41 | reset_solution("twentythree" 23) 42 | reset_solution("twentyfour" 24) 43 | reset_solution("twentyfive" 25) 44 | configure_file("templates/advent_setup.h.in" "advent/advent_setup.h") 45 | configure_file("templates/advent_solutions.h.in" "advent/advent_solutions.h") 46 | configure_file("templates/advent_test_inputs.h.in" "advent/advent_test_inputs.h") 47 | endif() 48 | 49 | message("Building...") 50 | 51 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 52 | include_directories(. "./utils") 53 | 54 | set(CMAKE_CXX_STANDARD 20) 55 | set(CMAKE_CXX_STANDARD_REQUIRED True) 56 | 57 | message ("cxx Flags:" ${CMAKE_CXX_FLAGS}) 58 | 59 | set(EXENAME advent2024) 60 | 61 | source_group("framework\\src" FILES "main.cpp") 62 | add_executable(${EXENAME} "main.cpp") 63 | 64 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${EXENAME}) 65 | 66 | set( TEMPLATE_FILES 67 | "templates/advent_template.h.in" 68 | "templates/advent_template.cpp.in" 69 | "templates/advent_template.txt.in" 70 | "templates/advent_setup.h.in" 71 | "templates/advent_solutions.h.in" 72 | "templates/advent_test_inputs.h.in" 73 | ) 74 | 75 | source_group("templates" FILES ${TEMPLATE_FILES}) 76 | target_sources(${EXENAME} PUBLIC ${TEMPLATE_FILES}) 77 | 78 | set( FRAMEWORK_FILES 79 | "advent/advent_assert.h" 80 | "advent/advent_headers.h" 81 | "advent/advent_of_code.h" 82 | "advent/advent_testcase_setup.h" 83 | "advent/advent_types.h" 84 | "advent/advent_utils.h" 85 | ) 86 | 87 | set( FRAMEWORK_SOURCE_FILES "src/advent_of_code_testcases.cpp" ) 88 | 89 | source_group("framework" FILES ${FRAMEWORK_FILES}) 90 | source_group("framework\\src" FILES ${FRAMEWORK_SOURCE_FILES}) 91 | target_sources(${EXENAME} PUBLIC ${FRAMEWORK_FILES} ${FRAMEWORK_SOURCE_FILES}) 92 | 93 | set(TEST_CONFIG_FILES 94 | "advent/advent_setup.h" 95 | "advent/advent_solutions.h" 96 | "advent/advent_test_inputs.h" 97 | ) 98 | 99 | source_group("test_config" FILES ${TEST_CONFIG_FILES}) 100 | target_sources(${EXENAME} PUBLIC ${TEST_CONFIG_FILES}) 101 | 102 | 103 | 104 | set( UTILS_FILES 105 | "utils/a_star.h" 106 | "utils/binary_find.h" 107 | "utils/bit_ops.h" 108 | "utils/brackets.h" 109 | "utils/combine_maps.h" 110 | "utils/comparisons.h" 111 | "utils/conway_simulation.h" 112 | "utils/coords.h" 113 | "utils/coords_iterators.h" 114 | "utils/coords3d.h" 115 | "utils/enums.h" 116 | "utils/erase_remove_if.h" 117 | "utils/grid.h" 118 | "utils/has_duplicates.h" 119 | "utils/index_iterator.h" 120 | "utils/index_iterator2.h" 121 | "utils/int_range.h" 122 | "utils/is_sorted.h" 123 | "utils/isqrt.h" 124 | "utils/istream_block_iterator.h" 125 | "utils/istream_line_iterator.h" 126 | "utils/md5.h" 127 | "utils/modular_int.h" 128 | "utils/parse_utils.h" 129 | "utils/position3d.h" 130 | "utils/push_back_unique.h" 131 | "utils/range_contains.h" 132 | "utils/ring_buffer.h" 133 | "utils/shared_lock_guard.h" 134 | "utils/small_vector.h" 135 | "utils/sorted_vector.h" 136 | "utils/span.h" 137 | "utils/sparse_array.h" 138 | "utils/split_string.h" 139 | "utils/string_line_iterator.h" 140 | "utils/swap_remove.h" 141 | "utils/to_value.h" 142 | "utils/transform_if.h" 143 | "utils/trim_string.h" 144 | ) 145 | 146 | set (UTILS_SOURCE_FILES "utils/aoc_utils.natvis" "utils/isqrt.cpp" "utils/md5.cpp" "utils/parse_utils.cpp") 147 | 148 | source_group("utils" FILES ${UTILS_FILES}) 149 | source_group("utils\\src" FILES ${UTILS_SOURCE_FILES}) 150 | 151 | target_sources(${EXENAME} PUBLIC ${UTILS_FILES} ${UTILS_SOURCE_FILES}) 152 | 153 | # Add extra files as extra parameters 154 | function(add_day day_num) 155 | set(THESE_FILES "advent${day_num}/advent${day_num}.h" "advent${day_num}/advent${day_num}.cpp" "advent${day_num}/advent${day_num}.txt" ${ARGN}) 156 | source_group("advent${day_num}" FILES ${THESE_FILES}) 157 | target_sources(${EXENAME} PUBLIC ${THESE_FILES}) 158 | message("Added day " ${day_num} " files") 159 | endfunction() 160 | 161 | add_day(1) 162 | add_day(2) 163 | add_day(3) 164 | add_day(4) 165 | add_day(5) 166 | add_day(6) 167 | add_day(7) 168 | add_day(8) 169 | add_day(9) 170 | add_day(10) 171 | add_day(11) 172 | add_day(12) 173 | add_day(13) 174 | add_day(14) 175 | add_day(15) 176 | add_day(16) 177 | add_day(17) 178 | add_day(18) 179 | add_day(19) 180 | add_day(20) 181 | add_day(21) 182 | add_day(22) 183 | add_day(23) 184 | add_day(24) 185 | add_day(25) -------------------------------------------------------------------------------- /advent_of_code/advent/advent_assert.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef _MSC_VER 9 | #define InternalAdventPlatformSpecificHint(condition) __assume(condition) 10 | #define InternalAdventPlatformSpecificUnreachable __assume(false) 11 | #else 12 | #define InternalAdventPlatformSpecificHint(condition) do{}while(false) 13 | #define InternalAdventPlatformSpecificUnreachable do{int* x = nullptr; int y = *x; }while(false) 14 | #endif 15 | 16 | #define AdventCheck(test_bool) advent::check_advent_assert(__FILE__,__LINE__,test_bool,#test_bool) 17 | #define AdventCheckMsg(test_bool,...) advent::check_advent_assert_msg(__FILE__,__LINE__,test_bool,#test_bool,__VA_ARGS__) 18 | #define AdventUnreachable() advent::check_advent_assert_msg(__FILE__,__LINE__,false,"Entered unreachable location!"); \ 19 | InternalAdventPlatformSpecificUnreachable 20 | 21 | namespace advent 22 | { 23 | class test_failed 24 | { 25 | std::string m_what; 26 | public: 27 | std::string_view what() const { return m_what; } 28 | explicit test_failed(std::string what_happened) : m_what{ std::move(what_happened) } {} 29 | }; 30 | 31 | namespace 32 | { 33 | inline std::string make_what_happened_str_impl(std::ostringstream& msg) 34 | { 35 | return msg.str(); 36 | } 37 | 38 | template 39 | inline std::string make_what_happened_str_impl(std::ostringstream& msg, const T& first, const Args&...rest) 40 | { 41 | msg << ' ' << first; 42 | return make_what_happened_str_impl(msg, rest...); 43 | } 44 | 45 | template 46 | inline std::string make_what_happened_str(const T& first, const Args& ... args) 47 | { 48 | std::ostringstream msg; 49 | msg << first; 50 | return make_what_happened_str_impl(msg, args...); 51 | } 52 | 53 | template 54 | inline void check_advent_assert_impl( 55 | std::string_view file, 56 | int line_no, 57 | bool check_passes, 58 | std::string_view check_str, 59 | const Args&...msg) 60 | { 61 | #if NDEBUG 62 | InternalAdventPlatformSpecificHint(check_passes); 63 | #endif 64 | if (!check_passes) [[unlikely]] 65 | { 66 | const auto file_break = file.find_last_of("\\/"); 67 | if (file_break < file.size()) 68 | { 69 | file.remove_prefix(file_break + 1); 70 | } 71 | auto what = make_what_happened_str( 72 | file, 73 | '(', 74 | line_no, 75 | "): '", 76 | check_str, 77 | '\'', 78 | msg... 79 | ); 80 | 81 | std::cerr << "\nAdventCheck failed: " << what << '\n'; 82 | test_failed error{ std::move(what) }; 83 | throw error; 84 | } 85 | } 86 | 87 | inline void check_advent_assert(std::string_view file, int line_no, bool check_passes, std::string_view check_str) 88 | { 89 | check_advent_assert_impl(file, line_no, check_passes, check_str); 90 | } 91 | 92 | template 93 | inline void check_advent_assert_msg(std::string_view file, int line_no, bool check_passes, std::string_view check_str, const Args&...args) 94 | { 95 | check_advent_assert_impl(file, line_no, check_passes, check_str, " Msg: ", args...); 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /advent_of_code/advent/advent_headers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent1/advent1.h" 4 | #include "advent2/advent2.h" 5 | #include "advent3/advent3.h" 6 | #include "advent4/advent4.h" 7 | #include "advent5/advent5.h" 8 | #include "advent6/advent6.h" 9 | #include "advent7/advent7.h" 10 | #include "advent8/advent8.h" 11 | #include "advent9/advent9.h" 12 | #include "advent10/advent10.h" 13 | #include "advent11/advent11.h" 14 | #include "advent12/advent12.h" 15 | #include "advent13/advent13.h" 16 | #include "advent14/advent14.h" 17 | #include "advent15/advent15.h" 18 | #include "advent16/advent16.h" 19 | #include "advent17/advent17.h" 20 | #include "advent18/advent18.h" 21 | #include "advent19/advent19.h" 22 | #include "advent20/advent20.h" 23 | #include "advent21/advent21.h" 24 | #include "advent22/advent22.h" 25 | #include "advent23/advent23.h" 26 | #include "advent24/advent24.h" 27 | #include "advent25/advent25.h" -------------------------------------------------------------------------------- /advent_of_code/advent/advent_logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef NDEBUG 4 | #include "threadsafe_ofstream.h" 5 | #include 6 | #endif 7 | #include 8 | 9 | #ifdef NDEBUG 10 | class AdventLogger 11 | { 12 | public: 13 | explicit AdventLogger(const char*) {} 14 | template 15 | AdventLogger& operator<<(T&&) { return *this; } 16 | }; 17 | #else 18 | using AdventLogger = threadsafe_ofstream; 19 | #endif 20 | 21 | static AdventLogger advlog{ "advent_log.txt" }; 22 | #ifndef NDEBUG 23 | namespace 24 | { 25 | std::string_view cut_file_down(std::string_view in) 26 | { 27 | in.remove_prefix(in.find_last_of("/\\")); 28 | return in; 29 | } 30 | } 31 | #define LOG advlog << cut_file_down(__FILE__) << ":" << __LINE__ << ": " 32 | #define ERR advlog << "ERROR: " << __FILE__ ":" << __LINE__ << ": " 33 | #else 34 | #include 35 | #define LOG advlog 36 | #define ERR std::cerr 37 | #endif -------------------------------------------------------------------------------- /advent_of_code/advent/advent_of_code.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | bool verify_all(const std::vector& filters); -------------------------------------------------------------------------------- /advent_of_code/advent/advent_setup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent_testcase_setup.h" 4 | #include "advent_test_inputs.h" 5 | #include "advent_headers.h" 6 | #include "advent_solutions.h" 7 | 8 | static const verification_test tests[] = 9 | { 10 | DAY(one,DAY_01_1_SOLUTION,DAY_01_2_SOLUTION), 11 | DAY(two,DAY_02_1_SOLUTION,DAY_02_2_SOLUTION), 12 | DAY(three,DAY_03_1_SOLUTION,DAY_03_2_SOLUTION), 13 | DAY(four,DAY_04_1_SOLUTION,DAY_04_2_SOLUTION), 14 | DAY(five,DAY_05_1_SOLUTION,DAY_05_2_SOLUTION), 15 | DAY(six,DAY_06_1_SOLUTION,DAY_06_2_SOLUTION), 16 | DAY(seven,DAY_07_1_SOLUTION,DAY_07_2_SOLUTION), 17 | DAY(eight,DAY_08_1_SOLUTION,DAY_08_2_SOLUTION), 18 | DAY(nine,DAY_09_1_SOLUTION,DAY_09_2_SOLUTION), 19 | DAY(ten, DAY_10_1_SOLUTION, DAY_10_2_SOLUTION), 20 | DAY(eleven, DAY_11_1_SOLUTION, DAY_11_2_SOLUTION), 21 | DAY(twelve, DAY_12_1_SOLUTION, DAY_12_2_SOLUTION), 22 | DAY(thirteen, DAY_13_1_SOLUTION, DAY_13_2_SOLUTION), 23 | DAY(fourteen, DAY_14_1_SOLUTION, DAY_14_2_SOLUTION), 24 | DAY(fifteen, DAY_15_1_SOLUTION, DAY_15_2_SOLUTION), 25 | DAY(sixteen, DAY_16_1_SOLUTION, DAY_16_2_SOLUTION), 26 | DAY(seventeen, DAY_17_1_SOLUTION, DAY_17_2_SOLUTION), 27 | DAY(eighteen, DAY_18_1_SOLUTION, DAY_18_2_SOLUTION), 28 | DAY(nineteen, DAY_19_1_SOLUTION, DAY_19_2_SOLUTION), 29 | DAY(twenty, DAY_20_1_SOLUTION, DAY_20_2_SOLUTION), 30 | DAY(twentyone, DAY_21_1_SOLUTION, DAY_21_2_SOLUTION), 31 | DAY(twentytwo, DAY_22_1_SOLUTION, DAY_22_2_SOLUTION), 32 | DAY(twentythree, DAY_23_1_SOLUTION, DAY_23_2_SOLUTION), 33 | DAY(twentyfour, DAY_24_1_SOLUTION, DAY_24_2_SOLUTION), 34 | DAY(twentyfive, DAY_25_1_SOLUTION,"MERRY CHRISTMAS!") 35 | }; 36 | 37 | #undef ARG 38 | #undef TESTCASE 39 | #undef FUNC_NAME 40 | #undef TEST_DECL 41 | #undef DAY 42 | #undef DUMMY 43 | #undef DUMMY_DAY 44 | -------------------------------------------------------------------------------- /advent_of_code/advent/advent_solutions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | Put your solutions for each day in here and DO NOT submit it to source control. 5 | */ 6 | 7 | #define DAY_01_1_SOLUTION dummy 8 | #define DAY_01_2_SOLUTION dummy 9 | #define DAY_02_1_SOLUTION dummy 10 | #define DAY_02_2_SOLUTION dummy 11 | #define DAY_03_1_SOLUTION dummy 12 | #define DAY_03_2_SOLUTION dummy 13 | #define DAY_04_1_SOLUTION dummy 14 | #define DAY_04_2_SOLUTION dummy 15 | #define DAY_05_1_SOLUTION dummy 16 | #define DAY_05_2_SOLUTION dummy 17 | #define DAY_06_1_SOLUTION dummy 18 | #define DAY_06_2_SOLUTION dummy 19 | #define DAY_07_1_SOLUTION dummy 20 | #define DAY_07_2_SOLUTION dummy 21 | #define DAY_08_1_SOLUTION dummy 22 | #define DAY_08_2_SOLUTION dummy 23 | #define DAY_09_1_SOLUTION dummy 24 | #define DAY_09_2_SOLUTION dummy 25 | #define DAY_10_1_SOLUTION dummy 26 | #define DAY_10_2_SOLUTION dummy 27 | #define DAY_11_1_SOLUTION dummy 28 | #define DAY_11_2_SOLUTION dummy 29 | #define DAY_12_1_SOLUTION dummy 30 | #define DAY_12_2_SOLUTION dummy 31 | #define DAY_13_1_SOLUTION dummy 32 | #define DAY_13_2_SOLUTION dummy 33 | #define DAY_14_1_SOLUTION dummy 34 | #define DAY_14_2_SOLUTION dummy 35 | #define DAY_15_1_SOLUTION dummy 36 | #define DAY_15_2_SOLUTION dummy 37 | #define DAY_16_1_SOLUTION dummy 38 | #define DAY_16_2_SOLUTION dummy 39 | #define DAY_17_1_SOLUTION dummy 40 | #define DAY_17_2_SOLUTION dummy 41 | #define DAY_18_1_SOLUTION dummy 42 | #define DAY_18_2_SOLUTION dummy 43 | #define DAY_19_1_SOLUTION dummy 44 | #define DAY_19_2_SOLUTION dummy 45 | #define DAY_20_1_SOLUTION dummy 46 | #define DAY_20_2_SOLUTION dummy 47 | #define DAY_21_1_SOLUTION dummy 48 | #define DAY_21_2_SOLUTION dummy 49 | #define DAY_22_1_SOLUTION dummy 50 | #define DAY_22_2_SOLUTION dummy 51 | #define DAY_23_1_SOLUTION dummy 52 | #define DAY_23_2_SOLUTION dummy 53 | #define DAY_24_1_SOLUTION dummy 54 | #define DAY_24_2_SOLUTION dummy 55 | #define DAY_25_1_SOLUTION dummy 56 | #define DAY_25_2_SOLUTION "Merry Christmas!" 57 | -------------------------------------------------------------------------------- /advent_of_code/advent/advent_test_inputs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace advent 7 | { 8 | namespace combine_inputs_internal 9 | { 10 | inline std::string impl(std::string_view joiner, std::ostringstream& collector) 11 | { 12 | return collector.str(); 13 | } 14 | 15 | template 16 | inline std::string impl(std::string_view joiner, std::ostringstream& collector, std::string_view next_string, StringViews...remaining) 17 | { 18 | collector << joiner << next_string; 19 | return impl(joiner, collector,remaining...); 20 | } 21 | } 22 | 23 | template 24 | inline std::string combine_inputs(std::string_view first_string, StringViews...remaining) 25 | { 26 | std::ostringstream collector; 27 | std::string joiner(NUM_NEWLINES, '\n'); 28 | collector << first_string; 29 | return combine_inputs_internal::impl(joiner, collector, remaining...); 30 | } 31 | } 32 | 33 | /* 34 | 35 | Define inline definitions of test inputs here for use in the testcases. 36 | 37 | For example: 38 | 39 | constexpr const char* TEST_ONE_A = "test1_input"; 40 | 41 | Use can also combine strings together with combine_inputs, for example, which will also add newlinse automatically using the template parameter to decide how many: 42 | 43 | constexpr const char* TEST_ONE_B = "test2"; 44 | static const auto TEST_ONE = advent::combine_inputs<2>(TEST_ONE_A, TEST_ONE_B); 45 | will set TEXT_ONE to "test1_input\n\ntest2" 46 | 47 | */ 48 | -------------------------------------------------------------------------------- /advent_of_code/advent/advent_testcase_setup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using TestFunc = std::function; 10 | using TestFuncWithArg = std::function; 11 | 12 | struct TestExecutable 13 | { 14 | TestFunc func; 15 | ResultType execute() { return func(); } 16 | explicit TestExecutable(TestFunc func_) : func{func_}{} 17 | }; 18 | 19 | struct TestWithArgExecutable 20 | { 21 | TestFuncWithArg func; 22 | std::string arg; 23 | ResultType execute(); 24 | TestWithArgExecutable(TestFuncWithArg func_, std::string arg_) : func(func_) , arg(std::move(arg_)){} 25 | }; 26 | 27 | using Test = std::variant; 28 | 29 | // This describes a test to run. 30 | struct verification_test 31 | { 32 | std::string name; 33 | Test test_func; 34 | std::optional expected_result; 35 | verification_test(std::string name_, TestFunc func) : verification_test{ std::move(name_), func, std::nullopt }{} 36 | verification_test(std::string name_, TestFunc func, std::string result) : verification_test{std::move(name_), func, std::optional{std::move(result)} }{} 37 | verification_test(std::string name_, TestFuncWithArg func, std::string arg) : verification_test{ std::move(name_), func, std::move(arg), std::nullopt } {} 38 | verification_test(std::string name_, TestFuncWithArg func, std::string arg, std::string result) : verification_test{ std::move(name_), func, std::move(arg), std::optional{std::move(result)} } {} 39 | private: 40 | verification_test(std::string n, TestFunc t, std::optional r) : name(std::move(n)),test_func(TestExecutable{t}),expected_result(std::move(r)){} 41 | verification_test(std::string n, TestFuncWithArg t, std::string arg, std::optional r) : name(std::move(n)),test_func(TestWithArgExecutable{t , std::move(arg)}),expected_result(std::move(r)){} 42 | }; 43 | 44 | // A type to use to indicate the result is not known yet. Using this in a verification test 45 | // will run the test and report the result, but will count as neither pass nor failure. 46 | struct Dummy {}; 47 | static constexpr Dummy dummy; 48 | 49 | verification_test make_test(std::string name, TestFunc func, int64_t result); 50 | verification_test make_test(std::string name, TestFunc func, std::string result); 51 | verification_test make_test(std::string name, TestFunc func, Dummy); 52 | 53 | verification_test make_test(std::string name, TestFuncWithArg func, int64_t result, std::string arg); 54 | verification_test make_test(std::string name, TestFuncWithArg func, std::string result, std::string arg); 55 | verification_test make_test(std::string name, TestFuncWithArg func, Dummy, std::string arg); 56 | 57 | #define ARG(func_name) std::string{ #func_name },func_name 58 | #define ARG_WITH_PARAM(func_name,param) std::string{ #func_name "(" #param ")" }, func_name 59 | #define TESTCASE(func_name,expected_result) make_test(ARG(func_name),expected_result) 60 | #define TESTCASE_WITH_ARG(func_name,arg,expected_result) make_test(ARG_WITH_PARAM(func_name,arg),expected_result,arg) 61 | #define FUNC_NAME(day_num,part_num) advent_ ## day_num ## _p ## part_num 62 | #define TEST_DECL(day_num,part_num,expected_result) TESTCASE(FUNC_NAME(day_num,part_num),expected_result) 63 | #define DAY(day_num,part1_result,part2_result) \ 64 | TEST_DECL(day_num,1,part1_result), \ 65 | TEST_DECL(day_num,2,part2_result) -------------------------------------------------------------------------------- /advent_of_code/advent/advent_types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using ResultType = std::variant; 9 | enum class AdventDay 10 | { 11 | one, two 12 | }; 13 | 14 | namespace stdr = std::ranges; 15 | namespace stdv = stdr::views; -------------------------------------------------------------------------------- /advent_of_code/advent/advent_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "advent_assert.h" 10 | 11 | namespace advent 12 | { 13 | inline std::ifstream open_input(const std::string& filename) 14 | { 15 | auto result = std::ifstream{ filename }; 16 | AdventCheck(result.is_open()); 17 | #ifndef NDEBUG 18 | if (std::filesystem::file_size(filename) <= 0) 19 | { 20 | std::cerr << "\nWARNING! File '" << filename << "' is empty."; 21 | } 22 | #endif 23 | return result; 24 | } 25 | 26 | // Opens a file with the name "adventX/adventX.txt" 27 | inline std::ifstream open_puzzle_input(int day) 28 | { 29 | const std::string name = std::format("advent{0}/advent{0}.txt", day); 30 | return open_input(name); 31 | } 32 | 33 | // Open a file with the format "adventX/testcase_Y.txt" 34 | inline std::ifstream open_testcase_input(int day, char id) 35 | { 36 | const std::string name = std::format("advent{0}/testcast_{1}.txt", day, id); 37 | return open_input(name); 38 | } 39 | } -------------------------------------------------------------------------------- /advent_of_code/advent1/advent1.cpp: -------------------------------------------------------------------------------- 1 | #include "advent1.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY1DBG 5 | #define DAY1DBG 1 6 | #else 7 | #define ENABLE_DAY1DBG 1 8 | #ifdef NDEBUG 9 | #define DAY1DBG 0 10 | #else 11 | #define DAY1DBG ENABLE_DAY1DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY1DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY1DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_one_p1() 45 | { 46 | auto input = advent::open_puzzle_input(1); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_one_p2() 51 | { 52 | auto input = advent::open_puzzle_input(1); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY1DBG 57 | #undef ENABLE_DAY1DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent1/advent1.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_one_p1(); 6 | ResultType advent_one_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent1/advent1.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent1/advent1.txt -------------------------------------------------------------------------------- /advent_of_code/advent10/advent10.cpp: -------------------------------------------------------------------------------- 1 | #include "advent10.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY10DBG 5 | #define DAY10DBG 1 6 | #else 7 | #define ENABLE_DAY10DBG 1 8 | #ifdef NDEBUG 9 | #define DAY10DBG 0 10 | #else 11 | #define DAY10DBG ENABLE_DAY10DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY10DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY10DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_ten_p1() 45 | { 46 | auto input = advent::open_puzzle_input(10); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_ten_p2() 51 | { 52 | auto input = advent::open_puzzle_input(10); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY10DBG 57 | #undef ENABLE_DAY10DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent10/advent10.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_ten_p1(); 6 | ResultType advent_ten_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent10/advent10.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent10/advent10.txt -------------------------------------------------------------------------------- /advent_of_code/advent11/advent11.cpp: -------------------------------------------------------------------------------- 1 | #include "advent11.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY11DBG 5 | #define DAY11DBG 1 6 | #else 7 | #define ENABLE_DAY11DBG 1 8 | #ifdef NDEBUG 9 | #define DAY11DBG 0 10 | #else 11 | #define DAY11DBG ENABLE_DAY11DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY11DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY11DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_eleven_p1() 45 | { 46 | auto input = advent::open_puzzle_input(11); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_eleven_p2() 51 | { 52 | auto input = advent::open_puzzle_input(11); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY11DBG 57 | #undef ENABLE_DAY11DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent11/advent11.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_eleven_p1(); 6 | ResultType advent_eleven_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent11/advent11.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent11/advent11.txt -------------------------------------------------------------------------------- /advent_of_code/advent12/advent12.cpp: -------------------------------------------------------------------------------- 1 | #include "advent12.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY12DBG 5 | #define DAY12DBG 1 6 | #else 7 | #define ENABLE_DAY12DBG 1 8 | #ifdef NDEBUG 9 | #define DAY12DBG 0 10 | #else 11 | #define DAY12DBG ENABLE_DAY12DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY12DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY12DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_twelve_p1() 45 | { 46 | auto input = advent::open_puzzle_input(12); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_twelve_p2() 51 | { 52 | auto input = advent::open_puzzle_input(12); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY12DBG 57 | #undef ENABLE_DAY12DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent12/advent12.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_twelve_p1(); 6 | ResultType advent_twelve_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent12/advent12.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent12/advent12.txt -------------------------------------------------------------------------------- /advent_of_code/advent13/advent13.cpp: -------------------------------------------------------------------------------- 1 | #include "advent13.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY13DBG 5 | #define DAY13DBG 1 6 | #else 7 | #define ENABLE_DAY13DBG 1 8 | #ifdef NDEBUG 9 | #define DAY13DBG 0 10 | #else 11 | #define DAY13DBG ENABLE_DAY13DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY13DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY13DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_thirteen_p1() 45 | { 46 | auto input = advent::open_puzzle_input(13); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_thirteen_p2() 51 | { 52 | auto input = advent::open_puzzle_input(13); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY13DBG 57 | #undef ENABLE_DAY13DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent13/advent13.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_thirteen_p1(); 6 | ResultType advent_thirteen_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent13/advent13.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent13/advent13.txt -------------------------------------------------------------------------------- /advent_of_code/advent14/advent14.cpp: -------------------------------------------------------------------------------- 1 | #include "advent14.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY14DBG 5 | #define DAY14DBG 1 6 | #else 7 | #define ENABLE_DAY14DBG 1 8 | #ifdef NDEBUG 9 | #define DAY14DBG 0 10 | #else 11 | #define DAY14DBG ENABLE_DAY14DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY14DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY14DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_fourteen_p1() 45 | { 46 | auto input = advent::open_puzzle_input(14); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_fourteen_p2() 51 | { 52 | auto input = advent::open_puzzle_input(14); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY14DBG 57 | #undef ENABLE_DAY14DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent14/advent14.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_fourteen_p1(); 6 | ResultType advent_fourteen_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent14/advent14.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent14/advent14.txt -------------------------------------------------------------------------------- /advent_of_code/advent15/advent15.cpp: -------------------------------------------------------------------------------- 1 | #include "advent15.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY15DBG 5 | #define DAY15DBG 1 6 | #else 7 | #define ENABLE_DAY15DBG 1 8 | #ifdef NDEBUG 9 | #define DAY15DBG 0 10 | #else 11 | #define DAY15DBG ENABLE_DAY15DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY15DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY15DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_fifteen_p1() 45 | { 46 | auto input = advent::open_puzzle_input(15); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_fifteen_p2() 51 | { 52 | auto input = advent::open_puzzle_input(15); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY15DBG 57 | #undef ENABLE_DAY15DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent15/advent15.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_fifteen_p1(); 6 | ResultType advent_fifteen_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent15/advent15.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent15/advent15.txt -------------------------------------------------------------------------------- /advent_of_code/advent16/advent16.cpp: -------------------------------------------------------------------------------- 1 | #include "advent16.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY16DBG 5 | #define DAY16DBG 1 6 | #else 7 | #define ENABLE_DAY16DBG 1 8 | #ifdef NDEBUG 9 | #define DAY16DBG 0 10 | #else 11 | #define DAY16DBG ENABLE_DAY16DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY16DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY16DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_sixteen_p1() 45 | { 46 | auto input = advent::open_puzzle_input(16); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_sixteen_p2() 51 | { 52 | auto input = advent::open_puzzle_input(16); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY16DBG 57 | #undef ENABLE_DAY16DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent16/advent16.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_sixteen_p1(); 6 | ResultType advent_sixteen_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent16/advent16.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent16/advent16.txt -------------------------------------------------------------------------------- /advent_of_code/advent17/advent17.cpp: -------------------------------------------------------------------------------- 1 | #include "advent17.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY17DBG 5 | #define DAY17DBG 1 6 | #else 7 | #define ENABLE_DAY17DBG 1 8 | #ifdef NDEBUG 9 | #define DAY17DBG 0 10 | #else 11 | #define DAY17DBG ENABLE_DAY17DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY17DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY17DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_seventeen_p1() 45 | { 46 | auto input = advent::open_puzzle_input(17); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_seventeen_p2() 51 | { 52 | auto input = advent::open_puzzle_input(17); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY17DBG 57 | #undef ENABLE_DAY17DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent17/advent17.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_seventeen_p1(); 6 | ResultType advent_seventeen_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent17/advent17.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent17/advent17.txt -------------------------------------------------------------------------------- /advent_of_code/advent18/advent18.cpp: -------------------------------------------------------------------------------- 1 | #include "advent18.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY18DBG 5 | #define DAY18DBG 1 6 | #else 7 | #define ENABLE_DAY18DBG 1 8 | #ifdef NDEBUG 9 | #define DAY18DBG 0 10 | #else 11 | #define DAY18DBG ENABLE_DAY18DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY18DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY18DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_eighteen_p1() 45 | { 46 | auto input = advent::open_puzzle_input(18); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_eighteen_p2() 51 | { 52 | auto input = advent::open_puzzle_input(18); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY18DBG 57 | #undef ENABLE_DAY18DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent18/advent18.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_eighteen_p1(); 6 | ResultType advent_eighteen_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent18/advent18.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent18/advent18.txt -------------------------------------------------------------------------------- /advent_of_code/advent19/advent19.cpp: -------------------------------------------------------------------------------- 1 | #include "advent19.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY19DBG 5 | #define DAY19DBG 1 6 | #else 7 | #define ENABLE_DAY19DBG 1 8 | #ifdef NDEBUG 9 | #define DAY19DBG 0 10 | #else 11 | #define DAY19DBG ENABLE_DAY19DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY19DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY19DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_nineteen_p1() 45 | { 46 | auto input = advent::open_puzzle_input(19); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_nineteen_p2() 51 | { 52 | auto input = advent::open_puzzle_input(19); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY19DBG 57 | #undef ENABLE_DAY19DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent19/advent19.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_nineteen_p1(); 6 | ResultType advent_nineteen_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent19/advent19.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent19/advent19.txt -------------------------------------------------------------------------------- /advent_of_code/advent19/testcase_a.txt: -------------------------------------------------------------------------------- 1 | --- scanner 0 --- 2 | 404,-588,-901 3 | 528,-643,409 4 | -838,591,734 5 | 390,-675,-793 6 | -537,-823,-458 7 | -485,-357,347 8 | -345,-311,381 9 | -661,-816,-575 10 | -876,649,763 11 | -618,-824,-621 12 | 553,345,-567 13 | 474,580,667 14 | -447,-329,318 15 | -584,868,-557 16 | 544,-627,-890 17 | 564,392,-477 18 | 455,729,728 19 | -892,524,684 20 | -689,845,-530 21 | 423,-701,434 22 | 7,-33,-71 23 | 630,319,-379 24 | 443,580,662 25 | -789,900,-551 26 | 459,-707,401 27 | 28 | --- scanner 1 --- 29 | 686,422,578 30 | 605,423,415 31 | 515,917,-361 32 | -336,658,858 33 | 95,138,22 34 | -476,619,847 35 | -340,-569,-846 36 | 567,-361,727 37 | -460,603,-452 38 | 669,-402,600 39 | 729,430,532 40 | -500,-761,534 41 | -322,571,750 42 | -466,-666,-811 43 | -429,-592,574 44 | -355,545,-477 45 | 703,-491,-529 46 | -328,-685,520 47 | 413,935,-424 48 | -391,539,-444 49 | 586,-435,557 50 | -364,-763,-893 51 | 807,-499,-711 52 | 755,-354,-619 53 | 553,889,-390 54 | 55 | --- scanner 2 --- 56 | 649,640,665 57 | 682,-795,504 58 | -784,533,-524 59 | -644,584,-595 60 | -588,-843,648 61 | -30,6,44 62 | -674,560,763 63 | 500,723,-460 64 | 609,671,-379 65 | -555,-800,653 66 | -675,-892,-343 67 | 697,-426,-610 68 | 578,704,681 69 | 493,664,-388 70 | -671,-858,530 71 | -667,343,800 72 | 571,-461,-707 73 | -138,-166,112 74 | -889,563,-600 75 | 646,-828,498 76 | 640,759,510 77 | -630,509,768 78 | -681,-892,-333 79 | 673,-379,-804 80 | -742,-814,-386 81 | 577,-820,562 82 | 83 | --- scanner 3 --- 84 | -589,542,597 85 | 605,-692,669 86 | -500,565,-823 87 | -660,373,557 88 | -458,-679,-417 89 | -488,449,543 90 | -626,468,-788 91 | 338,-750,-386 92 | 528,-832,-391 93 | 562,-778,733 94 | -938,-730,414 95 | 543,643,-506 96 | -524,371,-870 97 | 407,773,750 98 | -104,29,83 99 | 378,-903,-323 100 | -778,-728,485 101 | 426,699,580 102 | -438,-605,-362 103 | -469,-447,-387 104 | 509,732,623 105 | 647,635,-688 106 | -868,-804,481 107 | 614,-800,639 108 | 595,780,-596 109 | 110 | --- scanner 4 --- 111 | 727,592,562 112 | -293,-554,779 113 | 441,611,-461 114 | -714,465,-776 115 | -743,427,-804 116 | -660,-479,-426 117 | 832,-632,460 118 | 927,-485,-438 119 | 408,393,-506 120 | 466,436,-512 121 | 110,16,151 122 | -258,-428,682 123 | -393,719,612 124 | -211,-452,876 125 | 808,-476,-593 126 | -575,615,604 127 | -485,667,467 128 | -680,325,-822 129 | -627,-443,-432 130 | 872,-547,-609 131 | 833,512,582 132 | 807,604,487 133 | 839,-516,451 134 | 891,-625,532 135 | -652,-548,-490 136 | 30,-46,-14 -------------------------------------------------------------------------------- /advent_of_code/advent2/advent2.cpp: -------------------------------------------------------------------------------- 1 | #include "advent2.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY2DBG 5 | #define DAY2DBG 1 6 | #else 7 | #define ENABLE_DAY2DBG 1 8 | #ifdef NDEBUG 9 | #define DAY2DBG 0 10 | #else 11 | #define DAY2DBG ENABLE_DAY2DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY2DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY2DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_two_p1() 45 | { 46 | auto input = advent::open_puzzle_input(2); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_two_p2() 51 | { 52 | auto input = advent::open_puzzle_input(2); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY2DBG 57 | #undef ENABLE_DAY2DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent2/advent2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_two_p1(); 6 | ResultType advent_two_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent2/advent2.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent2/advent2.txt -------------------------------------------------------------------------------- /advent_of_code/advent20/advent20.cpp: -------------------------------------------------------------------------------- 1 | #include "advent20.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY20DBG 5 | #define DAY20DBG 1 6 | #else 7 | #define ENABLE_DAY20DBG 1 8 | #ifdef NDEBUG 9 | #define DAY20DBG 0 10 | #else 11 | #define DAY20DBG ENABLE_DAY20DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY20DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY20DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_twenty_p1() 45 | { 46 | auto input = advent::open_puzzle_input(20); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_twenty_p2() 51 | { 52 | auto input = advent::open_puzzle_input(20); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY20DBG 57 | #undef ENABLE_DAY20DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent20/advent20.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_twenty_p1(); 6 | ResultType advent_twenty_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent20/advent20.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent20/advent20.txt -------------------------------------------------------------------------------- /advent_of_code/advent21/advent21.cpp: -------------------------------------------------------------------------------- 1 | #include "advent21.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY21DBG 5 | #define DAY21DBG 1 6 | #else 7 | #define ENABLE_DAY21DBG 1 8 | #ifdef NDEBUG 9 | #define DAY21DBG 0 10 | #else 11 | #define DAY21DBG ENABLE_DAY21DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY21DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY21DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_twentyone_p1() 45 | { 46 | auto input = advent::open_puzzle_input(21); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_twentyone_p2() 51 | { 52 | auto input = advent::open_puzzle_input(21); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY21DBG 57 | #undef ENABLE_DAY21DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent21/advent21.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_twentyone_p1(); 6 | ResultType advent_twentyone_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent21/advent21.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent21/advent21.txt -------------------------------------------------------------------------------- /advent_of_code/advent22/advent22.cpp: -------------------------------------------------------------------------------- 1 | #include "advent22.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY22DBG 5 | #define DAY22DBG 1 6 | #else 7 | #define ENABLE_DAY22DBG 1 8 | #ifdef NDEBUG 9 | #define DAY22DBG 0 10 | #else 11 | #define DAY22DBG ENABLE_DAY22DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY22DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY22DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_twentytwo_p1() 45 | { 46 | auto input = advent::open_puzzle_input(22); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_twentytwo_p2() 51 | { 52 | auto input = advent::open_puzzle_input(22); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY22DBG 57 | #undef ENABLE_DAY22DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent22/advent22.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_twentytwo_p1(); 6 | ResultType advent_twentytwo_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent22/advent22.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent22/advent22.txt -------------------------------------------------------------------------------- /advent_of_code/advent23/advent23.cpp: -------------------------------------------------------------------------------- 1 | #include "advent23.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY23DBG 5 | #define DAY23DBG 1 6 | #else 7 | #define ENABLE_DAY23DBG 1 8 | #ifdef NDEBUG 9 | #define DAY23DBG 0 10 | #else 11 | #define DAY23DBG ENABLE_DAY23DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY23DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY23DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_twentythree_p1() 45 | { 46 | auto input = advent::open_puzzle_input(23); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_twentythree_p2() 51 | { 52 | auto input = advent::open_puzzle_input(23); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY23DBG 57 | #undef ENABLE_DAY23DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent23/advent23.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_twentythree_p1(); 6 | ResultType advent_twentythree_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent23/advent23.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent23/advent23.txt -------------------------------------------------------------------------------- /advent_of_code/advent24/advent24.cpp: -------------------------------------------------------------------------------- 1 | #include "advent24.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY24DBG 5 | #define DAY24DBG 1 6 | #else 7 | #define ENABLE_DAY24DBG 1 8 | #ifdef NDEBUG 9 | #define DAY24DBG 0 10 | #else 11 | #define DAY24DBG ENABLE_DAY24DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY24DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY24DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_twentyfour_p1() 45 | { 46 | auto input = advent::open_puzzle_input(24); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_twentyfour_p2() 51 | { 52 | auto input = advent::open_puzzle_input(24); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY24DBG 57 | #undef ENABLE_DAY24DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent24/advent24.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_twentyfour_p1(); 6 | ResultType advent_twentyfour_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent24/advent24.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent24/advent24.txt -------------------------------------------------------------------------------- /advent_of_code/advent25/advent25.cpp: -------------------------------------------------------------------------------- 1 | #include "advent25.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY25DBG 5 | #define DAY25DBG 1 6 | #else 7 | #define ENABLE_DAY25DBG 1 8 | #ifdef NDEBUG 9 | #define DAY25DBG 0 10 | #else 11 | #define DAY25DBG ENABLE_DAY25DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY25DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY25DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_twentyfive_p1() 45 | { 46 | auto input = advent::open_puzzle_input(25); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_twentyfive_p2() 51 | { 52 | auto input = advent::open_puzzle_input(25); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY25DBG 57 | #undef ENABLE_DAY25DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent25/advent25.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_twentyfive_p1(); 6 | ResultType advent_twentyfive_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent25/advent25.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent25/advent25.txt -------------------------------------------------------------------------------- /advent_of_code/advent3/advent3.cpp: -------------------------------------------------------------------------------- 1 | #include "advent3.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY3DBG 5 | #define DAY3DBG 1 6 | #else 7 | #define ENABLE_DAY3DBG 1 8 | #ifdef NDEBUG 9 | #define DAY3DBG 0 10 | #else 11 | #define DAY3DBG ENABLE_DAY3DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY3DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY3DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_three_p1() 45 | { 46 | auto input = advent::open_puzzle_input(3); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_three_p2() 51 | { 52 | auto input = advent::open_puzzle_input(3); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY3DBG 57 | #undef ENABLE_DAY3DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent3/advent3.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_three_p1(); 6 | ResultType advent_three_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent3/advent3.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent3/advent3.txt -------------------------------------------------------------------------------- /advent_of_code/advent4/advent4.cpp: -------------------------------------------------------------------------------- 1 | #include "advent4.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY4DBG 5 | #define DAY4DBG 1 6 | #else 7 | #define ENABLE_DAY4DBG 1 8 | #ifdef NDEBUG 9 | #define DAY4DBG 0 10 | #else 11 | #define DAY4DBG ENABLE_DAY4DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY4DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY4DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_four_p1() 45 | { 46 | auto input = advent::open_puzzle_input(4); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_four_p2() 51 | { 52 | auto input = advent::open_puzzle_input(4); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY4DBG 57 | #undef ENABLE_DAY4DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent4/advent4.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_four_p1(); 6 | ResultType advent_four_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent4/advent4.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent4/advent4.txt -------------------------------------------------------------------------------- /advent_of_code/advent5/advent5.cpp: -------------------------------------------------------------------------------- 1 | #include "advent5.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY5DBG 5 | #define DAY5DBG 1 6 | #else 7 | #define ENABLE_DAY5DBG 1 8 | #ifdef NDEBUG 9 | #define DAY5DBG 0 10 | #else 11 | #define DAY5DBG ENABLE_DAY5DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY5DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY5DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_five_p1() 45 | { 46 | auto input = advent::open_puzzle_input(5); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_five_p2() 51 | { 52 | auto input = advent::open_puzzle_input(5); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY5DBG 57 | #undef ENABLE_DAY5DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent5/advent5.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_five_p1(); 6 | ResultType advent_five_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent5/advent5.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent5/advent5.txt -------------------------------------------------------------------------------- /advent_of_code/advent6/advent6.cpp: -------------------------------------------------------------------------------- 1 | #include "advent6.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY6DBG 5 | #define DAY6DBG 1 6 | #else 7 | #define ENABLE_DAY6DBG 1 8 | #ifdef NDEBUG 9 | #define DAY6DBG 0 10 | #else 11 | #define DAY6DBG ENABLE_DAY6DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY6DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY6DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_six_p1() 45 | { 46 | auto input = advent::open_puzzle_input(6); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_six_p2() 51 | { 52 | auto input = advent::open_puzzle_input(6); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY6DBG 57 | #undef ENABLE_DAY6DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent6/advent6.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_six_p1(); 6 | ResultType advent_six_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent6/advent6.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent6/advent6.txt -------------------------------------------------------------------------------- /advent_of_code/advent7/advent7.cpp: -------------------------------------------------------------------------------- 1 | #include "advent7.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY7DBG 5 | #define DAY7DBG 1 6 | #else 7 | #define ENABLE_DAY7DBG 1 8 | #ifdef NDEBUG 9 | #define DAY7DBG 0 10 | #else 11 | #define DAY7DBG ENABLE_DAY7DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY7DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY7DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_seven_p1() 45 | { 46 | auto input = advent::open_puzzle_input(7); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_seven_p2() 51 | { 52 | auto input = advent::open_puzzle_input(7); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY7DBG 57 | #undef ENABLE_DAY7DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent7/advent7.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_seven_p1(); 6 | ResultType advent_seven_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent7/advent7.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent7/advent7.txt -------------------------------------------------------------------------------- /advent_of_code/advent8/advent8.cpp: -------------------------------------------------------------------------------- 1 | #include "advent8.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY8DBG 5 | #define DAY8DBG 1 6 | #else 7 | #define ENABLE_DAY8DBG 1 8 | #ifdef NDEBUG 9 | #define DAY8DBG 0 10 | #else 11 | #define DAY8DBG ENABLE_DAY8DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY8DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY8DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_eight_p1() 45 | { 46 | auto input = advent::open_puzzle_input(8); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_eight_p2() 51 | { 52 | auto input = advent::open_puzzle_input(8); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY8DBG 57 | #undef ENABLE_DAY8DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent8/advent8.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_eight_p1(); 6 | ResultType advent_eight_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent8/advent8.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent8/advent8.txt -------------------------------------------------------------------------------- /advent_of_code/advent9/advent9.cpp: -------------------------------------------------------------------------------- 1 | #include "advent9.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY9DBG 5 | #define DAY9DBG 1 6 | #else 7 | #define ENABLE_DAY9DBG 1 8 | #ifdef NDEBUG 9 | #define DAY9DBG 0 10 | #else 11 | #define DAY9DBG ENABLE_DAY9DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY9DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY9DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_nine_p1() 45 | { 46 | auto input = advent::open_puzzle_input(9); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_nine_p2() 51 | { 52 | auto input = advent::open_puzzle_input(9); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY9DBG 57 | #undef ENABLE_DAY9DBG 58 | -------------------------------------------------------------------------------- /advent_of_code/advent9/advent9.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_nine_p1(); 6 | ResultType advent_nine_p2(); 7 | -------------------------------------------------------------------------------- /advent_of_code/advent9/advent9.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/advent9/advent9.txt -------------------------------------------------------------------------------- /advent_of_code/main.cpp: -------------------------------------------------------------------------------- 1 | #include "advent/advent_of_code.h" 2 | 3 | #include 4 | #include 5 | 6 | int main(int argc, char** argv) 7 | { 8 | // Use the filter to only run certain tests. 9 | // This uses some magic to test against the name of the function, 10 | // so putting "eighteen" as the argument will only run advent_eighteen_p1() 11 | // and advent_eighteen_p2() (as well as any other test functions with "eighteen" 12 | // in the function name. 13 | // Leave blank to run everything. 14 | std::vector filters; 15 | for(int i=1;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "../advent/advent_of_code.h" 14 | #include "../advent/advent_headers.h" 15 | #include "../advent/advent_setup.h" 16 | #include "../advent/advent_assert.h" 17 | 18 | namespace 19 | { 20 | struct ResultStringifier 21 | { 22 | std::string operator()(const std::string& in) const noexcept { return in; } 23 | template 24 | std::string operator()(T in) const { return std::to_string(in); } 25 | }; 26 | } 27 | 28 | std::string to_string(const ResultType& rt) 29 | { 30 | return std::visit(ResultStringifier{}, rt); 31 | } 32 | 33 | std::string to_string(const std::optional& os) 34 | { 35 | return os.value_or(""); 36 | } 37 | 38 | // Result a test can give. 39 | enum class test_status : char 40 | { 41 | pass, 42 | fail, 43 | unknown, 44 | filtered 45 | }; 46 | 47 | // Full results of a test. 48 | struct test_result 49 | { 50 | std::string name; 51 | std::string result; 52 | std::string expected; 53 | test_status status = test_status::unknown; 54 | std::chrono::nanoseconds time_taken; 55 | }; 56 | 57 | template 58 | bool check_result(const test_result& result) 59 | { 60 | return status == result.status; 61 | } 62 | 63 | std::string two_digits(int num) 64 | { 65 | std::ostringstream oss; 66 | oss << std::setfill('0') << std::setw(2) << num; 67 | return oss.str(); 68 | } 69 | 70 | std::optional to_human_readable(long long count, int inner_max, int outer_max, const std::string& suffix) 71 | { 72 | if (count < inner_max) 73 | return std::to_string(count) + suffix; 74 | 75 | if (count < (static_cast(inner_max) * static_cast(outer_max))) 76 | { 77 | std::ostringstream oss; 78 | oss << count / inner_max << ':' << two_digits(count % inner_max) << suffix; 79 | return oss.str(); 80 | } 81 | 82 | return std::optional{}; 83 | } 84 | 85 | std::string to_human_readable(std::chrono::hours time) 86 | { 87 | const auto count = time.count(); 88 | std::ostringstream oss; 89 | oss << count / 24 << " days and " << count % 24 << " hours"; 90 | return oss.str(); 91 | } 92 | 93 | std::string to_human_readable(std::chrono::minutes time) 94 | { 95 | const auto res = to_human_readable(time.count(), 60, 24, "s"); 96 | if (res.has_value()) 97 | return res.value(); 98 | 99 | const auto h = std::chrono::duration_cast(time); 100 | return to_human_readable(h); 101 | } 102 | 103 | std::string to_human_readable(std::chrono::seconds time) 104 | { 105 | const auto res = to_human_readable(time.count(), 60,60,"s"); 106 | if (res.has_value()) 107 | return res.value(); 108 | 109 | const auto m = std::chrono::duration_cast(time); 110 | return to_human_readable(m); 111 | } 112 | 113 | std::optional to_human_readable(long long count, const std::string& suffix_short, const std::string& suffix_long) 114 | { 115 | if (count < 10'000) 116 | return std::to_string(count) + suffix_short; 117 | if (count < 100'000) 118 | { 119 | std::ostringstream oss; 120 | oss << std::setprecision(3) << static_cast(count) / 1000.0 << suffix_long; 121 | return oss.str(); 122 | } 123 | return std::optional{}; 124 | } 125 | 126 | std::string to_human_readable(std::chrono::milliseconds time) 127 | { 128 | const auto res = to_human_readable(time.count(), "ms", "s"); 129 | if (res.has_value()) 130 | return res.value(); 131 | 132 | const auto s = std::chrono::duration_cast(time); 133 | return to_human_readable(s); 134 | } 135 | 136 | std::string to_human_readable(std::chrono::microseconds time) 137 | { 138 | const auto res = to_human_readable(time.count(), "us", "ms"); 139 | if (res.has_value()) 140 | return res.value(); 141 | 142 | const auto ms = std::chrono::duration_cast(time); 143 | return to_human_readable(ms); 144 | } 145 | 146 | std::string to_human_readable(std::chrono::nanoseconds time) 147 | { 148 | const auto res = to_human_readable(time.count(), "ns", "us"); 149 | if (res.has_value()) 150 | return res.value(); 151 | 152 | const auto us = std::chrono::duration_cast(time); 153 | return to_human_readable(us); 154 | } 155 | 156 | template 157 | ResultType test_execute_wrapper(TestType test) 158 | { 159 | #ifdef NDEBUG 160 | return test.execute(); 161 | #else 162 | try 163 | { 164 | return test.execute(); 165 | } 166 | catch (const advent::test_failed& tf) 167 | { 168 | return std::string{ "ERROR: " } + std::string{ tf.what() }; 169 | } 170 | #endif 171 | } 172 | 173 | template 174 | std::pair run_test_func(TestType test) 175 | { 176 | const auto start_time = std::chrono::high_resolution_clock::now(); 177 | const ResultType res = test_execute_wrapper(std::move(test)); 178 | const auto end_time = std::chrono::high_resolution_clock::now(); 179 | return std::pair{res, end_time - start_time}; 180 | } 181 | 182 | struct TestExecutor 183 | { 184 | template 185 | std::pair operator()(TestType test) { return run_test_func(std::move(test)); } 186 | }; 187 | 188 | test_result run_test(const verification_test& test, const std::vector& filter) 189 | { 190 | if(!filter.empty()) 191 | { 192 | auto filter_pred = [name = std::string_view{ test.name }](std::string_view filter_item) 193 | { 194 | return name.find(filter_item) != name.npos; 195 | }; 196 | const bool matches_filter = std::ranges::any_of(filter, filter_pred); 197 | if(!matches_filter) 198 | { 199 | return test_result{ 200 | test.name, 201 | "", 202 | to_string(test.expected_result), 203 | test_status::filtered 204 | }; 205 | } 206 | } 207 | std::cout << "Running test " << test.name << "..."; 208 | const auto [res,time_taken] = std::visit(TestExecutor{}, test.test_func); 209 | const auto string_result = to_string(res); 210 | std::cout << "\nFinished " << test.name << ": took " << to_human_readable(time_taken) << " and got " << string_result << '\n'; 211 | auto get_result = [&](test_status status) 212 | { 213 | return test_result{ test.name,string_result,to_string(test.expected_result),status,time_taken }; 214 | }; 215 | 216 | if(!test.expected_result.has_value()) 217 | { 218 | return get_result(test_status::unknown); 219 | } 220 | else 221 | { 222 | return get_result(string_result == *test.expected_result ? test_status::pass : test_status::fail); 223 | } 224 | } 225 | 226 | bool verify_all(const std::vector& filter) 227 | { 228 | constexpr auto NUM_TESTS = std::size(tests); 229 | std::array results; 230 | std::ranges::transform(tests, begin(results), 231 | [&filter](const verification_test& test) 232 | { 233 | return run_test(test, filter); 234 | }); 235 | 236 | auto result_to_string = [&filter](const test_result& result) 237 | { 238 | std::ostringstream oss; 239 | oss << result.name << ": " << result.result << " - "; 240 | switch (result.status) 241 | { 242 | case test_status::pass: 243 | oss << "PASS\n"; 244 | break; 245 | case test_status::fail: 246 | oss << "FAIL (expected " << result.expected << ")\n"; 247 | break; 248 | case test_status::filtered: 249 | return std::string{ "" }; 250 | default: // unknown 251 | oss << "[Unknown]\n"; 252 | break; 253 | } 254 | return oss.str(); 255 | }; 256 | 257 | std::ranges::transform(results,std::ostream_iterator(std::cout), result_to_string); 258 | 259 | auto get_count = [&results](auto pred) 260 | { 261 | return std::ranges::count_if(results, pred); 262 | }; 263 | 264 | const auto total_time = std::transform_reduce(begin(results), end(results), std::chrono::nanoseconds{ 0 }, 265 | std::plus{}, [](const test_result& result) {return result.time_taken; }); 266 | 267 | std::cout << 268 | "RESULTS:\n" 269 | " PASSED : " << get_count(check_result) << "\n" 270 | " FAILED : " << get_count(check_result) << "\n" 271 | " UNKNOWN: " << get_count(check_result) << "\n" 272 | " TIME : " << to_human_readable(total_time) << '\n'; 273 | return std::ranges::none_of(results,check_result); 274 | } 275 | 276 | verification_test make_test(std::string name, TestFunc func, int64_t result) 277 | { 278 | return make_test(std::move(name), func, std::to_string(result)); 279 | } 280 | 281 | verification_test make_test(std::string name, TestFunc func, std::string result) 282 | { 283 | return verification_test{ std::move(name),func,std::move(result) }; 284 | } 285 | 286 | verification_test make_test(std::string name, TestFunc func, Dummy) 287 | { 288 | return verification_test{ std::move(name),func }; 289 | } 290 | 291 | verification_test make_test(std::string name, TestFuncWithArg func, int64_t result, std::string arg) 292 | { 293 | return make_test(std::move(name), func, std::to_string(result), std::move(arg)); 294 | } 295 | 296 | verification_test make_test(std::string name, TestFuncWithArg func, std::string result, std::string arg) 297 | { 298 | return verification_test{std::move(name), func, std::move(arg), std::move(result)}; 299 | } 300 | 301 | verification_test make_test(std::string name, TestFuncWithArg func, Dummy, std::string arg) 302 | { 303 | return verification_test{std::move(name), func, std::move(arg)}; 304 | } 305 | 306 | ResultType TestWithArgExecutable::execute() 307 | { 308 | std::istringstream iss{ std::move(arg)}; 309 | return func(iss); 310 | } -------------------------------------------------------------------------------- /advent_of_code/src/isqrt.cpp: -------------------------------------------------------------------------------- 1 | #include "isqrt.h" 2 | 3 | #include 4 | namespace 5 | { 6 | uint32_t isqrt_implementation(uint32_t guess_base, uint32_t input) 7 | { 8 | assert(input > 0); 9 | uint64_t guess = 1; 10 | while (true) 11 | { 12 | auto sqr = [](uint64_t x) -> uint64_t {return x * x; }; 13 | const uint64_t trial_result = guess_base + guess; 14 | const uint64_t trial_square = sqr(trial_result); 15 | if (trial_square == input) // Perfect match! 16 | { 17 | return static_cast(trial_result); 18 | } 19 | else if (trial_square < input) // Too small. Try a bigger number. 20 | { 21 | guess *= 2; 22 | } 23 | else if (guess == 1) // We have an imperfect result: guess_base is too small, but guess_base+1 is too big 24 | { 25 | return guess_base; 26 | } 27 | else // guess > 1 && trial_result is too big. 28 | { 29 | // Roll the guess back a stage (div by 2) and restart with a better base. 30 | return isqrt_implementation(guess_base + static_cast(guess / 2), input); 31 | } 32 | } 33 | } 34 | } 35 | 36 | // Return the square root of an integer. If not exact, this is rounded down. 37 | // Guaranteed to have no floating point inaccuracies. 38 | uint32_t utils::isqrt(uint32_t input) 39 | { 40 | switch (input) 41 | { 42 | default: 43 | return isqrt_implementation(0, input); 44 | case 0: 45 | return 0; 46 | // Add more common cases here if optimisation is needed. 47 | } 48 | } 49 | 50 | int32_t utils::isqrt(int32_t input) 51 | { 52 | assert(input >= 0); 53 | return static_cast(isqrt(static_cast(input))); 54 | } -------------------------------------------------------------------------------- /advent_of_code/src/parse_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "../utils/parse_utils.h" 2 | 3 | #include 4 | 5 | std::string_view utils::remove_specific_prefix(std::string_view input, std::string_view prefix) 6 | { 7 | assert(input.starts_with(prefix)); 8 | input.remove_prefix(prefix.size()); 9 | return input; 10 | } 11 | 12 | std::string_view utils::remove_specific_suffix(std::string_view input, std::string_view suffix) 13 | { 14 | assert(input.ends_with(suffix)); 15 | input.remove_suffix(suffix.size()); 16 | return input; 17 | } -------------------------------------------------------------------------------- /advent_of_code/templates/advent_setup.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent_testcase_setup.h" 4 | #include "advent_test_inputs.h" 5 | #include "advent_headers.h" 6 | #include "advent_solutions.h" 7 | 8 | static const verification_test tests[] = 9 | { 10 | DAY(one,DAY_01_1_SOLUTION,DAY_01_2_SOLUTION), 11 | DAY(two,DAY_02_1_SOLUTION,DAY_02_2_SOLUTION), 12 | DAY(three,DAY_03_1_SOLUTION,DAY_03_2_SOLUTION), 13 | DAY(four,DAY_04_1_SOLUTION,DAY_04_2_SOLUTION), 14 | DAY(five,DAY_05_1_SOLUTION,DAY_05_2_SOLUTION), 15 | DAY(six,DAY_06_1_SOLUTION,DAY_06_2_SOLUTION), 16 | DAY(seven,DAY_07_1_SOLUTION,DAY_07_2_SOLUTION), 17 | DAY(eight,DAY_08_1_SOLUTION,DAY_08_2_SOLUTION), 18 | DAY(nine,DAY_09_1_SOLUTION,DAY_09_2_SOLUTION), 19 | DAY(ten, DAY_10_1_SOLUTION, DAY_10_2_SOLUTION), 20 | DAY(eleven, DAY_11_1_SOLUTION, DAY_11_2_SOLUTION), 21 | DAY(twelve, DAY_12_1_SOLUTION, DAY_12_2_SOLUTION), 22 | DAY(thirteen, DAY_13_1_SOLUTION, DAY_13_2_SOLUTION), 23 | DAY(fourteen, DAY_14_1_SOLUTION, DAY_14_2_SOLUTION), 24 | DAY(fifteen, DAY_15_1_SOLUTION, DAY_15_2_SOLUTION), 25 | DAY(sixteen, DAY_16_1_SOLUTION, DAY_16_2_SOLUTION), 26 | DAY(seventeen, DAY_17_1_SOLUTION, DAY_17_2_SOLUTION), 27 | DAY(eighteen, DAY_18_1_SOLUTION, DAY_18_2_SOLUTION), 28 | DAY(nineteen, DAY_19_1_SOLUTION, DAY_19_2_SOLUTION), 29 | DAY(twenty, DAY_20_1_SOLUTION, DAY_20_2_SOLUTION), 30 | DAY(twentyone, DAY_21_1_SOLUTION, DAY_21_2_SOLUTION), 31 | DAY(twentytwo, DAY_22_1_SOLUTION, DAY_22_2_SOLUTION), 32 | DAY(twentythree, DAY_23_1_SOLUTION, DAY_23_2_SOLUTION), 33 | DAY(twentyfour, DAY_24_1_SOLUTION, DAY_24_2_SOLUTION), 34 | DAY(twentyfive, DAY_25_1_SOLUTION,"MERRY CHRISTMAS!") 35 | }; 36 | 37 | #undef ARG 38 | #undef TESTCASE 39 | #undef FUNC_NAME 40 | #undef TEST_DECL 41 | #undef DAY 42 | #undef DUMMY 43 | #undef DUMMY_DAY -------------------------------------------------------------------------------- /advent_of_code/templates/advent_solutions.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | Put your solutions for each day in here and DO NOT submit it to source control. 5 | */ 6 | 7 | #define DAY_01_1_SOLUTION dummy 8 | #define DAY_01_2_SOLUTION dummy 9 | #define DAY_02_1_SOLUTION dummy 10 | #define DAY_02_2_SOLUTION dummy 11 | #define DAY_03_1_SOLUTION dummy 12 | #define DAY_03_2_SOLUTION dummy 13 | #define DAY_04_1_SOLUTION dummy 14 | #define DAY_04_2_SOLUTION dummy 15 | #define DAY_05_1_SOLUTION dummy 16 | #define DAY_05_2_SOLUTION dummy 17 | #define DAY_06_1_SOLUTION dummy 18 | #define DAY_06_2_SOLUTION dummy 19 | #define DAY_07_1_SOLUTION dummy 20 | #define DAY_07_2_SOLUTION dummy 21 | #define DAY_08_1_SOLUTION dummy 22 | #define DAY_08_2_SOLUTION dummy 23 | #define DAY_09_1_SOLUTION dummy 24 | #define DAY_09_2_SOLUTION dummy 25 | #define DAY_10_1_SOLUTION dummy 26 | #define DAY_10_2_SOLUTION dummy 27 | #define DAY_11_1_SOLUTION dummy 28 | #define DAY_11_2_SOLUTION dummy 29 | #define DAY_12_1_SOLUTION dummy 30 | #define DAY_12_2_SOLUTION dummy 31 | #define DAY_13_1_SOLUTION dummy 32 | #define DAY_13_2_SOLUTION dummy 33 | #define DAY_14_1_SOLUTION dummy 34 | #define DAY_14_2_SOLUTION dummy 35 | #define DAY_15_1_SOLUTION dummy 36 | #define DAY_15_2_SOLUTION dummy 37 | #define DAY_16_1_SOLUTION dummy 38 | #define DAY_16_2_SOLUTION dummy 39 | #define DAY_17_1_SOLUTION dummy 40 | #define DAY_17_2_SOLUTION dummy 41 | #define DAY_18_1_SOLUTION dummy 42 | #define DAY_18_2_SOLUTION dummy 43 | #define DAY_19_1_SOLUTION dummy 44 | #define DAY_19_2_SOLUTION dummy 45 | #define DAY_20_1_SOLUTION dummy 46 | #define DAY_20_2_SOLUTION dummy 47 | #define DAY_21_1_SOLUTION dummy 48 | #define DAY_21_2_SOLUTION dummy 49 | #define DAY_22_1_SOLUTION dummy 50 | #define DAY_22_2_SOLUTION dummy 51 | #define DAY_23_1_SOLUTION dummy 52 | #define DAY_23_2_SOLUTION dummy 53 | #define DAY_24_1_SOLUTION dummy 54 | #define DAY_24_2_SOLUTION dummy 55 | #define DAY_25_1_SOLUTION dummy 56 | #define DAY_25_2_SOLUTION "Merry Christmas!" -------------------------------------------------------------------------------- /advent_of_code/templates/advent_template.cpp.in: -------------------------------------------------------------------------------- 1 | #include "advent@DAYDIGIT@.h" 2 | #include "advent/advent_utils.h" 3 | 4 | #ifdef FORCE_DAY@DAYDIGIT@DBG 5 | #define DAY@DAYDIGIT@DBG 1 6 | #else 7 | #define ENABLE_DAY@DAYDIGIT@DBG 1 8 | #ifdef NDEBUG 9 | #define DAY@DAYDIGIT@DBG 0 10 | #else 11 | #define DAY@DAYDIGIT@DBG ENABLE_DAY@DAYDIGIT@DBG 12 | #endif 13 | #endif 14 | 15 | #if DAY@DAYDIGIT@DBG 16 | #include 17 | #endif 18 | 19 | namespace 20 | { 21 | #if DAY@DAYDIGIT@DBG 22 | std::ostream& log = std::cout; 23 | #else 24 | struct { template auto& operator<<(const T&) const noexcept { return *this; } } log; 25 | #endif 26 | } 27 | 28 | namespace 29 | { 30 | int64_t solve_p1(std::istream& input) 31 | { 32 | return 0; 33 | } 34 | } 35 | 36 | namespace 37 | { 38 | int64_t solve_p2(std::istream& input) 39 | { 40 | return 0; 41 | } 42 | } 43 | 44 | ResultType advent_@DAYTXT@_p1() 45 | { 46 | auto input = advent::open_puzzle_input(@DAYDIGIT@); 47 | return solve_p1(input); 48 | } 49 | 50 | ResultType advent_@DAYTXT@_p2() 51 | { 52 | auto input = advent::open_puzzle_input(@DAYDIGIT@); 53 | return solve_p2(input); 54 | } 55 | 56 | #undef DAY@DAYDIGIT@DBG 57 | #undef ENABLE_DAY@DAYDIGIT@DBG -------------------------------------------------------------------------------- /advent_of_code/templates/advent_template.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "advent/advent_types.h" 4 | 5 | ResultType advent_@DAYTXT@_p1(); 6 | ResultType advent_@DAYTXT@_p2(); -------------------------------------------------------------------------------- /advent_of_code/templates/advent_template.txt.in: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkadye/advent_of_code_framework/f40d01ea9d0a46059a26f0d525eaeeab2b065dda/advent_of_code/templates/advent_template.txt.in -------------------------------------------------------------------------------- /advent_of_code/templates/advent_test_inputs.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace advent 7 | { 8 | namespace combine_inputs_internal 9 | { 10 | inline std::string impl(std::string_view joiner, std::ostringstream& collector) 11 | { 12 | return collector.str(); 13 | } 14 | 15 | template 16 | inline std::string impl(std::string_view joiner, std::ostringstream& collector, std::string_view next_string, StringViews...remaining) 17 | { 18 | collector << joiner << next_string; 19 | return impl(joiner, collector,remaining...); 20 | } 21 | } 22 | 23 | template 24 | inline std::string combine_inputs(std::string_view first_string, StringViews...remaining) 25 | { 26 | std::ostringstream collector; 27 | std::string joiner(NUM_NEWLINES, '\n'); 28 | collector << first_string; 29 | return combine_inputs_internal::impl(joiner, collector, remaining...); 30 | } 31 | } 32 | 33 | /* 34 | 35 | Define inline definitions of test inputs here for use in the testcases. 36 | 37 | For example: 38 | 39 | constexpr const char* TEST_ONE_A = "test1_input"; 40 | 41 | Use can also combine strings together with combine_inputs, for example, which will also add newlinse automatically using the template parameter to decide how many: 42 | 43 | constexpr const char* TEST_ONE_B = "test2"; 44 | static const auto TEST_ONE = advent::combine_inputs<2>(TEST_ONE_A, TEST_ONE_B); 45 | will set TEXT_ONE to "test1_input\n\ntest2" 46 | 47 | */ -------------------------------------------------------------------------------- /advent_of_code/utils/a_star.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "swap_remove.h" 9 | #include "sorted_vector.h" 10 | 11 | namespace utils 12 | { 13 | // NodeType: An arbitrary node. No particular requirements. User provided functors are used to interact. 14 | // IsEndPointFunc: A function bool f(Node) that returns true if the argument is an end-point. 15 | // GetNextNodesFunc: Return any iterable type containing NodeTypes that can be reached from a NodeType argument. 16 | // GetCostBetweenNodesFunc: Functor with the signature: CostType f(NodeType,NodeType). 17 | // GetHeuristicForNode: Functor with CostType f(NodeType) to get the heuristic. 18 | // AreNodesEqual: A function bool f(NodeType,NodeType) that returns true if both nodes are equal 19 | template < 20 | typename NodeType, 21 | typename IsEndPointFunc, 22 | typename GetNextNodesFunc, 23 | typename GetCostBetweenNodesFunc, 24 | typename GetHeuristicForNode, 25 | typename AreNodesEqual> 26 | auto a_star( 27 | const NodeType& start_point, 28 | const IsEndPointFunc& is_end_point, 29 | const GetNextNodesFunc& get_next_nodes, 30 | const GetCostBetweenNodesFunc& get_cost_between_nodes, 31 | const GetHeuristicForNode& get_heuristic, 32 | const AreNodesEqual& are_nodes_equal, 33 | std::size_t estimated_number_of_nodes = 1) 34 | { 35 | using ID = std::size_t; 36 | using CostType = decltype(get_cost_between_nodes(start_point, start_point)); 37 | struct AStarNode 38 | { 39 | NodeType node; 40 | CostType cost; 41 | CostType with_heuristic; 42 | ID id; 43 | ID previous_id; 44 | }; 45 | 46 | ID latest_id = 0; 47 | auto checked_nodes = utils::make_sorted_vector([](const AStarNode & l, const AStarNode & r) 48 | { 49 | return l.id < r.id; 50 | }); 51 | 52 | auto get_checked_node_by_id = [&checked_nodes](ID id) -> AStarNode& 53 | { 54 | AStarNode dummy; 55 | dummy.id = id; 56 | const auto find_result = checked_nodes.find(dummy); 57 | assert(find_result != end(checked_nodes)); 58 | return *find_result; 59 | }; 60 | 61 | auto nodes_to_search = utils::make_sorted_vector([](const AStarNode& l, const AStarNode& r) 62 | { 63 | return l.with_heuristic > r.with_heuristic; 64 | }); 65 | nodes_to_search.reserve(estimated_number_of_nodes); 66 | checked_nodes.reserve(estimated_number_of_nodes); 67 | 68 | nodes_to_search.insert(AStarNode{ start_point,0,0,++latest_id,0 }); 69 | 70 | while (!nodes_to_search.empty()) 71 | { 72 | AStarNode current_node = std::move(nodes_to_search.back()); 73 | nodes_to_search.pop_back(); 74 | 75 | // Handle end-point 76 | if (is_end_point(current_node.node)) 77 | { 78 | std::vector result; 79 | const auto final_cost = current_node.cost; 80 | while (true) 81 | { 82 | result.push_back(std::move(current_node.node)); 83 | if (current_node.previous_id == 0) 84 | { 85 | std::reverse(begin(result), end(result)); 86 | return std::make_pair(result, final_cost); 87 | } 88 | current_node = get_checked_node_by_id(current_node.previous_id); 89 | } 90 | 91 | } 92 | 93 | // Get next nodes 94 | auto next_nodes = get_next_nodes(current_node.node); 95 | for (auto& n : next_nodes) 96 | { 97 | const auto prev_node_check = std::any_of(begin(checked_nodes), end(checked_nodes), 98 | [&n,&are_nodes_equal](const AStarNode& asn) 99 | { 100 | return are_nodes_equal(n, asn.node); 101 | }); 102 | if (prev_node_check) 103 | { 104 | continue; 105 | } 106 | AStarNode node; 107 | node.cost = current_node.cost + get_cost_between_nodes(current_node.node, n); 108 | node.with_heuristic = node.cost + get_heuristic(n); 109 | auto new_it = nodes_to_search.insert(nodes_to_search.upper_bound(node), std::move(node)); 110 | new_it->node = std::move(n); 111 | new_it->previous_id = current_node.id; 112 | new_it->id = ++latest_id; 113 | } 114 | 115 | // Update checked nodes 116 | checked_nodes.push_back(std::move(current_node)); 117 | } 118 | 119 | // If we run out of nodes, there's no path. 120 | return std::make_pair(std::vector{}, CostType{}); 121 | } 122 | } -------------------------------------------------------------------------------- /advent_of_code/utils/advent_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | // Returns a map with items from both inputs. Where a key is duplicated, combine_func is used to combine 7 | // the values pointed to. 8 | template 9 | inline std::map combine_maps(std::map a, std::map b, BinaryOp combine_func) 10 | { 11 | if (a.size() < b.size()) return combine_maps(std::move(b), std::move(a),combine_func); 12 | 13 | while (!b.empty()) 14 | { 15 | auto node = b.extract(cbegin(b)); 16 | const auto it_to = a.find(node.key()); 17 | if (it_to == end(a)) 18 | { 19 | a.insert(std::move(node)); 20 | } 21 | else 22 | { 23 | it_to->second = combine_func(it_to->second, node.mapped()); 24 | } 25 | } 26 | return a; 27 | } 28 | 29 | template 30 | inline void erase_remove_if(Cont& c, Pred p) 31 | { 32 | c.erase(std::remove_if(begin(c), end(c), p), end(c)); 33 | } 34 | 35 | template 36 | bool push_back_unique(Container& cont, ElemType&& elem) 37 | { 38 | const auto find_result = std::find(begin(cont), end(cont), elem); 39 | if (find_result == end(cont)) 40 | { 41 | cont.push_back(std::forward(elem)); 42 | return true; 43 | } 44 | return false; 45 | } -------------------------------------------------------------------------------- /advent_of_code/utils/aoc_utils.natvis: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | {{ size={size()} }} 12 | 13 | size() 14 | capacity() 15 | 16 | size() 17 | heap_memory() 18 | reinterpret_cast<value_type*>(stack_memory()) 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /advent_of_code/utils/binary_find.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace utils 6 | { 7 | template 8 | inline FwdIt binary_find(FwdIt start, FwdIt finish, const T& val, const Pred& pred) noexcept 9 | { 10 | assert(std::is_sorted(start, finish, pred)); 11 | const auto result = std::lower_bound(start, finish, val, pred); 12 | if (result == finish) 13 | { 14 | return finish; 15 | } 16 | if (pred(val, *result)) 17 | { 18 | return finish; 19 | } 20 | if (pred(*result, val)) 21 | { 22 | return finish; 23 | } 24 | return result; 25 | } 26 | 27 | template 28 | inline FwdIt binary_find(FwdIt start, FwdIt finish, const T& val) noexcept 29 | { 30 | return binary_find(start, finish, val, std::less{}); 31 | } 32 | 33 | // Predicate is a function that can be called predicate(*FwdIt). 34 | // predicate returns: 35 | // equivalent - return this value 36 | // less - this iterator points to a value that is too small 37 | // greater - this iterator points to a value that is too large 38 | template 39 | inline FwdIt binary_find_by_predicate(FwdIt start, FwdIt finish, const ThreeWayPredicate& predicate) 40 | { 41 | static_assert(std::is_invocable_r_v, "predicate must accept FwdIt::value_type as an argument, and return a std::weak_ordering"); 42 | if (start == finish) return finish; 43 | const auto range_len = std::distance(start, finish); 44 | const FwdIt midpoint = stdr::next(start, range_len / 2); 45 | 46 | const bool is_final_check = (start == midpoint); 47 | 48 | const std::weak_ordering position = predicate(*midpoint); 49 | 50 | if (position == std::weak_ordering::equivalent) // Found it 51 | { 52 | return midpoint; 53 | } 54 | else if (midpoint == start) 55 | { 56 | return finish; 57 | } 58 | 59 | FwdIt next_start = start; 60 | FwdIt next_finish = finish; 61 | 62 | if (position == std::weak_ordering::less) 63 | { 64 | next_start = midpoint; 65 | } 66 | else if (position == std::weak_ordering::greater) // Iterator's value to too big 67 | { 68 | next_finish = midpoint; 69 | } 70 | else // That should cover all the cases 71 | { 72 | AdventUnreachable(); 73 | } 74 | 75 | const FwdIt result = utils::binary_find_by_predicate(next_start, next_finish, predicate); 76 | return (result != next_finish) ? result : finish; 77 | } 78 | 79 | // This helper version of find_by_predicate allows a reference value to be passed in. 80 | template 81 | inline FwdIt binary_find_by_predicate(FwdIt start, FwdIt finish, const RefType& ref, const ThreeWayPredicate& predicate) 82 | { 83 | using ValueType = decltype(*start); 84 | static_assert(std::is_invocable_r_v, "predicate must have a signature like std::weak_ordering predicate(decltype(*FwdIt,RefType)"); 85 | auto unary_predicate = [&ref, &predicate](const ValueType& val) 86 | { 87 | return predicate(val, ref); 88 | }; 89 | return utils::binary_find_by_predicate(start, finish, unary_predicate); 90 | } 91 | 92 | namespace ranges 93 | { 94 | template 95 | inline auto binary_find(RangeType&& range, const T& val, const Pred& pred) noexcept 96 | { 97 | return utils::binary_find(begin(range), end(range), val, pred); 98 | } 99 | 100 | template 101 | inline auto binary_find(RangeType&& range, const T& val) noexcept 102 | { 103 | return binary_find(begin(range),end(range), val, std::less{}); 104 | } 105 | 106 | // Predicate is a function that can be called predicate(*FwdIt). 107 | // predicate returns: 108 | // equivalent - return this value 109 | // less - this iterator points to a value that is too small 110 | // greater - this iterator points to a value that is too large 111 | template 112 | inline auto binary_find_by_predicate(RangeType&& range, const ThreeWayPredicate& predicate) 113 | { 114 | return utils::binary_find_by_predicate(begin(range), end(range), predicate); 115 | } 116 | 117 | // This helper version of find_by_predicate allows a reference value to be passed in. 118 | template 119 | inline auto binary_find_by_predicate(RangeType&& range, const RefType& ref, const ThreeWayPredicate& predicate) 120 | { 121 | return utils::binary_find_by_predicate(begin(range), end(range), ref, predicate); 122 | } 123 | } 124 | } -------------------------------------------------------------------------------- /advent_of_code/utils/bit_ops.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef _WIN32 6 | #include 7 | #ifndef _WIN64 8 | #include 9 | #endif 10 | #endif 11 | 12 | namespace utils 13 | { 14 | template 15 | T population(T input) noexcept 16 | { 17 | static_assert(std::is_integral_v, "Can only get population of an integer type"); 18 | static_assert(std::is_unsigned_v, "Can only get population of an unsigned type."); 19 | #ifdef _WIN32 20 | int cpu_info[4]; 21 | __cpuid(cpu_info, 1); 22 | constexpr int popcnt_mask = 1 << 23; 23 | if (cpu_info[2] & popcnt_mask) 24 | { 25 | if constexpr (sizeof(T) <= 2) 26 | { 27 | return static_cast(__popcnt16(input)); 28 | } 29 | if constexpr (sizeof(T) <= 4) 30 | { 31 | return static_cast(__popcnt(input)); 32 | } 33 | #ifdef _WIN64 34 | if constexpr (sizeof(T) == 8) 35 | { 36 | return static_cast(__popcnt64(input)); 37 | } 38 | #endif 39 | if constexpr (sizeof(T) > 4) 40 | { 41 | T result = 0; 42 | while (input > 0) 43 | { 44 | const uint32_t low_bits = input; 45 | input = input >> 32; 46 | result += __popcnt(low_bits); 47 | } 48 | return result; 49 | } 50 | } 51 | #endif 52 | T result = 0; 53 | while (input != 0) 54 | { 55 | result += input & T{ 1 }; 56 | input = input >> 1; 57 | } 58 | return result; 59 | } 60 | } -------------------------------------------------------------------------------- /advent_of_code/utils/brackets.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "advent/advent_utils.h" 5 | 6 | namespace utils 7 | { 8 | [[nodiscard]] inline std::size_t find_closing_bracket( 9 | std::string_view input, 10 | char open_bracket, char close_bracket, 11 | std::size_t open_pos = 0) 12 | { 13 | AdventCheck(input[open_pos] == open_bracket); 14 | int num_open_brackets = 1; 15 | for (std::size_t i = open_pos + 1; i < input.size(); ++i) 16 | if (input[i] == open_bracket) ++num_open_brackets; 17 | else if (input[i] == close_bracket) 18 | { 19 | --num_open_brackets; 20 | if (num_open_brackets == 0) 21 | { 22 | return i; 23 | } 24 | } 25 | return std::string_view::npos; 26 | } 27 | 28 | [[nodiscard]] inline std::size_t bracket_aware_find_first_of( 29 | std::string_view input, 30 | std::string_view open_brackets, 31 | std::string_view closing_brackets, 32 | std::string_view find_targets, 33 | std::size_t search_start = 0) 34 | { 35 | AdventCheck(open_brackets.size() == closing_brackets.size()); 36 | AdventCheck(!find_targets.empty()); 37 | for (std::size_t i = search_start; i < input.size(); ++i) 38 | { 39 | const char current_char = input[i]; 40 | if (find_targets.find(current_char) < find_targets.size()) 41 | { 42 | return i; 43 | } 44 | const auto open_bracket_find_result = open_brackets.find(current_char); 45 | if (open_bracket_find_result < open_brackets.size()) 46 | { 47 | const char close_bracket = closing_brackets[open_bracket_find_result]; 48 | i = find_closing_bracket(input, current_char, close_bracket, i); 49 | if (i >= input.size()) 50 | { 51 | break; 52 | } 53 | } 54 | } 55 | return std::string_view::npos; 56 | } 57 | 58 | [[nodiscard]] inline std::size_t bracket_aware_find( 59 | std::string_view input, 60 | std::string_view open_brackets, 61 | std::string_view closing_brackets, 62 | char find_target, 63 | std::size_t search_start = 0) 64 | { 65 | std::string_view targets(&find_target, 1); 66 | return bracket_aware_find_first_of(input, open_brackets, closing_brackets, targets, search_start); 67 | } 68 | 69 | [[nodiscard]] inline std::size_t bracket_aware_find( 70 | std::string_view input, 71 | char open_bracket, 72 | char close_bracket, 73 | char find_target, 74 | std::size_t start_search = 0) 75 | { 76 | std::string_view open(&open_bracket, 1); 77 | std::string_view close(&close_bracket, 1); 78 | return bracket_aware_find(input, open, close, find_target, start_search); 79 | } 80 | } -------------------------------------------------------------------------------- /advent_of_code/utils/combine_maps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace utils 4 | { 5 | 6 | // Returns a map with items from both inputs. Where a key is duplicated, combine_func is used to combine 7 | // the values pointed to. 8 | template 9 | inline MapType combine_maps(MapType a, MapType b, BinaryOp combine_func) 10 | { 11 | if (a.size() < b.size()) return combine_maps(std::move(b), std::move(a), combine_func); 12 | 13 | while (!b.empty()) 14 | { 15 | auto node = b.extract(cbegin(b)); 16 | const auto it_to = a.find(node.key()); 17 | if (it_to == end(a)) 18 | { 19 | a.insert(std::move(node)); 20 | } 21 | else 22 | { 23 | it_to->second = combine_func(it_to->second, node.mapped()); 24 | } 25 | } 26 | return a; 27 | } 28 | } -------------------------------------------------------------------------------- /advent_of_code/utils/comparisons.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace utils 4 | { 5 | template 6 | [[nodiscard]] inline FwdIt min_element_transform(FwdIt first, FwdIt last, const Transform& transform) noexcept 7 | { 8 | if (first == last) 9 | { 10 | return last; 11 | } 12 | using ValType = decltype(*first); 13 | FwdIt result = first; 14 | FwdIt it = first; 15 | std::advance(it, 1); 16 | for (FwdIt it = first; it != last; std::advance(it,1)) 17 | { 18 | if (transform(*it) < transform(*result)) 19 | { 20 | result = it; 21 | } 22 | } 23 | return result; 24 | } 25 | 26 | template 27 | [[nodiscard]] inline FwdIt max_element_transform(FwdIt first, FwdIt last, const Transform& transform) noexcept 28 | { 29 | if (first == last) 30 | { 31 | return last; 32 | } 33 | using ValType = decltype(*first); 34 | FwdIt result = first; 35 | FwdIt it = first; 36 | std::advance(it, 1); 37 | for (; it != last; std::advance(it,1)) 38 | { 39 | if (transform(*it) > transform(*result)) 40 | { 41 | result = it; 42 | } 43 | } 44 | return result; 45 | } 46 | 47 | template 48 | [[nodiscard]] inline std::pair minmax_element_transform(FwdIt first, FwdIt last, const Transform& transform) noexcept 49 | { 50 | if (first == last) 51 | { 52 | return std::pair{ first,last }; 53 | } 54 | using ValType = decltype(*first); 55 | FwdIt min = first; 56 | FwdIt max = first; 57 | FwdIt it = first; 58 | std::advance(it, 1); 59 | for (FwdIt it = first; it != last; std::advance(it,1)) 60 | { 61 | if (transform(*it) < transform(*min)) 62 | { 63 | min = it; 64 | } 65 | else if (transform(*it) > transform(*max)) 66 | { 67 | max = it; 68 | } 69 | } 70 | return std::pair{ min,max }; 71 | } 72 | 73 | template 74 | [[nodiscard]] inline auto min_transform(FwdIt first, FwdIt last, const Transform& transform) noexcept 75 | { 76 | return *min_element_transform(first, last, transform); 77 | } 78 | 79 | template 80 | [[nodiscard]] inline auto max_transform(FwdIt first, FwdIt last, const Transform& transform) noexcept 81 | { 82 | return *max_element_transform(first, last, transform); 83 | } 84 | 85 | template 86 | [[nodiscard]] inline auto minmax_transform(FwdIt first, FwdIt last, const Transform& transform) noexcept 87 | { 88 | const auto [min,max] = minmax_element_transform(first, last, transform); 89 | return std::pair{ *min,*max }; 90 | } 91 | 92 | template 93 | struct Larger 94 | { 95 | [[nodiscard]] constexpr T operator()(const T& x, const T& y) const noexcept 96 | { 97 | return std::max(x,y); 98 | } 99 | }; 100 | 101 | template 102 | struct Smaller 103 | { 104 | [[nodiscard]] constexpr T operator()(const T& x, const T& y) const noexcept 105 | { 106 | return std::min(x, y); 107 | } 108 | }; 109 | 110 | namespace utils_internal 111 | { 112 | template 113 | [[nodiscard]] T arg_folder(const BinaryOp& op, const T& first_arg, const T& second_arg) 114 | { 115 | return op(first_arg,second_arg); 116 | } 117 | 118 | template 119 | [[nodiscard]] T arg_folder(const BinaryOp& op, const T& first_arg, const T& second_arg, const T& third_arg, const ExtraArgs&...extra_args) 120 | { 121 | return op(first_arg,arg_folder(op,second_arg,third_arg,extra_args...)); 122 | } 123 | } 124 | 125 | template 126 | [[nodiscard]] auto min(const Args&... args) noexcept 127 | { 128 | static_assert(sizeof...(Args) >= 2,"utils::min must be called with at least two arguments"); 129 | } 130 | 131 | template 132 | [[nodiscard]] T max(const T& FirstArg, const T& SecondArg) 133 | { 134 | return Larger{}(FirstArg, SecondArg); 135 | } 136 | 137 | template 138 | [[nodiscard]] T max(const T& FirstArg, const T& SecondArg, const T& ThirdArg, const Args&... RestOfArgs) 139 | { 140 | return Larger{}(FirstArg, max(SecondArg, ThirdArg, RestOfArgs...)); 141 | } 142 | 143 | namespace ranges 144 | { 145 | template 146 | [[nodiscard]] inline auto min_element_transform(RangeType&& range, const Transform& transform) noexcept 147 | { 148 | return utils::min_element_transform(range.begin(),range.end(),transform); 149 | } 150 | 151 | template 152 | [[nodiscard]] inline auto max_element_transform(RangeType&& range, const Transform& transform) noexcept 153 | { 154 | return utils::max_element_transform(range.begin(), range.end(), transform); 155 | } 156 | 157 | template 158 | [[nodiscard]] inline auto minmax_element_transform(RangeType&& range, const Transform& transform) noexcept 159 | { 160 | return utils::minmax_element_transform(range.begin(), range.end(), transform); 161 | } 162 | 163 | template 164 | [[nodiscard]] inline auto min_transform(RangeType&& range, const Transform& transform) noexcept 165 | { 166 | return utils::min_transform(range.begin(), range.end(), transform); 167 | } 168 | 169 | template 170 | [[nodiscard]] inline auto max_transform(RangeType&& range, const Transform& transform) noexcept 171 | { 172 | return utils::max_transform(range.begin(), range.end(), transform); 173 | } 174 | 175 | template 176 | [[nodiscard]] inline auto minmax_transform(RangeType&& range, const Transform& transform) noexcept 177 | { 178 | return utils::minmax_transform(range.begin(), range.end(), transform); 179 | } 180 | } 181 | } -------------------------------------------------------------------------------- /advent_of_code/utils/conway_simulation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "advent/advent_assert.h" 13 | #include "sorted_vector.h" 14 | #include "range_contains.h" 15 | #include "erase_remove_if.h" 16 | #include "shared_lock_guard.h" 17 | 18 | namespace utils::conway_simulation 19 | { 20 | // CoordType: a type describing coordinates 21 | // UpdateCellFunc: a function with the signature: bool(const CoordType& coord, bool is_on, std::size_t number_of_on_neighbours) 22 | // GatherNeighboursFunc: a function with the signature std::vector(const CoordType&) 23 | // Results are cached and assumed to not change tick-to-tick. 24 | template 25 | class state 26 | { 27 | public: 28 | using coord_type = CoordType; 29 | 30 | state(UpdateCellFunc update_func, GatherNeighboursFunc gather_neighbours_func) 31 | : m_on_cells{} 32 | , m_update_cell{ std::move(update_func) } 33 | , m_gather_neighbours{ std::move(gather_neighbours_func) } 34 | {} 35 | 36 | template 37 | state(ItType init_start, ItType init_end, UpdateCellFunc update, GatherNeighboursFunc gather) 38 | : m_on_cells(init_start,init_end) 39 | , m_update_cell{ std::move(update) } 40 | , m_gather_neighbours{ std::move(gather) } 41 | { 42 | m_on_cells.unique(); 43 | } 44 | 45 | [[nodiscard]] bool is_cell_on(const CoordType& cell) const noexcept { return m_on_cells.contains(cell); } 46 | [[nodiscard]] std::size_t number_of_cells_on() const { return m_on_cells.size(); } 47 | void tick(); 48 | void tick_n_times(std::size_t num_ticks); 49 | template 50 | void set_state(ItType first, ItType last) 51 | { 52 | m_on_cells = sorted_vector(first, last); 53 | m_on_cells.unique(); 54 | } 55 | private: 56 | // Primary state 57 | sorted_vector m_on_cells; 58 | UpdateCellFunc m_update_cell; 59 | GatherNeighboursFunc m_gather_neighbours; 60 | 61 | // Spare stuff for optimisation 62 | mutable std::map> m_cached_neighbours; 63 | mutable std::shared_mutex m_cached_neighbours_lock; 64 | sorted_vector m_next_cells; 65 | sorted_vector m_relevant_cells; 66 | 67 | // Private functions 68 | 69 | const std::vector& get_neighbours(const CoordType& coords) const; 70 | }; 71 | 72 | template 73 | auto make_range_update( 74 | const std::pair& turn_on_range, 75 | const std::pair& turn_off_range) 76 | { 77 | AdventCheck(turn_on_range.first <= turn_on_range.second); 78 | AdventCheck(turn_off_range.first <= turn_off_range.second); 79 | return [=](const CoordType&, bool is_on, std::size_t num_neighbours_on) 80 | { 81 | if (is_on) 82 | { 83 | return range_contains(num_neighbours_on, turn_off_range.first, turn_off_range.second); 84 | } 85 | // else 86 | return range_contains(num_neighbours_on, turn_on_range.first, turn_on_range.second); 87 | }; 88 | } 89 | 90 | template 91 | auto make_default_gather_func(int range) 92 | { 93 | AdventCheck(range > 0); 94 | using CoordType = std::array; 95 | return [range](const CoordType& cell) 96 | { 97 | std::vector result; 98 | result.reserve(static_cast(std::pow(2 * range + 1, DIMS)) - 1); 99 | CoordType current_offset; 100 | std::fill(begin(current_offset), end(current_offset), 0 - range); 101 | auto is_current_all = [¤t_offset](int val) 102 | { 103 | return std::all_of(begin(current_offset), end(current_offset), [val](int v) {return v == val; }); 104 | }; 105 | while (true) 106 | { 107 | if (!is_current_all(0)) 108 | { 109 | result.push_back(current_offset); 110 | } 111 | 112 | // Increment. 113 | const auto inc_it = std::find_if(begin(current_offset), end(current_offset), 114 | [range](int val) {return val != range; }); 115 | if (inc_it == end(current_offset)) // We reached the end. 116 | { 117 | break; 118 | } 119 | AdventCheck(*inc_it < range); 120 | ++(*inc_it); 121 | std::fill(begin(current_offset), inc_it, 0 - range); 122 | } 123 | 124 | std::transform(begin(result), end(result), begin(result), 125 | [&cell](CoordType offset) 126 | { 127 | std::transform(begin(cell), end(cell), begin(offset), begin(offset), std::plus{}); 128 | return offset; 129 | }); 130 | 131 | return result; 132 | }; 133 | } 134 | 135 | template 136 | auto make_default_gather_func(int range, const std::array& limits) 137 | { 138 | using CoordType = std::array; 139 | return [range, limits](const CoordType& cell) 140 | { 141 | const auto base_func = make_default_gather_func(range); 142 | auto base_result = base_func(cell); 143 | erase_remove_if(base_result, 144 | [&limits](const CoordType& c) 145 | { 146 | for (std::size_t i = 0; i < c.size(); ++i) 147 | { 148 | if (!range_contains(c[i], 0, static_cast(limits[i]-1))) 149 | { 150 | return true; 151 | } 152 | } 153 | return false; 154 | }); 155 | return base_result; 156 | }; 157 | } 158 | 159 | template 160 | auto make_default_gather_func(int range, std::size_t limit) 161 | { 162 | std::array limits; 163 | std::fill(begin(limits), end(limits), limit); 164 | return make_default_gather_func(range, limits); 165 | } 166 | 167 | template 168 | auto make_conway_state(UpdateCellFunc update, GatherNeighboursFunc gather) 169 | { 170 | return state(std::move(update), std::move(gather)); 171 | } 172 | 173 | template 174 | auto make_conway_state(ItType first, ItType last, UpdateCellFunc update, GatherNeighboursFunc gather) 175 | { 176 | return state(first,last,std::move(update), std::move(gather)); 177 | } 178 | 179 | template 180 | inline void state::tick_n_times(std::size_t num_ticks) 181 | { 182 | for (std::size_t i = 0; i < num_ticks; ++i) 183 | { 184 | tick(); 185 | } 186 | } 187 | 188 | template 189 | inline void conway_simulation::state::tick() 190 | { 191 | // Clear the cached containers. 192 | m_next_cells.clear(); 193 | m_relevant_cells.clear(); 194 | 195 | // Gather all relevant cells 196 | std::mutex relevant_cells_lock; 197 | auto gather_relevant = [this,&relevant_cells_lock](const CoordType& on_cell) 198 | { 199 | const auto& neighbours = get_neighbours(on_cell); 200 | std::lock_guard relevant_cells_guard{ relevant_cells_lock }; 201 | m_relevant_cells.reserve((neighbours.size() + 1) * m_on_cells.size()); 202 | m_relevant_cells.push_back(on_cell); 203 | std::copy(begin(neighbours), end(neighbours), std::back_inserter(m_relevant_cells)); 204 | }; 205 | std::for_each(std::execution::unseq, begin(m_on_cells), end(m_on_cells), gather_relevant); 206 | 207 | m_relevant_cells.unique(); 208 | 209 | std::copy_if(begin(m_relevant_cells), end(m_relevant_cells), std::back_inserter(m_next_cells), 210 | [this](const CoordType& cell) 211 | { 212 | const auto& neighbours = get_neighbours(cell); 213 | const std::size_t num_neighbours_on = std::count_if(begin(neighbours), end(neighbours), 214 | [this](const CoordType& neighbour) 215 | { 216 | return is_cell_on(neighbour); 217 | }); 218 | return m_update_cell(cell, is_cell_on(cell), num_neighbours_on); 219 | }); 220 | 221 | m_on_cells.swap(m_next_cells); 222 | } 223 | 224 | template 225 | inline const std::vector& conway_simulation::state::get_neighbours(const CoordType& coords) const 226 | { 227 | { 228 | utils::shared_lock_guard guard{ m_cached_neighbours_lock }; 229 | const auto find_result = m_cached_neighbours.lower_bound(coords); 230 | 231 | // If we have a chached result, return that. 232 | if (find_result != end(m_cached_neighbours) && find_result->first == coords) 233 | { 234 | return find_result->second; 235 | } 236 | } 237 | 238 | // Otherwise gather neighbours and cache the result. 239 | auto neighbours = std::make_pair(coords, m_gather_neighbours(coords)); 240 | std::lock_guard guard{ m_cached_neighbours_lock }; 241 | const auto insert_it = m_cached_neighbours.insert(std::move(neighbours)); 242 | AdventCheck(insert_it.second); 243 | return insert_it.first->second; 244 | } 245 | } -------------------------------------------------------------------------------- /advent_of_code/utils/coords3d.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace utils 7 | { 8 | template 9 | struct coords3d 10 | { 11 | CoordsType x; 12 | CoordsType y; 13 | CoordsType z; 14 | constexpr coords3d(CoordsType i_x, CoordsType i_y, CoordsType i_z) noexcept 15 | : x{ i_x }, y{ i_y }, z{ i_z } {} 16 | constexpr explicit coords3d(CoordsType init) noexcept : coords3d{ init,init,init } {} 17 | constexpr coords3d() noexcept : coords3d{ CoordsType{0} } {} 18 | constexpr coords3d(const coords3d&) noexcept = default; 19 | template requires std::is_convertible_v 20 | constexpr coords3d& operator=(const coords3d& other) noexcept 21 | { 22 | x = other.x; 23 | y = other.y; 24 | z = other.z; 25 | return *this; 26 | } 27 | constexpr coords3d& operator+=(const coords3d& c) noexcept 28 | { 29 | x += c.x; 30 | y += c.y; 31 | z += c.z; 32 | return *this; 33 | } 34 | constexpr auto operator<=>(const coords3d& other) const noexcept 35 | { 36 | auto to_tuple = [](const coords3d& c) 37 | { 38 | return std::tuple{ c.z,c.x,c.y }; 39 | }; 40 | return to_tuple(*this) <=> to_tuple(other); 41 | } 42 | constexpr bool operator==(const coords3d&) const noexcept = default; 43 | }; 44 | 45 | template 46 | auto operator+(const coords3d& l, const coords3d& r) noexcept 47 | { 48 | using ResultType = decltype(l.x + r.x); 49 | return coords3d{l.x + r.x, l.y + r.y, l.z + r.z}; 50 | } 51 | 52 | template 53 | auto operator/(const coords3d& l, RType r) noexcept 54 | { 55 | using ResultType = decltype(l.x / r); 56 | return coords3d{l.x / r, l.y / r, l.z / r}; 57 | } 58 | 59 | template 60 | std::ostream& operator<<(std::ostream& oss, const coords3d& coords) 61 | { 62 | oss << coords.x << "," << coords.y << "," << coords.z; 63 | return oss; 64 | } 65 | } -------------------------------------------------------------------------------- /advent_of_code/utils/coords_iterators.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "coords.h" 4 | #include "int_range.h" 5 | 6 | 7 | namespace utils::coords_iterators 8 | { 9 | namespace internal_helpers 10 | { 11 | template 12 | inline constexpr std::size_t width(const basic_coords& first, const basic_coords& last) noexcept 13 | { 14 | const auto [x_min, x_max] = std::minmax(first.x, last.x); 15 | const auto w = x_max - x_min; 16 | return static_cast(w); 17 | } 18 | 19 | template 20 | inline constexpr std::ptrdiff_t swidth(const basic_coords& first, const basic_coords& last) noexcept 21 | { 22 | return static_cast(width(first, last)); 23 | } 24 | 25 | template 26 | inline constexpr std::size_t height(const basic_coords& first, const basic_coords& last) noexcept 27 | { 28 | const auto [y_min, y_max] = std::minmax(first.y, last.y); 29 | const auto h = y_max - y_min; 30 | return static_cast(h); 31 | } 32 | 33 | template 34 | inline constexpr std::ptrdiff_t sheight(const basic_coords& first, const basic_coords& last) noexcept 35 | { 36 | return static_cast(height(first, last)); 37 | } 38 | 39 | template 40 | inline constexpr std::size_t size(const basic_coords& first, const basic_coords& last) noexcept 41 | { 42 | const auto w = width(first, last); 43 | const auto h = height(first, last); 44 | return w * h; 45 | } 46 | 47 | template 48 | inline constexpr std::ptrdiff_t ssize(const basic_coords& first, const basic_coords& last) noexcept 49 | { 50 | return static_cast(size(first, last)); 51 | } 52 | 53 | template 54 | inline T get_at_idx(T first, T last, std::size_t idx) 55 | { 56 | const bool incrementing = (first <= last); 57 | const T tidx = static_cast(idx); 58 | const T result = incrementing ? first + tidx : first - tidx; 59 | return result; 60 | }; 61 | 62 | template 63 | class elem_adaptor 64 | { 65 | basic_coords start; 66 | basic_coords finish; 67 | public: 68 | constexpr elem_adaptor(const basic_coords& first, const basic_coords& last) : start{ first }, finish{ last } {} 69 | constexpr basic_coords operator()(std::size_t idx) const noexcept 70 | { 71 | AdventCheck(idx < size(start, finish)); 72 | const auto w = width(start, finish); 73 | const auto widx = idx % w; 74 | const auto hidx = idx / w; 75 | const T x = get_at_idx(start.x, finish.x, widx); 76 | const T y = get_at_idx(start.y, finish.y, hidx); 77 | return basic_coords{x, y}; 78 | } 79 | }; 80 | 81 | template 82 | using elem_range_base = int_range_adaptor>; 83 | } 84 | 85 | template 86 | class elem_range : public internal_helpers::elem_range_base 87 | { 88 | public: 89 | constexpr elem_range(const basic_coords& first, const basic_coords& last) noexcept 90 | : internal_helpers::elem_range_base{ internal_helpers::elem_adaptor{first,last} , internal_helpers::ssize(first,last) } 91 | {} 92 | explicit constexpr elem_range(const basic_coords& last) noexcept : elem_range{ basic_coords{},last } {} 93 | 94 | static elem_range get_row(T x_start, T x_finish, T y_const) noexcept 95 | { 96 | const basic_coords first{ x_start,y_const }; 97 | const basic_coords last{ x_finish,y_const + 1 }; 98 | return elem_range{first, last}; 99 | } 100 | 101 | static elem_range get_row(const basic_coords& first, T x_finish) noexcept 102 | { 103 | return get_row(first.x, x_finish, first.y); 104 | } 105 | 106 | static elem_range get_row(T x_start, const basic_coords& finish) noexcept 107 | { 108 | return get_row(x_start, finish.x, finish.y); 109 | } 110 | 111 | static elem_range get_row(const basic_coords& start, const basic_coords& finish) noexcept 112 | { 113 | AdventCheck(start.y == finish.y); 114 | return get_row(start, finish.x); 115 | } 116 | 117 | static elem_range get_column(T x_const, T y_start, T y_finish) noexcept 118 | { 119 | const basic_coords first{ x_const,y_start }; 120 | const basic_coords last{ x_const + 1,y_finish }; 121 | return elem_range{first, last}; 122 | } 123 | 124 | static elem_range get_column(const basic_coords& first, T y_finish) noexcept 125 | { 126 | return get_column(first.x, first.y, y_finish); 127 | } 128 | 129 | static elem_range get_column(T y_start, const basic_coords& finish) noexcept 130 | { 131 | return get_column(finish.x, y_start, finish.y); 132 | } 133 | 134 | static elem_range get_column(const basic_coords& start, const basic_coords& finish) noexcept 135 | { 136 | AdventCheck(start.x == finish.x); 137 | return get_column(start, finish.y); 138 | } 139 | 140 | static elem_range get_range(const basic_coords& start, const basic_coords& finish) noexcept 141 | { 142 | const bool going_right = finish.x >= start.x; 143 | const bool going_up = finish.y >= start.y; 144 | const T finish_x = going_right ? finish.x + 1 : finish.x-1; 145 | const T finish_y = going_up ? finish.y + 1 : finish.y - 1; 146 | return elem_range{start, basic_coords{finish_x,finish_y} }; 147 | } 148 | }; 149 | 150 | namespace internal_helpers 151 | { 152 | template 153 | class row_adaptor 154 | { 155 | basic_coords start; 156 | basic_coords finish; 157 | public: 158 | constexpr row_adaptor(const basic_coords& first, const basic_coords& last) noexcept : start{ first }, finish{ last } {} 159 | constexpr elem_range operator[](std::size_t idx) const noexcept 160 | { 161 | AdventCheck(idx < height(start, finish)); 162 | const T y = get_at_idx(start.y, finish.y, idx); 163 | return elem_range::get_row(start.x, finish.x, y); 164 | } 165 | }; 166 | 167 | template 168 | using row_range_base = int_range_adaptor>; 169 | 170 | template 171 | class column_adaptor 172 | { 173 | basic_coords start; 174 | basic_coords finish; 175 | public: 176 | constexpr column_adaptor(const basic_coords& first, const basic_coords& last) noexcept : start{ first }, finish{ last } {} 177 | constexpr elem_range operator[](std::size_t idx) const noexcept 178 | { 179 | AdventCheck(idx < width(start, finish)); 180 | const T x = get_at_idx(start.x, finish.x, idx); 181 | return elem_range::get_column(x, start.y, finish.y); 182 | } 183 | }; 184 | 185 | template 186 | using column_range_base = int_range_adaptor>; 187 | } 188 | 189 | template 190 | class row_range : public internal_helpers::row_range_base 191 | { 192 | public: 193 | constexpr row_range(const basic_coords& first, const basic_coords& last) 194 | : int_range_adaptor>{ internal_helpers::row_adaptor{first,last},internal_helpers::height(first,last) } {} 195 | explicit constexpr row_range(const basic_coords& last) : row_range{ basic_coords{},last } {} 196 | }; 197 | 198 | template 199 | class column_range : internal_helpers::column_range_base 200 | { 201 | public: 202 | constexpr column_range(const basic_coords& first, const basic_coords& last) 203 | : int_range_adaptor>{ internal_helpers::column_adaptor{first,last},internal_helpers::width(first,last) } {} 204 | explicit constexpr column_range(const basic_coords& last) : column_range{ basic_coords{},last } {} 205 | }; 206 | } -------------------------------------------------------------------------------- /advent_of_code/utils/enums.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace utils 7 | { 8 | template 9 | concept enumeration = std::is_enum_v; 10 | 11 | template > 12 | inline constexpr OutType to_idx(InType in) noexcept 13 | { 14 | return static_cast(in); 15 | } 16 | 17 | [[nodiscard]] inline constexpr auto enum_order(enumeration auto left, enumeration auto right) noexcept 18 | { 19 | const auto left_val = to_idx(left); 20 | const auto right_val = to_idx(right); 21 | return left_val <=> right_val; 22 | } 23 | 24 | template 25 | struct EnumSorter 26 | { 27 | [[nodiscard]] constexpr auto operator()(T left, T right) const noexcept 28 | { 29 | return enum_order(left,right); 30 | } 31 | }; 32 | 33 | 34 | } -------------------------------------------------------------------------------- /advent_of_code/utils/erase_remove_if.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace utils 6 | { 7 | 8 | template 9 | inline void erase_remove_if(Cont& c, Pred p) 10 | { 11 | c.erase(std::remove_if(begin(c), end(c), p), end(c)); 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /advent_of_code/utils/has_duplicates.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace utils 6 | { 7 | template 8 | bool has_duplicates(FwdIt start_it, FwdIt end_it) 9 | { 10 | if (start_it == end_it) return false; 11 | const auto next_it = [start_it]() 12 | { 13 | auto result = start_it; 14 | std::advance(result, 1); 15 | return result; 16 | }(); 17 | 18 | for (auto it = next_it; it != end_it; std::advance(it,1)) 19 | { 20 | if (*start_it == *it) return true; 21 | } 22 | 23 | return has_duplicates(next_it, end_it); 24 | } 25 | 26 | namespace ranges 27 | { 28 | template 29 | bool has_duplicates(const Container& container) 30 | { 31 | return utils::has_duplicates(std::cbegin(container), std::cend(container)); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /advent_of_code/utils/index_iterator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "advent/advent_assert.h" 9 | 10 | namespace utils 11 | { 12 | 13 | class index_iterator_base : public std::random_access_iterator_tag 14 | { 15 | public: 16 | template 17 | constexpr static auto is_index_iterator(T in) 18 | { 19 | static_assert(std::is_base_of_v); 20 | return std::forward(in); 21 | } 22 | }; 23 | 24 | // Container must have operator[] defined, and 25 | // a size() method. 26 | template 27 | class index_iterator : public index_iterator_base 28 | { 29 | private: 30 | constexpr static auto get_index_return_type() { return Container{} [0] ; } 31 | public: 32 | // Traits 33 | using difference_type = std::ptrdiff_t; 34 | using value_type = typename Container::value_type; 35 | using pointer = typename Container::pointer_type; 36 | using reference = typename Container::reference_type; 37 | using iterator_category = std::random_access_iterator_tag; 38 | 39 | private: 40 | Container* container = nullptr; 41 | 42 | protected: 43 | difference_type pos = 0; 44 | 45 | constexpr index_iterator(Container* c, difference_type p) noexcept : container{ c }, pos{ p }{} 46 | constexpr reference get_from_real_index(difference_type index) const 47 | { 48 | AdventCheck(container != nullptr); 49 | AdventCheck(index >= 0); 50 | AdventCheck(static_castsize())>(index) < container->size()); 51 | return container->operator[](index); 52 | } 53 | public: 54 | // Constructors 55 | constexpr index_iterator() noexcept {} 56 | constexpr index_iterator(const index_iterator&) noexcept = default; 57 | constexpr index_iterator(index_iterator&&) noexcept = default; 58 | constexpr index_iterator& operator=(const index_iterator&) noexcept = default; 59 | constexpr index_iterator& operator=(index_iterator&&) noexcept = default; 60 | 61 | constexpr static index_iterator begin(Container& c) noexcept { return index_iterator{ &c,0 }; } 62 | constexpr static index_iterator end(Container& c) noexcept { return index_iterator{ &c,static_cast(c.size()) }; } 63 | 64 | // Dereference 65 | constexpr virtual reference operator[](difference_type offset) const 66 | { 67 | return get_from_real_index(pos + offset); 68 | } 69 | 70 | constexpr decltype(auto) operator*() const { return (*this)[0]; } 71 | 72 | // Comparisons 73 | constexpr std::strong_ordering operator<=>(const index_iterator& other) const noexcept 74 | { 75 | AdventCheck(container == other.container); 76 | return pos <=> other.pos; 77 | } 78 | // These aren't defined YET on my impementation 79 | constexpr bool operator==(const index_iterator& other) const noexcept 80 | { 81 | return (*this <=> other) == 0; 82 | } 83 | constexpr bool operator!=(const index_iterator& other) const noexcept { return !(*this == other); } 84 | constexpr bool operator<(const index_iterator& other) const noexcept 85 | { 86 | return (*this <=> other) < 0; 87 | } 88 | constexpr bool operator>(const index_iterator& other) const noexcept { return other < *this; } 89 | constexpr bool operator<=(const index_iterator& other) const noexcept { return !(*this > other); } 90 | constexpr bool operator>=(const index_iterator& other) const noexcept { return !(*this < other); } 91 | 92 | // Arithmetic 93 | constexpr virtual index_iterator& operator+=(difference_type offset) noexcept 94 | { 95 | pos += offset; 96 | return *this; 97 | } 98 | constexpr index_iterator& operator-=(difference_type offset) noexcept 99 | { 100 | return operator+=(-offset); 101 | } 102 | constexpr index_iterator& operator++() noexcept { return operator+=(1); } 103 | constexpr index_iterator& operator--() noexcept { return operator-=(1); } 104 | constexpr index_iterator operator++(int) noexcept 105 | { 106 | const auto res = operator++(); 107 | return res; 108 | } 109 | constexpr index_iterator operator--(int) noexcept 110 | { 111 | const auto res = operator--(); 112 | return res; 113 | } 114 | constexpr index_iterator operator+(difference_type offset) const noexcept 115 | { 116 | auto res = *this; 117 | res += offset; 118 | return res; 119 | } 120 | constexpr index_iterator operator-(difference_type offset) const noexcept 121 | { 122 | auto res = *this; 123 | res -= offset; 124 | return res; 125 | } 126 | constexpr difference_type operator-(index_iterator other) const noexcept 127 | { 128 | AdventCheck(container == other.container); 129 | return static_cast(pos) - static_cast(other.pos); 130 | } 131 | }; 132 | 133 | template 134 | index_iterator operator+(typename index_iterator::difference_type left, index_iterator right) 135 | { 136 | return right + left; 137 | } 138 | 139 | template 140 | using const_index_iterator = index_iterator; 141 | 142 | template 143 | class reverse_index_iterator : public index_iterator 144 | { 145 | public: 146 | using Base = index_iterator; 147 | using difference_type = Base::difference_type; 148 | using value_type = Base::value_type; 149 | using pointer = Base::pointer; 150 | using reference = Base::reference; 151 | using iterator_category = Base::iterator_category; 152 | private: 153 | constexpr reverse_index_iterator(Container* c, difference_type p) noexcept : Base{ c,p } {} 154 | using Base::pos; 155 | using Base::get_from_real_index; 156 | public: 157 | constexpr reverse_index_iterator() noexcept : index_iterator{} {} 158 | constexpr reverse_index_iterator& operator+=(difference_type offset) noexcept override final 159 | { 160 | pos -= offset; 161 | return *this; 162 | } 163 | 164 | constexpr virtual reference operator[](difference_type offset) const noexcept override final 165 | { 166 | // This looks weird, but is done to make this act like the standard 167 | // reverse iterators when they are converted to reverse ones. 168 | return get_from_real_index(pos - offset); 169 | } 170 | 171 | constexpr static reverse_index_iterator begin(Container& c) noexcept 172 | { 173 | return reverse_index_iterator{ &c, static_cast(c.size() - 1) }; 174 | } 175 | 176 | constexpr static reverse_index_iterator end(Container& c) noexcept 177 | { 178 | return reverse_index_iterator{ &c,-1 }; 179 | } 180 | }; 181 | 182 | template 183 | using const_reverse_index_iterator = reverse_index_iterator; 184 | 185 | // Use INDEX_ITERATOR_MEMBER_BOILERPLATE to add begin, end, etc... class functions. 186 | // Use INDEX_ITERATOR_NONMEMBER_BOILERPLATE to add standalone begin, end, etc... class functions 187 | // Use INDEX_ITERATOR_NONMEMBER_TEMPLATE_BOILERPLATE for templates. 188 | 189 | #define INDEX_ITERATOR_DECL_ITERATOR_TYPE_NONCONST(ITERATOR,BEGIN,END) \ 190 | constexpr auto BEGIN() noexcept { \ 191 | return index_iterator_base::is_index_iterator(ITERATOR::begin(*this)); \ 192 | } \ 193 | constexpr auto END() noexcept { \ 194 | return index_iterator_base::is_index_iterator(ITERATOR::end(*this)); \ 195 | } 196 | 197 | #define INDEX_ITERATOR_DECL_ITERATOR_TYPE_CONST(ITERATOR,BEGIN,END) \ 198 | constexpr auto BEGIN() const noexcept { \ 199 | return index_iterator_base::is_index_iterator(ITERATOR::begin(*this)); \ 200 | } \ 201 | constexpr auto END() const noexcept { \ 202 | return index_iterator_base::is_index_iterator(ITERATOR::end(*this)); \ 203 | } 204 | 205 | #define INDEX_ITERATOR_MEMBER_BOILERPLATE(...) \ 206 | using iterator = index_iterator<__VA_ARGS__>; \ 207 | using const_iterator = const_index_iterator<__VA_ARGS__>; \ 208 | using reverse_iterator = reverse_index_iterator<__VA_ARGS__>; \ 209 | using const_reverse_iterator = const_reverse_index_iterator<__VA_ARGS__>; \ 210 | INDEX_ITERATOR_DECL_ITERATOR_TYPE_NONCONST(iterator,begin,end) \ 211 | INDEX_ITERATOR_DECL_ITERATOR_TYPE_NONCONST(reverse_iterator,rbegin,rend) \ 212 | INDEX_ITERATOR_DECL_ITERATOR_TYPE_CONST(const_iterator,begin,end) \ 213 | INDEX_ITERATOR_DECL_ITERATOR_TYPE_CONST(const_iterator,cbegin,cend) \ 214 | INDEX_ITERATOR_DECL_ITERATOR_TYPE_CONST(const_reverse_iterator,rbegin,rend) \ 215 | INDEX_ITERATOR_DECL_ITERATOR_TYPE_CONST(const_reverse_iterator,crbegin,crend) 216 | 217 | #define INDEX_ITERATOR_MEMBER_BOILERPLATE_CONST(...) \ 218 | using iterator = const_index_iterator<__VA_ARGS__>; \ 219 | using const_iterator = const_index_iterator<__VA_ARGS__>; \ 220 | using reverse_iterator = const_reverse_index_iterator<__VA_ARGS__>; \ 221 | using const_reverse_iterator = const_reverse_index_iterator<__VA_ARGS__>; \ 222 | INDEX_ITERATOR_DECL_ITERATOR_TYPE_NONCONST(const_iterator,begin,end) \ 223 | INDEX_ITERATOR_DECL_ITERATOR_TYPE_NONCONST(const_reverse_iterator,rbegin,rend) \ 224 | INDEX_ITERATOR_DECL_ITERATOR_TYPE_CONST(const_iterator,begin,end) \ 225 | INDEX_ITERATOR_DECL_ITERATOR_TYPE_CONST(const_iterator,cbegin,cend) \ 226 | INDEX_ITERATOR_DECL_ITERATOR_TYPE_CONST(const_reverse_iterator,rbegin,rend) \ 227 | INDEX_ITERATOR_DECL_ITERATOR_TYPE_CONST(const_reverse_iterator,crbegin,crend) 228 | 229 | } 230 | 231 | using std::begin; 232 | using std::end; 233 | using std::cbegin; 234 | using std::cend; 235 | using std::rbegin; 236 | using std::rend; 237 | using std::crbegin; 238 | -------------------------------------------------------------------------------- /advent_of_code/utils/index_iterator2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "advent/advent_assert.h" 6 | 7 | namespace utils 8 | { 9 | template 10 | class const_index_iterator2 11 | { 12 | protected: 13 | const Container* container; 14 | std::size_t pos; 15 | public: 16 | using iterator_category = std::random_access_iterator_tag; 17 | using value_type = typename Container::value_type; 18 | using difference_type = typename Container::difference_type; 19 | using pointer = typename Container::pointer_type; 20 | using reference = typename Container::reference_type; 21 | const_index_iterator2(const Container& c, std::size_t initial_pos) : container{ &c }, pos{ initial_pos }{} 22 | const_index_iterator2() : container{ nullptr }, pos{ 0 }{} 23 | const_index_iterator2(const const_index_iterator2&) = default; 24 | const_index_iterator2(const_index_iterator2&&) = default; 25 | const_index_iterator2& operator=(const const_index_iterator2&) = default; 26 | const_index_iterator2& operator=(const_index_iterator2&&) = default; 27 | 28 | bool operator==(const const_index_iterator2& other) const 29 | { 30 | AdventCheck(container == other.container); 31 | return pos == other.pos; 32 | } 33 | 34 | bool operator!=(const const_index_iterator2& other) const 35 | { 36 | return !(operator==(other)); 37 | } 38 | 39 | difference_type operator-(const const_index_iterator2& other) const 40 | { 41 | AdventCheck(container == other.container); 42 | return static_cast(pos) - other.pos; 43 | } 44 | 45 | // friend const_index_iterator2& operator+=(const_index_iterator2& lhs, difference_type rhs); 46 | // friend const_index_iterator2& operator-=(const_index_iterator2& lhs, difference_type rhs); 47 | const value_type& operator*() const { return (*container)[pos]; } 48 | const value_type& operator->() const { return (*container)[pos]; } 49 | const_index_iterator2& operator+=(difference_type rhs) { pos += rhs; return *this; } 50 | const_index_iterator2& operator-=(difference_type rhs) { pos -= rhs; return *this; } 51 | const_index_iterator2& operator++() { return (*this) += difference_type{1}; } 52 | const_index_iterator2& operator--() { return (*this) -= difference_type{1}; } 53 | const_index_iterator2 operator++(int) 54 | { 55 | const const_index_iterator2 res{ *this }; 56 | ++(*this); 57 | return res; 58 | } 59 | const_index_iterator2 operator--(int) 60 | { 61 | const const_index_iterator2 res{ *this }; 62 | --(*this); 63 | return res; 64 | } 65 | }; 66 | 67 | template 68 | class index_iterator2 : public const_index_iterator2 69 | { 70 | private: 71 | using const_index_iterator2::container; 72 | using const_index_iterator2::pos; 73 | public: 74 | index_iterator2(const Container& c, std::size_t initial_pos) : const_index_iterator2{ c,initial_pos } {} 75 | index_iterator2() : const_index_iterator2{} {} 76 | index_iterator2(const index_iterator2&) = default; 77 | index_iterator2(index_iterator2&&) = default; 78 | index_iterator2& operator=(const index_iterator2&) = default; 79 | index_iterator2& operator=(index_iterator2&&) = default; 80 | 81 | typename Container::value_type& operator*() const { return (*const_cast(container))[pos]; } 82 | typename Container::value_type& operator->() const { return (*const_cast(container))[pos]; } 83 | index_iterator2& operator+=(int rhs) { pos += rhs; return *this; } 84 | index_iterator2& operator-=(int rhs) { pos -= rhs; return *this; } 85 | index_iterator2& operator++() { return (*this) += 1; } 86 | index_iterator2& operator--() { return (*this) -= 1; } 87 | index_iterator2 operator++(int) 88 | { 89 | const index_iterator2 res{ *this }; 90 | ++(*this); 91 | return res; 92 | } 93 | index_iterator2 operator--(int) 94 | { 95 | const index_iterator2 res{ *this }; 96 | --(*this); 97 | return res; 98 | } 99 | }; 100 | 101 | template 102 | inline const_index_iterator2 make_idx_it_cbegin(const Container& c) 103 | { 104 | return const_index_iterator2{ c,0 }; 105 | } 106 | 107 | template 108 | inline const_index_iterator2 make_idx_it_cend(const Container& c) 109 | { 110 | return const_index_iterator2{ c,c.size() }; 111 | } 112 | 113 | template 114 | inline const_index_iterator2 make_idx_it_begin(const Container& c) 115 | { 116 | return make_idx_it_cbegin(c); 117 | } 118 | 119 | template 120 | inline const_index_iterator2 make_idx_it_end(const Container& c) 121 | { 122 | return make_idx_it_cend(c); 123 | } 124 | 125 | template 126 | inline index_iterator2 make_idx_it_begin(Container& c) 127 | { 128 | return index_iterator2{ c,0 }; 129 | } 130 | 131 | template 132 | inline index_iterator2 make_idx_it_end(Container& c) 133 | { 134 | return index_iterator2{ c,c.size() }; 135 | } 136 | } 137 | 138 | // template 139 | // inline utils::const_index_iterator2& operator+=(utils::const_index_iterator2& lhs, typename utils::const_index_iterator2::difference_type rhs) 140 | // { 141 | // lhs.pos += rhs; 142 | // return lhs; 143 | // } 144 | // 145 | // template 146 | // inline utils::const_index_iterator2& operator-=(utils::const_index_iterator2& lhs, typename utils::const_index_iterator2::difference_type rhs) 147 | // { 148 | // lhs.pos -= rhs; 149 | // return lhs; 150 | // } 151 | 152 | template 153 | inline utils::const_index_iterator2 operator+(const utils::const_index_iterator2& left, int right) 154 | { 155 | auto result = left; 156 | result += right; 157 | return result; 158 | } 159 | 160 | template 161 | inline utils::const_index_iterator2 operator-(const utils::const_index_iterator2& left, int right) 162 | { 163 | auto result = left; 164 | result -= right; 165 | return result; 166 | } 167 | 168 | template 169 | inline utils::index_iterator2 operator+(const utils::index_iterator2& left, int right) 170 | { 171 | auto result = left; 172 | result += right; 173 | return result; 174 | } 175 | 176 | template 177 | inline utils::index_iterator2 operator-(const utils::index_iterator2& left, int right) 178 | { 179 | auto result = left; 180 | result -= right; 181 | return result; 182 | } -------------------------------------------------------------------------------- /advent_of_code/utils/int_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "index_iterator.h" 9 | 10 | namespace utils 11 | { 12 | 13 | template 14 | class int_range 15 | { 16 | INT min; 17 | INT max; 18 | INT stride; 19 | static constexpr INT get_max(INT min, INT max, INT stride) 20 | { 21 | const INT base_size = max - min; 22 | const bool even = (base_size % stride == 0); 23 | if (even) 24 | { 25 | return max; 26 | } 27 | else 28 | { 29 | const INT real_size = (base_size / stride) + 1; 30 | return min + (real_size * stride); 31 | } 32 | } 33 | public: 34 | // Typedefs 35 | using value_type = INT; 36 | using reference_type = INT; 37 | using pointer_type = INT*; 38 | using size_type = std::size_t; 39 | 40 | // Constructors 41 | constexpr int_range(INT start, INT finish, INT stride_length) noexcept : 42 | min{ start }, 43 | max{ get_max(start,finish,stride_length) }, 44 | stride{ stride_length } 45 | {} 46 | constexpr int_range(INT start, INT finish) noexcept : int_range{ start,finish,1 } {} 47 | constexpr int_range(INT finish) noexcept : int_range{ 0,finish } {} 48 | constexpr int_range() : int_range{ 0 } {} 49 | 50 | constexpr bool empty() const noexcept { return size() == 0u; } 51 | 52 | constexpr INT operator[](std::size_t pos) const noexcept { 53 | AdventCheck(pos < size()); 54 | return min + (stride * static_cast(pos)); 55 | } 56 | 57 | constexpr INT front() const noexcept { 58 | return min; 59 | } 60 | 61 | constexpr INT back() const noexcept { 62 | return max - stride; 63 | } 64 | 65 | // Operations 66 | constexpr size_type size() const noexcept { 67 | return static_cast((max - min) / stride); 68 | } 69 | 70 | constexpr int_range reverse() const noexcept requires std::signed_integral 71 | { 72 | return int_range{ max - stride, min - stride, -stride }; 73 | } 74 | 75 | INDEX_ITERATOR_MEMBER_BOILERPLATE_CONST(int_range) 76 | }; 77 | 78 | template requires std::regular_invocable 79 | class int_range_adaptor 80 | { 81 | int_range range; 82 | AdaptorFn adaptor_fn; 83 | constexpr int_range_adaptor(AdaptorFn fn, int_range rng) noexcept : adaptor_fn{ std::move(fn) }, range{ rng } {} 84 | public: 85 | // Typedefs 86 | using reference_type = std::invoke_result_t; 87 | using value_type = std::remove_cvref_t; 88 | using pointer_type = value_type*; 89 | using size_type = std::size_t; 90 | using difference_type = std::ptrdiff_t; 91 | 92 | const AdaptorFn& get_adapter() const noexcept { return adaptor_fn; } 93 | const int_range& get_underlying_range() const noexcept { return range; } 94 | 95 | // Constructors 96 | constexpr int_range_adaptor(AdaptorFn fn, std::ptrdiff_t start, std::ptrdiff_t finish, std::ptrdiff_t stride_length) noexcept : 97 | int_range_adaptor{ std::move(fn) , int_range{start,finish,stride_length} } {} 98 | constexpr int_range_adaptor(AdaptorFn fn, std::ptrdiff_t start, std::ptrdiff_t finish) noexcept 99 | : int_range_adaptor{ std::move(fn), start,finish,1 } {} 100 | constexpr int_range_adaptor(AdaptorFn fn, std::ptrdiff_t finish) noexcept : int_range_adaptor{ std::move(fn), 0,finish } {} 101 | constexpr int_range_adaptor(AdaptorFn fn) : int_range_adaptor{ std::move(fn), 0 } {} 102 | 103 | constexpr decltype(auto) operator[](std::size_t pos) const noexcept { 104 | AdventCheck(pos < size()); 105 | return adaptor_fn(range[pos]); 106 | } 107 | 108 | constexpr decltype(auto) operator[](std::size_t pos) noexcept { 109 | AdventCheck(pos < size()); 110 | return adaptor_fn(range[pos]); 111 | } 112 | 113 | constexpr decltype(auto) front() const noexcept { 114 | return (*this)[range.front()]; 115 | } 116 | 117 | constexpr decltype(auto) front() noexcept 118 | { 119 | return (*this)[range.front()]; 120 | } 121 | 122 | constexpr decltype(auto) back() const noexcept { 123 | return (*this)[range.back()]; 124 | } 125 | 126 | constexpr decltype(auto) back() noexcept { 127 | return (*this)[range.back()]; 128 | } 129 | 130 | // Operations 131 | constexpr size_type size() const noexcept { 132 | return range.size(); 133 | } 134 | 135 | constexpr bool empty() const noexcept 136 | { 137 | return size() == size_type{ 0 }; 138 | } 139 | 140 | constexpr int_range_adaptor reverse() const noexcept 141 | { 142 | return int_range_adaptor{ adaptor_fn, range.reverse() }; 143 | } 144 | 145 | INDEX_ITERATOR_MEMBER_BOILERPLATE_CONST(int_range_adaptor) 146 | }; 147 | } 148 | 149 | -------------------------------------------------------------------------------- /advent_of_code/utils/is_sorted.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace utils 4 | { 5 | template 6 | bool is_sorted(ItType first, ItType last, Predicate pred) noexcept 7 | { 8 | if (first == last) 9 | { 10 | return true; 11 | } 12 | ItType second = first; 13 | ++second; 14 | while (second != last) 15 | { 16 | if (pred(*second, *first)) 17 | { 18 | return false; 19 | } 20 | ++first; 21 | ++second; 22 | } 23 | return true; 24 | } 25 | 26 | template 27 | bool is_sorted(ItType first, ItType last) 28 | { 29 | using ValueType = decltype(*first); 30 | auto predicate = [](const ValueType& l, const ValueType& r) 31 | { 32 | return l < r; 33 | }; 34 | return utils::is_sorted(first, last, predicate); 35 | } 36 | } -------------------------------------------------------------------------------- /advent_of_code/utils/isqrt.cpp: -------------------------------------------------------------------------------- 1 | #include "isqrt.h" 2 | 3 | #include "advent/advent_assert.h" 4 | 5 | namespace 6 | { 7 | uint64_t isqrt_implementation(uint64_t guess_base, uint64_t input) noexcept 8 | { 9 | AdventCheck(input > 0); 10 | uint64_t guess = 1; 11 | while (true) 12 | { 13 | auto sqr = [](uint64_t x) -> uint64_t {return x * x; }; 14 | const uint64_t trial_result = guess_base + guess; 15 | const uint64_t trial_square = sqr(trial_result); 16 | if (trial_square == input) // Perfect match! 17 | { 18 | return trial_result; 19 | } 20 | else if (trial_square < input) // Too small. Try a bigger number. 21 | { 22 | guess *= 2; 23 | } 24 | else if (guess == 1) // We have an imperfect result: guess_base is too small, but guess_base+1 is too big 25 | { 26 | return guess_base; 27 | } 28 | else // guess > 1 && trial_result is too big. 29 | { 30 | // Roll the guess back a stage (div by 2) and restart with a better base. 31 | return isqrt_implementation(guess_base + guess / 2, input); 32 | } 33 | } 34 | } 35 | } 36 | 37 | // Return the square root of an integer. If not exact, this is rounded down. 38 | // Guaranteed to have no floating point inaccuracies. 39 | uint64_t utils::isqrt(uint64_t input) noexcept 40 | { 41 | switch (input) 42 | { 43 | default: 44 | return isqrt_implementation(0, input); 45 | case 0: 46 | return 0; 47 | // Add more common cases here if optimisation is needed. 48 | } 49 | } 50 | 51 | int64_t utils::isqrt(int64_t input) noexcept 52 | { 53 | AdventCheck(input >= 0); 54 | return static_cast(isqrt(static_cast(input))); 55 | } 56 | 57 | bool utils::is_square(uint64_t input) noexcept 58 | { 59 | const uint64_t root = utils::isqrt(input); 60 | return input == (root * root); 61 | } 62 | 63 | bool utils::is_square(int64_t input) noexcept 64 | { 65 | if(input < 0) return false; 66 | return is_square(static_cast(input)); 67 | } -------------------------------------------------------------------------------- /advent_of_code/utils/isqrt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace utils 6 | { 7 | 8 | uint64_t isqrt(uint64_t input) noexcept; 9 | int64_t isqrt(int64_t input) noexcept; 10 | bool is_square(uint64_t input) noexcept; 11 | bool is_square(int64_t input) noexcept; 12 | } -------------------------------------------------------------------------------- /advent_of_code/utils/istream_block_iterator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace utils 12 | { 13 | 14 | class istream_block_iterator 15 | { 16 | private: 17 | std::istream* m_stream; 18 | std::string_view m_sentinental; 19 | bool is_at_end() const { return m_stream == nullptr; } 20 | std::optional m_cached_result; 21 | void read_next_block() 22 | { 23 | if (is_at_end()) 24 | { 25 | throw std::range_error{ "Cannot deference an at-the-end stream block iterator" }; 26 | } 27 | 28 | std::ostringstream result_stream; 29 | std::string line; 30 | while (true) 31 | { 32 | std::getline(*m_stream, line); 33 | if (line == m_sentinental) 34 | { 35 | break; 36 | } 37 | result_stream << line << '\n'; 38 | if (m_stream->eof()) 39 | { 40 | m_stream = nullptr; 41 | break; 42 | } 43 | } 44 | 45 | // Get the result and remove the trailing '\n'. 46 | std::string result = result_stream.str(); 47 | if (!result.empty()) 48 | { 49 | AdventCheck(result.back() == '\n'); 50 | result.pop_back(); 51 | } 52 | m_cached_result = std::move(result); 53 | } 54 | void maybe_read_next_block() 55 | { 56 | if (!m_cached_result.has_value()) 57 | { 58 | read_next_block(); 59 | } 60 | } 61 | public: 62 | using pointer = const std::string*; 63 | using reference = const std::string&; 64 | using value_type = std::string; 65 | using difference_type = int; 66 | using iterator_category = std::input_iterator_tag; 67 | explicit istream_block_iterator(std::istream& stream, std::string_view sentinental = "") noexcept 68 | : m_stream{ &stream }, m_sentinental{ sentinental }{} 69 | istream_block_iterator() noexcept : m_stream{ nullptr }, m_sentinental{}{} 70 | istream_block_iterator(const istream_block_iterator&) noexcept = default; 71 | istream_block_iterator& operator=(const istream_block_iterator&) noexcept = default; 72 | 73 | bool operator==(const istream_block_iterator& other) const noexcept 74 | { 75 | return is_at_end() && other.is_at_end(); 76 | } 77 | 78 | bool operator!=(const istream_block_iterator& other) const noexcept 79 | { 80 | return !(this->operator==(other)); 81 | } 82 | 83 | std::string_view operator*() 84 | { 85 | maybe_read_next_block(); 86 | return m_cached_result.value(); 87 | } 88 | 89 | istream_block_iterator& operator++() noexcept 90 | { 91 | maybe_read_next_block(); 92 | m_cached_result.reset(); 93 | return *this; 94 | } 95 | istream_block_iterator operator++(int) noexcept 96 | { 97 | istream_block_iterator result = *this; 98 | ++(*this); 99 | return result; 100 | } 101 | }; 102 | 103 | class istream_block_range 104 | { 105 | std::istream& stream; 106 | public: 107 | explicit istream_block_range(std::istream& input) : stream{ input } {} 108 | istream_block_range(const istream_block_range& other) = default; 109 | istream_block_range() = delete; 110 | istream_block_iterator begin() const { return istream_block_iterator{ stream }; } 111 | istream_block_iterator end() const { return istream_block_iterator{}; } 112 | }; 113 | } 114 | 115 | inline utils::istream_block_iterator begin(utils::istream_block_range lr) { return lr.begin(); } 116 | inline utils::istream_block_iterator end(utils::istream_block_range lr) { return lr.end(); } -------------------------------------------------------------------------------- /advent_of_code/utils/istream_line_iterator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace utils 10 | { 11 | 12 | class istream_line_iterator 13 | { 14 | private: 15 | mutable std::istream* m_stream; 16 | char m_sentinental; 17 | bool is_at_end() const { return m_stream == nullptr; } 18 | mutable std::optional m_cached_result; 19 | void read_next_sequence() const 20 | { 21 | if (is_at_end()) 22 | { 23 | throw std::range_error{ "Cannot dereference an at-the-end stream line iterator" }; 24 | } 25 | std::string result; 26 | std::getline(*m_stream, result, m_sentinental); 27 | m_cached_result = std::move(result); 28 | 29 | if (m_stream->eof()) 30 | { 31 | m_stream = nullptr; 32 | } 33 | } 34 | void maybe_read_next_sequence() const 35 | { 36 | if (!m_cached_result.has_value()) 37 | { 38 | read_next_sequence(); 39 | } 40 | } 41 | public: 42 | using pointer = const std::string_view*; 43 | using reference = const std::string_view&; 44 | using value_type = std::string_view; 45 | using difference_type = int; 46 | using iterator_category = std::input_iterator_tag; 47 | explicit istream_line_iterator(std::istream& stream, char sentinental = '\n') noexcept 48 | : m_stream{ &stream }, m_sentinental{ sentinental }{} 49 | istream_line_iterator() noexcept : m_stream{ nullptr }, m_sentinental{ 0 }{} 50 | istream_line_iterator(const istream_line_iterator&) noexcept = default; 51 | istream_line_iterator& operator=(const istream_line_iterator&) noexcept = default; 52 | 53 | bool operator==(const istream_line_iterator& other) const noexcept 54 | { 55 | return is_at_end() && other.is_at_end(); 56 | } 57 | 58 | bool operator!=(const istream_line_iterator& other) const noexcept 59 | { 60 | return !(this->operator==(other)); 61 | } 62 | 63 | std::string_view operator*() const 64 | { 65 | maybe_read_next_sequence(); 66 | return m_cached_result.value(); 67 | } 68 | 69 | istream_line_iterator& operator++() noexcept 70 | { 71 | maybe_read_next_sequence(); 72 | m_cached_result.reset(); 73 | return *this; 74 | } 75 | istream_line_iterator operator++(int) noexcept 76 | { 77 | istream_line_iterator result = *this; 78 | ++(*this); 79 | return result; 80 | } 81 | }; 82 | 83 | class istream_line_range 84 | { 85 | std::istream& stream; 86 | char m_sentinental; 87 | public: 88 | explicit istream_line_range(std::istream& input, char splitter = '\n') : stream{ input } , m_sentinental{splitter} {} 89 | istream_line_range(const istream_line_range& other) = default; 90 | istream_line_range() = delete; 91 | istream_line_iterator begin() const { return istream_line_iterator{ stream , m_sentinental }; } 92 | istream_line_iterator end() const { return istream_line_iterator{}; } 93 | }; 94 | } 95 | 96 | inline utils::istream_line_iterator begin(utils::istream_line_range lr) { return lr.begin(); } 97 | inline utils::istream_line_iterator end(utils::istream_line_range lr) { return lr.end(); } -------------------------------------------------------------------------------- /advent_of_code/utils/md5.cpp: -------------------------------------------------------------------------------- 1 | #include "utils/md5.h" 2 | #include "utils/int_range.h" 3 | #include "utils/range_contains.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace utils; 11 | 12 | namespace 13 | { 14 | constexpr auto BLOCK_LENGTH = 512 / CHAR_BIT; 15 | constexpr auto DIGEST_LENGTH = 128 / CHAR_BIT; 16 | using Val = uint32_t; 17 | using Block = std::array; 18 | constexpr auto NUM_ROUNDS = 64; 19 | void validate_round(int index) noexcept 20 | { 21 | assert(range_contains_exc(index, 0, NUM_ROUNDS)); 22 | } 23 | 24 | template 25 | uint8_t get_char_in_pos(Int i, int pos) noexcept 26 | { 27 | static_assert(std::is_integral_v); 28 | static_assert(std::is_unsigned_v); 29 | assert(pos < sizeof(i)); 30 | 31 | const Int mask = 0b11111111; 32 | i = i >> (CHAR_BIT * pos); 33 | return i & mask; 34 | } 35 | 36 | struct MD5State 37 | { 38 | // Init with magic numbers. 39 | std::array vals{ 0x67452301,0xefcdab89,0x98badcfe,0x10325476 }; 40 | MD5State operator+=(const MD5State& other) noexcept 41 | { 42 | std::transform(begin(vals), end(vals), begin(other.vals), begin(vals), std::plus{}); 43 | return *this; 44 | } 45 | }; 46 | 47 | MD5State operator+(const MD5State& left, const MD5State& right) noexcept 48 | { 49 | MD5State result = left; 50 | result += right; 51 | return result; 52 | } 53 | 54 | uint8_t get_shift_amount(int index) noexcept 55 | { 56 | const std::array values{ 57 | 7,12,17,22, 7,12,17,22, 7,12,17,22, 7,12,17,22, 58 | 5, 9,14,20, 5, 9,14,20, 5, 9,14,20, 5, 9,14,20, 59 | 4,11,16,23, 4,11,16,23, 4,11,16,23, 4,11,16,23, 60 | 6,10,15,21, 6,10,15,21, 6,10,15,21, 6,10,15,21 61 | }; 62 | assert(range_contains_exc(index, 0, static_cast(values.size()))); 63 | return values[index]; 64 | } 65 | 66 | uint8_t get_block_index(int index) noexcept 67 | { 68 | const auto result = [index]() 69 | { 70 | switch (index / 16) 71 | { 72 | default: 73 | assert(false); 74 | return -1; 75 | case 0: 76 | return index; 77 | case 1: 78 | return 5 * index + 1; 79 | case 2: 80 | return 3 * index + 5; 81 | case 3: 82 | return 7 * index; 83 | } 84 | }(); 85 | return static_cast(result % 16); 86 | } 87 | 88 | Val calculate_k_value(int index) noexcept 89 | { 90 | validate_round(index); 91 | return static_cast(static_cast(0x1'0000'0000) * std::abs(std::sin(index + 1))); 92 | } 93 | 94 | std::array calculate_all_k_vals() noexcept 95 | { 96 | std::array result; 97 | const auto range = int_range(static_cast(result.size())); 98 | std::transform(begin(range), end(range), begin(result), calculate_k_value); 99 | return result; 100 | } 101 | 102 | const std::array all_k_vals = calculate_all_k_vals(); 103 | 104 | Val get_k_val(int index) noexcept 105 | { 106 | validate_round(index); 107 | return all_k_vals[index]; 108 | } 109 | 110 | Val func0(Val B, Val C, Val D) noexcept 111 | { 112 | return (B & C) | (~B & D); 113 | } 114 | 115 | Val func1(Val B, Val C, Val D) noexcept 116 | { 117 | return (D & B) | (~D & C); 118 | } 119 | 120 | Val func2(Val B, Val C, Val D) noexcept 121 | { 122 | return B ^ C ^ D; 123 | } 124 | 125 | Val func3(Val B, Val C, Val D) noexcept 126 | { 127 | return C ^ (B | ~D); 128 | } 129 | 130 | Val func(int i, Val B, Val C, Val D) noexcept 131 | { 132 | validate_round(i); 133 | switch (i / 16) 134 | { 135 | default: 136 | assert(false); 137 | return 0; 138 | case 0: 139 | return func0(B, C, D); 140 | case 1: 141 | return func1(B, C, D); 142 | case 2: 143 | return func2(B, C, D); 144 | case 3: 145 | return func3(B, C, D); 146 | } 147 | return 0; 148 | } 149 | 150 | struct RoundResult 151 | { 152 | Val func_result; 153 | Val k_value; 154 | uint8_t block_index; 155 | uint8_t shift_amount; 156 | }; 157 | 158 | RoundResult get_round_result(Val A, Val B, Val C, Val D, int index) noexcept 159 | { 160 | validate_round(index); 161 | return RoundResult{ 162 | func(index, B, C, D), 163 | get_k_val(index), 164 | get_block_index(index), 165 | get_shift_amount(index) 166 | }; 167 | } 168 | 169 | template 170 | UInt lrotate_bits(UInt val, uint8_t distance) noexcept 171 | { 172 | static_assert(std::is_integral_v); 173 | static_assert(std::is_unsigned_v); 174 | constexpr auto num_bits = sizeof(val) * CHAR_BIT; 175 | assert(distance < num_bits); 176 | 177 | const auto new_bottom_bits = val >> (num_bits - distance); 178 | const auto new_top_bits = val << distance; 179 | assert((new_bottom_bits & new_top_bits) == 0); 180 | return new_top_bits + new_bottom_bits; 181 | } 182 | 183 | MD5State do_round(MD5State state, const Block& block, int index) noexcept 184 | { 185 | #if MD5_PRINT_STEPS 186 | std::printf("MD5 state Pass %d; a=%08x b=%08x c=%08x d=%08x\n", 187 | index, state.vals[0], state.vals[1], state.vals[2], state.vals[3]); 188 | #endif 189 | auto get_rotated = [&state, index](int i) -> Val& 190 | { 191 | const auto idx = 64 + i - index; 192 | return state.vals[idx % 4]; 193 | }; 194 | auto& A = get_rotated(0); 195 | auto& B = get_rotated(1); 196 | auto& C = get_rotated(2); 197 | auto& D = get_rotated(3); 198 | const auto rr = get_round_result(A,B,C,D, index); 199 | assert(rr.block_index < block.size()); 200 | A = rr.func_result + A + rr.k_value + block[rr.block_index]; 201 | A = lrotate_bits(A, rr.shift_amount) + B; 202 | return state; 203 | } 204 | 205 | MD5State hash_block(const MD5State& state, const Block& block) noexcept 206 | { 207 | #if MD5_PRINT_STEPS 208 | printf("MD5 Block= {\n"); 209 | for (int i = 0; i < 16; ++i) 210 | { 211 | printf(" [%08x]\n", block[i]); 212 | } 213 | printf("}\n"); 214 | #endif 215 | const auto range = int_range(NUM_ROUNDS); 216 | const auto result = std::accumulate(begin(range), end(range), state, 217 | [&block](const MD5State& s, int index) 218 | { 219 | return do_round(s, block, index); 220 | }); 221 | #if MD5_PRINT_STEPS 222 | std::printf("MD5 state Pass %d; a=%08x b=%08x c=%08x d=%08x\n", 223 | 64, result.vals[0], result.vals[1], result.vals[2], result.vals[3]); 224 | #endif 225 | return result; 226 | } 227 | } 228 | 229 | MD5Digest MD5Hasher::get_digest() const noexcept 230 | { 231 | #if MD5_PRINT_STEPS 232 | { 233 | assert(message_size <= std::numeric_limits::max()); 234 | const auto msg_size = static_cast(message_size); 235 | std::vector test_buffer; 236 | test_buffer.resize(msg_size + 1, 0); 237 | std::memcpy(test_buffer.data(), blocks.data(), msg_size); 238 | MD5String(test_buffer.data()); 239 | } 240 | #endif 241 | auto fake_size = message_size; 242 | push_char_non_msg(static_cast(0x80), fake_size++); 243 | while ((fake_size % BLOCK_LENGTH) != BLOCK_LENGTH - sizeof(uint64_t)) 244 | { 245 | push_char_non_msg(0, fake_size++); 246 | } 247 | const auto suffix = message_size * 8; 248 | for (auto i : int_range(sizeof(uint64_t))) 249 | { 250 | push_char_non_msg(get_char_in_pos(suffix, i), fake_size++); 251 | } 252 | assert(fake_size % BLOCK_LENGTH == 0); 253 | const auto result = std::accumulate(begin(blocks), end(blocks), MD5State{}, 254 | [](const MD5State& s, const Block& b) 255 | { 256 | return s + hash_block(s, b); 257 | }); 258 | #if MD5_PRINT_STEPS 259 | printf("MD5 State final: a=%08x b=%08x, c=%08x d=%08x\n", result.vals[0], result.vals[1], result.vals[2], result.vals[3]); 260 | #endif 261 | return MD5Digest{ result.vals[0],result.vals[1],result.vals[2],result.vals[3] }; 262 | } 263 | 264 | void MD5Hasher::push_char_non_msg(uint8_t c, uint64_t location) const noexcept 265 | { 266 | const int block_idx = static_cast(location / BLOCK_LENGTH); 267 | blocks.resize(block_idx + 1, Block{}); 268 | Block& block = blocks[block_idx]; 269 | 270 | const std::size_t val_idx = (location / sizeof(Val)) % block.size(); 271 | Val& val = block[val_idx]; 272 | const auto byte_idx = location % sizeof(Val); 273 | assert(byte_idx != 0 || val == 0); 274 | 275 | const auto shift_amount = byte_idx * CHAR_BIT; 276 | assert(((Val{ 0xFF } << shift_amount) & val) == 0); 277 | const auto mask = static_cast(c) << shift_amount; 278 | val = val | mask; 279 | } 280 | 281 | void MD5Hasher::push_char(uint8_t c) noexcept 282 | { 283 | push_char_non_msg(c, message_size++); 284 | } 285 | 286 | uint32_t MD5Digest::get_word(int i) const noexcept 287 | { 288 | assert(i < 4); 289 | switch (i) 290 | { 291 | default: 292 | assert(false); 293 | return 0; 294 | case 0: 295 | return a; 296 | case 1: 297 | return b; 298 | case 2: 299 | return c; 300 | case 3: 301 | return d; 302 | } 303 | } 304 | 305 | uint8_t MD5Digest::get_byte(int i) const noexcept 306 | { 307 | assert(i < DIGEST_LENGTH); 308 | const auto word = get_word(i / 4); 309 | const int byte_index = i % sizeof(word); 310 | return get_char_in_pos(word, byte_index); 311 | } 312 | 313 | uint8_t MD5Digest::get_nybble(int i) const noexcept 314 | { 315 | assert(i < 2 * DIGEST_LENGTH); 316 | const auto byte = get_byte(i / 2); 317 | const auto result = (i % 2 ? byte & 0xF : byte >> 4); 318 | return result; 319 | } 320 | 321 | char MD5Digest::get_hex_char(int i) const noexcept 322 | { 323 | assert(i < 2 * DIGEST_LENGTH); 324 | constexpr const char* lookup = "0123456789abcdef"; 325 | assert(std::string{ lookup }.size() == 0x10); 326 | const auto val = get_nybble(i); 327 | assert(val < 0x10); 328 | const auto result = lookup[val]; 329 | return result; 330 | } 331 | 332 | std::string utils::MD5Digest::to_string() const 333 | { 334 | std::string result; 335 | result.reserve(2 * DIGEST_LENGTH); 336 | const auto range = int_range{ 2 * DIGEST_LENGTH }; 337 | std::transform(begin(range), end(range), std::back_inserter(result), 338 | [this](int i) {return get_hex_char(i); }); 339 | return result; 340 | } -------------------------------------------------------------------------------- /advent_of_code/utils/md5.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace utils 11 | { 12 | class MD5Digest 13 | { 14 | private: 15 | uint32_t a, b, c, d; 16 | public: 17 | MD5Digest(uint32_t A, uint32_t B, uint32_t C, uint32_t D) noexcept 18 | : a{ A }, b{ B }, c{ C }, d{ D }{} 19 | auto operator<=>(const MD5Digest& other) const noexcept = default; 20 | std::string to_string() const; 21 | uint32_t get_word(int i) const noexcept; 22 | constexpr std::size_t num_words() const noexcept { return 4; } 23 | uint8_t get_byte(int i) const noexcept; 24 | constexpr std::size_t num_bytes() const noexcept { return sizeof(uint32_t) * num_words(); } 25 | uint8_t get_nybble(int i) const noexcept; 26 | constexpr std::size_t num_nybbles() const noexcept { return 2 * num_bytes(); } 27 | char get_hex_char(int i) const noexcept; 28 | }; 29 | 30 | class MD5Hasher 31 | { 32 | using Block = std::array; 33 | mutable std::vector blocks; 34 | uint64_t message_size = 0; 35 | void push_data() noexcept 36 | { 37 | return; 38 | } 39 | void push_char_non_msg(uint8_t c, uint64_t location) const noexcept; 40 | void push_char(uint8_t c) noexcept; 41 | void push_string(const std::string& str) noexcept 42 | { 43 | for (auto c : str) 44 | { 45 | push_char(c); 46 | } 47 | } 48 | 49 | template 50 | void push_single_item(T&& item) 51 | { 52 | std::ostringstream oss; 53 | oss << std::forward(item); 54 | push_string(oss.str()); 55 | } 56 | public: 57 | template 58 | void push_data(T&& data, Rest&&...rest) 59 | { 60 | push_single_item(std::forward(data)); 61 | push_data(std::forward(rest)...); 62 | } 63 | 64 | MD5Digest get_digest() const noexcept; 65 | }; 66 | 67 | template 68 | inline MD5Digest get_digest(T&&... input) 69 | { 70 | MD5Hasher hasher; 71 | hasher.push_data(std::forward(input)...); 72 | return hasher.get_digest(); 73 | } 74 | 75 | class MD5InputIterator 76 | { 77 | public: 78 | class DereferenceResult 79 | { 80 | friend class MD5InputIterator; 81 | MD5Hasher* base; 82 | DereferenceResult(MD5Hasher* ref) : base{ ref } {} 83 | public: 84 | template 85 | DereferenceResult& operator=(T&& data) 86 | { 87 | if (base != nullptr) 88 | { 89 | base->push_data(std::forward(data)); 90 | } 91 | return *this; 92 | } 93 | }; 94 | private: 95 | DereferenceResult base; 96 | public: 97 | MD5InputIterator(MD5Hasher& hasher) : base{ &hasher } {} 98 | MD5InputIterator() : base{ nullptr } {} 99 | DereferenceResult& operator*() { return base; } 100 | MD5InputIterator& operator++() { return *this; } 101 | }; 102 | } 103 | 104 | template 105 | inline utils::MD5Hasher& operator<<(utils::MD5Hasher& hasher, T&& data) 106 | { 107 | hasher.push_data(std::forward(data)); 108 | return hasher; 109 | } -------------------------------------------------------------------------------- /advent_of_code/utils/min_transform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace utils 4 | { 5 | template 6 | [[nodiscard]] inline FwdIt min_element_transform(FwdIt first, FwdIt last, const Transform& transform) noexcept 7 | { 8 | if (first == last) 9 | { 10 | return last; 11 | } 12 | using ValType = decltype(*first); 13 | FwdIt result = first; 14 | for (FwdIt it = first; it != last; ++it) 15 | { 16 | if (transform(*it) < transform(*result)) 17 | { 18 | result = it; 19 | } 20 | } 21 | return result; 22 | } 23 | 24 | template 25 | [[nodiscard]] inline FwdIt max_element_transform(FwdIt first, FwdIt last, const Transform& transform) noexcept 26 | { 27 | if (first == last) 28 | { 29 | return last; 30 | } 31 | using ValType = decltype(*first); 32 | FwdIt result = first; 33 | for (FwdIt it = first; it != last; std::advance(it,1)) 34 | { 35 | if (transform(*it) > transform(*result)) 36 | { 37 | result = it; 38 | } 39 | } 40 | return result; 41 | } 42 | 43 | template 44 | [[nodiscard]] inline auto min_transform(FwdIt first, FwdIt last, const Transform& transform) noexcept 45 | { 46 | return *min_element_transform(first, last, transform); 47 | } 48 | 49 | template 50 | [[nodiscard]] inline auto max_transform(FwdIt first, FwdIt last, const Transform& transform) noexcept 51 | { 52 | return *max_element_transform(first, last, transform); 53 | } 54 | } -------------------------------------------------------------------------------- /advent_of_code/utils/parse_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils/parse_utils.h" 2 | 3 | #include "advent/advent_assert.h" 4 | 5 | std::string_view utils::remove_specific_prefix(std::string_view input, std::string_view prefix) 6 | { 7 | AdventCheck(input.starts_with(prefix)); 8 | input.remove_prefix(prefix.size()); 9 | return input; 10 | } 11 | 12 | std::string_view utils::remove_specific_suffix(std::string_view input, char suffix) 13 | { 14 | std::string_view sv{&suffix,1}; 15 | return remove_specific_suffix(input, sv); 16 | } 17 | 18 | std::string_view utils::remove_specific_suffix(std::string_view input, std::string_view suffix) 19 | { 20 | AdventCheck(input.ends_with(suffix)); 21 | input.remove_suffix(suffix.size()); 22 | return input; 23 | } 24 | 25 | std::string_view utils::remove_specific_prefix(std::string_view input, char prefix) 26 | { 27 | std::string_view sv{&prefix,1}; 28 | return remove_specific_prefix(input,sv); 29 | } 30 | -------------------------------------------------------------------------------- /advent_of_code/utils/parse_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "split_string.h" 7 | 8 | namespace utils 9 | { 10 | std::string_view remove_specific_prefix(std::string_view input, std::string_view prefix); 11 | std::string_view remove_specific_suffix(std::string_view input, std::string_view suffix); 12 | std::string_view remove_specific_prefix(std::string_view input, char prefix); 13 | std::string_view remove_specific_suffix(std::string_view input, char suffix); 14 | 15 | namespace internal 16 | { 17 | inline std::array get_elements_impl( 18 | std::string_view input, 19 | char delim, 20 | std::size_t current_idx) 21 | { 22 | return std::array{}; 23 | } 24 | 25 | 26 | template 27 | inline std::array get_elements_impl( 28 | std::string_view input, 29 | char delim, 30 | std::size_t current_idx, 31 | std::size_t first_elem, 32 | Indices... rest 33 | ) 34 | { 35 | const auto [elem, input_rest] = split_string_at_first(input, delim); 36 | if (current_idx == first_elem) 37 | { 38 | std::array result; 39 | result.front() = elem; 40 | const auto results_rest = get_elements_impl(input_rest, delim, current_idx + 1, rest...); 41 | std::copy(begin(results_rest), end(results_rest), begin(result) + 1); 42 | return result; 43 | } 44 | // Else 45 | return get_elements_impl(input_rest, delim, current_idx + 1, first_elem, rest...); 46 | } 47 | } 48 | 49 | template 50 | inline std::array get_string_elements(std::string_view input, char delim,Indices...indices) 51 | { 52 | static_assert(sizeof...(indices) > 0); 53 | return internal::get_elements_impl(input, delim, 0, indices...); 54 | } 55 | 56 | template 57 | inline std::array get_string_elements(std::string_view input, Indices...indices) 58 | { 59 | static_assert(sizeof...(indices) > 0); 60 | return get_string_elements(input, ' ', indices...); 61 | } 62 | 63 | inline std::string_view get_string_element(std::string_view input, char delim, std::size_t index) 64 | { 65 | return get_string_elements(input, delim, index)[0]; 66 | } 67 | 68 | inline std::string_view get_string_element(std::string_view input, std::size_t index) 69 | { 70 | return get_string_element(input, ' ', index); 71 | } 72 | } -------------------------------------------------------------------------------- /advent_of_code/utils/position3d.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "advent/advent_assert.h" 6 | 7 | namespace utils 8 | { 9 | enum class Axis : std::size_t 10 | { 11 | X = 0, 12 | Y = 1, 13 | Z = 2 14 | }; 15 | 16 | template 17 | class Vector3D 18 | { 19 | private: 20 | T m_x; 21 | T m_y; 22 | T m_z; 23 | public: 24 | // Constructors 25 | Vector3D() : Vector3D{ T{0} } {} 26 | explicit Vector3D(T init) : Vector3D{ init,init,init } {} 27 | Vector3D(T x, T y, T z) : m_x{ x }, m_y{ y }, m_z{ z }{} 28 | template 29 | Vector3D(X_T x, Y_T y, Z_T z) 30 | : Vector3D{ static_cast(x),static_cast(y),static_cast(z) } {} 31 | Vector3D(const Vector3D&) = default; 32 | template 33 | explicit Vector3D(const Vector3D& other) 34 | : Vector3D{ other.m_x, other.m_y, other.m_z } {} 35 | auto operator<=>(const Vector3D&) const = default; 36 | T& at(Axis axis) 37 | { 38 | switch (axis) 39 | { 40 | case Axis::X: 41 | return m_x; 42 | case Axis::Y: 43 | return m_y; 44 | case Axis::Z: 45 | return m_z; 46 | default: 47 | break; 48 | } 49 | AdventUnreachable(); 50 | return m_x; 51 | } 52 | T at(Axis axis) const 53 | { 54 | switch (axis) 55 | { 56 | case Axis::X: 57 | return m_x; 58 | case Axis::Y: 59 | return m_y; 60 | case Axis::Z: 61 | return m_z; 62 | default: 63 | break; 64 | } 65 | AdventUnreachable(); 66 | return m_x; 67 | } 68 | T& operator[](Axis axis) 69 | { 70 | return at(axis); 71 | } 72 | T operator[](Axis axis) const 73 | { 74 | return at(axis); 75 | } 76 | T& operator[](std::size_t axis) 77 | { 78 | AdventCheck(axis < 3u); 79 | return at(static_cast(axis)); 80 | } 81 | T operator[](std::size_t axis) const 82 | { 83 | AdventCheck(axis < 3u); 84 | return at(static_cast(axis)); 85 | } 86 | 87 | template 88 | Vector3D& operator+=(const Vector3D& other) 89 | { 90 | for (std::size_t i = 0u; i < 3; ++i) 91 | { 92 | (*this)[i] += other[i]; 93 | } 94 | return *this; 95 | } 96 | 97 | template 98 | Vector3D& operator*=(const ScalarType& val) 99 | { 100 | for (std::size_t i = 0u; i < 3; ++i) 101 | { 102 | (*this)[i] *= val; 103 | } 104 | return *this; 105 | } 106 | 107 | Vector3D operator-() const 108 | { 109 | Vector3D result = *this; 110 | result *= static_cast(-1); 111 | return result; 112 | } 113 | 114 | // +ve x. 115 | static Vector3D forward() 116 | { 117 | return Vector3D{ static_cast(1),static_cast(0),static_cast(0) }; 118 | } 119 | 120 | // -ve x 121 | static Vector3D backward() 122 | { 123 | return Vector3D{ static_cast(-1),static_cast(0),static_cast(0) }; 124 | } 125 | 126 | // +ve y 127 | static Vector3D right() 128 | { 129 | return Vector3D{ static_cast(0),static_cast(1),static_cast(0) }; 130 | } 131 | 132 | // -ve y 133 | static Vector3D left() 134 | { 135 | return Vector3D{ static_cast(0),static_cast(-1),static_cast(0) }; 136 | } 137 | 138 | // +ve z 139 | static Vector3D up() 140 | { 141 | return Vector3D{ static_cast(0),static_cast(0),static_cast(1) }; 142 | } 143 | 144 | // -ve z 145 | static Vector3D down() 146 | { 147 | return Vector3D{ static_cast(0),static_cast(0),static_cast(-1) }; 148 | } 149 | }; 150 | } 151 | 152 | template 153 | auto operator+(const utils::Vector3D& left, const utils::Vector3D& right) 154 | { 155 | auto result = left; 156 | result += right; 157 | return result; 158 | } -------------------------------------------------------------------------------- /advent_of_code/utils/push_back_unique.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace utils 6 | { 7 | 8 | template 9 | auto push_back_unique(Container& cont, ElemType&& elem) 10 | { 11 | const auto find_result = std::find_if(begin(cont), end(cont), 12 | [&elem](const auto& c) 13 | { 14 | return c == elem; 15 | }); 16 | if (find_result == end(cont)) 17 | { 18 | cont.emplace_back(std::forward(elem)); 19 | auto last = end(cont); 20 | std::advance(last, -1); 21 | return last; 22 | } 23 | return find_result; 24 | } 25 | } -------------------------------------------------------------------------------- /advent_of_code/utils/range_contains.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace utils 6 | { 7 | template 8 | inline bool range_contains_inc(const T& val, const U& min, const V& max) 9 | { 10 | if (min > max) 11 | { 12 | return range_contains_inc(val, max, min); 13 | } 14 | return min <= val && val <= max; 15 | } 16 | 17 | template 18 | inline bool range_contains_exc(const T& val, const U& min, const V& max) 19 | { 20 | if (min > max) 21 | { 22 | return range_contains_exc(val, max, min); 23 | } 24 | return min <= val && val < max; 25 | } 26 | 27 | template 28 | inline bool region_contains(T val, T comp_a, T comp_b) 29 | { 30 | const auto [min, max] = std::minmax(comp_a, comp_b); 31 | return range_contains_inc(val, min, max); 32 | } 33 | } -------------------------------------------------------------------------------- /advent_of_code/utils/ring_buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "index_iterator2.h" 6 | #include "small_vector.h" 7 | 8 | namespace utils 9 | { 10 | template 11 | class ring_buffer 12 | { 13 | utils::small_vector m_data; 14 | std::size_t m_front_idx; 15 | constexpr std::size_t get_idx(std::size_t i) const noexcept 16 | { 17 | return (i + m_front_idx) % SIZE; 18 | } 19 | public: 20 | using value_type = T; 21 | using side_type = std::size_t; 22 | using difference_type = std::ptrdiff_t; 23 | using reference_type = T&; 24 | using const_reference_type = const T&; 25 | using pointer_type = T*; 26 | using const_pointer_type = const T*; 27 | using iterator = index_iterator2>; 28 | using const_iterator = const_index_iterator2>; 29 | 30 | explicit ring_buffer() { m_data.resize(SIZE); } 31 | 32 | ring_buffer(const ring_buffer&) = default; 33 | ring_buffer(ring_buffer&&) = default; 34 | ring_buffer& operator=(const ring_buffer&) = default; 35 | ring_buffer& operator=(ring_buffer&&) = default; 36 | T& operator[](std::size_t i) noexcept { return m_data[get_idx(i)]; } 37 | const T& operator[](std::size_t i) const noexcept { return m_data[get_idx(i)]; } 38 | T& front() { return (*this)[0]; } 39 | const T& front() const { return (*this)[0]; } 40 | T& back() { return (*this)[SIZE - 1]; } 41 | const T& back() const { return (*this)[SIZE - 1]; } 42 | 43 | bool empty() const { return m_data.empty(); } 44 | std::size_t size() const { return m_data.size(); } 45 | std::size_t max_size() const { return m_data.max_size(); } 46 | 47 | void fill(const T& value) { std::fill(m_data.begin(),m_data.end(),value); } 48 | void swap(ring_buffer& other) { m_data.swap(other.m_data); std::swap(m_front_idx, other.m_front_idx); } 49 | void rotate(std::size_t new_front) { m_front_idx = get_idx(new_front); } 50 | void rotate(const_iterator new_front) { rotate(new_front - begin()); } 51 | 52 | const_iterator cbegin() const 53 | { 54 | return make_idx_it_cbegin(*this); 55 | } 56 | const_iterator cend() const 57 | { 58 | return make_idx_it_cend(*this); 59 | } 60 | const_iterator begin() const 61 | { 62 | return cbegin(); 63 | } 64 | const_iterator end() const 65 | { 66 | return cend(); 67 | } 68 | iterator begin() 69 | { 70 | return make_idx_it_begin(*this); 71 | } 72 | iterator end() 73 | { 74 | return make_idx_it_end(*this); 75 | } 76 | }; 77 | } 78 | 79 | template 80 | inline bool operator==(const utils::ring_buffer& left, const utils::ring_buffer& right) 81 | { 82 | return std::equal(begin(left), end(left), begin(right), end(right)); 83 | } 84 | 85 | template 86 | inline bool operator!=(const utils::ring_buffer& left, const utils::ring_buffer& right) 87 | { 88 | return !(left == right); 89 | } 90 | 91 | template 92 | inline bool operator<(const utils::ring_buffer& left, const utils::ring_buffer& right) 93 | { 94 | return std::lexicographical_compare(begin(left), end(left), begin(right), end(right)); 95 | } 96 | 97 | template 98 | inline bool operator>(const utils::ring_buffer& left, const utils::ring_buffer& right) 99 | { 100 | return right < left; 101 | } 102 | 103 | template 104 | inline bool operator<=(const utils::ring_buffer& left, const utils::ring_buffer& right) 105 | { 106 | return !(right < left); 107 | } 108 | 109 | template 110 | inline bool operator>=(const utils::ring_buffer& left, const utils::ring_buffer& right) 111 | { 112 | return !(left < right); 113 | } -------------------------------------------------------------------------------- /advent_of_code/utils/shared_lock_guard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace utils 4 | { 5 | 6 | template 7 | class shared_lock_guard 8 | { 9 | LockType& lock; 10 | public: 11 | explicit shared_lock_guard(LockType& init) 12 | : lock{ init } 13 | { 14 | lock.lock_shared(); 15 | } 16 | ~shared_lock_guard() noexcept 17 | { 18 | lock.unlock_shared(); 19 | } 20 | }; 21 | 22 | } -------------------------------------------------------------------------------- /advent_of_code/utils/span.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | #include "advent/advent_assert.h" 7 | 8 | namespace utils 9 | { 10 | template 11 | class span 12 | { 13 | ItType first, last; 14 | public: 15 | ItType begin() const noexcept { return first; } 16 | ItType end() const noexcept { return last; } 17 | span(const span& other) = default; 18 | span& operator=(const span& other) = default; 19 | span(ItType f, ItType l) : first{ f }, last{ l }{} 20 | std::size_t size() const noexcept 21 | { 22 | return std::distance(first, last); 23 | } 24 | bool empty() const noexcept { return first == last; } 25 | span remove_prefix(std::size_t num) const 26 | { 27 | AdventCheck(num <= size()); 28 | ItType new_first = first; 29 | std::advance(new_first, num); 30 | return span{ new_first,last }; 31 | } 32 | span remove_suffix(std::size_t num) const noexcept 33 | { 34 | AdventCheck(num <= size()); 35 | ItType new_last = last; 36 | std::ptrdiff_t offset = 0 - static_cast(num); 37 | std::advance(new_last, offset); 38 | return span{ first,new_last }; 39 | } 40 | auto operator[](std::size_t idx) const noexcept 41 | { 42 | AdventCheck(idx < size()); 43 | ItType location = first; 44 | std::advance(location, idx); 45 | return *location; 46 | } 47 | }; 48 | 49 | template 50 | auto make_span(const Container& container) 51 | { 52 | using ItType = decltype(begin(container)); 53 | return span{begin(container), end(container)}; 54 | } 55 | } -------------------------------------------------------------------------------- /advent_of_code/utils/sparse_array.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sorted_vector.h" 4 | #include 5 | 6 | namespace utils 7 | { 8 | template 9 | class sparse_array 10 | { 11 | public: 12 | using DataType = std::pair; 13 | struct Compare 14 | { 15 | bool operator()(const DataType& l, const DataType& r) const 16 | { 17 | return std::less{}(l.first, r.first); 18 | } 19 | }; 20 | using Container = utils::sorted_vector; 21 | 22 | private: 23 | Container m_data; 24 | ValueType m_default_val; 25 | 26 | public: 27 | const Container& get_data() const { return m_data; } 28 | const ValueType& get_default_value() const { return m_default_val; } 29 | explicit sparse_array(ValueType&& default_val) : m_default_val{ default_val } {} 30 | sparse_array() : sparse_array{ ValueType{} } {} 31 | void reserve(std::size_t new_capacity) { m_data.reserve(new_capacity); } 32 | 33 | ValueType get(const IndexType& idx) const 34 | { 35 | const auto find_it = m_data.binary_find_if(idx ,[]( const DataType& dt, const IndexType & idx) 36 | { 37 | return dt.first <=> idx; 38 | }); 39 | return (find_it != end(m_data) ? find_it->second : m_default_val); 40 | } 41 | 42 | void set(const IndexType& idx, ValueType&& val) 43 | { 44 | const auto find_it = m_data.binary_find_if(idx, [](const DataType & dt, const IndexType & idx) 45 | { 46 | return dt.first <=> idx; 47 | }); 48 | 49 | if (find_it != end(m_data)) 50 | { 51 | if (val != m_default_val) 52 | { 53 | find_it->second = std::forward(val); 54 | } 55 | else 56 | { 57 | m_data.erase_fast(find_it); 58 | } 59 | } 60 | else 61 | { 62 | if (val != m_default_val) 63 | { 64 | m_data.push_back(DataType{ idx,std::forward(val) }); 65 | } 66 | } 67 | } 68 | 69 | void set(const IndexType& idx, const ValueType& val) 70 | { 71 | const auto find_it = m_data.binary_find_if(idx, [](const DataType & dt, const IndexType & idx) 72 | { 73 | return dt.first <=> idx; 74 | }); 75 | 76 | if (find_it != end(m_data)) 77 | { 78 | if (val != m_default_val) 79 | { 80 | find_it->second = val; 81 | } 82 | else 83 | { 84 | m_data.erase_fast(find_it); 85 | } 86 | } 87 | else 88 | { 89 | if (val != m_default_val) 90 | { 91 | m_data.push_back(DataType{ idx, val }); 92 | } 93 | } 94 | } 95 | }; 96 | } -------------------------------------------------------------------------------- /advent_of_code/utils/split_string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace utils 9 | { 10 | [[nodiscard]] inline std::pair split_string_at_point(std::string_view str, std::size_t split_point) 11 | { 12 | if (split_point < str.size()) 13 | { 14 | return std::pair{ str.substr(0,split_point),str.substr(split_point + 1) }; 15 | } 16 | else 17 | { 18 | return std::pair{ str,"" }; 19 | } 20 | } 21 | 22 | [[nodiscard]] inline std::pair split_string_at_first(std::string_view str, std::string_view delim) 23 | { 24 | const auto split_point = str.find(delim); 25 | if (split_point < str.size()) 26 | { 27 | const std::string_view left = str.substr(0, split_point); 28 | const std::string_view right = str.substr(split_point + delim.size()); 29 | return std::pair{ left, right }; 30 | } 31 | else 32 | { 33 | return std::pair{ str,"" }; 34 | } 35 | } 36 | 37 | [[nodiscard]] inline std::pair split_string_at_first(std::string_view str, char delim) 38 | { 39 | return split_string_at_first(str, std::string_view(&delim, 1)); 40 | } 41 | 42 | [[nodiscard]] inline std::pair split_string_at_last(std::string_view str, std::string_view delim) 43 | { 44 | const auto split_point = str.rfind(delim); 45 | if (split_point < str.size()) 46 | { 47 | return std::pair{ str.substr(0,split_point),str.substr(split_point + delim.size()) }; 48 | } 49 | else 50 | { 51 | return std::pair{ str,"" }; 52 | } 53 | } 54 | 55 | [[nodiscard]] inline std::pair split_string_at_last(std::string_view str, char delim) 56 | { 57 | return split_string_at_last(str, std::string_view(&delim, 1)); 58 | } 59 | 60 | [[nodiscard]] inline std::vector split_string(std::string_view str, std::string_view delim) 61 | { 62 | std::vector result; 63 | std::string_view split_state = str; 64 | while (!split_state.empty()) 65 | { 66 | const auto [next_section, next_state] = split_string_at_first(split_state, delim); 67 | result.push_back(next_section); 68 | split_state = next_state; 69 | } 70 | return result; 71 | } 72 | 73 | [[nodiscard]] inline std::vector split_string(std::string_view str, char delim) 74 | { 75 | return split_string(str, std::string_view{ &delim,1 }); 76 | } 77 | 78 | [[nodiscard]] inline std::vector split_string(std::string_view str) 79 | { 80 | return split_string(str, ' '); 81 | } 82 | } -------------------------------------------------------------------------------- /advent_of_code/utils/string_line_iterator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "split_string.h" 7 | #include "trim_string.h" 8 | 9 | #include "advent/advent_assert.h" 10 | 11 | namespace utils 12 | { 13 | class string_line_iterator 14 | { 15 | public: 16 | enum class trim_behaviour : int8_t 17 | { 18 | trim_before_incrementing, 19 | do_not_trim 20 | }; 21 | private: 22 | std::string_view m_string; 23 | std::string_view m_sentinental; 24 | char m_sentinental_storage; 25 | trim_behaviour m_trim_behaviour; 26 | mutable std::optional> m_cached_split_result; 27 | std::pair get_split_result() const 28 | { 29 | if (is_at_end()) 30 | { 31 | throw std::range_error{ "Cannot dereference or increment an at-the-end string line iterator" }; 32 | } 33 | 34 | if (!m_cached_split_result.has_value()) 35 | { 36 | m_cached_split_result = utils::split_string_at_first(m_string,m_sentinental); 37 | } 38 | 39 | AdventCheck(m_cached_split_result.has_value()); 40 | return m_cached_split_result.value(); 41 | } 42 | bool is_at_end() const { return m_string.empty(); } 43 | std::string_view try_trim(std::string_view in) const noexcept 44 | { 45 | if(m_trim_behaviour == trim_behaviour::trim_before_incrementing) 46 | { 47 | in = trim_left(in); 48 | } 49 | return in; 50 | } 51 | public: 52 | using pointer = const std::string_view*; 53 | using reference = const std::string_view&; 54 | using value_type = std::string_view; 55 | using difference_type = int; 56 | using iterator_category = std::forward_iterator_tag; 57 | string_line_iterator(std::string_view string_to_split, std::string_view sentinental, trim_behaviour behaviour) noexcept 58 | : m_string{string_to_split}, m_sentinental{sentinental}, m_sentinental_storage{'\0'}, m_trim_behaviour{behaviour} 59 | { 60 | m_string = try_trim(m_string); 61 | } 62 | string_line_iterator(std::string_view string_to_split, char sentinental, trim_behaviour behaviour) noexcept 63 | : string_line_iterator{string_to_split, std::string_view{&m_sentinental_storage,1}, behaviour} 64 | { 65 | m_sentinental_storage = sentinental; 66 | } 67 | string_line_iterator(std::string_view string_to_split, std::string_view sentinental) noexcept 68 | : string_line_iterator{ string_to_split , sentinental , trim_behaviour::trim_before_incrementing }{} 69 | string_line_iterator(std::string_view string_to_split, char sentinental) noexcept 70 | : string_line_iterator{string_to_split, sentinental , trim_behaviour::trim_before_incrementing}{} 71 | string_line_iterator(std::string_view string_to_split, trim_behaviour behaviour) noexcept 72 | : string_line_iterator{string_to_split, '\n', behaviour}{} 73 | explicit string_line_iterator(std::string_view string_to_split) noexcept 74 | : string_line_iterator{ string_to_split, trim_behaviour::trim_before_incrementing } {} 75 | string_line_iterator() 76 | : string_line_iterator{"",'\0'}{} 77 | string_line_iterator(const string_line_iterator&) noexcept = default; 78 | string_line_iterator& operator=(const string_line_iterator&) noexcept = default; 79 | 80 | bool operator==(const string_line_iterator& other) const noexcept 81 | { 82 | return is_at_end() && other.is_at_end(); 83 | } 84 | 85 | bool operator!=(const string_line_iterator& other) const noexcept 86 | { 87 | return !(this->operator==(other)); 88 | } 89 | 90 | std::string_view operator*() const noexcept 91 | { 92 | auto [result,unneeded] = get_split_result(); 93 | return result; 94 | } 95 | 96 | string_line_iterator& operator++() noexcept 97 | { 98 | auto [unneeded,new_string] = get_split_result(); 99 | m_string = try_trim(new_string); 100 | m_cached_split_result.reset(); 101 | return *this; 102 | } 103 | string_line_iterator operator++(int) noexcept 104 | { 105 | string_line_iterator result = *this; 106 | operator++(); 107 | return result; 108 | } 109 | string_line_iterator operator+(std::size_t num) noexcept 110 | { 111 | for(std::size_t i=0;i 4 | #include 5 | 6 | #include "advent/advent_assert.h" 7 | 8 | namespace utils 9 | { 10 | template 11 | void swap_remove(VecType& vector, std::size_t idx) 12 | { 13 | AdventCheck(idx < vector.size()); 14 | vector[idx] = std::move(vector.back()); 15 | vector.pop_back(); 16 | } 17 | 18 | template 19 | void swap_remove(VecType& vector, typename VecType::iterator loc) 20 | { 21 | static_assert(!std::is_const_v, "Input must be non-const."); 22 | *loc = std::move(vector.back()); 23 | vector.pop_back(); 24 | } 25 | 26 | // Returns true if it successfully removes a value. 27 | template 28 | bool swap_remove_single(VecType& vector, typename VecType::const_reference value) 29 | { 30 | static_assert(!std::is_const_v, "Input must be non-const."); 31 | const VecType::iterator loc = std::find(begin(vector), end(vector), value); 32 | if (loc != end(vector)) 33 | { 34 | swap_remove(vector, loc); 35 | return true; 36 | } 37 | return false; 38 | } 39 | 40 | template 41 | typename VecType::size_type swap_remove_if(VecType& vector, const Pred& pred) 42 | { 43 | static_assert(!std::is_const_v, "Input must be non-const."); 44 | const auto original_size = vector.size(); 45 | typename VecType::size_type i = 0; 46 | while (i < vector.size()) 47 | { 48 | if (pred(vector[i])) 49 | { 50 | auto it = begin(vector); 51 | std::advance(it, i); 52 | swap_remove(vector, it); 53 | } 54 | else 55 | { 56 | ++i; 57 | } 58 | } 59 | return vector.size() - original_size; 60 | } 61 | 62 | template 63 | typename VecType::size_type swap_remove_all(VecType& vector, typename VecType::const_reference value) 64 | { 65 | static_assert(!std::is_const_v, "Input must be non-const."); 66 | return swap_remove_if(vector, [&value](const VecType::value_type& v) {return v == value; }); 67 | } 68 | } -------------------------------------------------------------------------------- /advent_of_code/utils/to_value.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "trim_string.h" 9 | #include "advent/advent_utils.h" 10 | 11 | namespace utils 12 | { 13 | template 14 | inline bool is_value(std::string_view sv) 15 | { 16 | static_assert(0 < base, "is_value only supprts positive bases."); 17 | static_assert(base <= 16, "is_value only supports bases up to 16."); 18 | if (sv.empty()) 19 | { 20 | return true; 21 | } 22 | 23 | switch (sv.front()) 24 | { 25 | case '+': 26 | case '-': 27 | sv.remove_prefix(1); 28 | break; 29 | default: 30 | break; 31 | } 32 | 33 | 34 | auto is_allowed_char = [sbase = std::size_t{base}](char c) 35 | { 36 | constexpr std::string_view allowed_chars{ "0123456789ABCDEF" }; 37 | c = std::toupper(c); 38 | const auto find_result = allowed_chars.find(c); 39 | return find_result < sbase; 40 | }; 41 | 42 | return stdr::all_of(sv, is_allowed_char); 43 | } 44 | 45 | template 46 | inline T to_value(std::string_view sv) 47 | { 48 | sv = trim_string(sv); 49 | AdventCheckMsg(is_value(sv),"Could not convert string to value: " , sv); 50 | if (sv.empty()) 51 | { 52 | return T{ 0 }; 53 | } 54 | if (sv.front() == '+') 55 | { 56 | sv.remove_prefix(1); 57 | } 58 | 59 | const char* first = sv.data(); 60 | const char* last = first + sv.size(); 61 | T value{}; 62 | const std::from_chars_result result = std::from_chars(first, last, value, base); 63 | AdventCheckMsg(result.ec == std::errc{},"ErrNo return parsing string '", sv); 64 | AdventCheckMsg(result.ptr == last,"Could not convert string to value: " , sv); 65 | return value; 66 | } 67 | } -------------------------------------------------------------------------------- /advent_of_code/utils/transform_if.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace utils 4 | { 5 | template 6 | OutputIt transform_if(FwdIt start, FwdIt end, OutputIt destination, Transform transform_func, PrePred pre_pred, PostPred post_pred) 7 | { 8 | for (auto it = start; it != end; ++it) 9 | { 10 | const auto& value = *it; 11 | if (pre_pred(value)) 12 | { 13 | auto transform_result = transform_func(value); 14 | if (post_pred(transform_result)) 15 | { 16 | *destination = std::move(transform_result); 17 | ++destination; 18 | } 19 | } 20 | } 21 | return destination; 22 | } 23 | 24 | template 25 | OutputIt transform_if_pre(FwdIt start, FwdIt end, OutputIt destination, Transform transform_func, Pred predicate_func) 26 | { 27 | return transform_if(start, end, destination, transform_func, predicate_func, [](const decltype(transform_func(*start))&) {return true; }); 28 | } 29 | 30 | template 31 | OutputIt transform_if_post(FwdIt start, FwdIt end, OutputIt destination, Transform transform_func, Pred predicate_func) 32 | { 33 | return transform_if(start, end, destination, transform_func, [](const decltype(*start)&) {return true; }, predicate_func); 34 | } 35 | 36 | namespace ranges 37 | { 38 | template 39 | OutputIt transform_if(RangeType&& range, OutputIt destination, Transform transform_func, PrePred pre_pred, PostPred post_pred) 40 | { 41 | return utils::transform_if(begin(range), end(range), destination, transform_func, pre_pred, post_pred); 42 | } 43 | 44 | template 45 | OutputIt transform_if_pre(RangeType&& range, OutputIt destination, Transform transform_func, Pred predicate_func) 46 | { 47 | return utils::transform_if_pre(begin(range), end(range), destination, transform_func, predicate_func); 48 | } 49 | 50 | template 51 | OutputIt transform_if_post(RangeType&& range, OutputIt destination, Transform transform_func, Pred predicate_func) 52 | { 53 | return utils::transform_if_post(begin(range), end(range), destination, transform_func, predicate_func); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /advent_of_code/utils/trim_string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace utils 8 | { 9 | inline std::string_view trim_left(std::string_view sv) 10 | { 11 | while (!sv.empty() && std::isspace(sv.front())) 12 | { 13 | sv.remove_prefix(1); 14 | } 15 | return sv; 16 | } 17 | 18 | inline std::string_view trim_right(std::string_view sv) 19 | { 20 | while (!sv.empty() && std::isspace(sv.back())) 21 | { 22 | sv.remove_suffix(1); 23 | } 24 | return sv; 25 | } 26 | 27 | inline std::string_view trim_string(std::string_view sv) 28 | { 29 | return trim_left(trim_right(sv)); 30 | } 31 | } --------------------------------------------------------------------------------