(void *) blog

Posted on by fortytwo_de


FizzBuzz es un problema ideado para comprobar que un programador es capaz de resolver problemas sencillos. Aunque es contraintuitivo, resulta que una gran parte de programadores no saben programar fuera de los quince problemas que saben resolver de memoria.

El enunciado del problema es muy sencillo:

Write a program that prints the numbers from 1 to 100. But for multiples of three print "Fizz" instead of the number and for the multiples of five print "Buzz". For numbers which are multiples of both three and five print "FizzBuzz".

La forma más directa de aproximarse a este problema es hacer una implementación al pie de la letra. Es decir (pseudocódigo):

if(n % 3 == 0):
    print "Fizz"
else if(n % 5 == 0):
    print "Buzz"
else if(n % 15 == 0):
    print "FizzBuzz"
else
    print n

Vale, hasta ahí todo bien. Las posibles ramificaciones de este programa son estas:

(realmente las ramas "Fizz", "Buzz" y "FizzBuzz" llevan un XOR delante, porque están dentro de else.)

La siguiente vuelta de tuerca que se le puede dar es eliminar la rama de "FizzBuzz", quitando el requerimiento de exclusividad:

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

int main(int argc, char** argv)
{
    int i;

    if(argc != 2) return EXIT_FAILURE;

    for(i = 1; i < atoi(argv[1]) + 1; i++)
    {
        if(i % 3 == 0)
            printf("Fizz");

        if(i % 5 == 0)
            printf("Buzz");

        if(!(i % 3 == 0 || i % 5 == 0))
            printf("%d", i);

        printf("\n");
    }

    return EXIT_SUCCESS;
}

Bien, esto es básicamente el ejemplo canónico de un FizzBuzz. A partir de aquí, se pueden hacer implementaciones más interesantes. Por ejemplo, se me ocurre una versión recursiva:

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

void fizzbuzz(int max)
{
    static int i = 1;
    if(i == max + 1) return;

    if(i % 3 == 0)
        printf("Fizz");

    if(i % 5 == 0)
        printf("Buzz");

    if(!(i % 3 == 0 || i % 5 == 0))
        printf("%d", i);

    printf("\n");

    i++;
    fizzbuzz(max);
}

int main(int argc, char** argv)
{
    if(argc != 2) return EXIT_FAILURE;

    fizzbuzz(atoi(argv[1]));

    return EXIT_SUCCESS;
}

Lo interesante aquí es la variable estática i. Las variables estáticas sólo se inicializan la primera vez, y aunque la declaración esté en una función persiste entre llamadas a la función (al contrario que las variables auto, que se destruyen cuando termina la función). Por lo tanto, las variables static son útiles para persistir estados en funciones recursivas. Son comparables a las variables globales.

Otra forma de resolver el problema que se me ocurre es usar una variable que contenga la información de cada número y determine si se debe mostrar "Fizz" o "Buzz".

Esto se puede conseguir de varias formas, pero la más elegante es usar un tipo de pocos bits y utilizarlos como "interruptores":

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

enum FizzBuzz
{
    FIZZ = 1,
    BUZZ = 2
};

int main(int argc, char** argv)
{
    int i;
    uint8_t fizzbuzz;
    if(argc != 2) return EXIT_FAILURE;

    for(i = 1; i < atoi(argv[1]) + 1; i++)
    {
        fizzbuzz = 
            ((i % 3 == 0) ? (1 << FIZZ) : 0) | 
            ((i % 5 == 0) ? (1 << BUZZ) : 0);

        if((fizzbuzz >> FIZZ) & 1)
            printf("Fizz");

        if((fizzbuzz >> BUZZ) & 1)
            printf("Buzz");

        if(fizzbuzz == 0)
            printf("%d", i);

        printf("\n");
    }

    return EXIT_SUCCESS;
}

Aquí uso la variable fizzbuzz para saber qué mensajes hay que mostrar. Esto me permite que las condiciones de los if sean mucho más legibles y uniformes, porque la lógica del problema está contenida en pocas líneas.

Y finalmente, solo for the lulz, una versión obfuscada de la solución:

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

#define A for(i=1;i<atoi(argv[1])+1;i++){
#define ME return 1; int lol[4] = {2054842694, 0, 2054845762, 0};
#define PLEASE if(!(i%3==0|i%5==0))printf("%d",i);printf("\n");}return 0;}
#define FIZZBUZZ if(i%3==0)printf("%s", (char*) lol); if(i%5==0)printf("%s", (char*) lol+8);
#define MAKE int main(int argc,char** argv){int i;if(argc!=2)

MAKE ME A FIZZBUZZ PLEASE

Puntos extra para quien consiga explicar en los comentarios cómo funciona esta versión obfuscada :-)

(Pista: puedes echar un ojo al repositorio en GitHub)

Posted on by fortytwo_de | Posted in C, Programación


One Response to FizzBuzz

  1. David says:


    No resulta ser tan fácil, si lo quieres conseguir con solo dos strings (“Fizz” y “Buzz”, pero sin “FizzBuzz”), y a la vez solo dos comprobaciones de la divisibilidad. Tu solución me parece muy limpia. La mia es quizás mas eficaz (aunque no estoy seguro), pero es un estilo horroroso:

    #include

    // please do not use in production code

    int main(void)
    {
    int i;

    for(i=1;i<=100;++i)
    {
    if( !( (i%3==0) && printf("Fizz") ) & !( (i%5==0) && printf("Buzz") ) )
    {
    printf("%d",i);
    }
    printf("\n");
    }

    return 0;
    }

    Ojo con el uso de & y &&.

    En tu versión obfuscada los números en el array “lol” simplemente los dejas interpretar como un string, que al final te da “Fizz” o “Buzz”. Hay que estar atento si el sistema guarda ints en little o big endian. El 0 al final marca el fin de un string.

    Me sorprende que tuviste que escribir lol+8. Yo pensaría que como lol es un array de ints, lol+8 suma 8*sizeof(int) a la dirección de lol. Hubiese pensado que tendría que ser lol+2. No entendio nada :( Además no funciona en mi sistema.


Leave a Reply to David Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>