5
\$\begingroup\$

I have a source file here:

#include <FizzBuzz.h>
fizzbuzz

And I want to make "fizzbuzz" turn into a FizzBuzz program solely through the preprocessor.

Your task is to write a FizzBuzz.h that uses only preprocessor directives (things like include, define, etc.) to create a working FizzBuzz program. Specifically, I want to see the use of macros, which will be required to make this work (at minimum, defining fizzbuzz to be some code).

However, to make sure people try and take full advantage of the power of macros, your score will be defined as the sum of the cubes of the length of the definition portion (the part after #define <symbol>) of each macro.

So, for example, the following file:

#define A 123
#define B A+A
#define C B*2+A

would have a total score of 179 (3^3 + 3^3 + 5^3). As a rule, I want multiple shorter lines instead of one long line.

\$\endgroup\$
6
  • \$\begingroup\$ Do you have any reason to believe that the answers won't all define one of the tokens to an empty string and the other to a one-line program? (Or in other words, what distinguishes this from a boring "golf fizzbuzz"?) \$\endgroup\$ Commented Aug 9, 2013 at 22:52
  • \$\begingroup\$ I thought of that myself. I'll probably reupload it with new restrictions. \$\endgroup\$
    – Joe Z.
    Commented Aug 9, 2013 at 22:52
  • \$\begingroup\$ Added a new scoring algorithm that should favour multiple short lines. \$\endgroup\$
    – Joe Z.
    Commented Aug 10, 2013 at 17:54
  • \$\begingroup\$ Can you give an exact specification of FizzBuzz? I guess we all know the idea, but do you want a function that gets a single number, or a loop (until when?) or what? \$\endgroup\$
    – ugoren
    Commented Aug 10, 2013 at 20:18
  • \$\begingroup\$ The same specification as here: codinghorror.com/blog/2007/02/why-cant-programmers-program.html \$\endgroup\$
    – Joe Z.
    Commented Aug 10, 2013 at 21:47

6 Answers 6

10
\$\begingroup\$

C, Score 1,283 1,213 1,205

EDIT: Instead of basing on Loki Astari's solution, now I'm based on breadbox's

The basic code is not exactly the same as breadbox's - I replaced the loop with recursion, which is longer, but has more repetition.

With GCC, it can be improved further, by using ?: instead of ?0:.

#define A "Fi"
#define D "Bu"
#define E "z"
#define L E E
#define F L,z
#define R F)
#define G A R
#define H D R
#define I ""
#define K "%d"
#define X printf
#define Y puts
#define Z main
#define M 99
#define N z%5
#define O z%3
#define P Z(z
#define Q P)
#define a Q{X
#define b a(O
#define c b?N
#define d c?K
#define e d:I
#define f e:G
#define i f;Y
#define j i(N
#define k j?I
#define l k:H
#define n l;z
#define o n++
#define p o>M
#define q p?0
#define r q:Q
#define s r;
#define fizzbuzz s}

Macro-free code:

main(z){printf(z%3?z%5?"%d":"":"Fizz",z);puts(z%5?"":"Buzz",z);z++>99?0:main(z);}

The 2nd parameter to puts does nothing. It allows me to utilize the zz",z) sequence.

\$\endgroup\$
2
  • \$\begingroup\$ It's a crime that this answer is the currently the lowest rated. \$\endgroup\$
    – breadbox
    Commented Aug 27, 2013 at 23:18
  • \$\begingroup\$ @breadbox, A late answer to an unpopular question - what can you do? And it doesn't contain much new compared to other. \$\endgroup\$
    – ugoren
    Commented Aug 28, 2013 at 4:21
6
\$\begingroup\$

C score 1602 1592 1535 1515 1505 1451

#include <stdio.h>
#define A       "%d"
#define B       "Bu"
#define C       "Fi"
#define w       "z"
#define D       w w
#define E       "\n"
#define F       main
#define G       printf
#define I       for
#define J       99
#define L       c++
#define O       A E
#define P       O:B
#define Q       P D
#define R       Q E
#define S       c%3
#define T       c%5
#define U       S?T
#define V       U?R
#define W       V:T
#define X       W?C
#define Y       X D
#define Z       Y E
#define a       Z:C
#define b       a D
#define d       b B
#define e       d D
#define f       e E
#define g       f,c
#define r       (g)
#define h       G r
#define i       ;L
#define j       J;h
#define k       i<=
#define l       k j
#define q       (l)
#define m       I q
#define n       m;
#define o       {n}
#define p       F()
#define s       c;p
#define fizzbuzz s o

Original source:

c;main(){for(;c++<=99;printf(c%3?c%5?"%d\n":"Buzz\n":c%5?"Fizz\n":"FizzBuzz\n",c));}

Now I am wondering if we change the code too:

c;main(){for(;c++<=99;printf(6*(c%3<1)+12*(c%5<1)+"%d  \n\0Buzz\n\0Fizz\n\0FizzBuzz\n\0",c));}

It looks longer. But more compressable using macros.

\$\endgroup\$
14
  • \$\begingroup\$ Doesn't work... c is uninitialized. Can be fixed at no cost by making c global. Even better - remove int. Even better - make it a parameter (but then it starts with 1). \$\endgroup\$
    – ugoren
    Commented Aug 13, 2013 at 7:29
  • \$\begingroup\$ @ugoren:Fixed :-) \$\endgroup\$ Commented Aug 13, 2013 at 7:52
  • \$\begingroup\$ You can also split some 3-char macros to 2*2. E.g. (g) -> (x + g). \$\endgroup\$
    – ugoren
    Commented Aug 13, 2013 at 7:54
  • \$\begingroup\$ With a bit more effort it goes below 1400. \$\endgroup\$
    – ugoren
    Commented Aug 13, 2013 at 7:57
  • \$\begingroup\$ You have 3 and 5 the wrong way round in your single-string solution. It might also be worth indexing "Buzz\n\0" as "FizzBuzz\n\0"+4. \$\endgroup\$ Commented Aug 14, 2013 at 7:33
