Зробіть лічильник Гейгера


29

Лічильник Гейгера - це пристрій, який використовується для виявлення випромінювання.

Ми будемо робити лічильну програму Гейгера.

Як ми всі знаємо, коли радіація потрапляє на комп'ютерну програму, вона видаляє рівно 1 байт навмання. Тож програма лічильника Гейгера - це програма, яка сама нічого не робить, але коли будь-який байт видалений, модифікована програма надрукує beep, що свідчить про наявність випромінювання.

Відповіді будуть набрані в байтах, менша кількість байтів буде кращою. Відповіді повинні бути не менше 1 байта.

Ваша програма може надрукувати beepз виведенням нового рядка або друком одного нового рядка для порожнього виводу, якщо це буде послідовно. Ваша програма може також використовувати інший випадок для beepтаких , як BEEP, bEEPабо Beepдо тих пір , як вона робить це послідовно.



7
Чи можемо ми використовувати символ управління BEL для виведення фактичного звукового сигналу?
Джо Кінг

2
@JoKing Я розігрувався з ідеєю, це забавно, але я повинен сказати "ні". Це занадто істотно відрізняється.
Пшеничний майстер

2
Я хочу бачити рішення в Сітківці.
mbomb007

3
Я намагаюся розібратися, як це зробити в SMBF ... але єдиний спосіб порівняння двох комірок передбачає їх зміну. І в SMBF, комірки, які потрібно перевірити, - це клітини, на яких зараз працює програма. Так це як Принцип невизначеності Гейзенберга. Таким чином, ви повинні визначити, чи змінилося щось, використовуючи лише контрольний потік.
mbomb007

Відповіді:


24

Втрачено , 303 293 263 253 238 228 байт

