Сделать счетчик Гейгера

29

Счетчик Гейгера - это устройство, которое используется для обнаружения радиации.

Мы будем делать счетную программу Гейгера.

Как мы все знаем, когда излучение попадает в компьютерную программу, оно удаляет ровно 1 байт случайным образом. Таким образом, программа счетчика Гейгера - это программа, которая сама по себе ничего не делает, но когда удаляется любой байт, распечатывается измененная программа beep, указывающая на наличие излучения.

Ответы будут оцениваться в байтах, причем меньшее количество байтов будет лучше. Ответы должны быть не менее 1 байта.

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

Мастер пшеницы
источник
Родственный , Родственный .
Пшеничный волшебник
7
Можем ли мы использовать управляющий символ BEL для вывода фактического звукового сигнала?
Джо Кинг
2
@ Шучу, я поиграл с идеей, это забавно, но я должен сказать нет. Это слишком существенно отличается.
Пшеничный волшебник
2
Я хочу увидеть решение в Retina.
mbomb007
3
Я пытаюсь понять, как это сделать в SMBF ... но единственный способ сравнить две ячейки - это изменить их. И в SMBF ячейки, которые вы должны проверить, являются ячейками, в которых в данный момент работает программа. Так что это как принцип неопределенности Гейзенберга. Таким образом, вы должны определить, изменилось ли что-нибудь, используя только поток управления.
mbomb007

Ответы:

24

Потерянный , 303 293 263 253 238 228 байт

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

Попробуйте онлайн!

Скрипт проверки (заимствовано из ответа пользователя 202729 ). К сожалению, это может проверить только половину кода за раз, но будьте уверены, я протестировал всю программу.

Ой, это было сложно. Я процитирую удаленный ответ WW:

Потерянный, пожалуй, самый интересный язык для этой задачи. В «Потерянном» начальное местоположение и направление указателя совершенно случайны, поэтому для создания детерминированных программ необходимо учитывать каждое возможное начальное местоположение и направление. В то же время, по характеру этой задачи вы должны также учитывать удаление любого отдельного байта.

К сожалению, его ответ не принял во внимание удаление новых строк, которые все испортили.

Объяснение:

(обратите внимание, что несколько байтов могут быть здесь и там)

Сначала поговорим об общей структуре кода:

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...@@.......;@..

Попробуйте онлайн!

Программа проверки.


объяснение

Мы используем автоопределение Hexagony длины шестиугольника здесь.

Если никакие байты не удалены, программа имеет длину стороны 4 и выглядит следующим образом:

Программа без удаленных байтов

Однако, если байт удаляется. Есть 2 случая.

  1. Удаленный байт идет после второго <.

    Поток выполнения будет:

    Программа с удаленным последним байтом

    На @5-й строке их 2 подряд , поэтому, даже если один из них будет удален, IP-адрес благополучно попадет в точку @.

  2. Удаленный байт находится на или перед вторым <.

    Тогда вторая половина останется нетронутой, и IP больше не будет перенаправляться вверх <. Изображение потока выполнения:

    Программа со вторым удаленным <code> << / code>

user202729
источник
19

Гексагония , 34 29 байт

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

Попробуйте онлайн! Проверка!

Объяснение:

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

Нет рака ...

Двойной //в начале гарантирует, что этот путь всегда выбран. Если удаляется какой-либо символ, @он удаляется с пути, либо смещается на один назад, либо удаляется сам:

Рак!

В этом случае мы удалили символ после |, который заставляет его следовать этому пути, печатая beep:

Первый гудок

Если вместо этого мы удалим символ перед |(или |самим собой), мы последуем за другим звуковым принтером:

Второй гудок

Затем мы учли все возможности и beepиспользуем только необлученные части программы.

Джо Кинг
источник
13

Самомодифицирующийся Brainfuck , 73 63 байта

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

Попробуйте онлайн! Проверка!

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

Объяснение:

Код разбит на два раздела по 3 байта NUL в середине. Оба они в основном печатают, 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-reversible hexdump:

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, поскольку для выбора между ними используется относительный переход, и радиация могла бы сдвинуть программу таким образом, чтобы переход пропустил первый байт после места назначения. Кроме того, 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

haltЕсли программа работает нормально, но если радиация удаляет ее, то память будет заполнена нулями, что будет $8000выполнять бесконечное число раз, печатая много нулевых байтов.

NieDzejkob
источник
Поскольку 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 байт

Увидев ответ WW с использованием 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\

Попробуйте онлайн!

По сути то же самое, что ответ Klein 000 или> <> ответ (я начал с ответа Klein). Единственное действительно нужное изменение - это превращение <в Lи .в  (перевод символов команды), вставка точек входа IP (необходимо 2, в противном случае удаление приведет к некомпилируемой программе) и вставка команды dela yдля получения два IP-адреса для объединения (таким образом, печатая только один beep), опять же, нужно два. Также необходимо вставить дополнительные NOP, чтобы длина строк оставалась неизменной. Кляйн также удобно использовать @для «печати и завершения».

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

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

Не выводит выходные данные, поскольку изогнутый входной сегмент вызывает повторное отражение обратно в терминатор нижней линии.

Draco18s
источник
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 топологию , которая представляет собой бутылку Klein.

Неотредактированная программа следует по пути выполнения:

Оранжевая дорожка

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

Разделы программы

Первое, на что стоит обратить внимание, это то, что <<в начале всегда будет отклоняться IP-адрес слева от источника. Если один из <s удален, другой занимает его место. Таким образом, если какой-либо байт будет удален из красной секции, будет следовать следующий путь выполнения:

Красная дорожка

Если синий байт удален, мы получаем очень простой путь:

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

Если новая строка удалена, мы получаем путь:

Зеленый путь

Желтый путь немного сложнее. Поскольку нижняя строка на один длиннее верхней строки, когда программа возводится в квадрат в начале выполнения, виртуальный символ добавляется в конец первой строки, чтобы сделать их одинакового размера. Если какой-либо байт во второй строке удален, строка укорачивается, и этот виртуальный символ не добавляется. Это важно, потому что !обычно перепрыгивает через виртуального персонажа, но /вместо этого он перепрыгивает .

Желтая дорожка

Мастер пшеницы
источник
1
Вы можете перенести мое ><>решение 000на 21 байт
Джо Кинг
@ JoKing Я думаю, что это будет лучше, чем его собственный ответ.
Пшеничный волшебник
1

Backhand , 25 21 байт

vv""ppeeeebb""jjHH@

Попробуйте онлайн! Проверка!

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

Джо Кинг
источник