window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster już istnieje') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() BRAINFUCK - JĘZYK, KTÓRY ZABIJE TWÓJ MÓZG - The Codest
The Codest
  • O nas
  • Nasze Usługi
    • Software Development
      • Frontend Development
      • Backend Development
    • Zespoły IT
      • Programiści frontendowi
      • Backend Dev
      • Inżynierowie danych
      • Inżynierowie rozwiązań chmurowych
      • Inżynierowie QA
      • Inne
    • Konsultacje IT
      • Audyt i doradztwo
  • Branże
    • Fintech i bankowość
    • E-commerce
    • Adtech
    • Healthtech
    • Produkcja
    • Logistyka
    • Motoryzacja
    • IOT
  • Wartość dla
    • CEO
    • CTO
    • Delivery Managera
  • Nasz zespół
  • Case Studies
  • Nasze Know How
    • Blog
    • Meetups
    • Webinary
    • Raporty
Kariera Skontaktuj się z nami
  • O nas
  • Nasze Usługi
    • Software Development
      • Frontend Development
      • Backend Development
    • Zespoły IT
      • Programiści frontendowi
      • Backend Dev
      • Inżynierowie danych
      • Inżynierowie rozwiązań chmurowych
      • Inżynierowie QA
      • Inne
    • Konsultacje IT
      • Audyt i doradztwo
  • Wartość dla
    • CEO
    • CTO
    • Delivery Managera
  • Nasz zespół
  • Case Studies
  • Nasze Know How
    • Blog
    • Meetups
    • Webinary
    • Raporty
Kariera Skontaktuj się z nami
Strzałka w tył WSTECZ
2017-05-13
Software Development

BRAINFUCK - JĘZYK, KTÓRY ZABIJE TWÓJ MÓZG

Radosław Bułat

Książka "The Pragmatic Programmer" (jeśli jeszcze jej nie przeczytałeś, przestań czytać ten artykuł i zrób to teraz!) mówi, że każdego roku powinniśmy uczyć się jednego nowego języka programowania.

Chociaż niektórzy mogą twierdzić, że to zbyt duży wysiłek, wszyscy możemy się zgodzić, że może to być dobry pomysł. Wybór nowego języka do nauki nie jest taki łatwy. Nie chcemy poświęcać czasu na coś, czego możemy nigdy nie użyć w praktyce, prawda? Ale może czasami powinniśmy zrobić wyjątek i nauczyć się czegoś dla przyjemności? Chciałbym zaprezentować język Brainfuck. Jest to język, którego można nauczyć się w kilka minut, więc nie ma problemu z inwestowaniem zbyt dużej ilości czasu na próżno. Mogę również obiecać, że rozwiązywanie dowolnego problemu za pomocą Brainfuck będzie stymulować twój mózg (wszystkie f*cks są tylko bonusem ;)). Zaczynajmy! Według Wikipedii:

Brainfuck jest ezoteryczny język programowania stworzony w 1993 roku przez Urbana Müllera. Język ten składa się tylko z ośmiu prostych poleceń i wskaźnika instrukcji. Choć jest on w pełni kompletny pod względem Turinga, nie jest przeznaczony do praktycznego użytku, ale do stawiania wyzwań i zabawiania programistów.

Przegląd języka

Wyobraźmy sobie nieskończenie długą wstęgę (lub taśmę) składającą się z komórek, z których każda ma wartość początkową 0. Istnieje również ruchomy wskaźnik danych, który początkowo wskazuje na pierwszą komórkę. Istnieją również dwa strumienie bajtów dla wejścia i wyjścia. Instrukcje są wykonywane sekwencyjnie, jedna po drugiej. Maszyna zatrzymuje się po wykonaniu ostatniej instrukcji.

Polecenie

Co robi?

>

przesunięcie wskaźnika danych do następnej komórki po prawej stronie

<

przesunięcie wskaźnika danych do następnej komórki po lewej stronie

+

przyrost wartości bieżącej komórki

–

zmniejszenie wartości bieżącej komórki

.

wyświetla bajt aktualnie wskazywanej komórki w ASCII kod

,

odczytuje jeden bajt ze stdin i zapisuje jego wartość w bieżącej komórce

[

jeśli bieżąca komórka ma wartość 0, przeskocz do pasującej komórki ]

]

