From 144442afba8b45709d0c3fe7b8992a1e3d6bac82 Mon Sep 17 00:00:00 2001 From: Niranjan <112152164+niranjank2022@users.noreply.github.com> Date: Fri, 21 Apr 2023 01:29:14 +0530 Subject: [PATCH 1/5] [feat/docs]: improve the Fibonacci algorithm (#1232) * Improve the documentation of factorial.c * Improve the documentation of fibonacci.c * Update starting terms of fibonacci as 0 and 1 * Update math/fibonacci.c Co-authored-by: Sharon "Cass" Cassidy <122662061+CascadingCascade@users.noreply.github.com> * docs: Documenting the code * test: Add test * fix: fix the test expression Co-authored-by: Sharon "Cass" Cassidy <122662061+CascadingCascade@users.noreply.github.com> * feat: Restrict non-integer inputs * fix: Change atoi() to sscanf() * fix: Change atoi() to sscanf() * fix: scanf() to getInput() * fix: while, continue and break Co-authored-by: Sharon "Cass" Cassidy <122662061+CascadingCascade@users.noreply.github.com> * fix: Increase buffer size * fix: Doesn't accept lengthy characters * fix: Accepts empty characters * fix: fibonacci.c Co-authored-by: Sharon "Cass" Cassidy <122662061+CascadingCascade@users.noreply.github.com> * feat: Add wikipedia link * feat: Add author Co-authored-by: David Leal * feat: Record time duration of function execution * chore: apply suggestions from code review Co-authored-by: Sharon "Cass" Cassidy * chore: apply suggestions from code review Co-authored-by: Sharon "Cass" Cassidy --------- Co-authored-by: Sharon "Cass" Cassidy <122662061+CascadingCascade@users.noreply.github.com> Co-authored-by: David Leal Co-authored-by: Sharon "Cass" Cassidy --- math/fibonacci.c | 125 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 113 insertions(+), 12 deletions(-) diff --git a/math/fibonacci.c b/math/fibonacci.c index 3af48962..60752e7a 100644 --- a/math/fibonacci.c +++ b/math/fibonacci.c @@ -1,23 +1,124 @@ -#include +/** + * @file + * @brief Program to print the nth term of the Fibonacci series. + * @details + * Fibonacci series generally starts from 0 and 1. Every next term in + * the series is equal to the sum of the two preceding terms. + * For further info: https://en.wikipedia.org/wiki/Fibonacci_sequence + * + * @author [Luiz Carlos Aguiar C](https://github.com/IKuuhakuI) + * @author [Niranjan](https://github.com/niranjank2022) + */ -// Fibonnacci function -int fib(int number) +#include /// for assert() +#include /// for errno - to determine whether there is an error while using strtol() +#include /// for input, output +#include /// for exit() - to exit the program +#include /// to calculate time taken by fib() +/** + * @brief Determines the nth Fibonacci term + * @param number - n in "nth term" and it can't be negative as well as zero + * @return nth term in unsigned type + * @warning + * Only till 47th and 48th fibonacci element can be stored in `int` and + * `unsigned int` respectively (takes more than 20 seconds to print) + */ +unsigned int fib(int number) { - if (number == 1 || number == 2) + // Check for negative integers + if (number <= 0) + { + fprintf(stderr, "Illegal Argument Is Passed!\n"); + exit(EXIT_FAILURE); + } + + // Base conditions + if (number == 1) + return 0; + + if (number == 2) return 1; - else - return fib(number - 1) + fib(number - 2); + + // Recursive call to the function + return fib(number - 1) + fib(number - 2); } +/** + * @brief Get the input from the user + * @return valid argument to the fibonacci function + */ +int getInput(void) +{ + int num, excess_len; + char buffer[3], *endPtr; + + while (1) + { // Repeat until a valid number is entered + printf("Please enter a valid number:"); + fgets(buffer, 3, stdin); // Inputs the value from user + + excess_len = 0; + if (!(buffer[0] == '\n' || + buffer[1] == '\n' || + buffer[2] == '\n')) { + while (getchar() != '\n') excess_len++; + } + + num = strtol(buffer, &endPtr, + 10); // Attempts to convert the string to integer + + // Checking the input + if ( // The number is too large + (excess_len > 0 || num > 48) || + // Characters other than digits are included in the input + (*endPtr != '\0' && *endPtr != '\n') || + // No characters are entered + endPtr == buffer) + { + continue; + } + + break; + } + + printf("\nEntered digit: %d (it might take sometime)\n", num); + return num; +} + +/** + * @brief self-test implementation + * @return void + */ +static void test() +{ + assert(fib(5) == 3); + assert(fib(2) == 1); + assert(fib(9) == 21); +} + +/** + * @brief Main function + * @return 0 on exit + */ int main() { - int number; + // Performing the test + test(); + printf("Tests passed...\n"); - // Asks for the number that is in n position in Fibonnacci sequence - printf("Number: "); - scanf("%d", &number); + // Getting n + printf( + "Enter n to find nth fibonacci element...\n" + "Note: You would be asked to enter input until valid number ( less " + "than or equal to 48 ) is entered.\n"); - printf("%d \n", fib(number)); + int number = getInput(); + clock_t start, end; + start = clock(); + printf("Fibonacci element %d is %u ", number, fib(number)); + end = clock(); + + printf("in %.3f seconds.\n", ((double)(end - start)) / CLOCKS_PER_SEC ); return 0; -} \ No newline at end of file +} From 3ba43b75ed5ea265ae6a9d905de4ee61ecd21435 Mon Sep 17 00:00:00 2001 From: David Leal Date: Wed, 26 Apr 2023 11:27:51 -0600 Subject: [PATCH 2/5] docs: improve contributing guidelines --- CONTRIBUTING.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d6064dbe..87686af3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -109,6 +109,9 @@ static void test() { assert(func(...) == ...); // this ensures that the algorithm works as expected // can have multiple checks + + // this lets the user know that the tests passed + printf("All tests have successfully passed!\n"); } /** From d07ab7d0f1b3845e3de73b1642ed2cb25638b933 Mon Sep 17 00:00:00 2001 From: David Leal Date: Thu, 27 Apr 2023 10:38:05 -0600 Subject: [PATCH 3/5] docs: add self-test examples (#1250) * docs: add self-test examples * updating DIRECTORY.md --------- Co-authored-by: github-actions[bot] --- CONTRIBUTING.md | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ DIRECTORY.md | 2 ++ 2 files changed, 98 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 87686af3..01638a59 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -57,6 +57,102 @@ For LeetCode solutions, please check its [**guide**](https://github.com/TheAlgor - Make sure to add examples and test cases in your `main()` function. - If you find an algorithm or document without tests, please feel free to create a pull request or issue describing suggested changes. - Please try to add one or more `test()` functions that will invoke the algorithm implementation on random test data with the expected output. Use the `assert()` function to confirm that the tests will pass. Requires including the `assert.h` library. +- Test cases should fully verify that your program works as expected. Rather than asking the user for input, it's best to make sure the given output is the correct output. + +##### Self-test examples + +1. [ROT13 Cipher](https://github.com/TheAlgorithms/C/blob/master/cipher/rot13.c) (complex). + +```c + // NOTE: the `rot13` function is defined in another part of the code. + + char test_01[] = "The more I C, the less I see."; + rot13(test_01); + assert(strcmp(test_01, "Gur zber V P, gur yrff V frr.") == 0); + + char test_02[] = "Which witch switched the Swiss wristwatches?"; + rot13(test_02); + assert(strcmp(test_02, "Juvpu jvgpu fjvgpurq gur Fjvff jevfgjngpurf?") == 0); + + char test_03[] = "Juvpu jvgpu fjvgpurq gur Fjvff jevfgjngpurf?"; + rot13(test_03); + assert(strcmp(test_03, "Which witch switched the Swiss wristwatches?") == 0); +``` + +2. [Sudoku Solver](https://github.com/TheAlgorithms/C/blob/master/misc/sudoku_solver.c) (medium). + +```c + uint8_t test_array[] = {3, 0, 6, 5, 0, 8, 4, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 7, 0, 0, 0, 0, 3, 1, 0, 0, 3, 0, 1, 0, 0, + 8, 0, 9, 0, 0, 8, 6, 3, 0, 0, 5, 0, 5, 0, 0, 9, 0, + 6, 0, 0, 1, 3, 0, 0, 0, 0, 2, 5, 0, 0, 0, 0, 0, 0, + 0, 0, 7, 4, 0, 0, 5, 2, 0, 6, 3, 0, 0}; + struct sudoku a = {.N = 9, .N2 = 3, .a = test_array}; + assert(solve(&a)); // ensure that solution is obtained + // NOTE: `solve` is defined in another part of the code. + + uint8_t expected[] = {3, 1, 6, 5, 7, 8, 4, 9, 2, 5, 2, 9, 1, 3, 4, 7, 6, + 8, 4, 8, 7, 6, 2, 9, 5, 3, 1, 2, 6, 3, 4, 1, 5, 9, + 8, 7, 9, 7, 4, 8, 6, 3, 1, 2, 5, 8, 5, 1, 7, 9, 2, + 6, 4, 3, 1, 3, 8, 9, 4, 7, 2, 5, 6, 6, 9, 2, 3, 5, + 1, 8, 7, 4, 7, 4, 5, 2, 8, 6, 3, 1, 9}; + for (int i = 0; i < a.N; i++) + for (int j = 0; j < a.N; j++) + assert(a.a[i * a.N + j] == expected[i * a.N + j]); +``` + +3. Small C program that showcases and explains the use of tests. + +```c +#include /// for IO operations +#include /// for assert +#include /// for bool + +/** + * @brief Verifies if the given array + * contains the given number on it. + * @param arr the array to be used for checking + * @param number the number to check if it's inside the array + * @return false if the number was NOT found in the array + * @return true if the number WAS found in the array + */ +bool is_number_on_array(const int *arr, const int number) { + for (int i = 0; i < sizeof(arr); i++) { + if (arr[i] == number) { + return true; + } + else { + // Number not in the current index, keep searching. + } + } + + return false; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void tests() { + int arr[] = { 9, 14, 21, 98, 67 }; + + assert(is_number_on_array(arr, 9) == true); + assert(is_number_on_array(arr, 4) == false); + assert(is_number_on_array(arr, 98) == true); + assert(is_number_on_array(arr, 512) == false); + + printf("All tests have successfully passed!\n"); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + tests(); // run self-test implementations + return 0; +} +``` #### Typical structure of a program diff --git a/DIRECTORY.md b/DIRECTORY.md index cad509a7..d970ad9c 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -3,6 +3,7 @@ * [Alaw](https://github.com/TheAlgorithms/C/blob/HEAD/audio/alaw.c) ## Cipher + * [Affine](https://github.com/TheAlgorithms/C/blob/HEAD/cipher/affine.c) * [Rot13](https://github.com/TheAlgorithms/C/blob/HEAD/cipher/rot13.c) ## Client Server @@ -182,6 +183,7 @@ * [Cartesian To Polar](https://github.com/TheAlgorithms/C/blob/HEAD/math/cartesian_to_polar.c) * [Catalan](https://github.com/TheAlgorithms/C/blob/HEAD/math/catalan.c) * [Collatz](https://github.com/TheAlgorithms/C/blob/HEAD/math/collatz.c) + * [Euclidean Algorithm Extended](https://github.com/TheAlgorithms/C/blob/HEAD/math/euclidean_algorithm_extended.c) * [Factorial](https://github.com/TheAlgorithms/C/blob/HEAD/math/factorial.c) * [Factorial Large Number](https://github.com/TheAlgorithms/C/blob/HEAD/math/factorial_large_number.c) * [Factorial Trailing Zeroes](https://github.com/TheAlgorithms/C/blob/HEAD/math/factorial_trailing_zeroes.c) From 2b885108b87561de7ebe9f8975cbdcdc2b276384 Mon Sep 17 00:00:00 2001 From: Aditya Pal Date: Fri, 28 Apr 2023 01:07:59 +0530 Subject: [PATCH 4/5] feat: add LeetCode problem 434 (#1252) * feat: add LeetCode problem 434 Adds solution of problem 434 for leetcode. Beats 100% Time, 97.18% space * docs: updating `leetcode/DIRECTORY.md` * Update 434.c --------- Co-authored-by: PalAditya Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Alexander Pantyukhin --- leetcode/DIRECTORY.md | 1 + leetcode/src/434.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 leetcode/src/434.c diff --git a/leetcode/DIRECTORY.md b/leetcode/DIRECTORY.md index 4807b447..d4436ea4 100644 --- a/leetcode/DIRECTORY.md +++ b/leetcode/DIRECTORY.md @@ -89,6 +89,7 @@ | 387 | [First Unique Character in a String](https://leetcode.com/problems/first-unique-character-in-a-string) | [C](./src/387.c) | Easy | | 389 | [Find the Difference](https://leetcode.com/problems/find-the-difference) | [C](./src/389.c) | Easy | | 404 | [Sum of Left Leaves](https://leetcode.com/problems/sum-of-left-leaves) | [C](./src/404.c) | Easy | +| 434 | [Number of Segments in a String](https://leetcode.com/problems/number-of-segments-in-a-string) | [C](./src/434.c) | Easy | | 442 | [Find All Duplicates in an Array](https://leetcode.com/problems/find-all-duplicates-in-an-array) | [C](./src/442.c) | Medium | | 461 | [Hamming Distance](https://leetcode.com/problems/hamming-distance) | [C](./src/461.c) | Easy | | 476 | [Number Complement](https://leetcode.com/problems/number-complement) | [C](./src/476.c) | Easy | diff --git a/leetcode/src/434.c b/leetcode/src/434.c new file mode 100644 index 00000000..a2d05d5c --- /dev/null +++ b/leetcode/src/434.c @@ -0,0 +1,20 @@ +// Given a string s, returns the number of segments in the string. +int countSegments(char * s){ + int sLen = strlen(s); + int prevSpace = 1; + int result = 0; + char currChar; + + for (int i = 0; i < sLen; i++){ + currChar = s[i]; + + //A string of whitespaces will only be counted once as the condition below is only true when we transition from whitespace to non-whitespace. + //Since we start with assumed whitespace (prevSpace = 1), initial whitespaces are handled as well, if any + if (s[i] != ' ' && prevSpace) { + result++; + } + prevSpace = (currChar == ' '); + } + + return result; +} From 71a7cf3bc4696a49f5bc4e81ce8d569d2c238cb2 Mon Sep 17 00:00:00 2001 From: MRio <55620821+AtlantaEmrys2002@users.noreply.github.com> Date: Sun, 30 Apr 2023 16:47:09 +0100 Subject: [PATCH 5/5] feat: added hangman game #967 (#1248) * Add files via upload feat: added hangman game #967 * Update hangman.c * Update hangman.c * Update hangman.c * Update hangman.c * Update hangman.c * Update hangman.c Updated so that game instance was held as struct - can include current guess in game_instance too if preferred. * Update hangman.c * Update hangman.c * Add files via upload Adding test file * Update hangman.c * Update hangman.c Co-authored-by: David Leal Co-authored-by: Sharon "Cass" Cassidy --- games/hangman.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++++ games/words.txt | 8 ++ 2 files changed, 299 insertions(+) create mode 100644 games/hangman.c create mode 100644 games/words.txt diff --git a/games/hangman.c b/games/hangman.c new file mode 100644 index 00000000..5d2697df --- /dev/null +++ b/games/hangman.c @@ -0,0 +1,291 @@ +/** + * @file + * @brief C implementation of [Hangman Game](https://en.wikipedia.org/wiki/Hangman_(game)) + * @details + * Simple, readable version of hangman. + * Changed graphic to duck instead of traditional stick figure (same number of guesses). + * @author [AtlantaEmrys2002](https://github.com/AtlantaEmrys2002) +*/ + +#include /// for main() - tolower() +#include /// for main(), new_word(), new_guess(), won() - I/O operations +#include /// for all functions - exit(), rand() and file functions +#include /// for main() - for string operations strlen, strchr, strcpy +#include /// for new_game() - used with srand() for declaring new game instance + +/* + * @brief game_instance structure that holds current state of game + */ +struct game_instance{ + + char current_word[30]; ///< word to be guessed by player + char hidden[30]; ///< hidden version of word that is displayed to player + int size; ///< size of word + int incorrect; ///< number of incorrect guesses + char guesses[25]; ///< previous guesses + int guesses_size; ///< size of guesses array + +}; + +// function prototypes +struct game_instance new_game(void); // creates a new game +int new_guess(char, const char guesses[], int size); // checks if player has already played letter +int in_word(char, const char word[], unsigned int size); // checks if letter is in word +void picture(int score); // outputs image of duck (instead of hang man) +void won(const char word[], int score); // checks if player has won or lost + +/** + * @brief Main Function + * @returns 0 on exit + */ +int main() { + + struct game_instance game = new_game(); // new game created + char guess; // current letter guessed by player + + // main loop - asks player for guesses + while ((strchr(game.hidden, '_') != NULL) && game.incorrect <= 12) { + do { + printf("\n****************************\n"); + printf("Your word: "); + + for (int i = 0; i < game.size; i++) { + printf("%c ", game.hidden[i]); + } + + if (game.guesses_size > 0) { + printf("\nSo far, you have guessed: "); + for (int i = 0; i < game.guesses_size; i++) { + printf("%c ", game.guesses[i]); + } + } + + printf("\nYou have %d guesses left.", (12 - game.incorrect)); + printf("\nPlease enter a letter: "); + scanf(" %c", &guess); + guess = tolower(guess); + + } while (new_guess(guess, game.guesses, game.guesses_size) != -1); + + game.guesses[game.guesses_size] = guess; // adds new letter to guesses array + game.guesses_size++; // updates size of guesses array + + if (in_word(guess, game.current_word, game.size) == 1) { + printf("That letter is in the word!"); + for (int i = 0; i < game.size; i++) { + if ((game.current_word[i]) == guess) { + game.hidden[i] = guess; + } + } + } else { + printf("That letter is not in the word.\n"); + (game.incorrect)++; + } + picture(game.incorrect); + } + + won(game.current_word, game.incorrect); + return 0; +} + +/** + * @brief checks if letter has been guessed before + * @param new_guess letter that has been guessed by player + * @param guesses array of player's previous guesses + * @param size size of guesses[] array + * @returns 1 if letter has been guessed before + * @returns -1 if letter has not been guessed before + */ +int new_guess(char new_guess, const char guesses[], int size) { + + for (int j = 0; j < size; j++) { + if (guesses[j] == new_guess) { + printf("\nYou have already guessed that letter."); + return 1; + } + } + + return -1; +} + +/** + * @brief checks if letter is in current word + * @param letter letter guessed by player + * @param word current word + * @param size length of word + * @returns 1 if letter is in word + * @returns -1 if letter is not in word + */ +int in_word(char letter, const char word[], unsigned int size) { + + for (int i = 0; i < size; i++) { + if ((word[i]) == letter) { + return 1; + } + } + + return -1; +} + +/** + * @brief creates a new game - generates a random word and stores in global variable current_word + * @returns current_game - a new game instance containing randomly selected word, its length and hidden version of word + */ +struct game_instance new_game() { + + char word[30]; // used throughout function + + FILE *fptr; + fptr = fopen("games/words.txt", "r"); + + if (fptr == NULL){ + fprintf(stderr, "File not found.\n"); + exit(EXIT_FAILURE); + } + + // counts number of words in file - assumes each word on new line + int line_number = 0; + while (fgets(word, 30, fptr) != NULL) { + line_number++; + } + + rewind(fptr); + + // generates random number + int random_num; + srand(time(NULL)); + random_num = rand() % line_number; + + // selects randomly generated word + int s = 0; + while (s <= random_num){ + fgets(word, 30, fptr); + s++; + } + + // formats string correctly + if (strchr(word, '\n') != NULL){ + word[strlen(word) - 1] = '\0'; + } + + fclose(fptr); + + // creates new game instance + struct game_instance current_game; + strcpy(current_game.current_word, word); + current_game.size = strlen(word); + for (int i = 0; i < (strlen(word)); i++) { + current_game.hidden[i] = '_'; + } + current_game.incorrect = 0; + current_game.guesses_size = 0; + + return current_game; +} + +/** + * @brief checks if player has won or lost + * @param word the word player has attempted to guess + * @param score how many incorrect guesses player has made + * @returns void + */ +void won(const char word[], int score) { + if (score > 12) { + printf("\nYou lost! The word was: %s.\n", word); + } + else { + printf("\nYou won! You had %d guesses left.\n", (12 - score)); + } +} + +/* + * @brief gradually draws duck as player gets letters incorrect + * @param score how many incorrect guesses player has made + * @returns void + */ +void picture(int score) { + + switch(score) { + + case 12: + printf("\n _\n" + " __( ' )> \n" + " \\_ < _ ) "); + break; + + case 11: + printf("\n _\n" + " __( ' )\n" + " \\_ < _ ) "); + break; + + case 10: + printf("\n _\n" + " __( )\n" + " \\_ < _ ) "); + break; + + case 9: + printf("\n \n" + " __( )\n" + " \\_ < _ ) "); + break; + + case 8: + printf("\n \n" + " __( \n" + " \\_ < _ ) "); + break; + + case 7: + printf("\n \n" + " __ \n" + " \\_ < _ ) "); + break; + + case 6: + printf("\n \n" + " _ \n" + " \\_ < _ ) "); + break; + + case 5: + printf("\n \n" + " _ \n" + " _ < _ ) "); + break; + + case 4: + printf("\n \n" + " \n" + " _ < _ ) "); + break; + + case 3: + printf("\n \n" + " \n" + " < _ ) "); + break; + + case 2: + printf("\n \n" + " \n" + " _ ) "); + break; + + case 1: + printf("\n \n" + " \n" + " ) "); + break; + + case 0: + break; + + default: + printf("\n _\n" + " __( ' )> QUACK!\n" + " \\_ < _ ) "); + break; + } +} diff --git a/games/words.txt b/games/words.txt new file mode 100644 index 00000000..0db94bf6 --- /dev/null +++ b/games/words.txt @@ -0,0 +1,8 @@ +dog +cat +tree +flower +table +programming +language +testing \ No newline at end of file