Fizz Buzz with unique characters in columns

21

5

Inspired by Digits in their lanes and 1, 2, Fizz, 4, Buzz

Introduction

Your task is to generate exactly the following output:

1
2
Fizz
4
  Buzz
    Fizz
7
8
      Fizz
        Buzz
 11
          Fizz
   13
    14
            FizzBuzz
     16
      17
              Fizz
       19
                  Buzz
                    Fizz
 22
    23
                      Fizz
                        Buzz
   26
                          Fizz
     28
      29
                            FizzBuzz
       31
      32
                              Fizz
34
                                  Buzz
                                    Fizz
 37
  38
                                      Fizz
                                        Buzz
        41
                                          Fizz
  43
   44
                                            FizzBuzz
      46
       47
                                              Fizz
         49
                                                  Buzz

Challenge

This challenge is based on the Fizz Buzz challenge, and here is a recap: output the numbers from 1 to 100 inclusive, each number on its own line, but if the number is a multiple of 3, you should output "Fizz" instead of the original number, if the number is a multiple of 5, you should output "Buzz" instead of the original number. If the number is a multiple of 15, you should output "FizzBuzz" instead of the original number.

However, in addition to the requirement above, you should also indent each line using spaces to make that every column contains unique characters (excluding spaces and newlines) only. The spaces prepended to each line are the minimum required to make all the lines appeared before it (inclusive) has unique characters in each column.

For example, 1,2,Fizz,4 does not need any indentation because they already have unique characters in each column (column 1: 12F4, column2: i, column3: z, column4: z), but when adding Buzz we need to indent by two spaces because otherwise we would have two z's in both the 3rd and the 4th column. Since two spaces is enough to achieve the goal you should not indent it by three spaces. 7 and 8 does not need any indentation but when outputting 11 we need to indent by one space because the 1st column already has a 1. 13 then needs to be indented by three spaces because now 1st, 2nd and 3rd column all have a 1. Indentation for the remaining lines follow the same rule.

To make the challenge simpler, The upper limit has been changed to 50.

Specs

  • You can write a program or a function. Neither of them should take any non-empty input. Taking an empty input is fine.

  • Since this is a KC challenge you need to produce the output as specified in the Introduction section. A single trailing newline is fine. No heading newlines or extra heading spaces. No extra trailing spaces for each line.

  • Your program can exit with error or have non-empty STDERR output as long as STDOUT conforms to the specification.

  • This is intra-language , the program with lowest number of bytes wins in its language.

  • Default loopholes apply.

Weijun Zhou

Posted 2018-03-28T03:43:10.453

Reputation: 3 396

2The given output doesn't exactly match the spec, e.g. lines 12, 20, 35 and 50. – Bubbler – 2018-03-28T04:10:29.970

1But the second character in the first two lines is carriage return. – Acccumulation – 2018-03-28T14:53:28.467

I have excluded spaces, now I should exclude newlines as well. – Weijun Zhou – 2018-03-28T15:23:25.143

Answers

9

Python 2, 127 bytes

i=0;exec"print ord('<<<<>@<<BD=F?@HABJCNP=@RT?VABXCBZ<^`=>bdDf>?hBCjEn'[i])%60*' '+(i%3/2*'Fizz'+i%5/4*'Buzz'or`-~i`);i+=1;"*50

Try it online!

A fifty-byte lookup table seems to hurt the code size less than the logic necessary to track which characters have occurred in each column.

Lynn

Posted 2018-03-28T03:43:10.453

Reputation: 55 648

1Logic would have been better if we were required to print up to 100 instead... – Bubbler – 2018-03-28T22:55:12.100

5

Python 2, 167 166 163 161 157 bytes

a=eval(`[{0}]*99`);i=0
exec"f=i%3/2*'Fizz'+i%5/4*'Buzz'or`i+1`;i+=1;g=0\nwhile any(b>{c}for b,c in zip(a[g:],f)):g+=1\nmap(set.add,a[g:],f);print' '*g+f;"*50

