У меня был привет


30

задача

Читайте в возможно бесконечном текстовом потоке или файле, выводя его содержимое до helloтех пор, пока не будет выведено слово , соблюдая следующие правила.

  • После helloвывода ваш код должен немедленно завершиться. Например, не следует ждать новой строки.

  • Ваш код должен выводиться, как он идет. То есть он не должен читать огромное количество ввода, а затем начинать вывод.

  • Если поток / файл не содержит hello, ваш код должен просто выводить ввод навсегда или до тех пор, пока не будет достигнут конец потока / файла.

  • Это чувствительный к регистру вызов, поэтому helloон не равен Hello.

  • Вы можете предположить, что ввод состоит только из печатных символов ASCII и новых строк.

  • Ваш код не может ожидать, что текст будет завершен новой строкой или что во входных данных вообще будут какие-либо новые строки. Кроме того, ваш код не может предполагать, что он будет работать на машине с бесконечным объемом памяти.

  • Вы можете предположить, что ваш код будет вызываться из пустой директории.

Пример входного потока

I once had a horse called hellopina.

Выход

I once had a horse called hello

Чаевые

Запустите, yes | tr -d \\n | <your program>чтобы проверить, работает ли он с бесконечными потоками. Если он ничего не печатает и / или не теряет память, программа не соответствует спецификации. Он должен печатать yyyyyyyyyyyyyyyyyyyyyy...вечно без перевода строки.


1
Разрешено ли читать что-нибудь после "привет"? Вопрос, кажется, запрещает любое дополнительное чтение, которое может быть проблематичным в таких языках, как (Стандарт) C, которые обеспечивают буферизованный ввод с автоматическим опережающим чтением.
Тоби Спейт

Вы, вероятно, должны изменить принятый ответ на сборочный, так как он на 2 байта короче.
Rɪᴋᴇʀ

@Riker Было бы замечательно, если бы кто-то мог проверить это или хотя бы сказать, что он верит, что сначала это работает.

Ответы:


2

Желе , 24 байта

“Ṣẉ»ẇ⁸Ṇȧ®
ṫ-3;ƈ©Ȯ¤µ⁺Ç¿ṛ“

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

Объяснение:

ṫ-3;ƈ©Ȯ¤µ⁺Ç¿ṛ“ Main link. Arguments: 0
ṫ-3            Truncate the list to its 4 last elements.
   ;ƈ©Ȯ¤       Store a character from STDIN in the register, print it, and append it to the list (list is initially [0]).
        µ      Start a new monadic chain, everything to the left is a link.
          Ç    Execute the helper link with the existing list as its argument.
         ⁺ ¿   Do-while loop, left link is body, right link is condition.
            ṛ“ When the loop ends, replace the return value with [] (invisible on output).

“Ṣẉ»ẇ⁸Ṇȧ® Helper link. Arguments: string
“Ṣẉ»ẉ⁸Ṇ   Check if "hello" isn't in the string.
        ® Return the character we stored in the register.
       ȧ  Check if both of the above are truthy.

26

C (gcc) , 81 80 76 75 72 71 70 69 байт

main(n,c){while(~(c=getchar())&n-0xb33def<<7)n=n<<5^putchar(c)/96*c;}

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

Как это работает

Это полная программа. Мы определяем функцию f для наших целей. Чтобы сохранить байты, он объявляется с двумя аргументами, которые по умолчанию равны int . Это неопределенное поведение, но на практике n будет инициализироваться как 1 при запуске программы без дополнительных аргументов, c будет содержать младшие 32 бита указателя на вектор аргумента

Пока состояние

~(c=getchar())&n-0xb33def<<7

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

n=n<<5^putchar(c)/96*c

Чтобы полностью понять состояние, мы должны сначала изучить тело. Пока что мы наблюдаем только то, что c=getchar()считывает один байт из STDIN (если это возможно) и сохраняет его в переменной c .

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

char     decimal     binary (8 bits)
'h'      104         0 1 1 0 1 0 0 0
'e'      101         0 1 1 0 0 1 0 1
'l'      108         0 1 1 0 1 1 0 0
'l'      108         0 1 1 0 1 1 0 0
'o'      111         0 1 1 0 1 1 1 1

