4 ポイント 投稿者 GN⁺ 2024-04-25 | 1件のコメント | WhatsAppで共有
  • Pietは、コードが抽象画のように見えるよう作られた難解プログラミング言語で、幾何学的抽象美術を切り開いたPiet Mondrianにちなんで名付けられた
  • プログラムは20種類の認識色で構成されたグラフィックであり、実行系は色ブロック間を移動しながら色の変化量を命令として解釈する
  • すべてのデータは整数としてのみ存在し、スタックに保存されるが、色ブロックの大きさは値であっても push 命令なしに自動でスタックへ積まれることはない
  • フロー制御はDirection PointerとCodel Chooser、黒ブロック・外縁・白ブロックの規則で決まり、一部の動作は実装ごとに異なる可能性がある
  • 例や外部ツールのエコシステムはあるが、権威ある公式インタプリタはなく、エラー処理や非標準色の解釈も実装依存のまま残っている

Pietの基本アイデア

  • Pietは、プログラムコードが抽象美術のように見えるプログラミング言語である
  • 名前は幾何学的抽象美術を切り開いた Piet Mondrian に由来する
  • Mondrian という名前を使いたかったが、同名のスクリプト言語がすでにあったため、Pietという名前が使われた
  • 仕様策定後、小さなコミュニティが生まれ、プログラム、インタプリタ、IDE、コンパイラが作られてきた
  • 権威ある公式インタプリタは存在せず、利用可能な実装は仕様を少しずつ異なって解釈している場合がある
  • 仕様に対する補足説明はいくつか追加されたが、既存実装の一部はそれに従っていない可能性がある

色とコード単位

  • Pietでは合計20種類の色を使う
    • 18色は色相サイクルと明度サイクルに含まれる
    • 白と黒はどちらのサイクルにも含まれない
  • 色相サイクルred -> yellow -> green -> cyan -> blue -> magenta -> red の順である
  • 明度サイクルlight -> normal -> dark -> light の順である
    • lightdark より1段階暗いものとしても扱われ、その逆も成り立つ
  • オレンジや茶色のような非標準色も使用できるが、効果は実装依存である
    • 最も単純な場合、非標準色は白のように扱われる
    • 別の可能性として、黒のように扱われることもある

Codelと色ブロック

  • Pietのコードは、認識可能な色で構成されたグラフィックである
  • 個々のコードピクセルが言語的な意味を持つため、見やすいよう拡大されたプログラムでは、コード上の単一ピクセルをcodelと呼ぶ
  • 基本的な実行単位は色ブロックである
    • 色ブロックとは、同じ色のcodelが上下左右に連結した領域である
    • 対角線で接しているだけのブロックは連結しているとは見なされない
    • 色ブロックはどんな形でもよく、内部に別の色の穴を持つこともできる
    • 内部の穴はそのブロックの一部ではない

スタックと値の表現

  • Pietはすべてのデータ値をスタックに保存する
  • データ値は整数のみである
    • 命令によってUnicode文字値として入力・出力できる
  • スタックは概念上は無限の深さを持つが、実装は有限の最大スタックサイズを設けてもよい
  • 有限スタックでオーバーフローが発生した場合はランタイムエラーであり、その扱いは実装依存である
  • 黒と白以外の色ブロックは、そのブロック内のcodel数に等しい整数値を表す
    • 0以下の整数は直接表現できない
    • 演算子によって生成することはできる
    • 色ブロックの値は自動でスタックにpushされず、明示的な push 命令が必要である
  • 整数の大きさも概念上は無限だが、実装は有限の最大整数サイズを設けてもよい
    • 整数オーバーフローはランタイムエラーであり、その扱いは実装依存である

