From db41f27ea1158cefc025ad0a43281ea06e4dd5e0 Mon Sep 17 00:00:00 2001 From: Olivia Appleton Date: Sun, 4 Aug 2024 22:12:49 -0500 Subject: [PATCH] solve p22 in c++ --- README.rst | 2 +- cplusplus/README.rst | 1 + cplusplus/src/include/utils.h | 102 ++++++++++++++++++++++++++++++++++ cplusplus/src/p0022.cpp | 53 ++++++++++++++++++ cplusplus/test.cpp | 2 + cplusplus/test_euler.py | 1 + docs/cplusplus/p0015.rst | 10 ++-- docs/cplusplus/utils.rst | 18 ++++++ docs/index.rst | 2 +- 9 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 cplusplus/src/include/utils.h create mode 100644 cplusplus/src/p0022.cpp create mode 100644 docs/cplusplus/utils.rst diff --git a/README.rst b/README.rst index fcda1811..f0b9db90 100644 --- a/README.rst +++ b/README.rst @@ -50,7 +50,7 @@ Olivia's Project Euler Solutions | | |gcc|, |pcc|, |tcc| |br| | | |C-Cov| |br| | | | C11+ in: |msvc| [1]_ | | |CodeQL| | +------------+--------------------------+--------+-------------------+ -| C++ | C++98+ in: |br| |clang| | 13 | |Cpi| |br| | +| C++ | C++98+ in: |br| |clang| | 14 | |Cpi| |br| | | | |gcc| |br| | | |Cp-Cov| |br| | | | C++14+ in: |msvc| [1]_ | | |CodeQL| | +------------+--------------------------+--------+-------------------+ diff --git a/cplusplus/README.rst b/cplusplus/README.rst index c3d77e33..1fe32624 100644 --- a/cplusplus/README.rst +++ b/cplusplus/README.rst @@ -174,6 +174,7 @@ Problems Solved - ☒ `14 <./src/p0014.cpp>`__ - ☒ `15 <./src/p0015.cpp>`__ - ☒ `17 <./src/p0017.cpp>`__ +- ☒ `22 <./src/p0022.cpp>`__ - ☒ `34 <./src/p0034.cpp>`__ - ☒ `76 <./src/p0076.cpp>`__ - ☒ `836 <./src/p0836.cpp>`__ diff --git a/cplusplus/src/include/utils.h b/cplusplus/src/include/utils.h new file mode 100644 index 00000000..b87deecd --- /dev/null +++ b/cplusplus/src/include/utils.h @@ -0,0 +1,102 @@ +#pragma once +#include +#include +#ifdef _WIN32 +#include +#include +#define PATH_SEPARATOR "\\" +#else +#include +#include +#define PATH_SEPARATOR "/" +#endif + +char* get_parent_directory(char* path, const unsigned int levels) { +#ifdef _WIN32 + static char drive[_MAX_DRIVE]; + static char dir[_MAX_DIR]; + _splitpath(path, drive, dir, NULL, NULL); + for (unsigned int i = 0; i < levels; ++i) { + size_t len = strlen(dir); + if (len > 1 && (dir[len - 1] == '\\' || dir[len - 1] == '/')) { + dir[len - 1] = '\0'; + } + char* last_slash = strrchr(dir, '\\'); + if (!last_slash) last_slash = strrchr(dir, '/'); + if (last_slash) *last_slash = '\0'; + } + static char parent_dir[_MAX_PATH]; + snprintf(parent_dir, sizeof(parent_dir), "%s%s", drive, dir); + return parent_dir; +#else + char* dir = dirname(path); + for (unsigned int i = 0; i < levels; ++i) { + dir = dirname(dir); + if (strcmp(dir, "/") == 0 || strcmp(dir, ".") == 0) { + break; + } + } + return dir; +#endif +} + +std::string get_data_file(const char *name) { + const char* start = __FILE__; +#ifdef _WIN32 + char absolute_path[MAX_PATH]; + if (!_fullpath(absolute_path, start, MAX_PATH)) { + perror("_fullpath"); + return NULL; + } +#else + char* absolute_path = realpath(start, NULL); + if (!absolute_path) { + perror("realpath"); + return NULL; + } +#endif + char* parents_dir = get_parent_directory(absolute_path, 3); + const size_t p_len = strlen(parents_dir), + name_len = strlen(name); + char *file_path = (char *)malloc(p_len + name_len + 8); + memcpy(file_path, parents_dir, p_len); + memcpy(file_path + p_len, PATH_SEPARATOR "_data" PATH_SEPARATOR, 7); + memcpy(file_path + p_len + 7, name, name_len); + file_path[p_len + name_len + 7] = 0; + FILE* file = fopen(file_path, "r"); +#ifndef _WIN32 + free(absolute_path); +#endif +// free(parents_dir); + free(file_path); + if (!file) { + perror("fopen"); + return NULL; + } + + fseek(file, 0, SEEK_END); + size_t length = ftell(file); + fseek(file, 0, SEEK_SET); + + char* buffer = (char*)malloc(length + 1); + if (!buffer) { + perror("malloc"); + fclose(file); + return NULL; + } + + const size_t ret_code = fread(buffer, 1, length, file); + if (ret_code != length) { + if (feof(file)) + printf("Error reading %s: unexpected end of file, read %llu of %llu bytes expected\n", name, (unsigned long long)ret_code, (unsigned long long)length); + else if (ferror(file)) + perror("Error reading data file"); + } + + buffer[length] = 0; + fclose(file); + + std::string ret(buffer); + free(buffer); + return ret; +} diff --git a/cplusplus/src/p0022.cpp b/cplusplus/src/p0022.cpp new file mode 100644 index 00000000..db974353 --- /dev/null +++ b/cplusplus/src/p0022.cpp @@ -0,0 +1,53 @@ +/** + * Project Euler Problem 22 + * + * I know that this could be done faster with a traditional for loop, but I wanted + * to see if iterators were reasonably possible in C, since it makes the prime + * number infrastructure a lot easier to set up. + * + * Problem: + * + * If we list all the natural numbers below 10 that are multiples of 3 or 5, we + * get 3, 5, 6 and 9. The sum of these multiples is 23. + * + * Find the sum of all the multiples of 3 or 5 below 1000. + */ +#ifndef EULER_P0022 +#define EULER_P0022 +#include +#include +#include +#include "include/utils.h" + +unsigned long long p0022() { + unsigned long long answer = 0; + std::string fstring = get_data_file("p0022_names.txt"); + const unsigned int name_count = 5163; + std::vector names(5163, ""); + size_t idx = 0, i = 0, pi = 0; + do { + while (fstring[i] && fstring[i] != ',') + i++; + const size_t len = i - pi - 2; + names[idx] = fstring.substr(pi + 1, len); + idx++; + pi = ++i; + } while (fstring[i]); + std::sort(names.begin(), names.end()); + for (idx = 0; idx < name_count; idx++) { + unsigned long score = 0; + for (i = 0; names[idx][i]; i++) { + score += names[idx][i] & 0x3F; + } + answer += score * (idx + 1); + } + return answer; +} + +#ifndef UNITY_END +int main(int argc, char const *argv[]) { + std::cout << p0022() << std::endl; + return 0; +} +#endif +#endif diff --git a/cplusplus/test.cpp b/cplusplus/test.cpp index a9bcf398..66eec111 100644 --- a/cplusplus/test.cpp +++ b/cplusplus/test.cpp @@ -17,6 +17,7 @@ #include "src/p0015.cpp" // #include "src/p0016.cpp" #include "src/p0017.cpp" +#include "src/p0022.cpp" #include "src/p0034.cpp" #include "src/p0076.cpp" #include "src/p0836.cpp" @@ -45,6 +46,7 @@ static const Answer answers[] = { {15, 137846528820, p0015}, // {16, 1366, p0016}, {17, 21124, p0017}, + {22, 871198282, p0022}, {34, 40730, p0034}, {76, 190569291, (unsigned long long (*)()) p0076}, }; diff --git a/cplusplus/test_euler.py b/cplusplus/test_euler.py index d7272fc6..4764fa31 100644 --- a/cplusplus/test_euler.py +++ b/cplusplus/test_euler.py @@ -30,6 +30,7 @@ 14: 837799, 15: 137846528820, 17: 21124, + 22: 871198282, 34: 40730, 76: 190569291, 836: b"aprilfoolsjoke", diff --git a/docs/cplusplus/p0015.rst b/docs/cplusplus/p0015.rst index dcb08240..78e43221 100644 --- a/docs/cplusplus/p0015.rst +++ b/docs/cplusplus/p0015.rst @@ -1,17 +1,17 @@ -C++ Implementation of Problem 15 +C++ Implementation of Problem 22 ================================ -View source code :source:`cplusplus/src/p0015.cpp` +View source code :source:`cplusplus/src/p0022.cpp` Includes -------- -- `math.h <./math.html>`__ +- `utils.h <./utils.html>`__ Solution -------- -.. cpp:function:: unsigned long long p0015() +.. cpp:function:: unsigned long long p0022() .. cpp:function:: int main(int argc, char const *argv[]) @@ -19,6 +19,6 @@ Solution This function is only present in the Python test runner, or when compiling as a standalone program. -.. literalinclude:: ../../cplusplus/src/p0015.cpp +.. literalinclude:: ../../cplusplus/src/p0022.cpp :language: C++ :linenos: diff --git a/docs/cplusplus/utils.rst b/docs/cplusplus/utils.rst new file mode 100644 index 00000000..96fc475b --- /dev/null +++ b/docs/cplusplus/utils.rst @@ -0,0 +1,18 @@ +utils.h +======= + +View source code :source:`cplusplus/src/include/utils.h` + +.. cpp:namespace-push:: utils + +.. cpp:function:: std::string get_data_file(const char *name) + + Return a character array containing the whole contents of a file found in _data. + +.. cpp:function:: char *get_parent_directory(const char *name, const unsigned int levels) + +.. cpp:namespace-pop:: + +.. literalinclude:: ../../cplusplus/src/include/utils.h + :language: C++ + :linenos: diff --git a/docs/index.rst b/docs/index.rst index 49973140..1dfad5ac 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -169,7 +169,7 @@ Problems Solved +-----------+------------+------------+------------+------------+------------+------------+ |:prob:`21` | | | | |:py-d:`0021`| | +-----------+------------+------------+------------+------------+------------+------------+ -|:prob:`22` |:c-d:`0022` | |:cs-d:`0022`|:js-d:`0022`|:py-d:`0022`|:rs-d:`0022`| +|:prob:`22` |:c-d:`0022` |:cp-d:`0022`|:cs-d:`0022`|:js-d:`0022`|:py-d:`0022`|:rs-d:`0022`| +-----------+------------+------------+------------+------------+------------+------------+ |:prob:`23` | | | | |:py-d:`0023`| | +-----------+------------+------------+------------+------------+------------+------------+