Все они попадают в диапазон [96, 192) , поэтому c/96оцениваются в 1 для каждого из этих байтов и в 0 для всех оставшихся символов ASCII. Таким образом, putchar(c)/96*c( putchar печатает и возвращает свой аргумент) будет вычислено значение c, если c - `это строчная буква, один из {|}~символов или символ DEL; для всех остальных символов ASCII он будет равен 0 .

Значение n обновляется путем смещения его на пять бит влево, а затем с помощью XOR результата с результатом предыдущего абзаца. Поскольку int имеет ширину 32 бита (или, как мы предполагаем в этом ответе), некоторые из сдвинутых битов могут «падать влево» (целочисленное переполнение со знаком является неопределенным поведением, но gcc ведет себя как инструкция x64, которую он генерирует здесь). Начиная с неизвестного значения n , обновив его для всех символов hello , мы получим следующий результат.

 n  ?????????????????????????|???????
'h'                          |    01101000
'e'                          |         01100101
'l'                          |              01101100
'l'                          |                   01101100
'o'                          |                        01101111
-----------------------------+--------------------------------
    <------ discarded ------>|???????0101100110011110111101111

Обратите внимание, что младшие 25 битов образуют целое число 0xb33def , которое является магической константой в условии. Хотя между битами двух смежных байтов есть некоторое перекрытие, отображение байтов ниже 96 на 0 гарантирует, что нет никаких ложных срабатываний.

Условие состоит из двух частей:

  • ~(getchar()) принимает побитовое НЕ результата чтения (или попытки чтения) байта из STDIN.

    Если getchar завершится успешно, он вернет значение прочитанного байта как int . Поскольку вход полностью состоит из символов ASCII, в считываемом байте могут быть установлены только его младшие 7 битов, поэтому в этом случае для побитового НЕ будут установлены его старшие 25 битов.

    Если getchar терпит неудачу (больше нет ввода), он вернет -1, а побитовое НЕ будет 0 .

  • n-0xb33def<<7вычитает магическую константу из n , а затем сдвигает результат на 7 единиц влево.

    Если последние 5 прочитанных байтов были привет , младшие 25 бит n будут равны 0xb33def, и вычитание обнулит их. Сдвиг разности даст 0, так как 7 старших битов «упадут влево».

    С другой стороны, если последние 5 прочитанных байтов не были " привет" , будет установлен один из младших 25 битов разности; после сдвига будет один из старших 25 битов.

Наконец, если getchar был успешным, и мы еще не напечатали привет , будет установлен побитовый AND, все старшие 25 битов левого операнда и по крайней мере один из старших 25 битов правого операнда. Таким образом, вы &получите ненулевое целое число, и цикл продолжается.

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


Вы, вероятно, должны упомянуть, что это зависит от того, какой ввод кодируется в ASCII, прежде чем углубляться в объяснение.
Тоби Спейт

2
@TobySpeight Я не думаю, что это обычно указывать. Какого рода кодировку, несовместимую с ASCII, вы ожидаете от ответа C?
Деннис

EBCDIC - это очевидная кодировка, которая не является ASCII. C не предписывает какую-либо конкретную кодировку символов (только то, что десятичные цифры должны быть представлены последовательными значениями по порядку).
Тоби Спейт

вышеуказанная программа останавливается, если поток содержит строку «ascii» «« úá ÷ o »1: o 111 6f 2: ÷ 246 f6 3: 160 a0 4: ú 163 5:« 174
RosLuP

@RosLuP Спецификация вызова гарантирует, что ввод будет состоять из печатных символов ASCII и символов новой строки.
Деннис

19

Баш, 74 75 103 99 88 82 76 байт

-10 байт благодаря @DigitalTrauma!
-11 байт благодаря @manatwork!
-6 байт благодаря @Dennis!

IFS=
b=ppcg
while [ ${b/hello} ];do
read -rN1 a
b=${b: -4}$a
echo -n $a
done

Объяснение:

IFS=    # making sure we can read whitespace properly
b=ppcg  # set the variable b to some arbitrary 4 letter string

while [ ${b/hello} ]; do  # while the variable b doesn't contain "hello", do the following
    read -rN1 a           # get input
    b=${b: -4}$a          # set b to its last 4 chars + the inputted char
    echo -n $a            # output the inputted char
done

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


2
Это здорово! Я надеялся, что будет ответ Баша.

13

Лабиринт , 43 41 байт

Спасибо Sp3000 за сохранение 2 байта.

<_%-742302873844_::%*:*:420#+.:%):,*652_>

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

объяснение

Основная идея состоит в том, чтобы закодировать последние пять символов в базе 256 в одно целое число. Когда появляется новый символ, мы можем «добавить» его, умножив целое число на 256 и добавив новую кодовую точку. Если мы хотим посмотреть только последние 5 символов, мы берем значение по модулю 256 5 = 2 40 = 1099511627776. Затем мы можем просто проверить, равно ли это значение 448378203247, что мы получаем, когда мы обрабатываем кодовые точки helloкак основа - 256 цифр.

Что касается кода ... <...>это немного лабиринт идиома. Это позволяет вам писать бесконечный цикл без какого-либо условного потока управления в одной строке, сохраняя много байтов на пробелах и переводах строк. Основное условие для того, чтобы это работало, это наличие двух одноразовых значений в верхней части стека, когда мы достигаем <(мы обычно используем 0s для этого, но фактическое значение является произвольным).

Конечно, программе нужна условная логика, чтобы понять, когда завершить работу. Но условно завершить программу можно путем деления на значение, равное нулю, когда мы хотим, чтобы программа закончилась. В <...>конструкт работает путем сдвига всю строку влево (циклически) , когда IP - находится на левом конце, а затем сразу же сдвигая его обратно в рабочее положение. Это означает, что код фактически выполняется справа налево. Давайте изменим это:

_256*,:)%:.+#024:*:*%::_448378203247-%_

Это одна итерация цикла, которая читает символ, завершается, если мы достигли EOF, печатает символ, добавляет его в нашу кодировку, усекает его до 5 символов, проверяет равенство helloи повторяет. Вот как это работает подробно (помните, что Labyrinth основан на стеке):

_256*            Multiply the encoding by 256 in preparation for the next iteration.
,                Read one byte from STDIN.
:)%              Duplicate, increment, modulo. If we hit EOF, then , returns
                 -1, so incrementing and modulo terminates the program due to
                 the attempted division by zero. However, if we did read a
                 character, we've just compute n % (n+1), which is always n itself.
:.               Print a copy of the character we just read.
+                Add it to our encoding (we'll make sure to multiply the
                 encoding by 256 at the end of the iteration, so there's room
                 for our new character).
#024             Push 1024, using the stack depth to push the initial 1.
:*:*             Square it twice. That gives 2^40.
%                Take the encoding modulo 2^40 to truncate it to the last 5
                 characters.
::               Make two copies of the encoding.
_448378203247    Push the value that corresponds to "hello".
-                Subtract it from the encoding, giving zero iff the last 5
                 characters were "hello".
%                Take the other copy of the encoding modulo this value, again
                 terminating if we've reached "hello".
                 The actual value of this modulo - if it didn't terminate the
                 the program - is junk, but we don't really care, we just need
                 any disposable value here for the <...>
_                We push a zero as the second disposable value.

8

Brainfuck, 658 байт

+[>,.>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[-<->]+<[>-<[-]]>[-<,.>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[-<->]+<[>-<[-]]>[-<,.>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[-<->]+<[>-<[-]]>[-<,.>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[-<->]+<[>-<[-]]>[-<,.>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[-<->]+<[>-<[-]]>[-<<->>]]]]]<<]

Более 500 байтов находятся в константах, которые мне нужны для игры в гольф.

По сути, это конечный автомат, поэтому бесконечный ввод не является проблемой.

Это слегка прокомментированная версия

+
[
  >,.
  >h
  [-<->]
  +<
  [
    >-<[-][in input spot, not h]
  ]
  >
  [
    -
    <
    [in input spot, h has been read]
    ,.
    >e
    [-<->]
    +<
    [
      >-<[-][in input spot, not e]
    ]
    >
    [
      -
      <
      [in input spot, e has been read]
      ,.
      >l
      [-<->]
      +<
      [
        >-<[-][in input spot, not l]
      ]
      >
      [
        -
        <
        [in input spot, l has been read]
        ,.
        >l
        [-<->]
        +<
        [
          >-<[-][in input spot, not l]
        ]
        >
        [
          -
          <
          [in input spot, l has been read]
          ,.
          >o
          [-<->]
          +<
          [
            >-<[-][in input spot, not o]
          ]
          >
          [
            -
            <
            [in input spot, o has been read]
            <->>
          ]
        ]
      ]
    ]
  ]
  <<
]

Это выглядит весело :)

Добро пожаловать в Программирование Пазлов и Code Golf StackExchange!
betseg

1
Этот код имеет несколько проблем, но самая большая проблема заключается в том, что он не включает логику для ahehellobправильной обработки случаев ; в середине потенциального совпадения он только проверяет следующую букву helloи не ищет начала hдля начала.
Митч Шварц

8

Баш , 73 68 66 байт

IFS=
[[ $1 != olleh ]]&&read -rN1 c&&echo -n $c&&exec $0 $c${1::4}

Предполагается каталог без или только скрытые файлы. Должен быть запущен как <path/to/script>.

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

Как это работает (устарело)

В начале в то время цикла, мы первый тест , если строка в переменной s (изначально пустой) равна olleh ( привет назад, olé), и возвращает 0 (матч) или 1 (не совпадает) , соответственно. Хотя формально является частью условия цикла, результат не повлияет на него сам по себе, так как только последняя команда до этого doопределяет, выполняется ли условие.

Затем мы устанавливаем внутренний разделитель полей на пустую строку (чтобы readне задыхаться от пробелов), читаем raw bytes ( -r) из STDIN и сохраняем их в c. $?это код завершения предыдущей команды, поэтому он читает ровно один ( -N1) байт для несоответствия и нулевой bytes ( -N0). Чтение нулевых байтов, будь то из-за нажатия EOF или из-за того, что -N0было указано, приводит readк выходу с кодом состояния 1 , поэтому цикл while завершится; в противном случае тело выполняется, и мы начинаем заново.

В теле мы сначала печатаем прочитанный байт, а затем обновляем его с помощью s=$c${s::4}. Это добавляет байт чтения к (до) первых четырех байтов в s , так что s будет равен olleh, как только будет напечатан hello .


Очень мило на самом деле!

8

мозговой трах, 117 байт

--->>>------>>>+>>>+>>>++++<,[.-----<-[>--<-----]<[<<<]>>>[<[<<<+>>>>->+<<-]>[>>
+>]<[+[-<<<]]>>[<+>-]>>]<[[-]<<<,<]>]

отформатирован:

--->>>------>>>+>>>+>>>++++
<,
[
  .-----<-[>--<-----]<[<<<]
  >>>
  [
    <[<<<+>>> >->+<<-]
    >[>>+>]
    <[+[-<<<]]
    >>[<+>-]
    >>
  ]
  <[[-]<<<,<]
  >
]

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

Это инициализирует ленту с символами со helloсмещением на 107, разнесенными по одному значению каждые три ячейки, затем отслеживает последние пять увиденных символов и проверяет совпадение с каждым новым обработанным символом, используя флаг справа от строки для отслеживать, был ли матч.


7

Рубин , 46 60 байт

a="";loop{q=$<.getc;~p if a[-5..-1]=="hello"||!q;a+=q;$><<q}

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

Читает символы из stdin до последних 5 hello, затем выводит строку (или до тех пор, пока в stdin не останется символов). Завершается с ошибкой.

Эквивалентно:

a = ""
loop {
    q = $<.getc
    ~p if a[-5..-1] == "hello" || !q
    a += q
    $><< q
}

Или, более безликий

a = ""
loop do
    q = STDIN.getc
    break if a[-5..-1] == "hello" or not q
    a += q
    print q
end

1
aрастет каждый раз, когда читается символ Это сбой, если вход бесконечен?
Betseg

@betseg хм, может быть. Дайте мне посмотреть, смогу ли я это исправить
Конор О'Брайен

7

Python 3, 120 116 104 байт

Работает с бесконечными потоками, впервые в гольф, любые советы приветствуются.

import sys
a=1
c=''
while(a):
    a=sys.stdin.read(1)
    if a:print(end=a)
    c=(c+a)[-5:]
    if c=='hello':break

Спасибо @DJMcMayhem за сохранение нескольких байтов :)


Добро пожаловать на сайт! c=[0,c+1]['hello'[c]==a]должен сэкономить вам несколько байтов. Кроме того, a=1короче тоже.
DJMcMayhem

2
Вам не нужны скобки для whileв Python.
PurkkaKoodari

6

Haskell, 41 47 43 байта

f l|w@"hello"<-take 5l=w|a:b<-l=a:f b|1<2=l

Лень Хаскелла хорошо справляется с бесконечным вводом / выводом.

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

Редактировать: не обрабатывать конечный ввод - исправлено. Спасибо @Leo за указание.

Редактировать II: @ Орьян Йохансен сохранил 4 байта. Благодарность!


2
Ввод также может быть конечным, поэтому я думаю, что вам нужно разобраться со случаем, когда вы достигнете конца строки
Лев

@Leo: К сожалению, полностью пропустил это. Исправлена.
Nimi

2
Первый охранник может быть сокращен до |w@"hello"<-take 5l=w.
Эрджан Йохансен

@ ØrjanJohansen: о, это мило. Благодарность!
Nimi

6

Cubix, 94 83 82 79 63 56 байт

p>q'-?w.uh'e@U7.'hqi?oqB-!ul.-..$WWu_q<o'\;>....6t?.../!@

Expanded:

        p > q '
        - ? w .
        u h ' e
        @ U 7 .
' h q i ? o q B - ! u l . - . .
$ W W u _ q < o ' \ ; > . . . .
6 t ? . . . / ! @ . . . . . . .
. . . . . . . . . . . . . . . .
        . . . .
        . . . .
        . . . .
        . . . .

Заметки

  • Интерпретатор отключает поле ввода при запуске программы. Таким образом, бесконечный поток ввода невозможен. Эта программа принимает ввод за символом, поэтому, если бы не это ограничение, оно работало бы правильно.
  • Эта программа не очищает стек, и она очень быстро запутывается. Поскольку машина, на которой это будет использоваться, по-видимому, может давать бесконечные входные потоки, разумно предположить, что она также имеет бесконечную память.
  • Любая помощь в гольф очень ценится.

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

Вы можете попробовать программу здесь .

объяснение

Главная идея

Общая идея заключается в том, что мы хотим прочитать символ, а затем проверить его на предмет изменяющихся символов (сначала h, затем e, затем lи т. Д.). Чтобы отслеживать пропущенного персонажа, мы держим его в самом низу стека. Когда нам это нужно, мы легко можем снова поднять его на вершину.

Цикл чтения / записи

Цикл чтения-записи - это просто 5- я строка. Все неиспользуемые символы заменяются на no-ops ( .):

        . . . .
        . . . .
        . . . .
        @ . . .
' h q i ? o q B - ! u l . - . .
. . . . _ . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
        . . . .
        . . . .
        . . . .
        . . . .

Это можно разделить на две части: чтение и (написание и проверка). Первая часть содержит инструкции вплоть до знака вопроса. Вторая часть - это остальная часть строки. Поскольку это зацикливается, мы предполагаем, что мы начинаем со стека[...]

    @
'hqi?
    _

Explanation
'h          Push the character code of the h
            Stack: [..., 104]
  q         Send it to the bottom
            Stack: [104, ...]
   i        Read one character of the input (-1 for EOF)
            Stack: [104, ..., input]
    ?       Start of condition:
              if (input < 0):
    @           execute '@', ending the program
              if (input = 0):
                continue going right
              if (input > 0):
    _           turn to the right, reflect back ('_') and
                turn right again, effectively not changing 
                the direction at all

Вторая часть (написание и проверка) снова линейна. Стек начинается как [next-char, ..., input]. Мы абстрагировали следующий символ, потому что это меняется позже в программе.

oqB-!ul.-  Explanation
o          Output the character at the top of the stack
 q         Send the input to the bottom of the stack
           Stack: [input, next-char, ...]
  B        Reverse the stack
           Stack: [..., next-char, input]
   -       Push the difference of the top two characters, which
           is 0 if both are equal, something else otherwise
           Stack: [..., next-char, input, diff]
    !      if (diff = 0):
     u       make a u-turn to the right
           else:
      l.     execute two no-ops
        -    push [input - next-char - input], which is disregarded
             later, so it effectively is a no-op as well.

Теперь, IP начнется снова в начале этого цикла, сбрасывая следующий символ для проверки h.

Соответствие следующему персонажу

Если IP сделал разворот (т. Е. Символ, который мы прочитали и напечатали, соответствовал следующему символу 'hello'), нам нужно проверить, каким символом был ввод, и в зависимости от этого сдвинуть следующий символ в конец стека. После этого нам нужно вернуться к циклу чтения / записи, не помещая hего в стек, поэтому нам нужен другой способ попасть туда.

Перво-наперво: определите, каким персонажем был ввод. Стек выглядит следующим образом : [..., prev-char, input, 0].

        . . . .
        - ? . .
        u h ' e
        . . . .
. . . . . . . . . ! u . . . . .
. . . . . . . . . \ ; . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
        . . . .
        . . . .
        . . . .
        . . . .

Чтобы сравнить ввод, мы hснова используем код символа . Первоначально это было потому, что я не знал, как я собираюсь с этим справиться, и hэто первый символ в строке, который нужно проверить, но в итоге это оказалось довольно удобным. Если мы вычтем код символа h из ввода, мы получим, -3если вход есть e, 0если вход есть h, 4если вход lи 7если вход o.

Это полезно, потому что ?команда позволяет нам легко отделить отрицательные значения от положительных значений и нуля. Таким образом, если IP поворачивается влево, разница была отрицательной, поэтому ввод был e, поэтому следующий символ должен быть l. Если IP продолжает идти прямо, разница была 0, поэтому ввод был h, поэтому следующий символ должен быть e. Если вход является lили o, IP поворачивается направо.

Все инструкции, выполненные до вышеупомянутого знака вопроса:

;!e'h-     Explanation
;          Delete the top of the stack
           Stack: [..., prev-char, input]
 !         if (input = 0):
  e          execute 'e' (no-op)
   'h      Push the character code of h
           Stack: [..., prev-char, input, 104]
     -     Push the difference of the input and 104
           Stack: [..., prev-char, input, 104, diff]

Теперь IP меняет свое направление, как описано выше. Давайте рассмотрим различные возможности.

вход 'e'

Сначала мы рассмотрим ввод e, который заставляет IP двигаться вверх от ?, так как разница равна 3. Все нерелевантные символы были удалены из куба.

        . > q '
        . ? . .
        . . . .
        . . . .
. . q . . . . . . . . l . . . .
$ W W . . . . . . . . > . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
        . . . .
        . . . .
        . . . .
        . . . .

Символы выполняются в следующем порядке (исключая некоторые символы потока управления):

q'l$WWq
q           Save the difference (-3) to the bottom of the stack so
            we can tell whether the l on the bottom of the stack is
            the first or the second l in hello
            Stack: [-3, ...]
 'l         Push the character code of l to the stack
            Stack: [-3, ..., 108]
   $W       no-op
     W      Sidestep into the loop
      q     Send the character code to the bottom
            Stack: [108, -3, ...]

Теперь IP снова достиг цикла чтения / записи.

вход 'h'

Если вход был 'h', разница равна 0, поэтому IP не меняет своего направления. Снова куб, со всеми не относящимися к делу персонажами. Поскольку этот путь включает в себя довольно много неактивных операций, все пропущенные им операции были заменены &. IP начинается с вопросительного знака.

        . . . .
        . ? w .
        . . ' e
        . . . .
. . . . . . . . . ! . . . . . .
. . . u _ q < . . \ . . . . . .
. . ? & & & / . . & . . . . . .
. . & . . . . . . & . . . . . .
        . . . .
        & & & &
        . . . .
        . . . .

Выполненные инструкции:

'e!\?q_
'e          Push the character code of the e
            Stack: [..., 101]
  !         if (101 = 0):
   \          reflect away (effectively a no-op)
    ?       if (101 > 0):
              turn right (always happens)
     q      Move 101 to the bottom of the stack
            Stack: [101, ...]
      _     No-op

И теперь мы снова входим в цикл чтения / записи, так что мы закончили.

Другие входы

Все остальные входные данные приводят к положительной разнице, поэтому IP-адрес поворачивается направо на вопросительный знак. Нам все еще нужно разделить lи oто, что мы будем делать дальше.

Разделение 'l'и'o'

Имейте в виду, что разница составляет 7 для oи 4 для lи что мы должны завершить программу, если ввод был o. Вот куб снова с нерелевантными частями, замененными на a, .и нет-опы, кресты IP были заменены амперсандами.

        . . q .
        . ? w .
        . h ' .
        . U 7 .
. . . . . . . . . . . . . - . .
. . . . . . . . . . . . . & . .
. . . . . . / ! @ . . . . & . .
. . . . . . & . . . . . . & . .
        . . & .
        . . & .
        . . & .
        . . & .

h7'wq-!@    
h           no-op
 7          Push 7 to the stack
            Stack: [..., diff, 7]
  'wq       Push w to the stack and send it to
            the bottom. We don't care about it,
            so it's now part of the ellipsis.
            Stack: [..., diff, 7]
     -!     if (diff = 7):
       @        End the program

Различение между этими двумя 'l'с

Итак, теперь мы знаем, что вклад был l, но мы не знаем, какой l. Если это первое, нам нужно подтолкнуть другого lк нижней части стека, но если это второе, нам нужно подтолкнуть o. Помните, мы сохранили -3в конец стека как раз перед тем, как выдвинуть первый l? Мы можем использовать это для разделения двух ветвей.

        . . . .
        . . . .
        . . . .
        . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
6 t ? . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
        . . . .
        . . . . 
        . . . .
        . . . .

Стек начинается как [..., -3 or 140, ...]

Explanation
6t?         
6t          Take the 6th item from the top and move
            it to the top (which is either -3 or 140)
  ?         If that's positive, turn right, otherwise,
            turn left

Первый 'l'

Если это было первым 'l', нам нужно подтолкнуть другого 'l'. Для сохранения байтов мы используем те же символы, что и для первого 'l'. Мы можем упростить стек до [...]. Вот соответствующая часть куба, где нет операций, замененных амперсандами.

        p > q '
        . . . .
        . . . .
        . . . .
' . q . . . . . . . . l . . . .
$ W W . . . . . . . . > & & & &
. . ? . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
        . . . .
        . . . .
        . . . .
        . . . .

Следующие инструкции выполняются:

$'pq'lq
$'          no-op
  pq        no-op
    'l      Push the character code of l
            Stack: [..., 108]
      q     Send it to the bottom
            Stack: [108, ...]

Мы собираемся войти в цикл чтения / записи, поэтому мы закончили с этой веткой.

второй 'l'

Если вход был вторым 'l'в 'hello', то IP повернул направо на знак вопроса. Еще раз, мы можем упростить стек, [...]и IP начинается с, на ?этот раз, указывая на юг.

        . . . .
        . . . .
        . . . .
        . . . .
. . . . . . . . . . . . . . . .
. . . u _ q < o ' \ . . . . . .
. . ? . . . . . . & . . . . . .
. . & . . . . . . & . . . . . .
        . . . .
        & & & &
        . . . .
        . . . .

Выполненные инструкции:

'oq_
'o          Push the character code of 'o'
            Stack: [..., 111]
  q         Move the top item to the bottom
            Stack: [111, ...]
   _        No-op

И IP собирается снова войти в цикл чтения / записи, так что мы закончили и с этой веткой.


Героическое усилие!

5

C ++, 142 141 байт

#import<iostream>
void f(std::istream&i){i>>std::noskipws;char c;for(std::string s="     ";s!="hello"&&i>>c;)s.erase(0,1),s+=c,std::cout<<c;}

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


Будет ли это возможно с GCC? Я не вижу #importв программах GCC C ++ ...
ckjbgames

1
@ckjbgames #import- устаревшее расширение GCC.
Steadybox

1
@ckjbgames больше информации здесь: stackoverflow.com/questions/172262/…
iFreilicht

@iFreilicht Этот вопрос заставил меня задать этот вопрос.
ckjbgames

1
@ckjbgames, вы можете взглянуть на второй ответ: stackoverflow.com/a/172264/2533467 «Импорт в gcc отличается от импорта в VC ++. Это простой способ включить заголовок не более одного раза. "
iFreilicht

3

Узел, 124 байта

with(process)with(stdin)on('data',d=>[...d].map(c=>(s=(stdout.write(c),s+c).slice(-5))=='hello'&&exit()),setEncoding(),s='')

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


3

C #, 134 байта

using C=System.Console;class P{static void Main(){var s="";for(int c;(c=C.Read())>=0&!s.Contains("olleh");C.Write(s[0]))s=(char)c+s;}}

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

Читает символ, проверяет, что это не -1 (EOS) и что мы еще не видели "привет", затем добавляет его в строку и записывает символ. Мы готовимся, потому что s[0]это намного короче(char)s . Это имеет квадратичную стоимость в длине строки, так как он должен выделять и сканировать весь ввод каждый раз, когда он читает символ (это приведет к сбою после 2 Гбайт ввода из-за ограничений в CLR, это разрешено?)

using C=System.Console;

class P
{
    static void Main()
    {
        var s="";
        for(int c;(c=C.Read())>=0&!s.Contains("olleh");C.Write(s[0]))
            s=(char)c+s;
    }
}

Для (длиннее: 142 байта) версии, которая не будет хватает памяти и которая имеет постоянную стоимость за символ, см. Ниже:

using C=System.Console;class P{static void Main(){var s="     ";for(int c;(c=C.Read())>=0&s!="hello";C.Write(s[4]))s=s.Substring(1)+(char)c;}}

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

using C=System.Console;

class P
{
    static void Main()
    {
        var s="     ";
        for(int c;(c=C.Read())>=0&s!="hello";C.Write(s[4]))
            s=s.Substring(1)+(char)c;
    }
}

3

PHP, 57 55 53 байта

while(hello!=$s=substr($s.$c,-5))echo$c=fgetc(STDIN);

поскольку нет бесконечных файлов, я беру ввод из STDIN. Беги с -nr.

Циклический ввод, печать текущего символа, добавление к нему $s, сокращение $sдо последних 5 символов. Разорвать петлю, когда $sесть hello.


3

Vim, 39 байт

:im hello hello:se noma
:map : i

i

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

:im hello                        "Remap 'hello' in insert mode to
          hello                "write hello, then hit escape
                 :se noma       "then set the buffer to not-modifiable
:map : i                        "THEN remap ':' to 'i' so that can't be changed

i                                "enter insert mode and await an infinite stream of input

Это приемлемый метод ввода для Vim? Я думал, что программы Vim обычно ожидают, что входные данные уже находятся в буфере до их запуска.
Мартин Эндер

Если честно, я не знаю? Это правда, но вряд ли допускает бесконечный поток, поэтому я просто сделал это таким образом, не задумываясь об этом.
nmjcman101

Что произойдет, если во входном потоке есть escape-символ?
тусклый

@dim я спросил, а OP указал только печатные ASCII и переводы строк. ESC не включен в печатную
версию

3

PowerShell, 111 байт

Возможно, есть лучший способ сделать это, но я не могу видеть это в настоящее время.

while(($x=($x+$host.UI.RawUI.ReadKey("IncludeKeyDown").character+"     ").substring(1,5)).CompareTo("hello")){}

Это читает нажатия клавиш, не подавляя эхо. Символ добавляется к $ x, который обрезается до последних 5 символов и сравнивается с "привет". Это продолжается до тех пор, пока сравнение не станет правдой.

Примечание: это не работает в PowerShell ISE. ReadKey отключен в этой среде.


3

Схема 115 байтов

(do((c(read-char)(read-char))(i 0(if(eqv? c(string-ref"hello"i))(+ i 1)0)))((or(eof-object? c)(= i 5)))(display c))

Читаемая версия:

(do ((c (read-char) (read-char))                            ; read stdin
     (i 0 (if (eqv? c (string-ref "hello" i)) (+ i 1) 0)))  ; check target
    ((or (eof-object? c) (= i 5))) ; finish if end of stdin, or word found
  (display c))                     ; display each character

Это берет отдельный символ из stdin каждый раз в цикле и отмечает его положение на целевом слове, когда оно встречает символы «привет».

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


Классный ответ, добро пожаловать на сайт!
DJMcMayhem

3

AWK, 95 байт

BEGIN{RS="(.)"
split("hello",h,"")}{for(j=0;++j<6;){c=RT
printf c
if(c!=h[j])next
getline}exit}

Здесь я узнал 2 вещи:
1) Чтобы разделить записи между символами, нужно использовать, RS="(.)"а затем RTиспользовать вместо $1
2) ORSиспользуется printи по умолчанию равен "\n"
3) я не могу сосчитать до 2, а использование printf"дешевле", чем назначение ORSи с помощьюprint

Пример использования: поместите код в файл

awk -f FILE some_data_file

или

some process | awk -f FILE

Код был протестирован по yes | ...предложению Денниса, и я видел много-многоy s.

К вашему сведению, вы можете сделать присвоение RS в качестве опции и вытащить его из BEGINблока через:

awk -v RS='(.)'

Действительно хитрое решение! (Может быть , потому что в пятницу днем, но я считаю , это хорошая запись запутанным вызов тоже.) Хотя я бы попробовать более awkish подход: BEGIN{RS="(.)"}{printf RT}"olleh"==a=RT substr(a,1,4){exit}.
manatwork

Как ни странно, у меня есть почти точный ответ, готовый отправить час назад ... и забыл его отправить. : p
Роберт Бенсон

3

Python 3 (Linux), 73 72 байта

s=c='_';I=open(0)
while'olleh'!=s>''<c:c=I.read(1);s=c+s[print(end=c):4]

Спасибо @MitchSchwartz за отыгрывание 1 байта!

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


Я не понимаю Как whileправильно оценить состояние? Похоже, вы сравниваете логическое значение с пустой строкой.
iFreilicht

1
s[print(end=c):4]сохраняет байт
Митч Шварц

1
@iFreilicht Python анализирует цепочечные условия так же, как в математике (например, <b <c ). Условие является сокращением для 'olleh'!=s and s>''and''<c). Средний тест не нужен, но их цепочка короче, чем простая 'olleh'!=s and''<c.
Деннис

@ MitchSchwartz Что это делает. Спасибо!
Деннис

3

8086 машинный код, 22 байта

00000000  bf 11 01 b4 01 cd 21 ae  75 f6 81 ff 16 01 72 f3  |......!.u.....r.|
00000010  c3 68 65 6c 6c 6f                                 |.hello|
00000016

Эквивалентный код сборки:

org 0x100
use16
a:  mov di, msg
b:  mov ah, 1       ; read one byte from stdin with echo
    int 0x21        ; dos syscall -> result in AL
    scasb           ; if (DI++ == AL)
    jne a
    cmp di, msg+5
    jb b
    ret
msg db "hello"

Как это работает?

1
Я добавил эквивалентный ассемблерный код. Он в основном основан на одном очень полезном системном вызове DOS, который читает один байт из стандартного ввода и одновременно выводит его обратно в стандартный вывод. 8086 также имеет однобайтовую инструкцию сравнения строк, которая здесь пригодится.
user5434231

2

Pyth, 49 47 байт

Wn"hello"=>5+kp$__import__("sys").stdin.read(1)

Пиф не очень хорош для ввода одного символа ввода. Все $__import__("sys").stdin.read(1)просто делает это. Кроме того, это означает, что это работает только в автономном режиме.

Все остальное коротко ...

Программа представляет собой цикл без тела. Внутри условия программа читает символ, печатает его обратно, добавляет этот символ k(который изначально является пустой строкой), обрезает все, кроме последних 5 символов k, и затем проверяет, что результат не соответствует "hello".

32 символа получают один байт ввода, 15 символов делают все остальное.

Проверено на Linux, работает даже без перевода строки, бесконечного ввода и т. Д.


2

Луа, 68 64 байта

l=""while l~="hello"do c=io.read(1)io.write(c)l=l:sub(-4)..c end

1
Измените нарезку на l:sub(-4), тогда вы можете уменьшить инициализацию l="".
manatwork

@ Manatwork Это здорово. Спасибо за совет.
Blab


1

Рёда , 49 47 байт

{a=[0]*5{|x|[x];a=a[1:]+x;z if[a&""="hello"]}_}

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

Это анонимная функция, которая читает символы из своего входного потока и выводит их до тех пор, пока не будет найдено «привет». Он использует массив aдля отслеживания последних символов.

Он выводит некоторый мусор в STDERR, но я понял, что это разрешено .

Объяснение:

{
    a=[0]*5                /* Initialize the array with 5 zeroes. */
    {|x|                   /* For each x in the input stream: */
        [x];               /* Print x */
        a=a[1:]+x;         /* Add x and remove the sixth last character. */
        z if[a&""="hello"] /* If "hello" is found, crash the program */
                           /* with an undefined variable. */
    }_                     /* End for loop. */
}

Где находится документация Roda?
ckjbgames

@ckjbgames Здесь. Я использую последнюю версию 0.12, которая находится в его собственной ветке в Github.
fergusq

1

Java 7, 122 118 124 123 150 141 байт

void c()throws Exception{String a="aaaaa";for(int b;!a.equals("hello")&(b=System.in.read())>=0;a=a.substring(1)+(char)b)System.out.write(b);}

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


Могу поспорить, что это не может обрабатывать бесконечный ввод.
Тит

@Titus фиксированной ...
ткнуть

Я понизил голосование, не видя, writeчтобы его использовали вместо print. Я не могу отменить свое понижение, извините за это :(
Оливье Грегуар

1

Рубин, 51 байт

x="";$><<x[-1]while/hello./!~x=x[/.{0,5}$/]+$<.getc
  • Не ожидает перевода строки
  • Работает с бесконечным вводом

1

AHK , 116 байт

Loop,Read,%1%
{a=%A_LoopReadLine%`n
Loop,Parse,a
{Send % c:=A_LoopField
If((f:=c SubStr(f,1,4))=="olleh")
ExitApp
}}

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