実行フロー

  • インタプリタは、プログラム左上のcodelを含む色ブロックから実行を開始する
  • 実行中は2つの状態が保持される
    • Direction Pointer(DP): 初期状態では右を指し、右・左・下・上のいずれかを向く
    • Codel Chooser(CC): 初期状態では左を指し、左または右のいずれかを向く
  • 次の移動先は、現在の色ブロックの境界とDP・CCの組み合わせで決まる
    • DP方向に最も遠い現在の色ブロックの辺を探す
    • その辺の中から、DPの進行方向を基準にCC方向へ最も遠いcodelを選ぶ
    • そのcodelからDP方向にある直後のcodelが属する色ブロックへ移動する
  • この処理を繰り返し、終了条件に達するとプログラムは終了する

黒ブロック、外縁、白ブロック

  • 黒い色ブロックとプログラムの外縁は、実行フローを妨げる障壁として働く
  • インタプリタが黒ブロックへ移動しようとしたり外縁の外へ出ようとしたりすると、停止してCCを切り替える
  • 2回目の試行も失敗した場合は、DPを時計回りに1段階回転させる
  • CCとDPを交互に変更しながら合計8回試しても現在の色ブロックを出られなければ、プログラムは終了する
  • 白ブロックの移動

    • 白い色ブロックは、インタプリタが妨げられずに通過する自由領域である
    • 色ブロックから白領域へ移動すると、インタプリタはDP方向へ直進し、白でない色ブロックに到達するまで進む
    • 白ブロックを通って新しい色へ移動しても、命令は実行されない
    • この性質により、白ブロックは命令を実行せずに現在色を変えられるため、ループ記述に便利である
    • 白ブロック内の移動では、非白色ブロックから出口を選ぶ手順を使わず、直線移動のみを行う
  • 白ブロックで塞がれたとき

    • 白ブロックを直進中に黒ブロックまたは外縁に突き当たると、進行が妨げられたものとして扱われる
    • この場合CCを切り替えるが、移動しようとする位置は変わらないため、DPを直ちに時計回りに1段階回転させる
    • その後、現在の白codelから新しいDP方向へ再び直進する
    • 白ブロック内で障害に当たるたびに、CCの切り替えとDPの回転を繰り返す
    • 色ブロックに入れれば実行は継続し、白ブロック内で経路をたどり直し始めた場合は脱出経路がないため実行は終了する

命令体系

  • Pietの命令は、ある色ブロックから次の色ブロックへ移動する際の色の変化によって決まる
  • 色相サイクルで何段階進んだかと、明度サイクルで何段階進んだかが命令を定める
  • 白ブロックを経由した色遷移では命令は実行されない
  • スタックおよび算術命令

    • push: 直前に抜けた色ブロックの値をスタックに積む
    • pop: スタック最上位の値を取り出して捨てる
    • add: 上位2つの値を加算し、結果を再びスタックに積む
    • subtract: 2番目の値から最上位の値を引いた結果をスタックに積む
    • multiply: 上位2つの値を乗算する
    • divide: 2番目の値を最上位の値で整数除算する
    • 0除算は実装依存のエラーであり、命令を無視する方式が推奨される
    • mod: 2番目の値を最上位の値で割った余りをスタックに積む
    • 結果は除数、つまりスタック最上位の値と同じ符号を持つ
    • 最上位の値が0なら0除算エラーであり、命令を無視する方式が推奨される
    • 負の被除数に対する mod は、Wikipediaの modulus operation で説明される floored division と同じである
  • 比較、ポインタ、入出力命令

    • not: スタック最上位の値が0でなければ0に、0なら1に変える
    • greater: 2番目の値が最上位の値より大きければ1、そうでなければ0をスタックに積む
    • pointer: スタック最上位の値を取り出し、その回数だけDPを時計回りに回転させる
    • 負の値なら反時計回りに回転する
    • switch: スタック最上位の値を取り出し、その回数だけCCを切り替える
    • 負の値でも絶対値の回数だけ切り替える
    • duplicate: スタック最上位の値のコピーをスタックに積む
    • roll: 上位2つの値を取り出し、残りのスタックの一部を指定された深さと回数だけ回転させる
    • 深さが負ならエラーであり、命令は無視される
    • 実装依存の最大スタック深さを超えるrollは実装依存エラーであり、命令の無視が推奨される
    • in: STDINから数値または文字を読み取り、スタックに積む
    • 入力がない場合、または整数入力で整数を取得できない場合はエラーであり、命令は無視される
    • out: スタック最上位の値を数値または文字としてSTDOUTに出力する
    • スタック値が不足して実行できない演算は、命令が無視されて次の命令へ進む

