For the explanation of the readable version, please scroll down ;)
I’m very sorry that I didn’t take the DRY aspect seriously enough, so here is a much better version that avoids duplication of code where not necessary:
[/%$]⇒M['z,]⇒Z[ZZ]⇒ζ[[]]⇒β[Mβ]⇒‘[$$$3‘['F,'i,ζ]?\4‘['J,'a,ζ]?@5‘['B,'u,ζ]?**[$.]β?10,]c:0[$100<][1+c;!]#
To realize the DRY principle I made use of the operator definition functionality to simplify the program as far as possible:
Assignment of the MOD DUP combination for the three mod checks to operator M
.
[/%$]⇒M
[/%$]⇒M
[$$$3M[]['F,'i,'z,'z,]?\4M[]['J,'a,'z,'z,]?@5M[]['B,'u,'z,'z,]?**[$.][]?10,]c:0[$100<][1+c;!]#
Assignment of the print single z
character instruction set 'z,
to operator Z
.
['z,]⇒Z
[/%$]⇒M['z,]⇒Z
[$$$3M[]['F,'i,ZZ]?\4M[]['J,'a,ZZ]?@5M[]['B,'u,ZZ]?**[$.][]?10,]c:0[$100<][1+c;!]#
For even more efficient reuse of code, I assigned the duplication of Z
to the operator ζ
.
[ZZ]⇒ζ
[/%$]⇒M['z,]⇒Z[ZZ]⇒ζ
[$$$3M[]['F,'i,ζ]?\4M[]['J,'a,ζ]?@5M[]['B,'u,ζ]?**[$.][]?10,]c:0[$100<][1+c;!]#
And to to drive it to the max, I also assigned empty bracket pairs []
(that are used in the if-then-else
constructs and while loops
) to the operator β
, because... why not?
[[]]⇒β
[/%$]⇒M['z,]⇒Z[ZZ]⇒ζ[[]]⇒β
[$$$3Mβ['F,'i,ζ]?\4Mβ['J,'a,ζ]?@5Mβ['B,'u,ζ]?**[$.]β?10,]c:0[$100<][1+c;!]#
It is obvious that three repetitions of Mβ
are intolerable, so I assign this to the ‘
operator.
[Mβ]⇒‘
[/%$]⇒M['z,]⇒Z[ZZ]⇒ζ[[]]⇒β[Mβ]⇒‘
[$$$3‘['F,'i,ζ]?\4‘['J,'a,ζ]?@5‘['B,'u,ζ]?**[$.]β?10,]c:0[$100<][1+c;!]#
Wonderful! Compare this glorious contraption to the stale and boring old, way too inefficient and repetitive version:
[$$$3/%$[]['F,'i,'z,'z,]?\4/%$[]['J,'a,'z,'z,]?@5/%$[]['B,'u,'z,'z,]?**[$.][]?10,]c:0[$100<][1+c;!]#
In a more structured form:
[ {function c start}
$$$ {duplicate value 3 times}
3/%$[]['F,'i,'z,'z,]? {value%3, if value%3=0 print Fizz}
\4/%$[]['J,'a,'z,'z,]? {swap, value%4, if value%4=0 print Jazz}
@5/%$[]['B,'u,'z,'z,]? {rotate, value%5, if value%5=0 print Buzz}
**[$.][]? {multiply top 3 values, if result !=0 print number.}
10, {print newline}
]c: {define function c}
0 {start value}
[$100<][1+c;!]# {while value < 100, increment, call function c}
Example loop:
Assume we are are at n=6 (leads to better understandable stack values):
instr. data stack
[
6
$ 6,6 DUP
100 6,6,100
< 6,-1 7<100 ? → -1 (truthy value)
]
[
1 6,1
+ 7
c;! push c, fetch value of c (its start value), execute c
$$$ 7,7,7,7 DUP 3 times
3 7,7,7,7,3
/ 7,7,7,1,2 (produces mod, div)
% 7,7,7,1 POP
$ 7,7,7,1,1 DUP
[]['F,'i...]? 7,7,7,1 POP, popped value !=0, nothing is done
\ 7,7,1,7 SWAP
4 7,7,1,7,4
/ 7,7,1,3,1 MOD/DIV
% 7,7,1,3
$ 7,7,1,3,3
[]['J,'a...]? 7,7,1,3 POP, popped value !=0, nothing is done
@ 7,1,3,7 ROT
5 7,1,3,7,5
/ 7,1,3,2,1
% 7,1,3,2
$ 7,1,3,2,2
[]['B,'u...]? 7,1,3,2
* 7,1,6 MUL twice. If %3,%4 or %5 were zero, the result
* 7,6 is zero. (if Fizz, Jazz or Buzz were printed)
[ 0 is the falsy value. So if something was printed before, the first bracket of [$.][]?
$ 7,7 is not entered, the number not printed.
. 7 STDOUT: 7
][]?
10 7,10
, 7 STDOUT: Char(10)=newline
[$100 7,7,100 continue while loop
<] 7,-1
...
Try out the code in this online DUP interpreter or clone my Julia implementation of DUP on GitHub. My GitHub page comes with a detailed explanation of DUP.
1Your second bullet point is a bit vague... What's makes a division efficient? Why is that important for the challenge? – Sanchises – 2015-03-04T21:39:23.627
@sanchises, there still exist platforms, especially microcontrollers, that have very expensive (in cycles/time) division operations. At least one of the answers below avoids division/modulus altogether - but maybe hurts readability. It's something for voters to consider. – gnibbler – 2015-03-04T22:07:20.037
1@sanchises not vague at all IMHO the point is not using division/modulus at all. You can do it just keeping a variable for each n=(3,4,5...) and reseting it at the time it ill match and print a word and incrementing when not. The Dry part can be doing a function/method receiving (n,word) and thus the "maintenance" of adding more words a breeze – jean – 2015-03-06T14:19:11.773
1
Highly relevant: https://themonadreader.files.wordpress.com/2014/04/fizzbuzz.pdf
– Hjulle – 2015-04-10T11:35:50.9732You might enjoy this. – Martin Ender – 2015-05-01T21:37:11.733
"Extending this scheme requires O(2n) lines of code." How can you measure text in time complexity? – cat – 2016-03-17T21:31:00.810
@tac, good question. In a handwavy way, you have the predicate with n conditions first, then those with n-1 conditions, then n-2, etc. Since those early predicates are matched much less often, I think you'd end up with at least O(n * 2**n) time complexity. It's probably impractical to create and run the programs for more than n=20 or so – gnibbler – 2016-03-18T01:36:10.303
My bounty attracted a lot of attention, but we all know there's only one possible recipient of it. Perhaps I should leave it up for 5 days? – cat – 2016-03-19T03:09:43.860
The sample code would only print numbers 1-99. – FlipTack – 2016-12-26T12:43:04.503