PietPietのエディタをのエディタを
作った話作った話
春合宿2015
注意
• プログラミング初心者にも分かるように
かなり基本的なことについても説明して
います(多分)。
– 分かっている⼈は適当に聞き流して下さい。
目次
1.自己紹介
2.Pietについて
3.エディタの話
4.実践Pietコーディング
目次
1.自己紹介
2.Pietについて
3.エディタの話
4.実践Pietコーディング
自己紹介
• ID: dama
• 所属: 京都大学文学部⼈文学科2回生
• 役職: 代表(会⻑の繰り上がり)
• 活動: 競プロ・DTMとか
• 趣味: けん玉
作った物(1)
• Unambi Sweeper
– こんなやつ。
作った物(1)
• Unambi Sweeper
– Mine Sweeper とかいうパズルアクション
ゲームを改良した。
– 運ゲーになるのがウザかったので、必ず論理
的に解けるようにした。
– キーボードプレイがし易いように、UIも若⼲
改善した。
作った物(2)
• Unimbi Sweeper
– さっきと何が違うんや。
• さっきのはUn a mbi、こっちはUn i mbi。
• UnambiはUnambiguous(=両義的でない)の略。
– Unambi SweeperをUnityに移植したやつ。
• だから Uni mbi。
– ただUnityを触りたいがために作った。
目次
1.自己紹介
2.Pietについて
3.エディタの話
4.実践Pietコーディング
Pietってなんや
• 難解プログラミング言語の1つ。
難解プログラミング言語ってなんや
• 意図的に読解が困難なように設計された
プログラミング言語のこと。
• 英語でEsoteric programming language
(略してesolang)とかいう。
難解プログラミング言語の例
• Brainf*ck
– コンパイラが非常に小さい。
– '>', '<', '+', '-', '.', ',', '[', ']'の8個の命令か
ら成る。
– 詳しくは@_primenumberに聞いて下さい。
• Lazy K
– 純粋関数型言語。
– 組み込み関数が3つしか無い。
– 詳しくは@nonamea774に聞いて下さい。
Pietってなんや(再)
• ソースコードがドット絵。
• 抽象画っぽく⾒える。
• David Morgan-Mar氏がPiet Mondrianの
作品に影響を受けて考案した。
• "Hello, world!"と出⼒する
ソースコードの⼀例。→
– ふつくしい。
Pietって誰や
• Piet Mondrian(1872-1944)
• オランダ、アメルスフォールト出身の画家。
• 本格的な抽象絵画を
描いた最初期の画家。
• このスライドの背景も
Piet氏の作品。
蛇足
• David Morgan-Mar氏は、他にも Ook!
などいくつかのesolangを考案している。
– Ook!は、オランウータンの鳴き声"Ook.",
"Ook!", "Ook?"の3つのトークンを2つずつ組
み合わせて、Brainf*ckの8個の命令を置き換
えたもの。
• A, Misa, NyarukoなどBrainf*ckの派生は多い。
• 最初はMondrianにしようとしたが、既に
使われていたのでPietにしたらしい。
Pietの仕組み
• やっと本題。
• Pietは⾊の変化によってコマンドが実⾏さ
れる。
色
• Pietで使う⾊は、6*3+2=20⾊。
• ⾊相: 赤→⻩→緑→シアン→⻘→マゼンタ→赤
• 明度: 明⾊→普通→暗⾊→明⾊
• 追加⾊は処理系によって⽩や⿊になる。
#C00000
dark red
#C0C000
dark yellow
#00C000
dark green
#00C0C0
dark cyan
#0000C0
dark blue
#C000C0
dark magenta
#FFC0C0
light red
#FFFFC0
light yellow
#C0FFC0
light green
#C0FFFF
light cyan
#C0C0FF
light blue
#FFC0FF
light magenta
#FF0000
red
#FFFF00
yellow
#00FF00
green
#00FFFF
cyan
#0000FF
blue
#FF00FF
magenta
#FFFFFF white #000000 black
codel
• Pietでは⼀つ⼀つの⾊の違いが重要。
– ⾒易くするために拡大することがよくある。
• それらを"pixel"と呼んでしまうと、
拡大前の尺度か後の尺度か紛らわしい。
• そこで拡大前の1pixel分を"codel"と呼ぶ。
– 要するにPiet上で意味を持つ最小単位。
カラーブロック
• Pietの基本単位はカラーブロック。
• 縦か横に隣接した同⾊のcodelの塊。
– 斜めは違うよ。
• カラーブロック中に違う⾊の"穴"を内包す
る場合、その穴はカラーブロックには含ま
れず無視される。
– このシアンのカラーブロックは
8 codel。
スタック
• Pietは記憶領域としてスタックを⼀つだけ
持っている。
• データは整数型しか持たない。
– コマンドを使うとUnicode値と解釈して文字を
出⼒することも出来る(後述)。
スタックとは
• ⼀応スタックを知らない⼈のために。
• 後入れ先出しのデータ構造。
– 後から入れたデータから先に出していく。
– 積み木をどんどん上に積んでいって、取ると
きも上から取っていく感じ。
• 入れる動作を"push"、出す動作を"pop"と
いう。
実⾏の流れ
• Pietのインタプリタは左上のcodelから
プログラムの実⾏を始める。
• インタプリタは"Direction Pointer"(DP)を
持っている。
– DPは上下左右のいずれかを指す。
• 初期値は右。
• 更に"Codel Chooser"(CC)も持っている。
– CCは左か右を指す。
• 初期値は左。
DPとCC
• プログラムポインタは実⾏中以下のルール
に従ってカラーブロックを移動していく。
1.今いるカラーブロックの中でDPの向きに
⼀番離れた端っこのcodel達を探す。
2.DP方向に向かってCC側の端っこにある
codel1個を探す。
3.そのcodelからDP方向にあるカラーブロッ
クのcodelに移動する。
分からん
• ちょっと何言ってるか分かんない。
DPとCC(図解)
• 例えばこんなやつ。
– 適当に描いたから挙動はよく分からん。
DPとCC(図解)
• 左上のcodelから始まる。
– 矢印がプログラムポインタ。
DPとCC(図解)
• 今DPは右なので、右の端っこのcodel達を
探す。
– 十字のところ。
DPとCC(図解)
• DP方向(右)に向かってCC側(左)の端っこ
のcodelを探す。
– 赤い方の十字。
DPとCC(図解)
• そのcodelからDP方向(右)にあるカラーブ
ロックのcodelに移動する。
実⾏の流れ(続き)
• このように、プログラムが終了するまで
プログラムポインタがカラーブロックの
移動を繰り返す。
– プログラムの終了条件については後述。
コマンド
• コマンドは、プログラムポインタが移動す
るときの、移動元と移動先のカラーブロッ
クの⾊の差によって示される。
– ⾊の"差"とは「⾊相」と「明度」の変化量の
こと。
– ⽩と⿊は処理が異なる(後述)。
コマンド一覧
• 例えば、移動元の⾊がlight redだとすると以下
のようになる。
• 次から各コマンドの説明。
pop multiply not switch in(number) out(char)
なし add divide greater duplicate in(char)
push substract mod pointer roll out(number)
変化なし 1段階 2段階 3段階 4段階 5段階
変化
なし
1段階
2段階
push & pop
• push
– 移動元のカラーブロックに含まれるcodelの数
をスタックにプッシュする。
• pop
– スタックから1つポップしてその値を破棄する。
四則演算
• add
– スタックから2つポップして加算した結果を
プッシュする。
• substract
– スタックから2つポップして、2つ目にポップ
した値から1つ目にポップした値を引いた結果
をプッシュする。
– 例えばスタックが{2, 3, 5, 7}となっていたら、
7, 5の順にポップされ 5 - 7 = -2 が積まれる。
四則演算(続き)
• multiply
– スタックから2つポップして乗算した結果を
プッシュする。
• divide
– スタックから2つポップして、2つ目にポップ
した値を1つ目にポップした値で割った"商"を
プッシュする。
– 割る割られるの順序の考え方はsubstractと
同じ。
余ったやつ
• mod
– スタックから2つポップして、2つ目にポップ
した値を1つ目にポップした値で割った"余り"
をプッシュする。
– 割る割られるの(ry
論理値
• not
– スタックから1つポップしてその値が0なら1を、
0以外なら0をプッシュする。
• greater
– スタックから2つポップして2つ目の値が1つ目
より大きければ1を、そうでなければ0をプッ
シュする。
DPとCC
• pointer
– スタックから1つポップしてその値の分だけ
DPを時計回りに回転させる。
– 負数なら反時計回り。
• switch
– スタックから1つポップしてその値の分だけ
CCを切り替える。
– 要するに奇数なら切り替わって偶数なら切り
替わらない。
仲間外れ
• duplicate
– スタックのトップの値をコピーしてプッシュ
する。
• roll
– スタックから2つポップして、2つ目分の深さ
までのスタックの値を1つ目分の値の分だけ回
転させる。
– 1回転するというのは、トップの値をスタック
の指定された深さに埋め込み、それ以降の値
が1つずつ上に上がっていくことを意味する。
roll詳説
• ちょっと分かりにくいので具体的に説明。
• {1, 2, 3, 4, 3, 2}とあった場合。
– 2, 3 とポップして、深さ3まで2回転すること
になる。
– 深さ3とは{1, 2, 3, 4}のうち{2, 3, 4}の部分。
– まず1回転すると{1, 4, 2, 3}。
– もう1回転で{1, 3, 4, 2}。
• こんな感じ。
⼊出⼒
• in(number)
– 標準入⼒から数値を受け取りプッシュする。
• in(char)
– 標準入⼒から1文字受け取りそのUnicode値を
プッシュする。
• out(number)
– スタックから1つポップして、標準出⼒に渡す。
• out(char)
– スタックから1つポップして、その値を
Unicode値として持つ1文字を標準出⼒に渡す。
例外処理
• これらのコマンドが実⾏できない場合は、
単純に無視される。
• 例えば、
– ポップするしたい数の値がスタックに無い。
– 0で除算。
– rollの深さが負。
コマンド終わり
• 今度は⽩と⿊の話。
⿊ブロックと端
• ⿊のカラーブロックとプログラムの端っこ
は⾏き⽌まり。
• プログラムポインタの⾏き先がこの⾏き⽌
まりに差し掛かった時は、
1.移動を中⽌し、CCを切り替えて再度移動を試
みる。
2.それでも⾏き⽌まりなら、今度はDPを時計回
りに90度回して試す。
3.これをCC→DP→CC→……と繰り返して8通り
全てダメならプログラム終了。
白ブロック
• ⽩ブロックはフリーゾーン。
• インタプリタが⽩ブロックに差し掛かった
場合、
1.DP方向に⼀直線に滑って⾏く。
2.カラーブロックに辿り着けばそこに移動する
が、この移動によるコマンドは実⾏されない。
• コマンド無しで⾊が変わるのでループの実装に便利。
3.もし⾏き⽌まりにぶつかったら、先述の流れ
と同様にCCやDPを切り替えていく。
Pietの説明終わり
• ⻑かった……。
目次
1.自己紹介
2.Pietについて
3.エディタの話
4.実践Pietコーディング
レキシ
• 時は2013年11月。
• NF2013(京大の学園祭)にて、Unambi
Sweeper(先述)を出展する傍らPiet展覧会
にも作品を出展していた。
• こんなの。
カイソウ
• Piet展覧会に向けて作品を作っていた頃。
• とりあえずエディタが欲しかった。
• で、とりあえずこんなのがあった。
PietDev
PietDev
• ここ。
http://www.rapapaing.com/blog/?page_id=6
• JavaScriptで書かれてる。
• グラフィカルな編集が出来る。
• ステップ実⾏でデバッグも出来る。
• 便利︕
• だが……
PietDevのココが糞
• Canvasが使いづらい。
– ペンツールは1codelずつしか描けない。
• カラーブロックはポチポチポチ……
– かといって範囲選択が出来るわけではない。
• ポチポチポチ……
• Undo・Redoが出来ない。
• Canvasの幅、高さ、あるいはcodelの拡大
率を変えると……
– リセットされる︕︕︕︕︕
• 「あっ、codelが足りない」とかなったら死ぬ。
対応
• 最初はPietDevで我慢していたが諦めた。
• 代わりに、Edge(ドット絵エディタ)で描
いたものをPietDevにアップロードしてデ
バッグするという方法を採った。
– つらみ。
そういえば
• 前に作ったUnambi Sweeperだって
Canvasみたいなもんやし知⾒が活かせる
だろうから自分で作ってみるか。
– 実は全く活かせなかった。
• というわけで作ることにした。
– 実は、作り始めてからちゃんと探してみたら
(何故最初に探さなかったのか)他にもいくつか
エディタがあるらしいことが判明したのだが、
今更そんなことはどうでもいい。
命名
• PietのIDEを作るので、
命名
• PietのIDEを作るので、
Piet
IDE
命名
• PietのIDEを作るので、
P i e t
IDE
命名
• PietのIDEを作るので、
P IDE t
命名
• PietのIDEを作るので、
Pidet
命名
• PietのIDEを作るので、Pidetにした。
Pidetの仕様
• 基本的には、PietDevを改良した感じ。
– ペンツールで線が引ける。
– 範囲選択が出来る。
– Undo・Redoが出来る。
– 編集中に高さ・幅・codel拡大率を変えられる。
• その他
– 選択した⾊を基準として、他の⾊に対応する
コマンドがパレット上に表示される。
– codelをダブルクリックすると、そのcodelを
含むカラーブロックを選択できる。
Pidetの仕様(続き)
• 20⾊以外の⾊は⽩ブロックとして扱う。
• 例外処理がPietDevと多少異なる。
– PietDevの場合、コマンドが実⾏できなくて無
視する場合でも、とりあえずスタックから
ポップだけされている場合がある。
– Pidetでは、実⾏不能な場合は何も操作しない
ようにしている。
Pidetの仕様(更に続き)
• ステップ実⾏中、直前のコマンドが実⾏さ
れる前後のスタックの状態を表示して変化
が分かるようにした。
言語
• C#で作った。
作ってて思ったこと
• デバッガのデバッグはつらい。
– XとYを間違えると死ぬ。
やり残したこと
• 範囲選択からのコピペ。
• 選択範囲内での⾊の循環変更。
– 要するに相対的な変化量が変わらないように
(コマンドが変わらないように)⾊を変えたい。
• Pietで実⾏出来るいい感じのアイコン。
– "Pidet"とか出⼒させたい。
• (追記)後ろ2つは発表後に実装済み。
• (2015/9/6 追記)アイコンも作成済み。
目次
1.自己紹介
2.Pietについて
3.エディタの話
4.実践Pietコーディング
折角だから
• 新しく考える時間が無かったので
NF2013で展示したこいつを描きます。
\バーン︕︕︕/
なにこれ
• これは「FizzBuzz(簡易版)」です。
FizzBuzz
• 知らない⼈のために。
• FizzBuzzは、1から順に整数を言っていく
ゲーム。
• ただし、
– 3の倍数の時は"Fizz"
– 5の倍数の時は"Buzz"
– 15の倍数の時は"FizzBuzz"
• と言う。
FizzBuzz(簡易版)の仕様
• 入⼒として整数を1つ取り、
1からその数までFizzBuzzをして出⼒する。
• ただし、"Fizz"とか"Buzz"とかいう文字列
は⻑すぎるので、"F"とか"B"に省略。
• 区切り文字は改⾏文字ではなく半角空⽩。
– 何故そうしたかは覚えていない。
イメージ
• 例えばこんな感じ(適当)。
int n;
cin >> n;
for(int i = 1; i < n + 1; ++i)
{
if (i % 15 == 0) cout << "FB";
else if (i % 3 == 0) cout << "F";
else if (i % 5 == 0) cout << "B";
else cout << i;
if (i < n) cout<< " ";
}
問題点
• Pietで描く場合、"F"や"B"といった1文字1
文字を出⼒するのに結構場所が要る。
– 節約したい。
解決策
• "F"を出⼒する部分と"B"を出⼒する部分を
作って15の倍数の時は両方通るようにする。
– 実際にはスペース的な問題で"F"の部分が2箇
所になってしまった。
– つまり、"F"の2箇所を"F1"、"F2"とすると、
• 3の倍数の時は、"F1"
• 5の倍数の時は、"B"
• 15の倍数の時は、"F2"と"B"
– を通る。
イメージ
• こんな感じ(超適当)。
void f1() {cout << "F";}
void f2() {cout << "F";}
void b() {cout << "B";}
int n;
cin >> n;
for(int i = 1; i < n + 1; ++i)
{
if (i % 15 == 0) {f2(); b();}
else if (i % 3 == 0) f1();
else if (i % 5 == 0) b();
else cout << i;
if (i < n) cout<< " ";
}
うおおおおおおおおおおお
• お披露目。
• というわけで作ります。
– (追記)作りました。
– (追記)ライブコーディング⾒てない⼈⽤にざっ
くりとした解説を⽤意しました。
以上
• ありがとうございました。
– Pidetのpublishは考え中です、すみません。
– 2015/08/21 Pidet公開しました。
• https://github.com/kndama/Pidet

Pietのエディタを作った話