Stawianie jednej wskazówki na odpowiedź byłoby zdecydowanie zbyt dużą liczbą odpowiedzi.
Naucz się myśleć w Brainfuck. Jest zupełnie inny niż cokolwiek innego. Odczytywanie i pisanie oraz przepisywanie i przepisywanie wielu programów typu „pieprzenie mózgu”. Język nie daje wiele do pracy, dlatego ważne jest, aby korzystać z tego, co daje, elastycznie i wydajnie. Nie pozwól, aby jakieś abstrakcje dostały się między tobą a językiem - wejdź tam i zmagaj się z tym.
Zapewnij sobie komfort dzięki nieniszczącej kontroli przepływu. Aby wyjść z pętli decyzyjnej, zamiast zerować początkową komórkę, kopiując ją w inne miejsce, a następnie kopiując z powrotem po opuszczeniu pętli, często lepiej jest przesunąć wskaźnik do wcześniej istniejącego zera w pobliżu. Tak, oznacza to, że wskaźnik będzie w różnych miejscach, w zależności od tego, czy przeszedłeś przez pętlę, ale oznacza to również, że te miejsca prawdopodobnie mają różne układy pobliskich zer i nonzerów, których można użyć do ponownego zsynchronizowania położenia wskaźnika za pomocą innej pętli. Ta technika ma podstawowe znaczenie dla dobrego programowania Brainfuck, a różne jej formy będą stale przydatne.
To i fakt, że każdy >
lub <
koszty oznaczają, że szczegóły układu pamięci są ważne. Wypróbuj tyle wariantów swojego układu, ile masz cierpliwości. I pamiętaj, że układ pamięci nie musi być sztywnym mapowaniem danych do lokalizacji. Może zmieniać się w trakcie wykonywania.
Na większą skalę rozważ, a nawet spróbuj wdrożyć wiele różnych algorytmów. Początkowo nie będzie oczywiste, który algorytm będzie najlepszy; może nawet nie być oczywiste, jakie podstawowe podejście będzie najlepsze i prawdopodobnie będzie to coś innego niż to, co byłoby najlepsze w normalnym języku.
Jeśli masz do czynienia z dużymi lub zmiennymi rozmiarami danych, sprawdź, czy jest jakiś sposób, aby poradzić sobie z nimi lokalnie, bez konieczności śledzenia, jak duże są twoje dane lub ich lokalizacji numerycznej.
Te same dane mogą być dwiema różnymi rzeczami. (Najczęściej liczba lub znak, a także niezerowy znacznik pozycyjny. Ale patrz random.b , gdzie bit licznika podwaja się jako wartość jednej komórki automatu komórkowego).
Ten sam kod może robić dwie różne rzeczy i jest o wiele łatwiej to zrobić w języku, w którym kod jest tak ogólny, jak <+<
. Uważaj na takie możliwości. W rzeczywistości czasami możesz zauważyć, nawet w dobrze napisanym programie, że istnieją małe części, które można całkowicie usunąć, nic nie dodając, a przypadek nadal działałby bezbłędnie.
W większości języków często używasz kompilatora lub tłumacza, aby sprawdzić zachowanie programu. Język Brainfuck wymaga większej kontroli konceptualnej; jeśli potrzebujesz kompilatora, aby powiedzieć ci, co robi twój program, nie masz wystarczającej wiedzy na temat swojego programu i prawdopodobnie musisz się na niego jeszcze trochę gapić - przynajmniej jeśli chcesz mieć wystarczająco wyraźny obraz koncepcyjne halo podobnych programów, aby być dobrym w golfa. Ćwicząc, stworzysz kilkanaście wersji swojego programu, zanim spróbujesz uruchomić jedną, i do tego momentu będziesz mieć 95% pewności, że twoja najkrótsza będzie działać poprawnie.
Powodzenia! Bardzo niewiele osób próbuje zwięźle pisać Brainfuck, ale myślę, że to jedyny sposób, w jaki język może usprawiedliwić ciągłą uwagę - jako oszałamiająco niejasna forma sztuki.
Kilka wskazówek tutaj:
Stałe:
Strona stałych Esolangs zawiera niezwykle przydatną listę najkrótszych sposobów tworzenia określonych wartości. Uważam, że sprawdzam tę stronę co najmniej dwa razy na program.
Początek wszystkiego:
Spowoduje to ustawienie taśmy w formacie 3 * n ^ 2, który wygląda
3 6 12 24 48 96 192 128 0 0 '
Dlaczego to takie ważne?
Zejdźmy na dół listy:
0
a
A
.Na podstawie tego jednego algorytmu jesteśmy na początku praktycznie każdej sekwencji w zakresie ASCII, wraz z licznikiem dla każdej i nowej linii w zasięgu ręki.
Praktyczny przykład:
Drukowanie wszystkich wielkich i małych liter oraz cyfr.
Z algorytmem:
Bez:
Większość bajtów spędzamy na inicjalizacji taśmy w drugim przykładzie. Niektóre z nich zostały zrównoważone przez dodatkowe ruchy w pierwszym przykładzie, ale ta metoda ma wyraźnie tę zaletę.
Kilka innych interesujących algorytmów w tym samym stylu:
3 * 2 ^ n + 1:
Powoduje to przesunięcie wartości o 1, co pozwala osiągnąć kilka rzeczy. Powoduje to, że 12 jest znakiem powrotu karetki, 64 to faktyczny początek wielkiej litery, a 24 bliżej 26.
2 ^ n:
Ponieważ 64 jest dobre dla wielkich liter, 32 to ASCII dla spacji, a 128 może być użyte jako licznik dla 26 (130/5 = 26). Może to zaoszczędzić bajty w pewnych sytuacjach, w których cyfry i małe litery nie są potrzebne.
Wybierz implementację, która pasuje do pytania:
+[[-<+>>+>+<<]>]
) lub przetwarzanie większych / ujemnych liczb. Minusem jest to, że na niektóre typowe metody, takie jak[-]
i[->+<]
nie można polegać, na wypadek gdyby liczba była ujemna.Śledź, co się dzieje do cholery:
Przez cały czas powinieneś komentować, gdzie powinien znajdować się wskaźnik w stosunku do otaczających go danych, i upewnij się, że znasz zakres możliwych wartości każdej komórki. Jest to szczególnie ważne, gdy podzielisz wskaźnik przed pętlą, ponieważ później będziesz chciał ponownie połączyć dwie możliwości.
W dowolnym momencie mój kod jest zaśmiecony komentarzami w każdej innej linii, które wyglądają tak:
Dodatkową radą jest nadanie symbolom specjalnego znaczenia. W powyższym przykładzie,
'
gdzie jest wskaźnik,*
oznacza powtórzenie w tym kierunku,?
oznacza komórkę o nieznanej wartości,!0
oznacza komórkę niezerową,_
jest substytutem-
ip
jest substytutem+
.or
oznacza, że taśma może wyglądać jak jedno z przedstawień i musi być traktowana jako taka.Twój schemat symboli niekoniecznie musi być taki sam jak mój (który ma kilka wad), po prostu musi być spójny. Jest to również niezwykle przydatne podczas debugowania, ponieważ można uruchomić go do tego momentu i porównać rzeczywistą taśmę z tym, co powinieneś mieć, co może wskazać potencjalne wady w kodzie.
źródło
Moją główną radą byłoby nie.
OK, w porządku, chcesz czegoś bardziej przydatnego. BF jest już bardzo zwięzłym językiem, ale to, co naprawdę cię zabija, to arytmetyka, która skutecznie musi być wykonana jednoargumentowo. Warto przeczytać na stronie stałych w Esolang, aby dokładnie wybrać, jak efektywnie pisać duże liczby i jak najlepiej wykorzystać zawijanie.
Dostęp do pamięci jest również bardzo drogi. Ponieważ czytasz z taśmy, musisz pamiętać, gdzie porusza się głowa w danym momencie. W przeciwieństwie do innych języków, gdzie można po prostu napisać
a
,b
,c
, w bf trzeba wyraźnie przesunąć głowę pewna liczba bajtów lewo lub w prawo, więc trzeba mieć na uwadze to, gdzie można przechowywać co. Jestem prawie pewien, że optymalne uporządkowanie pamięci jest trudne, więc powodzenia.źródło
W tej odpowiedzi będę wielokrotnie odwoływał się do określonej komórki na taśmie. Nie ma znaczenia, która to komórka, ale jest to ta sama komórka w całej odpowiedzi. Na potrzeby tego wpisu nazywam tę komórkę „Todd”.
Próbując ustawić stałą wartość komórki, czasami opłaca się nie kończyć jej natychmiast. Powiedzmy na przykład, że chciałeś, aby Todd zawierał 30. Później w kodzie (który może modyfikować wartość Todda, ale nigdy go nie czyta), wrócisz do Todda. Jeśli wartość Todda wynosi 0, program kończy działanie. W przeciwnym razie wartość Todda jest drukowana na zawsze.
Według strony esolangs.org o stałych błędach w mózgu (które prawdopodobnie mogłyby stanowić sam w sobie wskazówkę!) Najkrótsza droga do uzyskania 30 to
>+[--[<]>>+<-]>+
. Prowadzenie>
to jest tylko po to, aby upewnić się, że nic po lewej stronie wskaźnika nie zostanie zmodyfikowane, ale w tym przypadku założymy, że nas to nie obchodzi i upuszczamy. Za pomocą tego kodu Twój kod wyglądałby mniej więcej tak:Możesz pomyśleć o pierwszej części kodu w ten sposób:
Ale pamiętaj, dwa ostatnie znaki w tym fragmencie:
>+
. Tak samo dobrze jest myśleć o tym w ten sposób:Zauważ, że
(GO TO TODD)
dwa razy! Zamiast tego możesz napisać kod w ten sposób:Zakładając, że liczba bajtów, których potrzebuje,
(GO TO TODD)
jest taka sama, jeden ruch mniej == jeden bajt mniej! Czasami fakt zmiany pozycji początkowej odbiera tę korzyść, ale nie zawsze.źródło
Mała wskazówka dotycząca wyzwań bez wkładu. Możesz użyć
,
zamiast[-]
, jeśli chcesz szybko wyczyścić komórkę, ponieważ większość interpreterów (w tym TIO.run jeden) ustawi zawartość komórki na reprezentację EOF równą zero. To sprawia, że programy są trochę nieprzenośne, ale kogo to obchodzi w golfowym kodzie?źródło