v^"peeb"<\>"beepvv"((>@@>>%%>>(((((([[[[[[\
>>>>>>>>>//>>>>>>>>>>>>>>/>>/>>>>>>>>>>>>>\\
>>>>>>>>//>>>>\>>>>>>>>>>/>>>>>>>>>>>>>>>>>\\
>/>>>>>>>/>>>>>>>>>>>>\>>>>>>>>>>>>>>>>>>>>>\\
>>>>>>>>>>>>>>>>>>>>>>\\>>>>\>>>>>>>>>>>>>>>>\

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

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

О, це було важко. Я цитую видалену відповідь WW:

Втрачені - мабуть, найцікавіша мова для цього виклику. У програші Lost розташування старту та напрямок вказівника цілком випадкові, тому, щоб зробити детерміновані програми, ви повинні враховувати кожне можливе місце початку та напрямок. У той же час, за характером цього виклику ви також повинні враховувати будь-який видалений байт.

На жаль, його відповідь не враховувала видалення нових рядків, які все накрутили.

Пояснення:

(зауважте, що кілька байтів можуть бути тут і там)

Спочатку поговоримо про загальну структуру коду:

v^^"peeb"<<\/"beepvv"((>>>@@>>%%>>(((((([[[[[[[\       Processing line
>>>>>>>>>>>//>>>>>>>>>>>>>>>>>>>/>>>>>>>>>>>>>>\\      Beep line
>>>>>>>>>//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\\     Back-up beep line
>//>>>>>>>>>>>>>>>>>>>>\\>>>>>>>>>>>>>>>>>>>>>>>>\\    Back-up return line
>>>>>>>>>>>>>>>>>>>>>>>>\\>>>>>>\>>>>>>>>>>>>>>>>>\    Return line

Все, крім лінії обробки, повинно складатися повністю з одного >або одного з \/. Чому? Ну, як приклад, давайте видалимо новий рядок:

v^^"peeb"<<\/"beepvv"((>>>@@>>%%>>(((((([[[[[[[\>>>>>>>>>>>//>>>>>>>>>>>>>>>>>>>/>>>>>>>>>>>>>>\\
>>>>>>>>>//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\\
>//>>>>>>>>>>>>>>>>>>>>\\>>>>>>>>>>>>>>>>>>>>>>>>\\
>>>>>>>>>>>>>>>>>>>>>>>>\\>>>>>>\>>>>>>>>>>>>>>>>>\

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


Найбільша частина детектора випромінювання - це секція в кінці кожного рядка.

 \
 \\
 >\\
 >>\\
 >>>\

Зазвичай IP, що проходить через цю лінію з першого рядка, виходитиме з останньої лінії. Однак якщо будь-який символ у рядку видалений, то цей рядок зміщується вниз, наприклад:

 \
 \\
 >\\
 >\\
 >>>\

І натомість IP виходить з рядка, якому не вистачає байта (за винятком останнього рядка, де він виходить другим до останнього).

Звідти кожен з перших чотирьох рядків буде перенаправлений на другий рядок:

v
>>>>>>>>>>
>>>>>>>>//
>/

Що потім призведе до будь-якого з двох beepепох.

v^"peeb"<<\/"beepvv"((>
>>>>>>>>>>//

Якщо будь-який байт у першому beeper був видалений, він замість цього переходить до другого:

v^^"peb"<<\/"beepvv"((>
>>>>>>>>>>>//

beepТоді обидва епохи ведуть назад до першого рядка та закінчення @.

Деякі інші деталі:

(((((([[[[[[[Використовуються для очищення стеки , коли покажчик починається всередині пару лапок і в кінцевому підсумку штовхає всю перший рядок в стек. Це повинно бути, на жаль, довгим, оскільки перший новий рядок можна видалити, щоб перший рядок був удвічі більшим за розмір. Експерименти в генерації beepвикористання арифметики замість лапок закінчилися довше.

\S і /збросанние по лінії є для гольфу байтів в верхньому рядку коду, перенаправивши покажчик на правильні лінії. Оскільки більшість нижніх рядків є лише наповнювачем, лише верхня лінія може бути в гольфі. Якщо у когось є якісь ідеї щодо коротшого стеку, захищеного від радіації, то ясніше коментуйте те, що у мене зараз.


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

@WW Я вже працював над цим до того часу, але \/роз'єднати beepпідштовхування та факт, що лише одній із лапок потрібна клавіша про вихід
Джо Кінг,

20

Шестикутник , 38 байт

.....;p;<>b;e;/<b;e;;p...@@.......;@..

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

Програма верифікації.


Пояснення

Тут ми використовуємо автоматичне виявлення шестикутника в шестикутнику.

Якщо жодних байтів не видалено, програма має бічну довжину 4 і виглядає так:

Program without any bytes removed

Якщо, однак, байт видаляється. Є 2 випадки.

  1. Видалений байт знаходиться після другого <.

    Потік виконання буде таким:

    Program with last byte removed

    На @5-му рядку є 2 поспіль , тож навіть якщо один із них буде видалений, IP надійно потрапить на a @.

  2. Вилучений байт знаходиться на рівні або перед другою <.

    Тоді друга половина залишиться недоторканою, а IP-адреса вже не буде перенаправлена ​​вгору <. Зображення потоку виконання:

    Program with the second <code><</code> removed


19

Шестикутник , 34 29 байт

//..>;e;<b@;p;/|/;e;;\.b@;p<@

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

Пояснення:

Ось звичайний код, відформатований у правильний шестикутник за допомогою HexagonyColorer :

No Cancer...

Подвійний //на початку забезпечує цей шлях завжди. Якщо який-небудь символ видалено, то значок @видаляється з контуру, або зміщується на одну назад, або видаляється сам:

Cancer!

У цьому випадку ми видалили символ після |, що змушує його слідувати цьому шляху, друкуючи beep:

First beep

Якщо ми замість цього видалимо символ перед |(або |самим), слідкуємо за іншим звуковим принтером:

Second beep

Тоді ми врахували всі можливості і beepвикористовуємо лише неопромінені частини програми.


13

Brainfuck , що самозмінюється , 73 63 байт

<<[[[[<<]]>[[.>>..>>.[,>]]]]   bbeepp+[<<<]>>[[>]>>>.>>..>>.,+]

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

Пробіли в середині коду насправді представляють байти NUL.

Пояснення:

Код розділений на два розділи по 3 байти в середині. Вони в основному друкуютьbeep якщо інший розділ опромінений (за кількома винятками).

По-перше, <<[[на початку - переконатися, що всі ]s відповідають будь-якому часу. [s не намагатиметься шукати збіги , ]якщо клітина є позитивною, в той час як ]s зробити . Якщо будь-який ]стрибок повернеться до одного з цих дужок, він зазвичай відскакує назад, тому що клітина є0 .

Наступна частина [[<<]]>потім перевіряє, чи довжина розділу 2 рівна. Якщо це так, він виконує другу половину розділу 1, яка друкує, beepвикористовуючи bbeeppна початку розділу 2.

[[.>>..>>.[,>]]]]

Потім він очищає весь розділ 2, щоб він не виконувався.

У розділі 2 ми перевіряємо , якщо довжина секції 1 і NUL байт ділиться на 3з +[<<<]>>.

[[>]>>>.>>..>>.,+]

Аналогічно друкуємо beep.


10

Z80Golf , 53 36 34 байт

-16 байт завдяки @Lynn
-2 байт завдяки @Neil

Оскільки це лише машинний код Z80, у цьому є багато недрукованих матеріалів, тому маємо xxd -r-реверсивний шестигранник:

00000000: ddb6 2120 10dd b615 280c 003e 62ff 3e65  ..! ....(..>b.>e
00000010: ffff 3e70 ff76 003e 62ff 3e65 ffff 3e70  ..>p.v.>b.>e..>p
00000020: ff76                                     .v

Спробуйте в Інтернеті! (вичерпний тестер в Python)

Пояснення

z80golf - гіпотетична машина Z80 Anarchy Golf, де call $8000є путчар, гетчар call $8003, haltробить інтерпретатор вихід, ваша програма розміщена на $0000, а вся інша пам'ять заповнена нулями. Зробити програми, захищені від радіаційного монтажу, досить складно, але загальноприйнятною методикою є використання однобайтових інструкцій безвідмовних дій. Наприклад,

or c        ; b1    ; a = a | c

просто один байт, і a | c | c == a | c, таким чином, можна зробити радіаційно-захисним, просто повторивши інструкцію. На Z80 8-бітове негайне навантаження - це два байти (де безпосереднє знаходиться у другому байті), тому ви можете надійно завантажувати деякі значення в регістри. Це те, що я спочатку робив на початку програми, тож ви можете проаналізувати більш довгі варіанти, які я архівував у нижній частині відповіді, але потім я зрозумів, що існує більш простий спосіб.

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

По-перше, нам потрібно вийти, якщо не спостерігалося випромінювання:

    or a, (ix+endbyte) ; dd b6 21 ; a |= memory[ix+0x0021]
    jr nz, midbyte     ; 20 10    ; jump to a halt instruction if not zero

Якщо будь-який байт був видалений, то всі байти зміщаться і $0020будуть містити останній 76, тому $0021буде нуль. Ми можемо дозволити собі випромінювати початок програми, навіть якщо надмірності практично немає:

  • Якщо зміщення стрибка $10буде знято, то випромінювання буде правильно виявлено, стрибок не буде здійснено, а зміщення не матиме значення. Перший байт наступної інструкції буде використано, але оскільки він розроблений, щоб бути стійким до видалення байтів, це не має значення.
  • Якщо $20вилучити код кодування , то зсув стрибка $10буде декодувати як djnz $ffe4(споживаючи наступний байт інструкції як зміщення - див. Вище), що є командою циклу - декремент B, і стрибок, якщо результат не дорівнює нулю. Тому що ffe4-ffffзаповнений нулями (nop ями), і лічильник програм обгортається, це запустить початок програми 256 разів, а потім, нарешті, продовжить. Я вражений цим твором.
  • Якщо вилучити заголовок $dd, решта фрагменту фрагменту зробіть як or (hl) / ld ($1020), hl, а потім перейдіть до наступної частини програми. orЧи не буде змінювати будь - які важливі регістри, а також тому , що HL дорівнює нулю в цій точці, то запис буде також скорочуються.
  • Вилучення $b6волі зробить решта декодування якld ($1020), ix і далі, як описано вище.
  • Видалення $21волі змусить декодер з'їсти $20, викликаючи djnzповедінку.

Зауважте, що використання or a, (ix+*)економить два байти за ld a, (**) / and a / and aрахунок інтегрованої перевірки нуля.

Тепер нам потрібно вирішити, яку з двох примірників корисного вантажу виконати:

    or (ix+midbyte)  ; dd b6 15
    jr z, otherimpl  ; 28 0c
    nop              ; 00
    ; first payload
    ld a, 'b'        ; 3e 62
    rst $0038        ; ff
    ld a, 'e'        ; 3e 65
    rst $0038        ; ff
    rst $0038        ; ff
    ld a, 'p'        ; 3e 70
    rst $0038        ; ff
midbyte:
    halt             ; 76
otherimpl:
    nop              ; 00
    ld a, 'b'        ; 3e 62
    ; ...            ; ...
    rst $0038        ; ff
endbyte:
    halt             ; 76

Дві копії розділені точкою, оскільки для вибору між ними використовується відносний стрибок, і випромінювання могло змістити програму таким чином, щоб перехід пропустив перший байт після пункту призначення. Крім того, nop кодується як нуль, що полегшує виявлення зміщених байтів. Зауважте, що не має значення, яку корисну навантаження обрано, якщо сам комутатор пошкоджений, оскільки тоді обидві копії є безпечними. Давайте переконаємось, що вона не вскочить у неініціалізовану пам'ять, хоча:

  • Видалення $ddзробить наступні два байти декодування якor (hl) / dec d . Клобери Д. Немає нічого.
  • Видалення $b6створить бездокументоване довше кодування dec d. Само, як і вище.
  • Видалення $15буде $28замість цього зчитуватися як зсув, а виконання триватиметься в $0c, як показано нижче.
  • Коли $28зникає, $0cрозшифровується як inc c. Корисне навантаження не хвилює c.
  • Видалення $0c- саме для цього потрібен nop. Інакше перший байт корисного навантаження був би прочитаний як зміщення стрибка, і програма перескочила б у неініціалізовану пам'ять.

Сама корисна навантаження досить проста. Я думаю, що невеликий розмір рядка робить цей підхід меншим, ніж цикл, і простіше зробити цей спосіб незалежним від позиції. eВ beepповторах, так що я можу збрити один ld a. Крім того , оскільки вся пам'ять між $0038і $8000обнуляється, я можу впасти через нього і використовувати більш короткий rstваріант з callінструкції, яка працює тільки $0, $8,$10 і так далі, аж до$38 .

Старіші підходи

64 байти

00000000: 2e3f 3f2e 3f3f 7e7e a7a7 201f 1e2b 2b1e  .??.??~~.. ..++.
00000010: 2b2b 6b00 7ea7 2814 003e 62cd 0080 3e65  ++k.~.(..>b...>e
00000020: cd00 80cd 0080 3e70 cd00 8076 003e 62cd  ......>p...v.>b.
00000030: 0080 3e65 cd00 80cd 0080 3e70 cd00 8076  ..>e......>p...v

58 байт

00000000: 2e39 392e 3939 7e7e a7a7 2019 3a25 00a7  .99.99~~.. .:%..
00000010: 2814 003e 62cd 0080 3e65 cd00 80cd 0080  (..>b...>e......
00000020: 3e70 cd00 8076 003e 62cd 0080 3e65 cd00  >p...v.>b...>e..
00000030: 80cd 0080 3e70 cd00 8076                 ....>p...v

53 байти

Це має пояснення в історії редагування, але воно не надто відрізняється.

00000000: 3a34 00a7 a720 193a 2000 a728 1400 3e62  :4... .: ..(..>b
00000010: cd00 803e 65cd 0080 cd00 803e 70cd 0080  ...>e......>p...
00000020: 7600 3e62 cd00 803e 65cd 0080 cd00 803e  v.>b...>e......>
00000030: 70cd 0080 76                             p...v

Що робити: будь-який не порожній вихід був чудовим, а не звуковий сигнал

1 байт

v

halts програма нормально, але якщо випромінювання її видаляє, то пам'ять буде заповнена нулями, завдяки чому $8000виконується нескінченна кількість разів, друкуючи багато нульових байтів.


Оскільки aпочинається з нуля, ви не можете використовувати or a, (N);замість ld a, (N); and a;? Схоже, ви можете зберегти пару байтів таким чином.
Ніл

@Neil Добре запитання! На жаль, на Z80 лише такі інструкції щодо завантаження можуть приймати такі адреси.
NieDzejkob

Фу, минуло вже давно, коли я робив будь-яке програмування Z80 ... можливо, я думав or a, (ix + N)?
Ніл

@Neil насправді це існує, і IX теж починається з нуля ... на жаль, збереження байтів у цій області змушує байти зміщуватися таким чином, що 20 19 на початку стає 20 18, а видалення 20створює безумовний стрибок назад, так що nop повинен бути доданий після першого переходу програми, перевернувши збереження байтів.
NieDzejkob

Ах, це соромно. Дякуємо, що перевірили!
Ніл


4

Кляйн , одна з кожної топології, налічуючи 291 байт

Після того, як побачив відповідь ВВ за допомогою001 топології, я вирішив зрозуміти, наскільки важко буде зробити лічильник Гейгера для кожної топології. (Спойлер: дуже важко. Важко зрозуміти, куди піде вказівник без жестів рукою, які змушують мене виглядати так, ніби я з'ясовую, яка рука моя ліва)

Перевірка!

(Я також думав про те, щоб написати програму, яка є дійсним лічильником Гейгера для всіх топологій, але це, можливо, доведеться почекати. Якщо хтось хоче, хоча спробувати, я пропоную суму в 500 повторень)

000 та 010, 21 байт

<<@"peeb"/
.@"peeb"<\

Спробуйте 000 онлайн!та спробуйте 010 онлайн!

Це переноситься з мого ><>рішення . Це, очевидно, працює 000, оскільки це топологія за замовчуванням для більшості 2D мов, але я був здивований, що вона також працює в 010.

001 та 011, 26 байт

!.<<@"peeb"/
.@"peeb"..<..

Спробуйте 001 онлайн!та спробуйте 011 онлайн!

Цей копіюється безпосередньо з відповіді WW . Спасибі!

100, 21 байт

//@"peeb"\
@"peeb".</

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

101, 21 байт

//@"peeb"/
@"peeb".<!

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

110, 26 байт

<.<@"peeb"\\
.\@."peeb".\<

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

111, 24 байти

<<@"peeb"<\
...@"peeb"//

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

200, 21 байт

<<@"peeb"\
@"peeb".!/

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

201, 31 байт

\\.\.@"peeb"</./
./...@"peeb"<\

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

На сьогоднішній день найбільш дратує.

210, 26 байт

/\\@"peeb"</\
/@.."peeb"<\

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

211, 27 байт

\\."peeb"((</
!/@@<"peeb"<\

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

Єдиний, де мені довелося впоратися, вводячи звуковий сигнал через правий бік.


Я щасливо відправлю цю щедрість.
Пшеничний майстер


2

Рунічні чари , 29 байт

>>yyLL@"peeb"/
     @"peeb"L\

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

По суті те саме, що відповідь Клейна 000 або> <> відповідь (я почав з Клайн). Єдина необхідна зміна полягала в тому, щоб перетворити <в Lі .на  (переклад символів команд), вставити точки входу IP (потрібно 2, інакше видалення призведе до некомпілюючої програми) та введення команди dela, yщоб отримати два IP-адреси для злиття (таким чином друкуючи лише один beep), знову ж таки, потрібно два. Також потрібно вставити додаткові НОП, щоб довжина рядків була однаковою. Клайн зручно також використовувати@ для "друку та припинення".

Немає можливості використовувати пробіл у нижній частині лівого краю, оскільки будь-які відбивачі для зміни напрямку гальмують можливість виявлення випромінювання. наприклад (26 байтів, опромінених y):

/yLL@"peeb"/
\<<  @"peeb"L\

Не видає вихід, завдяки зігнутому сегменту входу, що викликає повторне відображення назад до термінатора нижньої лінії.



1

Wumpus , 37 34 32 31 байт

777*7..@ $o&4"beep"|"@peeb"4&o@

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

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

Крім того, для тієї ж кількості байтів


" @o&4"beep"}@
@o&4"beep"}$}  

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

Цей використовує різницю в напрямку вказівника для непарних і парних довжин ліній. (Я насправді не знаю, як "працює насправді перша, коли видалено новий рядок)


1

Кляйн (001), 26 байт

!.<<@"peeb"/
.@"peeb"..<..

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

Перевірте!

Пояснення

Ця програма використовує унікальну топологію Кляйна, зокрема 001 топологію , яка є пляшкою Кляйна.

Нередагована програма слідує шляху виконання:

Помаранчевий шлях

Видалення байта з програми може вплинути на програму чотирма способами (кожен з іншого кольору):

Розділи програми

Перше, що слід зауважити, - це те <<, що завжди буде відхиляти ip зліва від початку на початку. Якщо один із <s видалено, інший займає своє місце. Отже, якщо будь-який байт буде видалений з червоного розділу, буде дотримуватися наступний шлях виконання:

Червоний шлях

Якщо блакитний байт буде видалений, ми отримаємо дуже простий шлях:

введіть тут опис зображення

Якщо новий рядок буде видалено, ми отримаємо шлях:

Зелений шлях

Жовтий шлях трохи складніший. Оскільки нижній рядок на один довший верхній рядок, коли програма на квадрат на початку виконання в квадрат, в кінець першого рядка додається віртуальний символ, щоб зробити їх однакового розміру. Якщо який-небудь байт у другому рядку видалено, рядок скорочується, а цей віртуальний символ не додається. Це важливо, тому що !зазвичай перестрибує через віртуальний персонаж, але за його відсутності /замість цього стрибає .

Жовтий шлях


1
Ви можете перенести моє ><>рішення 000за 21 байт
Джо Кінг,

@JoKing Я думаю, що це було б краще як власна відповідь.
Пшеничний майстер

1

Бекхенд , 25 21 байт

vv""ppeeeebb""jjHH@

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

Для цього використовується здатність Backhand змінювати значення кроку вказівника, щоб пропускати інструкцію на кожному кроці і акуратно вирішувати проблему надмірності. Потім він використовує jкоманду, щоб перевірити, чи опромінюється код, перейшовши до останнього символу ( @, зупинка), якщо ні, і перейти до другого останнього ( H, зупинка та вихідний стек), якщо так.

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