Last active
September 27, 2020 12:01
-
-
Save svagionitis/2f9c9ddc4dc760845beb to your computer and use it in GitHub Desktop.
Implement the look and say sequence in C. More info about the look and say sequence here http://en.wikipedia.org/wiki/Look-and-say_sequence
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @file look_and_say_seq.c | |
* @author Stavros Vagionitis | |
* @date 01 Feb 2015 | |
* @brief Implement the look and say sequence. More info | |
* here http://en.wikipedia.org/wiki/Look-and-say_sequence | |
*/ | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <string.h> | |
/** | |
* \brief Swap pointers | |
* | |
* \param p1 [IN/OUT] First pointer | |
* \param p2 [IN/OUT] Second pointer | |
*/ | |
void swap_ptr(uint8_t **p1, uint8_t **p2) | |
{ | |
if (!p1 && !*p1) | |
return; | |
if (!p2 && !*p2) | |
return; | |
uint8_t *tmp = *p2; | |
*p2 = *p1; | |
*p1 = tmp; | |
} | |
/** | |
* \brief Update the sequence giving the previous sequence. | |
* | |
* \param seq [IN] The previous sequence | |
* \param sizeof_seq [IN] The size of the previous sequence. | |
* \param new_seq [OUT] The new sequence | |
* \param sizeof_new_seq [OUT] The size of the new sequence. | |
* \return 1 if everything is ok, 0 if not. | |
*/ | |
uint8_t update_seq(const uint8_t *seq, const uint64_t sizeof_seq, uint8_t **new_seq, uint64_t *sizeof_new_seq) | |
{ | |
if(*new_seq) | |
*new_seq = NULL; | |
*sizeof_new_seq = 0; | |
if (seq == NULL) | |
{ | |
fprintf(stderr, "%s:%d seq is NULL\n", __func__, __LINE__); | |
return 0; | |
} | |
uint8_t *tmp = NULL; | |
uint64_t counter = 0; | |
for (uint64_t i = 0;i<sizeof_seq;i++) | |
{ | |
tmp = NULL; | |
if (i == 0) | |
counter++; | |
if (i > 0) | |
{ | |
// If the current digit is the same | |
// with the previous add it to the | |
// counter. | |
if (seq[i-1] == seq[i]) | |
counter++; | |
else | |
{ | |
// If the current digit is not the same | |
// with the previous, then allocate two | |
// places in the new sequence, one for the | |
// counter and the other for the previous digit. | |
*sizeof_new_seq += 2; | |
tmp = realloc(*new_seq, *sizeof_new_seq * sizeof(uint8_t)); | |
if (tmp != NULL) | |
*new_seq = tmp; | |
else | |
{ | |
fprintf(stderr, "%s:%d Mem Alloc failed\n", __func__, __LINE__); | |
if (*new_seq) | |
free(*new_seq); | |
return 0; | |
} | |
(*new_seq)[*sizeof_new_seq - 2] = counter; | |
(*new_seq)[*sizeof_new_seq - 1] = seq[i-1]; | |
// Start counter from 1 for | |
// counting the current digit. | |
counter = 1; | |
} | |
} | |
// The last number in sequence. | |
if (i == sizeof_seq - 1) | |
{ | |
*sizeof_new_seq += 2; | |
tmp = realloc(*new_seq, *sizeof_new_seq * sizeof(uint8_t)); | |
if (tmp != NULL) | |
*new_seq = tmp; | |
else | |
{ | |
fprintf(stderr, "%s:%d Mem Alloc failed\n", __func__, __LINE__); | |
if (*new_seq) | |
free(*new_seq); | |
return 0; | |
} | |
(*new_seq)[*sizeof_new_seq - 2] = counter; | |
(*new_seq)[*sizeof_new_seq - 1] = seq[i]; | |
} | |
} | |
return 1; | |
} | |
/** | |
* \brief Print the sequence numbers in a line. | |
* | |
* \param seq [IN] The sequence itself. | |
* \param size_seq [IN] The size of the sequence. | |
* \return 1 if everything is ok, 0 if not. | |
*/ | |
uint8_t print_seq(const uint8_t *seq, const uint64_t size_seq) | |
{ | |
if (seq == NULL) | |
{ | |
fprintf(stderr, "%s:%d seq is NULL\n", __func__, __LINE__); | |
return 0; | |
} | |
for (uint64_t i = 0;i<size_seq;i++) | |
{ | |
if (i != size_seq-1) | |
fprintf(stdout, "%u", seq[i]); | |
else | |
fprintf(stdout, "%u -- %llu\n", seq[i], size_seq); | |
} | |
return 1; | |
} | |
/** | |
* \brief Count digits of an unsigned integer | |
* | |
* \param num [IN] The number to count the digits | |
* \return the number of digits. | |
*/ | |
uint64_t count_digits(const uint64_t num) | |
{ | |
uint64_t c = 0; | |
uint64_t n = num; | |
while(n) | |
{ | |
n/=10; | |
c++; | |
} | |
return c; | |
} | |
void usage(char *argv0) | |
{ | |
fprintf(stdout, "%s [starting value] [iterations]\n", argv0); | |
exit(0); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
uint64_t start = 0; | |
uint64_t total_iter = 0; | |
if (argc != 3) | |
usage(argv[0]); | |
if (argv[1]) | |
start = (uint64_t)atoi(argv[1]); | |
else | |
usage(argv[0]); | |
if (argv[2]) | |
total_iter = (uint64_t)atoi(argv[2]); | |
else | |
usage(argv[0]); | |
// Current sequence. | |
uint8_t *seq = NULL; | |
uint64_t seq_size = count_digits(start); | |
seq = malloc(seq_size * sizeof(uint8_t)); | |
// Convert the starting number in a number sequence | |
int d = 0; | |
for(d = seq_size - 1; d >= 0;d--) | |
{ | |
seq[d] = start % 10; | |
start /= 10; | |
} | |
// New sequence. | |
uint8_t *new_seq = NULL; | |
uint64_t new_seq_size = 0; | |
for (uint64_t i = 0;i<total_iter;i++) | |
{ | |
update_seq(seq, seq_size, &new_seq, &new_seq_size); | |
print_seq(new_seq, new_seq_size); | |
seq_size = new_seq_size; | |
new_seq_size = 0; | |
swap_ptr(&seq, &new_seq); | |
if (new_seq) | |
free(new_seq); | |
} | |
if (seq) | |
free(seq); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
all: look_and_say_seq | |
look_and_say_seq: look_and_say_seq.c | |
gcc -o look_and_say_seq -O2 -Wall -W -ansi -pedantic -std=gnu99 look_and_say_seq.c | |
clean: | |
rm -rf look_and_say_seq |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment