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\$
  • \$\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\$ – Peter Taylor Aug 9 '13 at 22:52
  • \$\begingroup\$ I thought of that myself. I'll probably reupload it with new restrictions. \$\endgroup\$ – Joe Z. Aug 9 '13 at 22:52
  • \$\begingroup\$ Added a new scoring algorithm that should favour multiple short lines. \$\endgroup\$ – Joe Z. Aug 10 '13 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 Aug 10 '13 at 20:18
  • \$\begingroup\$ The same specification as here: codinghorror.com/blog/2007/02/why-cant-programmers-program.html \$\endgroup\$ – Joe Z. Aug 10 '13 at 21:47
9
\$\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\$
  • \$\begingroup\$ It's a crime that this answer is the currently the lowest rated. \$\endgroup\$ – breadbox Aug 27 '13 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 Aug 28 '13 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\$
  • \$\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 Aug 13 '13 at 7:29
  • \$\begingroup\$ @ugoren:Fixed :-) \$\endgroup\$ – Martin York Aug 13 '13 at 7:52
  • \$\begingroup\$ You can also split some 3-char macros to 2*2. E.g. (g) -> (x + g). \$\endgroup\$ – ugoren Aug 13 '13 at 7:54
  • \$\begingroup\$ With a bit more effort it goes below 1400. \$\endgroup\$ – ugoren Aug 13 '13 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\$ – Peter Taylor Aug 14 '13 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\$
  • \$\begingroup\$ Nice, but is i's initial value guaranteed? \$\endgroup\$ – Daniel Lubarov Oct 28 '13 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 Oct 28 '13 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\$
  • \$\begingroup\$ This is the kind of solution I was looking for. :D \$\endgroup\$ – Joe Z. Aug 12 '13 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 Aug 13 '13 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, privacy policy and cookie policy

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