I gave it a go in C (I wanted to do assembly but couldn't be arsed to write string to int and int to string conversions). [1] The trickiest part was figuring out how to terminate the program. My first attempt invoked nasal demons through dividing by zero, but I then realized I could intentionally cause a segfault with high probability (which is much better, right?). One could argue that my `fizz` and `buzz` variables are still "disguised booleans", but at least the generated assembly contains no branching or cmov instructions (aside from the ones inside libc functions like atoi and sprintf).
# Multi-pass FizzBuzz
n = 100
# [['1'], ['2'], ['3'], ['4'], ['5'], ...]
seq = [[str(i)] for i in range(1, n + 1)]
# [['1'], ['2'], ['3', 'Fizz'], ['4'], ['5'], ...]
for i in range(3, n + 1, 3):
seq[i-1].append('Fizz')
# [['1'], ['2'], ['3', 'Fizz'], ['4'], ['5', 'Buzz'], ..., ['15', ''Fizz', 'Buzz'], ...]
for i in range(5, n + 1, 5):
seq[i-1].append('Buzz')
# Arithmetic equivalent to:
# len=1 -> the whole thing (from zero to end, because zero = -zero)
# len=2 -> the length-1 suffix (just Fizz or Buzz)
# len=3 -> the length-2 suffix (Fizz and Buzz)
# The branch is hidden in the slice syntax:
# Python has to check whether `x` is negative in `terms[x:]`.
for terms in seq:
print(''.join(terms[-(len(terms) - 1):]))
Here's a version that uses generators instead of multiple passes over a list:
# Single-pass FizzBuzz
n = 100
def numbers():
for i in range(1, n+1):
yield [str(i)]
def fizzies():
nums = numbers()
try:
while True:
yield next(nums)
yield next(nums)
yield [*next(nums), 'Fizz']
except StopIteration:
pass
def buzzies():
fzs = fizzies()
try:
while True:
yield next(fzs)
yield next(fzs)
yield next(fzs)
yield next(fzs)
yield [*next(fzs), 'Buzz']
except StopIteration:
pass
for terms in buzzies():
print(''.join(terms[-(len(terms) - 1):]))
The conditional here only makes it stop when it reaches 100. The solution can be adapted to use a while loop if you’re okay with it running indefinitely.
Other would be to use goto (though Python doesn't have it) & introduce something that will panic/throw exception, like creating variable with value 1/(max-i).
Enumerating all values probably can't be done in python as that requires some sort of unchecked loop construct, that is a goto or bare loop nether of which is present in python. perhaps a recursive solution(throws up a little in mouth)
baring that I too got nerd sniped by this and unsatisfied by the limitations of the authors solution here is my attempt. and when I read up on fizzbuz to make sure I was solving the correct thing. (I was not and my elegant duel state engine was wasted) it turns out the problem solution could be as simple as
I think it was more about doing it without a Boolean-based branch construct like a ternary or switch or whatever flavor of thing that abstracts away the explicit checks for true/false by other means. Idk though for sure
Much like stop50's solution, I also used the modulo, but I make use of the terminal to overwrite the number. It's only three lines of code, but I split up the list to be more readable on here.
This works from 1 to 100000000000000000000 before it overflows, and 100000000000000000000 is above the max size of a unsigned 64 bit int, so I feel that it's good enough
I could see that both ways. Python’s for loops are different than, say, C’s, in that they always consume an iterator. The implementation is that it calls next(iter) until it raises a StopIteration exception, but you could argue that’s just an implementation detail and not cheating.
If you wanted to be more general, you could use map() to apply the function to every member of the iterator, and implementation details aside, that feels solidly in the spirit of the challenge.
Edit: Actually all you need is vim -es +'exec "norm! i\r\rFizz\r\rBuzz\rFizz\r\r\rFizz\rBuzz\r\rFizz\r\r\rFizzBuzz\<esc>Vggy7P101GdG"|%s/^$/\=line(".")/|%p|q!'
I always wanted to write this with duff's device. switch with fall through is almost never a good thing but it allows for some 'interesting' tricks. Wouldn't be hard, but I have kids so finding half an hour to concentrate is hard.
Saying the code doesn’t have conditions or booleans is only true if you completely ignore how the functions being called are being implemented.
Cycle involves conditionals, zip involves conditionals, range involves conditionals, array access involves conditionals, the string concatenation involves conditionals, the iterator expansion in the for loop involves conditionals.
This has orders of magnitude more conditionals than normal fizz buzz would.
Even the function calls involve conditionals (python uses dynamic dispatch). Even if call site caching is used to avoid repeated name lookups, that involves conditionals.
There is not a line of code in that file (even the import statement) that does not use at least one conditional.
So… interesting implementation, but it’s not “fizzbuzz without booleans or conditionals”.
I think that’s kind of vacuously true. Like, good luck writing this in any language where the resulting assembler all the way at the bottom of the runtime has zero branch operations. And I bet even then that most CPUs’ microcode or superscalar engine would have conditionals underlying the opcodes.
I’d settle for just not writing conditionals in the user’s own code. Range doesn’t have to be implemented with branches. Hypothetically, Python could prefill a long list of ints, and range could return the appropriate slice of it. That’d be goofy, of course, but the main idea is that the user doesn’t know or really care exactly how range() was written and optimized.
What exactly are we counting as “a conditional”? Is it only “if” statements? Do “case” or “switch” statements count? Do loops with loop conditions count? Do all the included functions being abused count for all the conditionals in them? Do short-circuited boolean operations count, or only boolean variables?
I mean, if we want to play fast and loose with those definitions then this also has no conditionals and no booleans.(Warning: Perl, somewhat golfed)
Without any other constraints, this is not an interesting challenge.
[1] https://gist.github.com/Andriamanitra/5c20f367dc4570dd5c8068...
Unless by conditionals we mean “no if/else” and not “no branch instructions”.
One hack would be to use recursion and let stack exhaustion stop you.
baring that I too got nerd sniped by this and unsatisfied by the limitations of the authors solution here is my attempt. and when I read up on fizzbuz to make sure I was solving the correct thing. (I was not and my elegant duel state engine was wasted) it turns out the problem solution could be as simple as
anyhow the rest of my clever but unneeded and useless enumeration system, remember to read the spec first. and the recursive solution:This works from 1 to 100000000000000000000 before it overflows, and 100000000000000000000 is above the max size of a unsigned 64 bit int, so I feel that it's good enough
If you wanted to be more general, you could use map() to apply the function to every member of the iterator, and implementation details aside, that feels solidly in the spirit of the challenge.
1..100 | % {"$_ $(('fizz','')[$_%3])$(('buzz','')[$_%5])"}
I am not sure that using [$_%3] to index into a two-value array doesn't count as a "disguised boolean" thought.
Now I see it's the same solution as in the post.
Edit: Actually all you need is vim -es +'exec "norm! i\r\rFizz\r\rBuzz\rFizz\r\r\rFizz\rBuzz\r\rFizz\r\r\rFizzBuzz\<esc>Vggy7P101GdG"|%s/^$/\=line(".")/|%p|q!'
Saying the code doesn’t have conditions or booleans is only true if you completely ignore how the functions being called are being implemented.
Cycle involves conditionals, zip involves conditionals, range involves conditionals, array access involves conditionals, the string concatenation involves conditionals, the iterator expansion in the for loop involves conditionals.
This has orders of magnitude more conditionals than normal fizz buzz would.
Even the function calls involve conditionals (python uses dynamic dispatch). Even if call site caching is used to avoid repeated name lookups, that involves conditionals.
There is not a line of code in that file (even the import statement) that does not use at least one conditional.
So… interesting implementation, but it’s not “fizzbuzz without booleans or conditionals”.
I’d settle for just not writing conditionals in the user’s own code. Range doesn’t have to be implemented with branches. Hypothetically, Python could prefill a long list of ints, and range could return the appropriate slice of it. That’d be goofy, of course, but the main idea is that the user doesn’t know or really care exactly how range() was written and optimized.
The technique could be implemented without conditionals, but not in python, and not using iterators.
You could do it in C, and use & and ~ to make the cyclic counters work.
But, like I mentioned, the code in the article is very far from being free of conditionals.
I mean, if we want to play fast and loose with those definitions then this also has no conditionals and no booleans.(Warning: Perl, somewhat golfed)