Zadanie
Wczytaj prawdopodobnie nieskończony strumień tekstowy lub plik, wyświetlając jego zawartość, aż słowo hello
zostanie wypisane, zgodnie z następującymi zasadami.
Po
hello
wygenerowaniu kod powinien zostać natychmiast zamknięty. Nie powinien na przykład czekać na nową linię.Twój kod powinien wypisywać na bieżąco. Oznacza to, że nie powinien czytać dużej ilości danych wejściowych, a następnie zacząć generować.
Jeśli strumień / plik nie zawiera
hello
, Twój kod powinien po prostu wyprowadzać dane wejściowe na zawsze lub do końca strumienia / pliku.Jest to wyzwanie uwzględniające wielkość liter, więc
hello
nie jest równeHello
.Możesz założyć, że dane wejściowe składają się wyłącznie z drukowalnych znaków ASCII i znaków nowej linii.
Twój kod nie może oczekiwać, że tekst zostanie zakończony znakiem nowej linii lub że na wejściu będą w ogóle jakieś nowe linie. Ponadto kod nie może zakładać, że będzie działał na komputerze z nieskończoną ilością pamięci.
Możesz założyć, że twój kod zostanie wywołany z pustego katalogu.
Przykładowy strumień wejściowy
I once had a horse called hellopina.
Wydajność
I once had a horse called hello
Wskazówka
Uruchom, yes | tr -d \\n | <your program>
aby sprawdzić, czy działa z nieskończonymi strumieniami. Jeśli nic nie drukuje i / lub wycieka pamięć, program nie jest zgodny ze specyfikacją. Powinien drukować yyyyyyyyyyyyyyyyyyyyyy...
wiecznie, bez nowych linii.
Odpowiedzi:
Galaretka , 24 bajty
Wypróbuj online!
Wyjaśnienie:
źródło
C (gcc) ,
8180767572717069 bajtówWypróbuj online!
Jak to działa
To jest pełny program. Definiujemy funkcję f dla naszych celów. Aby zapisać bajty, zadeklarowany jest dwoma argumentami domyślnie int . Jest to zachowanie nieokreślone, ale w praktyce n zostanie zainicjowane jako 1 podczas uruchamiania programu bez dodatkowych argumentów, c zachowa 32 dolne bity wskaźnika do wektora argumentu
Podczas gdy warunek
posiada będziemy wykonać podczas gdy ciało pętli za:
Aby w pełni zrozumieć ten warunek, musimy najpierw zbadać ciało. Na razie obserwujemy tylko, że
c=getchar()
czyta pojedynczy bajt ze STDIN (jeśli to możliwe) i przechowuje go w zmiennej c .Cześć sekwencji bajtów wygląda następująco w różnych reprezentacjach.
Wszystkie z nich mieszczą się w przedziale [96, 192) , więc
c/96
zostaną ocenione na 1 dla każdego z tych bajtów i na 0 dla wszystkich pozostałych znaków ASCII. W ten sposóbputchar(c)/96*c
( putchar wypisuje i zwraca argument) oceni na c, jeśli c jest`
, małą literą, jednym z{|}~
lub znakiem DEL; dla wszystkich innych znaków ASCII będzie miało wartość 0 .n jest aktualizowany poprzez przesunięcie go o pięć bitów w lewo, a następnie XOR wyniku z wynikiem z poprzedniego akapitu. Ponieważ int ma szerokość 32 bitów (a przynajmniej tak zakładamy w tej odpowiedzi), niektóre z przesuniętych bitów mogą „spaść z lewej strony” (przepełnienie liczby całkowitej ze znakiem jest zachowaniem niezdefiniowanym, ale gcc zachowuje się jak generowana tutaj instrukcja x64). Zaczynając od nieznanej wartości n , po zaktualizowaniu jej dla wszystkich znaków hello , otrzymujemy następujący wynik.
Zauważ, że dolne 25 bitów tworzy liczbę całkowitą 0xb33def , która jest magiczną stałą w tym stanie. Podczas gdy bitów dwóch sąsiednich bajtów zachodzi pewne nakładanie się, bajty odwzorowania poniżej 96 na 0 zapewniają, że nie ma żadnych fałszywych alarmów.
Warunek składa się z dwóch części:
~(getchar())
pobiera bitową NIE wyniku odczytu (lub próby odczytu) bajtu ze STDIN.Jeśli getchar powiedzie, to zwróci wartość odczytu bajtu jako int . Ponieważ dane wejściowe składają się wyłącznie ze znaków ASCII, odczytany bajt może mieć ustawione tylko 7 niższych bitów, więc bitowe NIE będzie miało w tym przypadku swoich najwyższych 25 bitów.
Jeśli getchar nie powiedzie się (nie ma więcej danych wejściowych), zwróci -1, a bitowe NIE będzie wynosić 0 .
n-0xb33def<<7
odejmuje stałą magiczną od poprzedniej od n , a następnie przesuwa wynik o 7 jednostek w lewo.Jeśli ostatnie 5 odczytanych bajtów było hello , najniższe 25 bitów n będzie równe 0xb33def i odjęcie ich wyzeruje . Przesunięcie różnicy da 0, ponieważ 7 najwyższych bitów „spadnie z lewej”.
Z drugiej strony, jeśli ostatnie 5 odczytanych bajtów nie było przywitanych , ustawiony zostanie jeden z 25 najniższych bitów różnicy; po zmianie jeden z najwyższych 25 bitów będzie.
Na koniec, jeśli getchar się powiódł i jeszcze nie wypisaliśmy cześć , bitowe ORAZ, wszystkie najwyższe 25 bitów lewego operandu i co najmniej jeden z najwyższych 25 bitów prawego operandu zostaną ustawione. W ten sposób
&
da niezerową liczbę całkowitą i pętla będzie kontynuowana.Z drugiej strony, jeśli dane wejściowe są wyczerpane lub już wydrukowaliśmy hello , jeden z bitowych argumentów AND będzie równy zero, a więc i wynik. W takim przypadku przerywamy pętlę i program się kończy.
źródło
Bash,
747510399888276 bajtów-10 bajtów dzięki @DigitalTrauma!
-11 bajtów dzięki @manatwork!
-6 bajtów dzięki @Dennis!
Wyjaśnienie:
Wypróbuj online!
źródło
Labirynt ,
4341 bajtówDzięki Sp3000 za oszczędność 2 bajtów.
Wypróbuj online!
Wyjaśnienie
Podstawową ideą jest zakodowanie pięciu ostatnich znaków w bazie 256 w jednej liczbie całkowitej. Kiedy pojawia się nowy znak, możemy go „dodać”, mnożąc liczbę całkowitą przez 256 i dodając nowy punkt kodowy. Jeśli chcemy spojrzeć tylko na 5 ostatnich znaków, bierzemy wartość modulo 256 5 = 2 40 = 1099511627776. Następnie możemy po prostu sprawdzić, czy wartość ta jest równa 448378203247, co otrzymujemy, gdy traktujemy punkty kodu
hello
jako podstawowe 256 cyfr.Co do kodu ...
<...>
to trochę idiom Labiryntu. Pozwala napisać nieskończoną pętlę bez żadnego warunkowego przepływu sterowania w pojedynczej linii, oszczędzając wiele bajtów na spacjach i liniach. Głównym warunkiem tego działania jest to, że po osiągnięciu stosu znajdują się dwie wartości jednorazowe<
(zwykle używamy0
do tego celu s, ale rzeczywista wartość jest dowolna).Oczywiście program potrzebuje pewnej logiki warunkowej, aby dowiedzieć się, kiedy zakończyć. Ale warunkowo zakończenie programu jest możliwe poprzez podzielenie przez wartość równą zero, gdy chcemy, aby program się zakończył. Te
<...>
prace konstrukt przez przeniesienie całego wiersza w lewo (cyklicznie), gdy IP jest na lewym końcu, a następnie przeniesienie go natychmiast z powrotem na miejsce. Oznacza to, że kod jest faktycznie wykonywany od prawej do lewej. Odwróćmy to:Jest to jedna iteracja pętli, która odczytuje znak, kończy się, jeśli osiągnęliśmy EOF, drukuje znak, dodaje go do naszego kodowania, obcina to do 5 znaków, sprawdza równość
hello
i powtarza. Oto jak to działa szczegółowo (pamiętaj, że Labirynt jest oparty na stosie):źródło
Brainfuck, 658 bajtów
Ponad 500 bajtów to stałe, które muszę trochę zagrać w golfa.
Zasadniczo jest to maszyna stanu, więc nieskończone wprowadzanie danych nie stanowi problemu.
To jest lekko skomentowana wersja
źródło
ahehellob
poprawnie; w środku potencjalnego dopasowania sprawdza tylko kolejną literęhello
i nie szukah
początku.Bash ,
736866 bajtówZakłada katalog, w którym nie ma lub ma tylko ukryte pliki. Musi być uruchomiony jako
<path/to/script>
.Wypróbuj online!
Jak to działa (nieaktualne)
Na początku while pętli, to pierwszy test, jeśli ciąg w zmiennej s (początkowo pustego) równa olleh ( cześć tyłu, Ole) i powrócić 0 (mecz) lub 1 (nie mecz) odpowiednio. Chociaż formalnie jest częścią warunku pętli, wynik nie wpłynie na nią samodzielnie, ponieważ tylko ostatnie polecenie
do
określa, czy warunek się utrzymuje.Następnie ustawiamy wewnętrzny separator pól na pusty ciąg (aby
read
nie dusił się na białych znakach), odczytuje surowe bajty (-r
) ze STDIN i przechowujemy jec
.$?
jest kodem wyjścia poprzedniego polecenia, więc odczytuje dokładnie jeden-N1
bajt ( ) dla niepasującego i zero bajtów (-N0
). Odczyt zerowych bajtów, czy to z powodu trafienia w EOF, czy dlatego, że-N0
został określony, powodujeread
zakończenie z kodem stanu 1 , więc pętla while zakończy się; w przeciwnym razie ciało zostanie wykonane i zaczniemy od nowa.W organizmie, najpierw wydrukować bajt czytamy, potem zmiana s z
s=$c${s::4}
. To dodaje bajt odczytu do (do) pierwszych czterech bajtów s , więc s będzie równe olleh po wydrukowaniu hello .źródło
pieprzenie mózgu, 117 bajtów
Sformatowany:
Wypróbuj online .
Inicjuje taśmę z
hello
przesuniętymi znakami107
, rozmieszczonymi z jedną wartością co trzy komórki, a następnie śledzi ostatnie pięć znaków i sprawdza dopasowanie każdego nowego przetworzonego znaku, używając flagi po prawej stronie ciągu, aby śledź, czy doszło do dopasowania.źródło
Rubinowy ,
4660 bajtówWypróbuj online!
Odczytuje znaki od standardowego wejścia do ostatnich 5
hello
, a następnie wyświetla ciąg znaków (lub dopóki w standardowym standardzie nie pozostaną żadne znaki). Kończy się z błędem.Równoważny:
Lub bardziej nie golfisty:
źródło
a
rośnie za każdym razem, gdy czytany jest znak. Czy to ulega awarii, jeśli dane wejściowe są nieskończone?Python 3,
120116104 bajtówDziała z nieskończonymi strumieniami, po raz pierwszy w golfa, wszelkie wskazówki są mile widziane.
Dzięki @DJMcMayhem za zapisanie niektórych bajtów :)
źródło
c=[0,c+1]['hello'[c]==a]
powinien zaoszczędzić trochę bajtów. Równieża=1
jest krótszy.while
Pythonie nie potrzebujesz nawiasu .Haskell,
414743 bajtówLeniwość Haskella dobrze sobie radzi z nieskończonym wyjściem / wyjściem.
Wypróbuj online!
Edycja: nie obsługuje wejścia skończonego - naprawiono. Dzięki @Leo za wskazanie.
Edycja II: @ Ørjan Johansen zapisał 4 bajty. Dzięki!
źródło
|w@"hello"<-take 5l=w
.Cubix,
94 83 82 79 6356 bajtówRozszerzony:
Notatki
Wypróbuj online
Możesz wypróbować program tutaj .
Wyjaśnienie
Główny pomysł
Ogólna idea polega na tym, że chcemy odczytać znak, a następnie porównać go z różnymi znakami (najpierw
h
, poteme
poteml
itd.). Aby śledzić postać, którą przegapiliśmy, trzymamy ją na samym dole stosu. Kiedy go potrzebujemy, możemy z łatwością przenieść go na szczyt.Pętla odczytu / zapisu
Pętla do odczytu i zapisu jest po prostu piątą linią. Wszystkie nieużywane znaki są zastępowane przez no-ops (
.
):Można to podzielić na dwie części: czytanie i (pisanie i sprawdzanie). Pierwsza część zawiera instrukcje do znaku zapytania włącznie. Druga część w górę to reszta linii. Ponieważ to się zapętla, zakładamy, że zaczynamy od stosu
[...]
Druga część (pisanie i sprawdzanie) jest znowu liniowa. Stos zaczyna się jako
[next-char, ..., input]
. Wyodrębniliśmy kolejny znak, ponieważ zmienia się on później w programie.Teraz IP zacznie się ponownie na początku tej pętli, resetując następny znak do sprawdzenia
h
.Dopasowywanie następnego znaku
Jeśli adres IP wykonał zwrot (tj. Znak, który przeczytaliśmy i wydrukowaliśmy, pasował do następnego znaku
'hello'
), musimy sprawdzić, jaki znak był wejściem i, zależnie od tego, przesunąć następny znak na dół stosu. Następnie musimy powrócić do pętli odczytu / zapisu bez pchaniah
do stosu, więc potrzebujemy innego sposobu, aby się tam dostać.Po pierwsze: określ, jaki znak był wprowadzony. Stos wygląda tak:
[..., prev-char, input, 0]
.Aby porównać dane wejściowe, ponownie użyjemy kodu znakowego
h
. Początkowo było tak, ponieważ tak naprawdę nie wiedziałem, jak sobie z tym poradzić ih
jest to pierwszy znak w ciągu, który można sprawdzić, ale okazało się to dość wygodne. Jeśli odejmiemy kod znakowy h od danych wejściowych, otrzymamy,-3
jeśli dane wejściowe sąe
,0
jeśli dane wejściowe sąh
,4
jeśli dane wejściowe sąl
i7
jeśli dane wejściowe sąo
.Jest to przydatne, ponieważ
?
polecenie pozwala nam łatwo oddzielić wartości ujemne od wartości dodatnich od zera. Jako taki, jeśli IP skręca w lewo, różnica była ujemna, więc wejście byłoe
, więc następny znak powinien byćl
. Jeśli adres IP kontynuuje prostą różnicę, różnica była0
, więc wejście byłoh
, więc następnym znakiem powinien być znake
. Jeśli dane wejściowe to anl
lub ano
, adres IP skręca w prawo.Wszystkie instrukcje wykonane przed wspomnianym znakiem zapytania to:
Teraz adres IP zmienia swój kierunek, jak opisano powyżej. Omówmy różne możliwości.
Wkład
'e'
Najpierw rozważymy dane wejściowe
e
, które powodują przesunięcie adresu IP w górę od?
, ponieważ różnica wynosi 3. Wszystkie nieistotne znaki zostały usunięte z kostki.Znaki są wykonywane w tej kolejności (z wyłączeniem niektórych znaków przepływu kontrolnego):
Teraz adres IP ponownie osiągnął pętlę odczytu / zapisu.
Wkład
'h'
Jeśli wejście było
'h'
, różnica wynosi 0, więc adres IP nie zmienia swojego kierunku. Oto znowu kostka, z usuniętymi wszystkimi nieistotnymi postaciami. Ponieważ ta ścieżka zawiera sporo no-opów, wszystkie przejrzane przez nią no-ops zostały zastąpione&
. Adres IP zaczyna się od znaku zapytania.Wykonywane instrukcje to:
A teraz znów wchodzimy w pętlę odczytu / zapisu, więc gotowe.
Inne dane wejściowe
Wszystkie pozostałe dane wejściowe powodują różnicę dodatnią, więc adres IP skręca w prawo przy znaku zapytania. Nadal musimy oddzielić
l
io
, więc to zrobimy dalej.Oddzielając
'l'
i'o'
Należy pamiętać, że różnica wynosi 7 dla
o
i 4 dlal
i że musimy zakończyć program, jeśli dane wejściowe too
. Oto znowu sześcian z nieistotnymi częściami zastąpionymi przez a,.
a no-ops krzyże IP zostały zastąpione znakami ampersands.Rozróżnianie między nimi
'l'
sTeraz wiemy, że dane wejściowe były
l
, ale nie wiemy, któryl
. Jeśli jest to pierwszy, musimy przesunąć kolejnyl
na spód stosu, ale jeśli jest to drugi, musimy przesunąćo
. Pamiętasz, jak zapisaliśmy-3
się na dole stosu tuż przed wypchnięciem pierwszegol
? Możemy to wykorzystać do rozdzielenia dwóch gałęzi.Stos zaczyna się jako
[..., -3 or 140, ...]
Pierwszy
'l'
Jeśli to był pierwszy
'l'
, musimy wcisnąć kolejny'l'
. Aby zapisać bajty, używamy tych samych znaków, co dla pierwszego'l'
. Możemy uprościć stos do[...]
. Oto odpowiednia część kostki, bez przestojów zastąpionych znakami ampersands.Wykonywane są następujące instrukcje:
Wkrótce przejdziemy do pętli odczytu / zapisu, więc skończyliśmy z tą gałęzią.
druga
'l'
Jeśli wejście był drugim
'l'
w'hello'
, IP skręcił w prawo na znak zapytania. Po raz kolejny możemy uprościć stos,[...]
a adres IP zaczyna się od?
, wskazując tym razem na południe.Wykonywane instrukcje to:
I adres IP niedługo wejdzie w pętlę odczytu / zapisu, więc skończyliśmy również z tą gałęzią.
źródło
C ++,
142141 bajtówWypróbuj online!
źródło
#import
w programach GCC C ++ ...#import
to przestarzałe rozszerzenie GCC.Węzeł, 124 bajty
Nie zakładając, że strumień zmieści się w dostępnej pamięci.
źródło
C #, 134 bajty
Wypróbuj online
Odczytuje znak, sprawdza, czy nie jest to -1 (EOS) i czy jeszcze nie widzieliśmy „cześć”, a następnie przygotowuje go do łańcucha i wypisuje znak. Przygotowujemy się, ponieważ
s[0]
jest znacznie krótszy niż(char)s
. Ma to kwadratowy koszt w długości ciągu, ponieważ musi on przydzielić i przeskanować całe dane wejściowe za każdym razem, gdy czyta znak (spowoduje to awarię po 2 GB danych wejściowych z powodu ograniczeń w CLR, czy to jest dozwolone?)W przypadku wersji (dłuższej: 142 bajty), której nie zabraknie pamięci i która ma stały koszt na znak, patrz poniżej:
Ten utrzymuje 5 ostatnich znaków w ciągu 5-długości, co oznacza krótkie porównania i tanie wyszukiwanie ostatniego znaku, ale jego aktualizacja jest znacznie droższa.
źródło
PHP,
57 5553 bajtówponieważ nie ma nieskończonych plików, pobieram dane wejściowe ze STDIN. Uruchom z
-nr
.Zapętlaj dane wejściowe, drukuj bieżący znak, dołącz go
$s
, przycinaj$s
do ostatnich 5 znaków. Przerwij pętlę, gdy$s
jesthello
.źródło
Vim, 39 bajtów
Wypróbuj online!
źródło
PowerShell, 111 bajtów
Prawdopodobnie jest na to lepszy sposób, ale w tej chwili tego nie widzę.
Odczytuje naciśnięcia klawiszy bez tłumienia echa. Znak jest dodawany do $ x, który jest przycinany do ostatnich 5 znaków i porównywany z „hello”. Trwa to do momentu, aż porównanie będzie prawdziwe.
Uwaga: to nie działa w programie PowerShell ISE. ReadKey jest wyłączony w tym środowisku.
źródło
Schemat 115 bajtów
Wersja do odczytu:
To pobiera indywidualny znak ze standardowego wejścia za każdym razem w pętli i zaznacza jego pozycję na słowie docelowym, gdy spotyka znaki „cześć”.
Zatrzymuje się, gdy skończy się wejście lub pojawiło się „cześć”. Brak pamięci w strumieniu nieskończonym.
źródło
AWK, 95 bajtów
Nauczyłem się tutaj 2 rzeczy:
1) Aby podzielić rekordy między postaciami,
RS="(.)"
a następnieRT
muszą być użyte zamiast$1
2)
ORS
jest używany przezprint
i ma domyślną wartość"\n"
3) Nie mogę liczyć na 2, a używanie
printf
jest „tańsze” niż przypisywanieORS
i za pomocąprint
Przykładowe użycie: Umieść kod w PLIKU
lub
Kod został przetestowany przy użyciu
yes | ...
sugestii Dennisa i widziałem wieley
s.Do twojej wiadomości, możesz wykonać przypisanie RS jako opcję i wyciągnąć go z
BEGIN
bloku poprzez:źródło
BEGIN{RS="(.)"}{printf RT}"olleh"==a=RT substr(a,1,4){exit}
.Python 3 (Linux),
7372 bajtyDzięki @MitchSchwartz za grę w golfa na 1 bajcie!
Wypróbuj online!
źródło
while
prawidłowo ocenia się warunek ? Wygląda na to, że porównujesz wartość logiczną z pustym ciągiem.s[print(end=c):4]
zapisuje bajt'olleh'!=s and s>''and''<c)
. Środkowy test nie jest potrzebny, ale łączenie ich w łańcuch jest krótsze niż proste'olleh'!=s and''<c
.Kod maszynowy 8086, 22 bajty
Równoważny kod zespołu:
źródło
Pyth,
4947 bajtówPyth nie jest zbyt dobry w przyjmowaniu jednego znaku wejściowego. Wszystko w
$__import__("sys").stdin.read(1)
po prostu to robi. Oznacza to również, że działa to tylko w trybie offline.Wszystko inne jest krótkie ...
Program jest bezcielesny podczas pętli. Wewnątrz warunku program odczytuje znak, drukuje go z powrotem, dołącza ten znak do
k
(który początkowo jest pustym ciągiem), przycina wszystkie oprócz ostatnich 5 znakówk
, a następnie sprawdza, czy wynik nie jest"hello"
.32 znaki otrzymują jeden bajt danych wejściowych, 15 znaków zajmuje resztę.
Testowany na Linuksie, działa nawet bez znaku nowej linii, nieskończonego wejścia itp.
źródło
Lua,
6864 bajtówźródło
l:sub(-4)
, a następnie możesz zmniejszyć inicjalizacjęl=""
.Ruby,
59494843 bajtówTeraz wolne od rant, krótsze i bez wycieku pamięci.
Zaoszczędził 5 bajtów, pozbywając się nawiasów i spacji dzięki Dennisowi
źródło
Röda ,
4947 bajtówWypróbuj online!
Jest to anonimowa funkcja, która odczytuje znaki ze strumienia wejściowego i wysyła je do momentu znalezienia „cześć”. Używa tablicy
a
do śledzenia ostatnich znaków.Wysyła jakieś śmieci do STDERR, ale zrozumiałem, że tak dozwolone .
Wyjaśnienie:
źródło
Java 7,
122118124123150141 bajtówTeraz zatrzymuje się po osiągnięciu końca strumienia. Teraz obsługuje nieskończone wprowadzanie danych bez wyczerpywania się pamięci.
źródło
write
że ktoś mnie używaprint
. Nie mogę cofnąć mojej opinii, przepraszam za to :(Rubinowy, 51 bajtów
źródło
AHK , 116 bajtów
Naprawdę nie ma w tym nic mądrego lub magicznego. Zmienna
%1%
jest pierwszym przekazywanym argumentem i powinna być ścieżką do pliku ze strumieniem. Plik musi zostać zapisany podczas aktualizacji, ale kod zostanie odczytany do końca, nawet jeśli rozszerzy się po rozpoczęciu odczytu.źródło
Mathematica, 107 bajtów
Dane wyjściowe stają się polem, w którym użytkownik może bez końca pisać tekst (w tym znaki nowej linii), aż 5 ostatnich znaków będzie równych
"hello"
; w tym momencie wychodzi.źródło
pieprzenie mózgu , 281 bajtów
Nie jestem pewien, dlaczego, ale po prostu czułem, że pieprzenie mózgu jest właściwe. Nie wymaga nieskończonej pamięci i może generować na zawsze.
Wyjaśnił
Wypróbuj online!
źródło
ahehellob
.