Виведіть джерело, один біт за раз


18

Напишіть непусту програму або функцію, що при виклику виводить одне значення, 1 або 0, а коли викликається кілька разів, вихідні числа створюють двійкове представлення вихідного коду вашої програми (на тій же сторінці коду, з якої складається ваш код / інтерпретовано).

Наприклад, якщо ваш вихідний код був abc(в ASCII), виведеннями будуть:

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.

Двійкове представлення джерела повинно містити щонайменше один 0 біт і один 1 біт.

Замість 1 і 0 можна вивести будь-які два чіткі послідовні значення (такі як trueі false).

Програми, що самостійно змінюють, які видають двійкове представлення вихідного джерела, дозволені за умови, що вони не читають вихідний код, щоб дізнатися, що друкувати далі.

Це , тому найкоротша відповідь у байтах виграє.

Відповіді:


8

Фанки , 47 41 37 байт

Повертає число, що представляє біт.

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

Для цього використовується формат quine f=_=>"f="+f. Він приймає символ у положенні ⌊i / 8⌋ , а потім отримує біт, приймаючи парність, n >> 7-i%8де nзнаходиться значення ascii поточного символу.

Це ітеративна функція, яка збільшується iз кожним викликом, як тільки він не буде вихідним кодом, він запише код nназавжди.

Спробуйте в Інтернеті!


Це поліглот із JavaScript?
Стен Струм

9

Баш , 105 байт

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

ПРИМІТКА . Переконайтеся, що fу каталозі, який ви тестуєте, у вашому файлі не має важливого файлу .


Якщо ви хочете перевірити це, ви можете скористатися такою командою:

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

Що має дати той самий вихід xxd -c1 -b path/to/script.sh|cut -d\ -f2|tr -d \\n.

Пояснення

Для цього використовується trapфокус - виклик trapвсередині trapдії просто надрукує цей рядок. Далі цей вихід отримує трубопровід, xxdякий перетворює його у бінарний (на жаль xxd -bp, не працює - таким чином, вирішення проблеми з cut& tr):

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

З цього нас цікавить лише один біт (скажімо N), який ми можемо вибрати cut -cN.

Щоб дізнатися, що Nми використовуємо (пам’ятайте, що це частина, яку потрібно збільшувати після кожного дзвінка), просто спробуйте встановити xвміст файлу, fа якщо його немає, встановіть його на 1:

x=`cat f||echo 1`

Останнє, що потрібно зробити, - оновити файл f- записавши x+1його:

echo $((x+1))>f

7

TI-Basic (серія TI-83), 592 357 309 байт

"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

Ця таблиця є можливою орієнтиром для двійкового представлення вихідного коду калькулятора, хоча в кінцевому підсумку я просто використав налагоджувач Virtual TI.

Для порівняння та / або історичного інтересу: перші лайки, написані на TI-Basic .

Як це працює

Str1зберігає вихідний код (тепер у славному шістнадцятковому, економивши багато місця над попередньою бінарною версією), не залишаючи бітів там, де Str1буде представлений сам вміст .

Ми припускаємо, що програма запускається на калькуляторі, пам'ять якого щойно очищена, так і Xє 0. Щоразу через програму ми збільшуємо X.

Зазвичай ми просто з'ясовуємо напівбайт, з якого ми намагаємося витягнути трохи, прочитати його Str1, перетворити з шістнадцяткових у бінарні та роздрукувати. Якщо ми на частини вихідного коду , який зберігає Str1(що становить дві третини від загальної довжини програми), то перший крок до відповідної частини рядка зберігання 31, 32і так далі.


4

Java 8, 249 241 237 234 148 байт

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;}

Заздалегідь вибачте за довгі пояснення. :)

  • Цілих 89 байт збережено завдяки @Nevay .

Спробуйте тут.

Пояснення:

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

Додаткове пояснення:

-part:

  • String s містить неформатоване вихідний код
  • %s використовується для того, щоб поставити цю струну в себе s.format(...)
  • %c, %1$cі 34використовуються для форматування подвійних лапок ( ")
  • s.format(s,34,s) зводить це все разом

Спробуйте тут, з вилученими / модифікованими частинами, щоб перевірити вихід квітів у власний вихідний код.

-част:


Старий 233 байт відповідає:

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);}

Спробуйте тут.

Пояснення:

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

Додаткове пояснення:

-part:

Те саме пояснення, що і вище, з додаванням:

  • %%- утекла форма модуля-знака ( %)

Спробуйте тут, з вилученими / модифікованими частинами, щоб перевірити вихід квітів у власний вихідний код.

