Cyclops Numbers – Solution

I hope this month’s Exercise didn’t terrify you. I remember seeing The Seventh Voyage of Sinbad when I was a kid. The cyclops bothered me so much I asked my mom questions about him for a month.

A cyclops number is neither 10 meters tall nor impervious to javelins. It is, however, easy to catch when you do as I did and use the sprintf() function to convert the value into a string. Afterwards, you scan the string for the presence of a zero digit and then determine whether that single zero dwells in the center of the odd-character string.

For my solution, I crafted the zero_count() function. It consumes a string and returns the number of zeros. This function helped reduce my solution’s main loop to a handful of if tests that pluck out a cyclopean value.

2022_09-Exercise.c

#include <stdio.h>
#include <string.h>

/* count the zero '0' characters in the string */
int zero_count(char *v)
{
    int a = 0;

    /*
       - crawl through the string
       - okay to modify v here
    */
    while( *v )
    {
        if( *v == '0' )
            a++;        /* count '0' character */
        v++;            /* increment pointer */
    }

    return(a);
}

int main()
{
    const char digits = 6;        /* storage for up to 5 digits */
    const int total = 100;        /* total numbers to find */
    const int columns = 9;        /* number of columns for output table */
    int cyclops,count,len,mid,x,y;
    char buffer[digits];
    int results[total];            /* store the results for fancy output */

    printf("The first %d cyclops numbers\n",total);
    cyclops = count = 0;
    while( count<total )
    {
        sprintf(buffer,"%d",cyclops);
        len = strlen(buffer);
        /* process strings greater than two characters
           and only odd-length strings */
        if( len>2 && len%2 )
        {
            /* must have only one zero */
            if( zero_count(buffer)==1 )
            {
                mid = len/2;            /* middle character offset */
                if(buffer[mid]=='0' )    /* is zero? */
                {
                    /* save the value and update the count */
                    results[count] = cyclops;
                    count++;
                }
            }
        }

        /* next potential cyclops value */
        cyclops++;
    }

    /* output the results in a fancy table */
    x = 0;
    while( count )
    {
        for( y=0; y<columns; y++ )
        {
            printf("%5d",results[(x*columns)+y]);
            count--;                /* decrement the count */
            if( !count )            /* if count is zero, stop */
                break;
            if( y<columns-1)
                putchar('\t');
        }
        x++;
        putchar('\n');
    }


    return(0);
}

The zero_count() function plows through string v looking for zero digit characters. It counts the total and returns this value.

In the main() function, a while loop uses variable count to tally the first 100 cyclops values. Three if tests cull the results as variable cyclops increments from zero.

The first if test ensures that the string length (len) value has at least three digits and an odd length: if( len>2 && len%2 )

The second if test confirms that the value has only one zero:

if( zero_count(buffer)==1 )

The final if test uses variable mid to seek out the string’s center digit: mid = len/2; As these variables are integers, the result is rounded. Then the final if test checks the center digit: if(buffer[mid]=='0' ) Upon success, the value is stored in the results[] array, and variable count is incremented.

The final while loop generates a multi-column table displaying the results. You can read details on how this loop works in a future Lesson.

I hope your solution met with success. From the earlier post on counting digits, obviously logarithms and division can also be used to determine the number of digits in a value. If you used one of these approaches in your solution, all the better!

3 thoughts on “Cyclops Numbers – Solution

  1. Just interested in your thoughts on the differences between (a) going through all the numbers and testing for Cyclops numbers, and (b) generating the Cyclops numbers in order. Your solution has the advantage of being easier to code, but as the numbers become longer and longer the proportion of Cyclops numbers will slowly but surely drop, meaning more and more time testing numbers which aren’t Cyclops. My solution generates all Cyclops numbers which (I hope!) means it is more efficient in the long run.

  2. #include <stdio.h>
    #include <stdlib.h>

    int increment(int *digits, int nDigits) {

    // increment an nDigits-long number, ensuring there are no zeros
    // digits are stored in an int array

    int *currDigit = digits + nDigits – 1; // find last digit
    int done = 0;
    while (!done) {
    (*currDigit)++;
    if (*currDigit == 10) {
    // time to tick over the next digit to the left
    *currDigit = 1;
    *currDigit–;
    done = (currDigit < digits); // have we gone past the front?
    }
    else
    return 1; // increment was successful
    }
    return 0; // No valid increment, all done
    }

    int main (void) {

    int *digitBuffer = NULL, *pre, *post, digits = 1, count = 0;
    const int countLimit = 100;

    while (count < countLimit) {
    if (!digitBuffer) {
    // first time entering loop with this number of digits
    digitBuffer = malloc(2 * digits * sizeof(int));
    if (!digitBuffer) {
    printf("No memory for malloc()\n");
    return 1;
    }
    pre = digitBuffer;
    post = digitBuffer + digits;
    for (int d = 0; d < digits; d++)
    *(pre + d) = *(post + d) = 1;
    *(post + digits – 1) = 0; // set *post ready to be incremented
    }
    if (increment(post, digits)) {
    // success! Print the Cyclops number and keep count
    for (int d = 0; d < digits; d++)
    putchar(‘0’ + *(pre + d));
    putchar(‘0’);
    for (int d = 0; d < digits; d++)
    putchar(‘0’ + *(post + d));
    putchar(‘\n’);
    count++;
    }
    else {
    // failed to increment, so … try to increment pre
    if (increment(pre, digits)) {
    // success! reset post to be ready to be incremented next loop
    for (int d = 0; d < digits – 1; d++)
    *(post + d) = 1;
    *(post + digits – 1) = 0;
    }
    else {
    // OK, run out of digits. Reset and start again with one more digit
    free(digitBuffer);
    digitBuffer = NULL;
    digits++;
    }
    }
    }

    free(digitBuffer);
    return 0;
    }

  3. Now that’s darn clever! I didn’t think of that approach, which is purely constructive as opposed to mine which is more of a hunt. I congratulate you on such a clever solution!

Leave a Reply