例とツール

1件のコメント

 
GN⁺ 2024-04-25
Hacker Newsのコメント
  • サンプルページの最後のプログラムは本当に驚き: Piet という名前の人が、Piet 言語を連想させる美術作品を見て実行してみたとのこと
    実行できてしまい、おそらくグラフィックアーティストが偶然動作するコンピュータープログラムを描いた史上初の事例かもしれない
    https://www.dangermouse.net/esoteric/piet/samples.html
    https://gitlab.fabcity.hamburg/hofalab/piet-get-together

    • 「動作する」の条件を十分に緩く取れば、たいていの絵の具の飛び散りはすでに有効な Perl プログラムだと示されたことがある
      https://www.mcmillen.dev/sigbovik/
    • Piet J. が小さなギャラリーで美術作品を見ていて Piet プログラムのようだと感じ、作者はその言語をまったく知らないと言っていた
      Piet が作品の写真を撮り、Piet パレットに近い色で整理した画像ファイルに変換してから実行してみると、実際に動作し、コードは ASCII 文字を読み込んでそのASCII 数値を出力する無限ループだった
      これは本当に信じがたいほどだ
    • π を計算するサンプルもよかった
      「当然、もっと大きなプログラムを書けばより正確な値が得られる」という説明は、私には初めて見るタイプの冗談のように感じられる
    • 残念ながら、それはnpietと現在の Piet 仕様の差異に依存している
      仕様上、インタプリタは現在の白いコーデルから新しい方向の DP へ滑り始め、色ブロックに入るか別の制限にぶつかるまで進まなければならない
      しかし npiet インタプリタは空白を調べたあと、最後の色付きコーデルの位置まで巻き戻す。いつか自分の Piet コンパイラのレキサーにその挙動をオプションとして入れたいが、まだ手を付けていない
      仕様に従えば、そのプログラムはほとんどすべてのブロックの端の角が白に隣接しているため、単純な非停止ループになる。複数のインタプリタやコンパイラを対象に複雑な Piet プログラムを書くのはかなり難しく、どれにも文書化されていない微妙な解釈の違いがある
      自分の Piet バックエンド出力はおおむねインタプリタ依存が少ないと思っているが、詳しく調べたのは他のインタプリタを 3 つか 4 つほどだけだ
      https://github.com/boothby/repiet/
    • こういう単純な絵、つまり大きな長方形ブロックがいくつかあるだけのものが有効なプログラムである確率はどれくらいなのか気になる
      文書をざっと見ると、「スタックに値が足りず取り出せない演算のような、実行できない演算はそのまま無視して次の命令へ進む」という条件のため、こうした画像はどれもエラーなしで実行できるのではないかと思える
      ただし、そのようなランダム画像のうち実際に「意味のある」ことをするものがどれだけあるかは別問題だ
  • Piet は難解プログラミング言語の中でも画期的な実験だが、開発者が本当に意図しない限りプログラムをモンドリアンの絵のように見せるという目標には届いていないと思う
    言語構造そのものが、何を「書いても」モンドリアンの絵のように見えるよう設計されていてほしい

    • とはいえ、モンドリアンは実質的に原色しか主に使っていなかったので、かなり制約が大きかっただろう
  • いつもこういう疑問が浮かぶ: アルゴリズムはどんな姿をしているのだろうか?
    Herman Hesse の小説 The Glass Bead Game に出てくるようなものを、現実に作れるだろうか? 原題は Magister Ludi
    視覚志向の人間として、可能だと信じたいし、実際にそういうツールを使ってみたこともある
    https://community.carbide3d.com/uploads/default/original/3X/5/b/5b0872a5666fec9b7bb6fd623c431de03263372d.jpeg
    ただ、前の問いに対する明確な答えがないと、こうしたツールはいつも次のようなものになる危険がある
    https://blueprintsfromhell.tumblr.com/
    https://scriptsofanotherdimension.tumblr.com/
    視覚的表現力とモジュール性のあいだでバランスを取るのも難しく、モジュール性を押し進めると、避けたかった テキストの壁 にあまりにも簡単に戻ってしまう

    • Piet を手で書いてみると、「アルゴリズムはどんな姿をしているのか」を探る面白さがある
      Sergei Lewis と私はそれぞれ Piet コードを生成するツールを作った。Sergei のアセンブラは、私の Piet バックエンドよりずっと見栄えのいいコードを生成する
      私のコンパイラ出力から実際にわかるのは、私が本当に手抜きで トランポリン を使っていたということくらいだ
      http://www.toothycat.net/wiki/wiki.pl?MoonShadow/Piet
      https://github.com/boothby/repiet/
      https://en.wikipedia.org/wiki/Trampoline_(computing)
    • どんなアルゴリズムでも、さらにはどんな精神的概念でも、視覚的表現 と 1:1 の関係があると信じている
      Steven Pinker の本を読んでいて得た考えだが、抽象語はもっと単純な言葉に分解でき、最終的には何らかの空間的関係を説明することになるという。たとえば "rekindle" は「2つのものを再び一緒にする」と見ることができる
      同じように for ループも「1つのものが複数の別のものの上を順に通っていく」という精神的概念で、これは 100 -> 010 -> 001 のような視覚表現を持つ
      だとすれば、こうした構成要素を純粋な 視覚変換 として定義する言語を作れるのではないかと気になる
    • 単純なプログラムなら、記号を にしたチューリングマシンを実装することも想像できる
  • こういうものは犯罪スリラーに出てきて、主人公や捜査官たちを行き詰まらせたあと、誰かがそれがコードだと見抜く場面に合いそう
    QR コードだけが実用的だと思っていたのに

  • 誰かが Piet で quine を作っていた: http://mamememo.blogspot.com/2009/10/piet-quine.html?m=1
    その記事の画像は壊れているが、コピーはこちらにある: https://codegolf.stackexchange.com/a/23255/103045

  • Piet を発見した瞬間は、畏敬、混乱、驚きが入り混じった特別な瞬間だ
    私の場合は、友人 Oz と一緒にやっているコンピュータサイエンスのポッドキャスト「The CS Primer Show」でのこの会話に記録されている: https://show.csprimer.com/episodes/e2-dont-let-a-gpt-have-all-the-fun

  • 大学で 難解プログラミング言語 を扱う小さな授業があった
    各自が Brainfuck や Piet のような言語を1つ選んでいじってみることになっていて、私は Piet を選び、かなり楽しんだ
    正直なところ、自分が作った小さなサンプルアプリは美的にそれほど優れてはいなかったし、Piet でアートを作るには Piet の達人になる必要がありそうだ

  • サンプルページがすばらしい
    キャンバスがだんだん精巧で見栄えのよいものへ進化していく様子が見て取れる
    https://www.dangermouse.net/esoteric/piet/samples.html

  • 「light は dark より1段階 暗い と見なす」とは、なかなか深い

  • Python やほかのそれほど難解ではない言語のコードを受け取り、Piet として出力する方法を学習するオートエンコーダを作れたら面白そう
    そうすれば Stable Diffusion みたいにランダムなアルゴリズムを生成できるかもしれない