x86-64 Machine Code (Linux), 40 bytes
0000000000000000 <goose>:
0: 67 6f
2: 6f
3: 73 65
5: 0a
0000000000000006 <duck>:
6: 64 75 63
9: 6b
a: 0a
Disassembly of section .text:
0000000000000000 <_start>:
0: b0 01 mov $0x1,%al
2: 40 b7 01 mov $0x1,%dil
5: be 00 00 00 00 mov $0x0,%esi
a: b2 06 mov $0x6,%dl
c: 0f 05 syscall
e: 0f c7 f1 rdrand %ecx
11: 67 e3 ec jecxz 0 <_start>
14: b0 01 mov $0x1,%al
16: be 00 00 00 00 mov $0x0,%esi
1b: 0f 05 syscall
The first 12 bytes are used to store the strings "goose\n" and "duck\n". Technically when duck is printed, it prints 6 bytes (while "duck\n" is 5 bytes), but chances are that the byte after where duck is located in the binary will be an invisible character.
The blocks that preceded the syscall are just setting up the sys_write system call. Normally in x86-64 this looks like (in Intel syntax rather than AT&T):
b8 01 00 00 00 mov $0x1,%eax ; syscall number for sys_write
bf 01 00 00 00 mov $0x1,%edi ; fd number for STDOUT
48 be 00 00 00 00 00 00 00 00 movabs $0x0,%rsi ; pointer to where the "duck\n" string is located (nasm syntax)
ba 06 00 00 00 mov $0x6,%edx ; number of bytes to write
0f 05 syscall
However we can use the lower bits addressing of the registers to produce shorter x86 opcodes.
For the second syscall, only rax gets clobbered (since it holds the return value for sys_write), so we have to reset it.
The randomness comes from using the rdrand
instruction, which sets a hardware random number into ecx. The next instruction then jumps back to _start if ecx is 0. This means that "duck" will only be printed again with a chance of 1/(2^32). However small this chance is, it technically is possible and non-deterministic.
The more interesting way to print out a series of "duck" strings before "goose" is to replace the rdrand and jecxz instructions with:
66 0f c7 f3 rdrand %bx
66 85 db test %bx,%bx
75 e9 jne 0 <_start>
Unfortunately this takes 2 more bytes, but the effect is that the result of rdrand is stored into bx, which is a 16 bit register. Additionally, each time this is run, the chance the code jumps back to start and prints "duck" again is (2^16 - 1)/(2^16). This means that after about 50000 loops there's over a 50% chance of bx being 0 in at least one of the loops. (The exact amount is 45426 loops). For a 90% chance of bx being 0 in at least one of the loops, just over 150000 loops need to occur.
Finally, with normal program behavior, this program should call sys_exit with this code:
0000000000000020 <_exit>:
20: b8 3c 00 00 00 mov $0x3c,%eax
25: 31 ff xor %edi,%edi
27: 0f 05 syscall
But since we can just leave this out and the program will exit with a segmentation fault, this is fine. The challenge has already been completed by this point.
For better inline comments, check out the original nasm source code in my repo.
11Could you define indeterminate? Could it mean either zero or one? – recursive – 2018-03-12T15:51:14.607
1Please define how randomly this should be generated. Uniform in range or with exponential decline? – HyperNeutrino – 2018-03-12T15:52:43.903
@recursive Nope, but let's go with a working definition... The program does not consistently present the same number of ducks. – AJFaraday – 2018-03-12T15:52:55.417
Is any leading or trailing white-space acceptable on the lines printed to STDOUT; what about leading newline(s) or excess trailing newlines (beyond the one that I assume would be allowed anyway)? – Jonathan Allan – 2018-03-12T16:33:43.193
Is there a maximum number of times one can "duck"? 1000? 100000000? – Οurous – 2018-03-12T19:55:41.407
Probably anything that's finite and produces some output – Manish Kundu – 2018-03-13T04:06:18.153
2
Speaking as a Minnesotan, what if mine prints "duck, duck, gray duck" instead? :)
– Mike Hill – 2018-03-14T19:13:59.480@MikeHill that variant intrigued me, someone else mentioned it in an answer. It’d definitely make a fun variation... – AJFaraday – 2018-03-14T19:15:44.867
@MikeHill Was about to say the same thing! – GendoIkari – 2018-03-14T22:10:16.277
@MikeHill, Clearly, "gray duck" is the proper output – Brian – 2018-03-14T22:22:45.937
I remember it. Am I the only one? =( – jpmc26 – 2018-03-15T23:05:11.280
1@jpmc26 I’m sure there are others. You’d have had to play it with others, for a start. – AJFaraday – 2018-03-15T23:13:08.007
@MikeHill In Danish language, the species mallard is known as "gråand" which litterally means grayduck. – Jeppe Stig Nielsen – 2018-03-16T09:26:03.137
Relevant etymology question – Engineer Toast – 2018-03-22T16:34:16.310