Output the Source, One Bit at a Time

18

2

Write a non-empty program or function that when called outputs a single value, 1 or 0, and when called multiple times, the output numbers produce the binary representation of your program's source code (in the same code page from which your code is compiled/interpreted).

For instance, if your source code was abc (in ASCII), the outputs would be:

1st call:  0           // ASCII letter 'a'
2nd call:  1
3rd call:  1
4th call:  0
5th call:  0
6th call:  0
7th call:  0
8th call:  1

9th call:  0           // ASCII letter 'b'
10th call: 1
11th call: 1
12th call: 0
13th call: 0
14th call: 0
15th call: 1
16th call: 0

17th call: 0           // ASCII letter 'c'
18th call: 1
19th call: 1
20th call: 0
21st call: 0
22nd call: 0
23rd call: 1
24th call: 1

After the 24th call, the behaviour is undefined.

The binary representation of the source must contain at least one 0 bit and one 1 bit.

Instead of 1 and 0, you can output any two distinct, consistent values (such as true and false).

Self-modifying programs that output the binary representation of the original source are allowed, provided that they don't read the source code to find out what to print next.

This is , so the shortest answer in bytes wins.

Steadybox

Posted 2017-10-25T18:22:45.167

Reputation: 15 798

Answers

8

Funky, 47 41 37 bytes

Returns a number representing a bit.