Try it online!

Edits:

  • while is shorter than for..range() by 1 byte.
  • Thanks to @ovs for shaving off 3 bytes. I always forget exec...
  • Adapted i%3/2 trick from Lynn's answer (-2 bytes).
  • @Lynn suggested a=map(set,[[]]*99), but I found another way using eval and repr with same bytes (-4 bytes).

Use a list of sets to track the chars used for each column, and set inequality for membership. The rest follows the exact spec given.

Bubbler

Posted 2018-03-28T03:43:10.453

Reputation: 16 616

4

C (gcc), 145 144 bytes (143 for hex)

i;main(){for(;i++<50;printf("%*s%s%.d\n","000402800:81>34@56B7BH14JH3N56P76R0RX12ZX8^23`67b9b"[i]-48,i%3?"":"Fizz",i%5?"":"Buzz",i%3*i%5?i:0));}

Try it online!

0000h: 69 3B 6D 61 69 6E 28 29 7B 66 6F 72 28 3B 69 2B ; i;main(){for(;i+
0010h: 2B 3C 35 30 3B 70 72 69 6E 74 66 28 22 25 2A 73 ; +<50;printf("%*s
0020h: 25 73 25 2E 64 5C 6E 22 2C 22 FE FE FE 02 FE 00 ; %s%.d\n","......
0030h: 06 FE FE 08 06 FF 0C 01 02 0E 03 04 10 05 10 16 ; ................
0040h: FF 02 18 16 01 1C 03 04 1E 05 04 20 FE 20 26 FF ; ........... . &.
0050h: 63 28 26 06 2C 00 01 2E 04 05 30 07 30 22 5B 69 ; c(&.,.....0.0"[i
0060h: 5D 2B 32 2C 69 25 33 3F 22 22 3A 22 46 69 7A 7A ; ]+2,i%3?"":"Fizz
0070h: 22 2C 69 25 35 3F 22 22 3A 22 42 75 7A 7A 22 2C ; ",i%5?"":"Buzz",
0080h: 69 25 33 2A 69 25 35 3F 69 3A 30 29 29 3B 7D    ; i%3*i%5?i:0));}

l4m2

Posted 2018-03-28T03:43:10.453

Reputation: 5 985

3

Ruby, 129 bytes