1

Mathematica, 107 байт

i="";EventHandler[Dynamic@i,"KeyDown":>(i=i<>CurrentValue@"EventKey";If[StringTake[i,-5]=="hello",Exit[]])]

Вывод становится полем, в котором пользователь может бесконечно набирать текст (включая новые строки), пока последние 5 символов не будут равны "hello"; в этот момент он выходит.


1

брейкфук , 281 байт

>++++++++[<+++++++++++++>-]>++++++++++[<++++++++++>-]<+>>+++++++++[<++++++++++++>-]>++++++++++[<+++++++++++>-]<+>+[[[[[,.<<<<[->>>>->+<<<<<]>>>>>[-<<<<<+>>>>>]<],.<<<[->>>->+<<<<]>>>>[-<<<<+>>>>]<],.<<[->>->+<<<]>>>[-<<<+>>>]<],.<<[->>->+<<<]>>>[-<<<+>>>]<],.<[->->+<<]>>[-<<+>>]<]

Я не уверен почему, но я просто чувствовал, что мозговитость была правильной вещью, чтобы сделать это. Не требует бесконечной памяти и может выводить вечно.

Разъяснения

Set up the buffers with helo
This is done Naively; sue me
>++++++++[<+++++++++++++>-]     h
>++++++++++[<++++++++++>-]<+>   e
>+++++++++[<++++++++++++>-]     l
>++++++++++[<+++++++++++>-]<+>  o