przeskoczyć do pasującego [

Wszystkie znaki inne niż ><+-.,[] są ignorowane.

Spójrzmy na prosty przykład:

,+.

Będzie on interpretowany w następujący sposób:

  • odczytać jeden bajt i zapisać go w bieżącej komórce (komórka0)
  • przyrost wartości bieżącej komórki (komórka0 = komórka0 + 1)
  • zapis zawartości bieżącej komórki na wyjście

W rezultacie jeden znak zostanie odczytany z wejścia i zostanie wypisany następny znak z tablicy ASCII.

Interpreter / kompilator

Zanim napiszemy jakieś użyteczne (?) programy w Brainfucku, potrzebujemy interpretera lub kompilatora. AFAIK, nie ma oficjalnego, ale to nie problem. W internecie są dziesiątki nieoficjalnych. Mogę polecić te dwa:

  • https://github.com/apankrat/bff - zainstalowane i używane lokalnie
  • https://copy.sh/brainfuck/ - online
  • https://ideone.com/ - online

H

"Hello World!" powinien być pierwszym programem, który piszemy ucząc się nowego języka. Jednak napisanie go w Brainfucku jest nieco trudniejsze niż w innych językach. Musimy zacząć od czegoś łatwiejszego... Napiszmy program, który wypisze pojedynczą literę "H" na ekranie (takie ekscytujące :D):

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.

Jak to działa? Ustawia wartość bieżącej komórki na 72 (wykonując 72 przyrosty) i drukuje ją na ekranie za pomocą "." (H ma kod 72 w ASCII). Teraz już wiesz, co powinniśmy zrobić, aby wydrukować "Hello World!" na ekranie, ale zanim to zrobimy, dokonamy małego refaktoryzacji. Napisanie tych wszystkich "+" wymaga zbyt dużo pisania i liczenia. Możemy to skrócić używając [ i ] dla pętli. Aby ustawić wartość na 72, możemy np. wykonać pętlę, która zwiększy wartość 7 razy o 10. W ten sposób otrzymamy 70. Dodając 2 otrzymamy 72. Wygląda to następująco:

++++++++++ # ustaw cell0 na 10
[# pętla, aż cell0 będzie równe 0
- # zmniejsz komórkę0
> # przesuń wskaźnik danych w prawo (komórka1)
+++++++ # zwiększ komórkę1 o 7
 # przesunięcie wskaźnika danych w prawo (komórka1)
++ # zwiększenie o 2
.            # wypisanie wyniku

Dołączyłem komentarze, aby wyjaśnić, jak wszystko działa. Ten sam program bez komentarzy:

++++++++++[->+++++++++.

Czyż nie jest piękny? 🙂

Hello World!

Wracając do naszego programu "Hello World!". Moglibyśmy ustawić wartość pierwszej komórki na 72 (H) i wydrukować ją, ustawić wartość drugiej komórki na 101 (e) i wydrukować ją, ustawić wartość trzeciej komórki na 108 i wydrukować ją itd. Oto implementacja tego algorytmu:

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
++++++++++++++++++++++++++++++++.>
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
+++++++++++++++++++++++++++++++++.>

Ponieważ nie jestem na tyle szalony, by pisać to znak po znaku, oszukałem trochę i wygenerowałem ten program w Rubim:

puts "Hello World!".chars.map { |c| c.ord.times.map { "+" }.join + ".>" }.join("n")`

Tak, tylko 1120 bajtów do wydrukowania "Hello World!"... Ale możemy zrobić to lepiej! Zamiast używać nowej komórki dla każdego znaku, użyjmy tylko jednej. Aby wydrukować literę "e" (101), możemy ponownie użyć wartości w komórce 0 (72). Możemy ją zwiększyć o jeden 29 razy (101 - 72). Wynik jest następujący:

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.
+++++++++++++++++++++++++++++.
+++++++.
.
+++.
-------------------------------------------------------------------------------.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++.
++++++++++++++++++++++++.
+++.
------.
--------.
-------------------------------------------------------------------.

Oszukałem po raz kolejny!

puts "Hello World!".chars.inject(["", 0]) { |(code, prev), char| [code + "++-"[char.ord - prev  0] * (char.ord - prev).abs + ".n", char.ord] }[0]`)

Poczyniliśmy znaczne postępy. 377 bajtów zamiast 1120 bajtów. Wciąż jest jednak miejsce na ulepszenia. Przedstawię kilka pomysłów:

  • używać 3 (lub więcej) komórek dla znaków, które są bliżej siebie w ASCII (małe, wielkie litery, spacja i wykrzyknik)
  • używać pętli zamiast powtarzania + i -

Oto wersja z Wikipedii, która wykorzystuje te pomysły:

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

To tylko 106 bajtów i wypisuje nową linię na końcu! Niesamowite.

Odwracanie ciągu

Teraz jesteśmy gotowi napisać coś bardziej wymagającego. Napiszmy program, który odczyta linię z wejścia i wydrukuje ją w odwrotnej kolejności. Pierwszym problemem jest odczytanie znaków i zatrzymanie się na znaku nowej linii. Pamiętaj, że nie ma przerwa, jeśli lub inne podobne stwierdzenia. Musimy użyć [ i ]. Zacznijmy od programu, który odczytuje wszystkie znaki z wejścia i umieszcza je w kolejnych komórkach:

,[>,]

Rozpoczyna się od odczytania pierwszego znaku i trwa do ostatniego , zwroty operacji 0. Jednakże, będzie się on zapętlał w nieskończoność w implementacji, która zwraca coś innego niż O dla EOF (język nie określa tego zachowania). Jak więc możemy zatrzymać się na znaku nowej linii? Oto sztuczka:

+[++++++++++>,----------]

Zaczynamy od komórki 0 ustawionej na 1, aby upewnić się, że nasza pętla zostanie wykonana co najmniej raz. W pętli zwiększamy wartość bieżącej komórki o 10, przesuwamy wskaźnik danych do następnej komórki, odczytujemy jeden znak i zmniejszamy jego wartość o 10. W ten sposób, jeśli zostanie odczytany znak nowej linii (10 w ASCII), program zatrzyma się w następnej iteracji, w przeciwnym razie jego wartość zostanie przywrócona przez dodanie 10.

Po tym kroku nasze komórki będą wyglądać następująco:

11 C1 C2 C3 0* 0 0

Cn jest n-tym znakiem na wejściu, a * jest bieżącą pozycją wskaźnika danych. Teraz musimy zacząć przesuwać wskaźnik danych w lewo i drukować wszystkie komórki, aż osiągniemy wartość 11. Oto moje podejście do tego zadania:

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

Zachęcam do samodzielnej analizy :-).

Podsumowanie

Kiedy natknąłem się na Brainfuck, ezoteryczny język programowania, początkowo odrzuciłem go jako nic więcej niż sztuczkę lub żart. Ten osobliwy i, jak wielu może twierdzić, oszałamiająco trudny język, wydawał mi się czymś przeznaczonym wyłącznie do rozrywki. Z czasem jednak moje postrzeganie Brainfucka zmieniło się diametralnie.

Enigmatyczna natura Brainfuck rzuca ci wyzwanie, zmuszając cię do poszerzenia swojej perspektywy na języki programowania. Ten ezoteryczny język pozwala docenić piękno i konieczność języków wysokiego poziomu, do których jesteśmy przyzwyczajeni. Uwydatnia znaczenie abstrakcji, właściwych konwencji nazewnictwa i zorganizowanego układu pamięci w dziedzinie języków programowania. Jest to coś, czego Brainfuck, ze swoim minimalistycznym projektem składającym się z zaledwie ośmiu prostych poleceń, nie zapewnia.

Brainfuck to kompletny język Turinga, który jeszcze bardziej podkreśla znaczenie posiadania przejrzystego, spójnego kodu źródłowego. Pomimo tego, że jest uznawany za jeden z najtrudniejszych języków ezoterycznych do pisania programów, jak na ironię jest on ulubionym językiem początkujących dla każdego, kto chce stworzyć własny kompilator lub interpreter Brainfuck. Powodem jest prostota zestawu poleceń i fakt, że nie wymaga on skomplikowanego parsowania.

Tworzenie programu Brainfuck jest wyjątkowe na dwa sposoby. Po pierwsze, trzeba dostosować się do korzystania z pojedynczego wskaźnika pamięci, co zmusza do innego myślenia o kodzie źródłowym. Po drugie, masz "opcję zero", czyli możliwość wyzerowania komórki pamięci, co nie jest powszechne w innych formalnych językach programowania.

Jeśli chodzi o naukę, w Brainfuck jest więcej niż na pierwszy rzut oka. Mając wystarczająco dużo czasu i odpowiednie nastawienie, możliwe jest napisanie tego samego programu na wiele sposobów przy użyciu różnych kodów Brainfuck. Ostatnia połowa tej podróży polega na byciu pomysłowym i znajdowaniu nowych, kreatywnych sposobów wykorzystania sześciu symboli.

Interpretery Brainfuck, choć minimalistyczne, pozwalają dogłębnie zrozumieć, jak działa kod, co drukuje program i na czym polega mechanika kompletnego języka Turinga. Ostatecznie Brainfuck nie jest tylko kolejnym ezoterycznym językiem programowania. To zupełnie nowy wymiar, inne spojrzenie na to, jak widzimy, rozumiemy i piszemy programy.

Powiązane artykuły

Software Development

Tworzenie przyszłościowych aplikacji internetowych: spostrzeżenia zespołu ekspertów The Codest

Odkryj, w jaki sposób The Codest wyróżnia się w tworzeniu skalowalnych, interaktywnych aplikacji internetowych przy użyciu najnowocześniejszych technologii, zapewniając płynne doświadczenia użytkowników na wszystkich platformach. Dowiedz się, w jaki sposób nasza wiedza napędza transformację cyfrową i biznes...

THEECODEST
Software Development

10 najlepszych firm tworzących oprogramowanie na Łotwie

Dowiedz się więcej o najlepszych łotewskich firmach programistycznych i ich innowacyjnych rozwiązaniach w naszym najnowszym artykule. Odkryj, w jaki sposób ci liderzy technologiczni mogą pomóc w rozwoju Twojej firmy.

thecodest
Rozwiązania dla przedsiębiorstw i scaleupów

Podstawy tworzenia oprogramowania Java: Przewodnik po skutecznym outsourcingu

Zapoznaj się z tym niezbędnym przewodnikiem na temat skutecznego tworzenia oprogramowania Java outsourcing, aby zwiększyć wydajność, uzyskać dostęp do wiedzy specjalistycznej i osiągnąć sukces projektu z The Codest.

thecodest
Software Development

Kompletny przewodnik po outsourcingu w Polsce

Wzrost liczby outsourcing w Polsce jest napędzany przez postęp gospodarczy, edukacyjny i technologiczny, sprzyjający rozwojowi IT i przyjazny klimat dla biznesu.

TheCodest
Rozwiązania dla przedsiębiorstw i scaleupów

Kompletny przewodnik po narzędziach i technikach audytu IT

Audyty IT zapewniają bezpieczne, wydajne i zgodne z przepisami systemy. Dowiedz się więcej o ich znaczeniu, czytając cały artykuł.

The Codest
Jakub Jakubowicz CTO & Współzałożyciel

Subskrybuj naszą bazę wiedzy i bądź na bieżąco!

    O nas

    The Codest - Międzynarodowa firma programistyczna z centrami technologicznymi w Polsce.

    Wielka Brytania - siedziba główna

    • Office 303B, 182-184 High Street North E6 2JA
      Londyn, Anglia

    Polska - lokalne centra technologiczne

    • Fabryczna Office Park, Aleja
      Pokoju 18, 31-564 Kraków
    • Brain Embassy, Konstruktorska
      11, 02-673 Warszawa, Polska

      The Codest

    • Strona główna
    • O nas
    • Nasze Usługi
    • Case Studies
    • Nasze Know How
    • Kariera
    • Słownik

      Nasze Usługi

    • Konsultacje IT
    • Software Development
    • Backend Development
    • Frontend Development
    • Zespoły IT
    • Backend Dev
    • Inżynierowie rozwiązań chmurowych
    • Inżynierowie danych
    • Inne
    • Inżynierowie QA

      Raporty

    • Fakty i mity na temat współpracy z zewnętrznym partnerem programistycznym
    • Z USA do Europy: Dlaczego amerykańskie startupy decydują się na relokację do Europy?
    • Porównanie centrów rozwoju Tech Offshore: Tech Offshore Europa (Polska), ASEAN (Filipiny), Eurazja (Turcja)
    • Jakie są największe wyzwania CTO i CIO?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Warunki korzystania z witryny

    Copyright © 2025 by The Codest. Wszelkie prawa zastrzeżone.

    pl_PLPolish
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench arArabic it_ITItalian jaJapanese ko_KRKorean es_ESSpanish nl_NLDutch etEstonian elGreek pl_PLPolish