3
\$\begingroup\$

C, score 1267

Best I could do:

#define a main
#define b for
#define c puts
#define d printf
#define e ""
#define f x Z
#define g y Z
#define h "%d"
#define x "Bu"
#define y "Fi"
#define z "z"
#define Z z z
#define A 101
#define B i++
#define C B%5
#define D C?e
#define E D:f
#define F i%3
#define G F?i
#define H G%5
#define I H?h
#define J I:e
#define K J:g
#define L K,i
#define M i<A
#define N M;c
#define O a(i
#define P N(E
#define Q d(L
#define R O)
#define S b(
#define T P)
#define U Q)
#define V U;
#define W R{S
#define X W;T
#define Y X)V
#define fizzbuzz Y}

This is roughly the same approach that the other entries are using, looks like. I suspect the marginal improvement comes from the brevity of the target program. At 75 bytes, it's the shortest C fizzbuzz I know (that doesn't depend on compiler-specific behavior):

main(i){for(;i<101;puts(i++%5?"":"Buzz"))printf(i%3?i%5?"%d":"":"Fizz",i);}
\$\endgroup\$
2
  • \$\begingroup\$ Nice, but is i's initial value guaranteed? \$\endgroup\$ Commented Oct 28, 2013 at 5:17
  • \$\begingroup\$ i's initial value will be one if the user invokes the program without extra command-line arguments. The behavior will change if other parameters are given on the command line, but that's true of most every program. \$\endgroup\$
    – breadbox
    Commented Oct 28, 2013 at 5:28
2
\$\begingroup\$

C, Score 28,703 18,043 4,367

#define S(x) #x"\n"                     // 6
#define X(a) W?Y(a)                     // 6
#define W c%5                           // 3
#define Y(a) S(a):Z(a)                  // 9
#define Z(a) S(a##Buzz)                 // 10
#define fizzbuzz A%Q}                   // 4
#define A char*B                        // 6
#define B p,C                           // 3
#define C c;D(E                         // 5
#define D main                          // 4
#define E ){F                           // 3
#define F for(G                         // 5
#define G ;c++H                         // 5
#define H <=I(K                         // 5
#define I 99;J                          // 4
#define J printf                        // 6
#define K *p+L                          // 4
#define L ~9?M                          // 4
#define M p:N,O                         // 5
#define N S(%d)                         // 5
#define O c))P                          // 4
#define P p=c                           // 3
#define Q 3?R;                          // 4
#define R X():T                         // 5
#define T X(Fizz)                       // 7