THE MAIN LOOP
+
[ matches o
    [ matches l
        [ matches l
            [ matches e
                [ matches h
                    ,. Read a character and immediently write it
                    <<<<[->>>>->+<<<<<] Subtract it from h
                    >>>>>[-<<<<<+>>>>>] Correct the h
                    < Terminate this part of the loop if it matches h
                ]
                ,. Same as above
                <<<[->>>->+<<<<] Subtract it from e
                >>>>[-<<<<+>>>>] Correct the e
                < Terminate this part of the loop if it matches e
            ]
            ,. Same as above
            <<[->>->+<<<] Subtract it from l
            >>>[-<<<+>>>] Correct the l
            < Terminate this part of the loop if it matches l
        ]
        ,. Same as above
        <<[->>->+<<<] Subtract it from l
        >>>[-<<<+>>>] Correct the l
        < Terminate this part of the loop if it matches l
    ]
    ,. Same as above
    <[->->+<<] Subtract it from o
    >>[-<<+>>] Correct the o
    < Terminate this part of the loop if it matches o
]

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


Я собирался сделать это так, но потом я понял, что это выводит нулевой байт бесконечно для ввода, который не содержит «привет»: tio.run/nexus/…
KarlKastor

Это также не удается ahehellob.
Митч Шварц
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.