f=_=>1&("%b"%("f="+f)[i//8])>>7-i++%8

This uses the quine format of f=_=>"f="+f. It takes the character at position ⌊i/8⌋, then, gets the bit by taking the pairity of n >> 7-i%8 where n is the ascii value of the current character.

This is an iterative function that increments i with each call, once it's out of source code, it will write the code for n forever.

Try it online!

ATaco

Posted 2017-10-25T18:22:45.167

Reputation: 7 898

Is this a polyglot with JavaScript? – Stan Strum – 2018-02-23T19:43:09.443

9

Bash, 105 bytes

trap -- 'trap|xxd -b -c1|cut -d\  -f2|tr -d \\n|cut -c`x=\`cat f||echo 1\`;echo $((x+1))>f;echo $x`' EXIT

NOTE: Make sure that you don't have an important file called f in the directory you're testing this.


If you want to test this, you can use the following command:

for i in $(seq 848); do bash path/to/script.sh 2> /dev/null; done | tr -d \\n

Which should give the same output xxd -c1 -b path/to/script.sh|cut -d\ -f2|tr -d \\n.

Explanation

This is using the trap trick - calling trap inside the trap action simply prints that line. Next that output gets piped to xxd which converts it to binary (unfortunately xxd -bp doesn't work - thus the workaround with cut & tr):

xxd -c1 -b $0|cut -d\  -f2|tr -d \\n

From that we're only interested in one bit (say N) which we can select with cut -cN.

To find out what N we're using (remember that's the part that needs to be incremented after each call), simply try to set x to the content of the file f and if it doesn't exist set it to 1:

x=`cat f||echo 1`

Last thing to do, is to update the file f - writing x+1 to it:

echo $((x+1))>f

ბიმო

Posted 2017-10-25T18:22:45.167

Reputation: 15 345

7

TI-Basic (TI-83 series), 592 357 309 bytes

"123456789ABCDEF02A3132333435363738394142434445463004AA003FB958833404593FB9588338045A3F3230363FDA582B383F303FCE5A405A6B3232333F5A70BB0FAA002BBB0CAA002B5A2B313FB932BA32F01058713459713511BB0FAA002BBB0CAA002B597031377132722B31→Str1
iPart(X/4→Y
iPart(X/8→Z
206
IS>(X,8
0
If Z and Z<223
Z+inString(Str1,sub(Str1,Z,1
iPart(2fPart(2^(X-4Y-5)inString(Str1,sub(Str1,Y+17-2Ans,1

This table is a possible reference for the calculator's binary representation of the source code, though ultimately I just used Virtual TI's debugger.

For comparison and/or historical interest: the first quines written in TI-Basic.

How it works

Str1 stores the source code (now in glorious hexadecimal, saving lots of space over the previous binary version), leaving out the bits where the contents of Str1 itself would be represented.

We're assuming that the program starts out on a calculator whose memory has just been cleared, so X is 0. Every time through the program, we increment X.

Usually, we just figure out the half-byte we're trying to extract a bit from, read it out of Str1, convert from hexadecimal to binary, and print it. If we're on the part of the source code that's storing Str1 (which is two-thirds of the total length of the program), then we first move to the corresponding part of the string storing 31, 32, and so on.

Misha Lavrov

Posted 2017-10-25T18:22:45.167

Reputation: 4 846

4

Java 8, 249 241 237 234 148 bytes

int i;v->{String s="int i;v->{String s=%c%s%1$c;return s.format(s,34,s).charAt(-i/8)>>(--i&7)&1;}";return s.format(s,34,s).charAt(-i/8)>>(--i&7)&1;}

Sorry in advance for the long explanations. :)

  • Whopping 89 bytes saved thanks to @Nevay.

Try it here.

Explanation:

int i;                     // Index-integer on class-level
v->{                       // Method with empty unused parameter and integer return-type
  String s="int i;v->{String s=%c%s%1$c;return s.format(s,34,s).charAt(-i/8)>>(--i&7)&1;}";
                           //  String containing the unformatted source code
  return s.format(s,34,s)  //    Quine to get the source code,
      .charAt(-i/8)        //     and get the character at index `-i/8`
     >>                    //    And bitwise right-shift it with:
       (--i&7)             //     `i-1` bitwise-AND 7
                           //     by first decreasing `i` by 1 with `--i`
      &1;                  //   Then bitwise-AND everything above with 1
}                          // End of method

Additional explanation:

-part:

  • String s contains the unformatted source code
  • %s is used to put this String into itself with s.format(...)
  • %c, %1$c and 34 are used to format the double-quotes (")
  • s.format(s,34,s) puts it all together

Try it here with some parts removed/modified to verify the quine outputs it's own source code.

-part:


Old 233 bytes answer:

int i;v->{String s="int i;v->{String s=%c%s%1$c;return Long.toString((s.format(s,34,s).charAt(i/8)&255)+256,2).substring(1).charAt(i++%%8);}";return Long.toString((s.format(s,34,s).charAt(i/8)&255)+256,2).substring(1).charAt(i++%8);}

Try it here.

Explanation:

int i;                           // Index-integer on class-level
v->{                             // Method with empty unused parameter and char return-type
  String s="int i;v->{String s=%c%s%1$c;return Long.toString((s.format(s,34,s).charAt(i/8)&255)+256,2).substring(1).charAt(i++%%8);}";
                                 //  String containing the unformatted source code
  return Long.toString(
          (s.format(s,32,s)      //  Quine-formatting
          .charAt(i/8)           //  Take the current character
           &255)+256,2).substring(1)
                                 //  Convert it to an 8-bit binary-String 
         .charAt(i++%8);         //  And return the bit at index `i` modulo-8
                                 //  and increase index `i` by 1 afterwards with `i++`
}                                // End of method

Additional explanation:

-part:

Same explanation as above, with the addition of:

  • %% is the escaped form of the modulo-sign (%)

Try it here with some parts removed/modified to verify the quine outputs it's own source code.

-part:

  • i/8 will automatically truncate on integer division, so when i is 0-7, it will become 0; if i is 8-15, it will become 1; etc.
  • So s.charAt(i/8) takes the current character of the source-code, eight times after each other. Try it here with a modified version.
  • 255 is 0xFF or 11111111 (the max value for an unsigned byte)
  • 256 is 0x100 or 100000000.
  • The & upcasts the ASCII-character to an integer. At that point, it's anywhere between 0 and 255 (00000000 to 11111111).
  • Long.toString(...,2) converts it to the 9-bit binary String representation
  • +256 and .substring(1) will ensure there are leading zeroes, and will convert the 9-bit to an 8-bit.

Try it here with some parts removed/modified to verify the entire bytes.

Kevin Cruijssen

Posted 2017-10-25T18:22:45.167

Reputation: 67 575

1149 bytes: int i;v->{String s="int i;v->{String s=%c%s%1$c;return 1&s.format(s,34,s).charAt(-i/8)>>(--i&7);}";return 1&s.format(s,34,s).charAt(-i/8)>>(--i&7);} – Nevay – 2017-10-26T10:22:43.230

@Nevay Whopping 88 bytes saved. Thanks! And since it's actually quite a bit of a different approach than I originally had, I kept the old answer, and added the new. (If you want I'll remove it again and you can post it yourself, but you told me in the past you prefer to golf other people's - mainly mine XD - code instead of posting your own answer, right?) – Kevin Cruijssen – 2017-10-26T12:07:02.590

2

Javascript ES6, 73 58 52 bytes

o=_=>`o=${o}`.charCodeAt((o.n=1+o.n|0)/8)>>(7-o.n%8)&1

Explanation

Breakdown of the code:

  • o=_=>: define a function.
  • `o=${o}`: construct a string; o is converted to a string, which in this case is the function's source code.
  • .charCodeAt(: get a character in the string as its ASCII character code.
  • (o.n=1+o.n|0)/8: select a character. This is also where the counter is incremented.
  • )>>(7-o.n%8): shift the resulting character code so that the desired bit is in the right position.
  • &1: set all other bits to 0.

RamenChef

Posted 2017-10-25T18:22:45.167

Reputation: 1 163

You can shorten this with a lambda into o=_=>(o+'').charCodeAt(('n'in top?++n:n=0)/8|0)>>(7-n%8)&1 – ATaco – 2017-10-25T23:19:10.273

This counts as defining a function. – ATaco – 2017-10-25T23:21:53.097

1Try o=_=>('o='+o).charCodeAt(('n'in top?++n:n=0)/8|0)>>(7-n%8)&1 – ATaco – 2017-10-25T23:32:55.460

Instead of 'n'in top?++n:n=0 you can use ++n||(n=0) or ++n?n:n=0 or n=++n||0 or n=1+n||0 which all utilise the falsiness of NaN that is produced by incrementing undefined – Bergi – 2017-10-26T03:33:40.400

o=_=>('o='+o).charCodeAt((o.n=1+o.n|0)>>3)>>(~o.n&7)&1 – tsh – 2017-10-26T04:09:59.490

1o=_=>('o='+o).charCodeAt((o.n=1+o.n|0)/8)>>(~o.n&7)&1 – tsh – 2017-10-26T05:21:32.353

2

q/kdb+, 45 bytes

Solution:

a:-1;f:{((,/)0b vs'4h$"a:-1;f:",($).z.s)a+:1}

Example:

q)f[] / call function f with no parameters
0b   
q)f[]
1b   
q)f[]
1b   
q)f[]
0b   
q)f[]
0b   
q)f[]
0b   
q)f[]
0b   
q)f[]
1b   
q)f[]  
q)"c"$0b sv 01100001b / join back to a byte and cast to a character
"a"

Explanation:

I think I understood the brief.

First setup a global variable a with starting value of -1. Function f builds the binary representation of the string representation of the function (everything including the {}) prepended with the a:-1;f: junk, and indexes into this binary list at index a (which gets incremented each call).

a:-1;f:{(raze 0b vs'4h$"a:-1;f:",string .z.s)a+:1} / ungolfed solution
a:-1;                                              / stick -1 in variable a
     f:{                                         } / define function f
                                             a+:1  / increment a by 1 (:: is required as a is a global variable), indexes into the left
        (                                   )      / do all this together
                                 string .z.s       / z.s is the function, string converts it to a string
                       "a:-1;f:",                  / prepend "a:-1;f:" to the start
                    4h$                            / cast to bytes
              0b vs'                               / convert each byte to binary
         raze                                      / flatten binary into long list

streetster

Posted 2017-10-25T18:22:45.167

Reputation: 3 635

2

Python 2, 164 bytes

lambda s='lambda s=%r,i=[]:i.append(1)or"{:08b}".format(ord((s%%s)[~-len(i)/8]))[~-len(i)%%8]',i=[]:i.append(1)or"{:08b}".format(ord((s%s)[~-len(i)/8]))[~-len(i)%8]

Try it online!

Explanation

Let's start with a standard Python 2 quine.

s = '...'; print s % s

Okay, well, this outputs it just like that. We need binary!

s = '...'; print "\n".join("\n".join("{:08b}".format(ord(i))) for i in s % s)

Right, that just converts everything to binary. But the title says "one bit at a time". We need something to persist through multiple runs. I know, let's make it a function!

lambda s = '...': "\n".join("\n".join("{:08b}".format(ord(i))) for i in s % s)

Wait, that doesn't help... Hmm, how can we keep track of the index of the bit needed to be output? Ooh, ooh, let's have an integer to keep track.

lambda s = '...', i = 0: "{:08b}".format(ord((s % s)[i / 8]))[i % 8]

Um... that always outputs the first bit. Oh, we need to increment the tracker! Oh crap, Python doesn't allow integers as default arguments to be modified. And assignments aren't expressions in Python, so you can't do that in a lambda. Welp, this is impossible in Python, case closed.

...Well, not quite. Python does allow lists as default arguments to be modified. (And it bites Python programmers all the time.) Let's use its length!

lambda s = '...', i = []: "{:08b}".format(ord((s % s)[len(i) / 8]))[len(i) % 8]

That still doesn't modify the tracker though... We can append something to it to increase its length... But how? Ah, well, we've got list.append. lst.append(1) is equivalent to lst += [1]. Great!

lambda s = '...', i = []: i.append(1) and "{:08b}".format(ord((s % s)[len(i) / 8]))[len(i) % 8]

Whoops, this skips the first bit because the length of the tracker is 1 before the bit is outputted. We need to decrement the length where it's used.

lambda s = '...', i = []: i.append(1) and "{:08b}".format(ord((s % s)[(len(i) - 1) / 8]))[(len(i) - 1) % 8]

There it is, folks! Golf it and you've got my solution!

totallyhuman

Posted 2017-10-25T18:22:45.167

Reputation: 15 378

2

Perl 5, 59 bytes

sub{$_=q{unpack(B.++$-,"sub{\$_=q{$_};eval}")=~/.$/g};eval}

Try it online!

Dom Hastings

Posted 2017-10-25T18:22:45.167

Reputation: 16 415