puts (1..50).map{|n|" "*(".<<<<>@<<BD=F?@HABJCNP=@RT?VABXCBZ<^`=>bdDf>?hBCjEn"[n].ord%60)+("FizzBuzz
"[i=n**4%-15,i+13]||n.to_s)}

Try it online!

Double credit goes to Lynn here, for the lookup table approach and the fizzbuzz algorithm.

The FizzBuzz algorithm is very interesting, and it hinges on the remarkable coincidence that all positive, non-composite numbers less than 15 (other than 3 and 5), when raised to the 4th power, are 1 more than a multiple of 15. In fact:

 n     n**4  n**4%15  n**4%-15
 1        1     1       -14
 2       16     1       -14
 3       81     6        -9
 4      256     1       -14
 5      625    10        -5
 6     1296     6        -9
 7     2401     1       -14
 8     4096     1       -14
 9     6561     6        -9
10    10000    10        -5
11    14641     1       -14
12    20736     6        -9
13    28561     1       -14
14    38416     1       -14
15    50625     0         0

The values 3**4%15 and 5**4%15 are exactly 4 apart: the length of the string "Fizz". We can exploit this by using them to index from the end of a string, at least 9 characters in length. Multiples of 3 will index from the beginning of the string, and multiples of 5 will index from 5 characters from the end. Every other number will attempt to index from before the beginning of the string, and fail, returning nil. Then 15, of course, indexes from the 0th character. The fact that "FizzBuzz" is only 8 characters long is a small obstacle; we use a newline character to pad it, which will later be ignored by puts.

It's possible that the lookup table can be out-golfed by a more procedural approach, but my attempt was in the neighborhood of 190 bytes.

benj2240

Posted 2018-03-28T03:43:10.453

Reputation: 801

2Interesting. It should be noted that the fact all numbers coprime to 15 when raised to 4th power equal to 1 modulo 15 can be derived from Fermat's little theorem. – Weijun Zhou – 2018-03-28T21:45:30.990

2

[JavaScript (Node.js) REPL], 144 bytes

(f=(i,s=[['Fizz'][i%3]]+[['Buzz'][i%5]]||i+[],b=i>1?f(i-1):[])=>[...s].some((p,j)=>b.some(w=>w[j]==p&0!=p))?f(i,' '+s):b.push(s)&&b)(50).join`

`

Try it online!

Warning program itself runs unacceptable time

JavaScript (Node.js), 132 bytes by Arnauld

f=(a=n=[],s=`${b=++n%5?'':'Buzz',n%3?b||n:'Fizz'+b}
`)=>n>50?'':a.some(x=>[...x].some((c,i)=>c!=0&c==s[i]))?f(a,' '+s):s+f([s,...a])

Try it online!

l4m2

Posted 2018-03-28T03:43:10.453

Reputation: 5 985

Your answer doesn’t seem to be the same as the TIO link – Jo King – 2018-03-28T11:43:40.517

@JoKing TIO outputs array, and i don't know whether it's allowed – l4m2 – 2018-03-28T12:36:20.147

2

Java (JDK 10), 185 bytes

v->{for(int n=0,l;n<50;System.out.printf((l>0?"%"+l:"%")+"s%s%n","",(n%3<1?"Fizz":"")+(n%5<1?"Buzz":n%3<1?"":n)))l="####%'##)+$-&'/()1*57$'9;&=()?*)A#EG$%IK+M%&O)*Q,U#".charAt(n++)-35;}

Try it online!

Credits

Olivier Grégoire

Posted 2018-03-28T03:43:10.453

Reputation: 10 647

1

Haskell, 190 187 186 178 176 bytes

unlines$foldl(\a x->a++[[z|z<-iterate(' ':)x,all(\m->null[p|(p,q)<-m`zip`z,p==q&&p>' '])a]!!0])[]$h<$>[1..50]
a%b=a`mod`b<1
h n|n%15="FizzBuzz"|n%3="Fizz"|n%5="Buzz"|1<2=show n

Try it online!

The slightly more readable (and annotated) version:

-- check if a is evenly divisible by b
a%b=a`mod`b<1
-- produce correct FizzBuzz output for a number
h n|n%15="FizzBuzz"|n%3="Fizz"|n%5="Buzz"|1<2=show n
-- test if all chars distinct between two strings
x#y=null[a|(a,b)<-x`zip`y,a==b&&a>' ']
-- given a new string and all previous strings
-- shift the new string to the right until all
-- chars are distinct
x!y=[z|z<-iterate(' ':)y,all(z#)x]!!0
g=h<$>[1..50]
f'=foldl step[]g
  where step acc x = acc++[acc!x]

Edit: I ended up inlining some functions in the golfed version to save more bytes.

Cristian Lupascu

Posted 2018-03-28T03:43:10.453

Reputation: 8 369

@Laikoni Right. Fixed. – Cristian Lupascu – 2018-03-28T11:06:03.730

1

Jstx, 122 bytes

◄50-☺6*ø($♥:ø↕♂Fizz♀☺(◙$♣:ø↕♂Buzz♀6☺(◙"ø↕$6◙♂<<<<>@<<BD=F?@HABJCNP=@RT?VABXCBZ<^`=>bdDf>?hBCjEn'[i])%60*♀&P◄59▼ö,► 7.☻a0.2

Try it online!

Quantum64

Posted 2018-03-28T03:43:10.453

Reputation: 371