From 27e7432ea9ca4736020948ac3d81c2b262f90a16 Mon Sep 17 00:00:00 2001 From: Mike Rivnak Date: Mon, 9 Dec 2024 22:23:22 -0500 Subject: [PATCH] c: palindrome-products --- c/palindrome-products/HELP.md | 73 ++++++++++ c/palindrome-products/README.md | 62 +++++++++ c/palindrome-products/palindrome_products.c | 140 ++++++++++++++++++++ c/palindrome-products/palindrome_products.h | 25 ++++ 4 files changed, 300 insertions(+) create mode 100644 c/palindrome-products/HELP.md create mode 100644 c/palindrome-products/README.md create mode 100644 c/palindrome-products/palindrome_products.c create mode 100644 c/palindrome-products/palindrome_products.h diff --git a/c/palindrome-products/HELP.md b/c/palindrome-products/HELP.md new file mode 100644 index 0000000..3cfb596 --- /dev/null +++ b/c/palindrome-products/HELP.md @@ -0,0 +1,73 @@ +# Help + +## Running the tests + +Get the first test compiling, linking and passing by following the [three rules of test-driven development][3-tdd-rules]. + +The included makefile can be used to create and run the tests using the `test` task. + +```console +$ make test +``` + +Create just the functions you need to satisfy any compiler errors and get the test to fail. +Then write just enough code to get the test to pass. +Once you've done that, move onto the next test. + +As you progress through the tests, take the time to refactor your implementation for readability and expressiveness and then go on to the next test. + +Try to use standard C99 facilities in preference to writing your own low-level algorithms or facilities by hand. + +## Checking for memory leaks + +The makefile comes also with a build that checks some common mistakes regarding memory leaks and out of bound access to arrays. +To run these checks, use the following at the command line: + +```console +$ make memcheck +``` + +[3-tdd-rules]: https://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.html + +## Submitting your solution + +You can submit your solution using the `exercism submit palindrome_products.c palindrome_products.h` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [C track's documentation](https://exercism.org/docs/tracks/c) +- The [C track's programming category on the forum](https://forum.exercism.org/c/programming/c) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Make sure you have read the [C track-specific documentation][c-track] on the Exercism site. +This covers the basic information on setting up the development environment expected by the exercises. + +## Submitting Incomplete Solutions + +If you are struggling with a particular exercise, it is possible to submit an incomplete solution so you can see how others have completed the exercise. + +## Resources + +To get help if having trouble, you can use the following resources: + +- [StackOverflow][] can be used to search for your problem and see if it has been answered already. You can also ask and answer questions. +- [CPPReference][] can be used to look up information on C concepts, operators, types, standard library functions and more. +- [TutorialsPoint][] has similar content as CPPReference in its C programming section. +- [The C Programming][K&R] book by K&R is the original source of the language and is still useful today. + +[c-track]: https://exercism.org/docs/tracks/c +[stackoverflow]: http://stackoverflow.com/questions/tagged/c +[cppreference]: https://en.cppreference.com/w/c +[tutorialspoint]: https://www.tutorialspoint.com/cprogramming/ +[K&R]: https://www.amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/0131103628/ \ No newline at end of file diff --git a/c/palindrome-products/README.md b/c/palindrome-products/README.md new file mode 100644 index 0000000..4bd1c1f --- /dev/null +++ b/c/palindrome-products/README.md @@ -0,0 +1,62 @@ +# Palindrome Products + +Welcome to Palindrome Products on Exercism's C Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Detect palindrome products in a given range. + +A palindromic number is a number that remains the same when its digits are reversed. +For example, `121` is a palindromic number but `112` is not. + +Given a range of numbers, find the largest and smallest palindromes which +are products of two numbers within that range. + +Your solution should return the largest and smallest palindromes, along with the factors of each within the range. +If the largest or smallest palindrome has more than one pair of factors within the range, then return all the pairs. + +## Example 1 + +Given the range `[1, 9]` (both inclusive)... + +And given the list of all possible products within this range: +`[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 15, 21, 24, 27, 20, 28, 32, 36, 25, 30, 35, 40, 45, 42, 48, 54, 49, 56, 63, 64, 72, 81]` + +The palindrome products are all single digit numbers (in this case): +`[1, 2, 3, 4, 5, 6, 7, 8, 9]` + +The smallest palindrome product is `1`. +Its factors are `(1, 1)`. +The largest palindrome product is `9`. +Its factors are `(1, 9)` and `(3, 3)`. + +## Example 2 + +Given the range `[10, 99]` (both inclusive)... + +The smallest palindrome product is `121`. +Its factors are `(11, 11)`. +The largest palindrome product is `9009`. +Its factors are `(91, 99)`. + +## Source + +### Created by + +- @ryanplusplus + +### Contributed to by + +- @bcc32 +- @Gamecock +- @h-3-0 +- @patricksjackson +- @QLaille +- @vlzware +- @wolf99 +- @ZapAnton + +### Based on + +Problem 4 at Project Euler - https://projecteuler.net/problem=4 \ No newline at end of file diff --git a/c/palindrome-products/palindrome_products.c b/c/palindrome-products/palindrome_products.c new file mode 100644 index 0000000..6ddd3f0 --- /dev/null +++ b/c/palindrome-products/palindrome_products.c @@ -0,0 +1,140 @@ +#include "palindrome_products.h" + +#include +#include +#include +#include +#include +#include + +bool is_palindrome(const int number); +void free_factor(factor_t *f); + +product_t *get_palindrome_product(int from, int to) +{ + product_t *result = malloc(sizeof(product_t)); + result->smallest = INT_MAX; + result->largest = INT_MIN; + result->factors_lg = NULL; + result->factors_sm = NULL; + memset(result->error, '\0', MAXERR); + + if (from > to) + { + snprintf(result->error, MAXERR - 1, "invalid input: min is %d and max is %d", from, to); + return result; + } + + for (int i = from; i <= to; i++) + { + for (int j = from; j <= to; j++) + { + int product = i * j; + if (!is_palindrome(product)) + { + continue; + } + + if (product < result->smallest) + { + free_factor(result->factors_sm); + result->factors_sm = malloc(sizeof(factor_t)); + result->factors_sm->factor_a = i; + result->factors_sm->factor_b = j; + result->factors_sm->next = NULL; + result->smallest = product; + } + else if (product == result->smallest) + { + factor_t *new = malloc(sizeof(factor_t)); + new->factor_a = i; + new->factor_b = j; + new->next = NULL; + + factor_t *tail = result->factors_sm; + while (true) + { + if (tail->next == NULL) + { + break; + } + tail = tail->next; + } + + tail->next = new; + } + + if (product > result->largest) + { + free_factor(result->factors_lg); + result->factors_lg = malloc(sizeof(factor_t)); + result->factors_lg->factor_a = i; + result->factors_lg->factor_b = j; + result->factors_lg->next = NULL; + result->largest = product; + } + else if (product == result->largest) + { + factor_t *new = malloc(sizeof(factor_t)); + new->factor_a = i; + new->factor_b = j; + new->next = NULL; + + factor_t *tail = result->factors_lg; + while (true) + { + if (tail->next == NULL) + { + break; + } + tail = tail->next; + } + + tail->next = new; + } + } + } + + if (result->factors_lg == NULL && result->factors_sm == NULL) + { + snprintf(result->error, MAXERR - 1, "no palindrome with factors in the range %d to %d", from, to); + } + + return result; +} +void free_product(product_t *p) +{ + if (p == NULL) + { + return; + } + + free_factor(p->factors_sm); + free_factor(p->factors_lg); + free(p); +} + +void free_factor(factor_t *f) +{ + if (f == NULL) + { + return; + } + + free_factor(f->next); + free(f); +} + +bool is_palindrome(const int number) +{ + int reverse = 0; + int temp = number; + + while (temp != 0) + { + reverse = (reverse * 10) + (temp % 10); + temp = temp / 10; + } + + return reverse == number; +} diff --git a/c/palindrome-products/palindrome_products.h b/c/palindrome-products/palindrome_products.h new file mode 100644 index 0000000..e7a3dd8 --- /dev/null +++ b/c/palindrome-products/palindrome_products.h @@ -0,0 +1,25 @@ +#ifndef PALINDROME_PRODUCTS_H +#define PALINDROME_PRODUCTS_H + +#define MAXERR 100 + +typedef struct factors +{ + int factor_a; + int factor_b; + struct factors *next; +} factor_t; + +typedef struct product +{ + int smallest; + int largest; + factor_t *factors_sm; + factor_t *factors_lg; + char error[MAXERR]; +} product_t; + +product_t *get_palindrome_product(int from, int to); +void free_product(product_t *p); + +#endif