Original macro-free program:

c,*p;
main(){
        for(;c++<=99;printf(*p+~9?p:"%d\n",c))
                p=c%3?c%5?"\n":"Buzz\n":c%5?"Fizz\n":"FizzBuzz\n";
}
\$\endgroup\$
2
  • \$\begingroup\$ This is the kind of solution I was looking for. :D \$\endgroup\$
    – Joe Z.
    Commented Aug 12, 2013 at 17:59
  • \$\begingroup\$ The same macro tricks that you like are what makes my solution longer than Loki Astari's - he uses C string concatenation instead of ##. \$\endgroup\$
    – ugoren
    Commented Aug 13, 2013 at 7:58
1
\$\begingroup\$

C++, Score 68,508

I know this does not meet the criteria (lots of really short macro definitions), but I think it has an advantage over the other answers. First the solution:

#include <iostream>
#define X(a) H(a,N)H(1,L)
#define W(a,b,c) H(U(a,b),c)H(a,M)
#define V J::
#define U(a,b) !(a)&&!(b)
#define T ==0
#define S K<<
#define R %5 T
#define Q main
#define P int
#define O %3 T
#define N "Buzz"
#define M "Fizz"
#define L V endl
#define K V cout
#define J std
#define I if
#define H(a,b) I(a)S(b);
#define G(a,b,c) W(a,b,c)X(b)
#define F(a) G((a)O,(a)R,a)
#define E(a,b,c,d) F(a*20+b*4+c*2+d+1)
#define D(a,b,c) E(a,b,c,0)E(a,b,c,1)
#define C(a,b) D(a,b,0)D(a,b,1)
#define B(a) C(a,0)C(a,1)C(a,2)C(a,3)C(a,4)
#define A B(0)B(1)B(2)B(3)B(4)
#define fizzbuzz P Q(){A}

Second, I think the advantage to this is that it truly uses the preprocessor to its "best" advantage. Namely, it does not use any looping constructs or variables in determining FizzBuzz. All parameters are constants, thus all the expressions can be compile time evaluated. Any if-condition that is false can be optimized away, so the final optimized form of the compiled program is really just a bunch of statements like cout << something; cout << endl.

\$\endgroup\$
1
\$\begingroup\$

C++, Score 24,806 (Revised from Earlier Answer)

I came across code I posted last September and decided to refine it. I was able to cut it down significantly (for a savings of 43,702 "points") while keeping in the spirit of my original submission (no variables, just pre-processed constants). Not that anyone cares, but hey, I was bored. :)

#include <iostream>
#define _ {A}
#define a ()
#define b main
#define c int
#define d a _
#define e c b
#define f "u"
#define g "B"
#define h "i"
#define i "F"
#define j "z"
#define k w v
#define l endl
#define m <<
#define n cout
#define o ::
#define p std
#define q g f
#define r i h
#define s j j
#define t N)O
#define u l;
#define v n m
#define w p o
#define y q s
#define z r s
#define Z(a,b) M(a)k b;
#define Y 0;
#define X return
#define W 100
#define V %5
#define U %3
#define T ==0
#define S w v w u
#define R(a) Z(a,y)
#define Q(a) Z(a,z)
#define P(a,b,c) Z(!(a)&&!(b),c)
#define O X Y
#define N >W
#define M if
#define L V T
#define K U T
#define J(a,b,c) P(a,b,c)Q(a)R(b)S
#define I(a) M(a t
#define H(a) I(a)J((a)K,(a)L,a)
#define G(a) H(a+1)H(a+2)
#define F(a) G(a)G(a+2)
#define E(a) F(a)F(a+4)
#define D(a) E(a)E(a+8)
#define C(a) D(a)D(a+16)
#define B(a) C(a)C(a+32)
#define A B(0)B(64)
#define fizzbuzz e d
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.