-част:

  • i/8автоматично скорочується на цілочисельний поділ, тому коли iбуде 0-7, воно стане 0; якщо i8-15, це стане 1; тощо.
  • Так s.charAt(i/8)приймає поточний символ вихідного коду, вісім разів один за одним. Спробуйте тут із модифікованою версією.
  • 255є 0xFFабо 11111111(максимальне значення для неподписаного байта)
  • 256є 0x100або 100000000.
  • &Скиди в ASCII-символ в ціле число. У цей момент він знаходиться десь між 0і255 ( 00000000до 11111111).
  • Long.toString(...,2) перетворює його в 9-бітове бінарне представлення String
  • +256і .substring(1)забезпечить наявність провідних нулів, і перетворить 9-бітний у 8-бітний.

Спробуйте тут, з вилученими / модифікованими частинами, щоб перевірити цілий байт.


1
149 байт: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 Цілих 88 байт збережено. Спасибі! А оскільки це насправді зовсім інший підхід, ніж я був спочатку, я дотримав стару відповідь і додав нову. (Якщо ви хочете , я видалю його знову , і ви можете залишити його собі, але ви сказали мені в минулому ви віддаєте перевагу гольф інших людей - в основному моє XD - код замість розміщення свого власного відповіді, справа)
Кевін Cruijssen

2

Javascript ES6, 73 58 52 байти

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

Пояснення

Розбивка коду:

  • o=_=>: визначити функцію.
  • `o=${o}`: побудувати рядок; oперетворюється на рядок, який у цьому випадку є вихідним кодом функції.
  • .charCodeAt(: отримати символ у рядку як код символу ASCII.
  • (o.n=1+o.n|0)/8: виберіть символ. Тут також збільшується лічильник.
  • )>>(7-o.n%8): змістіть отриманий код символу так, щоб потрібний біт знаходився в потрібному положенні.
  • &1: встановити всі інші біти на 0.

Ви можете скоротити це за допомогою лямбда наo=_=>(o+'').charCodeAt(('n'in top?++n:n=0)/8|0)>>(7-n%8)&1
Атако

Це вважається визначальним функцією.
Атако

1
Спробуйтеo=_=>('o='+o).charCodeAt(('n'in top?++n:n=0)/8|0)>>(7-n%8)&1
ATaco

Замість того , 'n'in top?++n:n=0ви можете використовувати ++n||(n=0)або ++n?n:n=0чи n=++n||0або n=1+n||0які все використовують falsiness з NaNякий виробляється збільшеннямundefined
Берги

1
o=_=>('o='+o).charCodeAt((o.n=1+o.n|0)/8)>>(~o.n&7)&1
tsh

2

q / kdb + , 45 байт

Рішення:

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

Приклад:

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"

Пояснення:

Я думаю, що я зрозумів коротке.

Спочатку встановіть глобальну змінну aіз початковим значенням -1. Функція fбудує двійкове представлення рядкового подання функції (все, включаючи {}), що є попередньо зі a:-1;f:сміттям, та індексує цей бінарний список в індексі a (який збільшується кожен виклик).

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

2

Пітон 2 , 164 байти

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]

Спробуйте в Інтернеті!

Пояснення

Почнемо зі стандартної квітки Python 2.

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

Гаразд, добре, це виводить це просто так. Нам потрібен бінарний!

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

Правильно, що просто перетворює все на бінарне. Але в заголовку написано «по одній штуці». Нам потрібно щось зберігати через кілька прогонів. Я знаю, давайте зробимо це функцією!

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

Зачекайте, це не допомагає ... Гм, як ми можемо відслідковувати індекс біта, необхідного для виведення? О-о-о, давай будемо ціле число для відстеження.

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

Гм ... що завжди видає перший біт. О, нам потрібно збільшити трекер! О дерьмо, Python не дозволяє змінювати цілі числа як аргументи за замовчуванням. І завдання не є виразами в Python, тому ви не можете робити це в лямбда. Welp, це неможливо в Python, справа закрита.

... Ну, не зовсім. Python робить дозволяють списки в якості аргументів по замовчуванням повинні бути змінені. (І він постійно кусає програмістів Python.) Давайте використовувати його довжину!

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

Це все ще не змінює трекер. Ми можемо додати щось до нього, щоб збільшити його довжину ... Але як? Ах, ну, у нас є list.append. lst.append(1)еквівалентно lst += [1]. Чудово!

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

Ну, це пропускає перший біт, оскільки довжина трекера дорівнює 1, перш ніж біт виводиться. Нам потрібно зменшити довжину, де вона використовується.

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

Ось це, люди! Гольф це, і ти отримав моє рішення!


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.