前回Pascalの三角形を描いた後、@rithmety様のご指導あり。iteratorの書き方をお教えいただいた上、段数バグっていた(1段少なかった)件も判明。ありがとうございます。今回はPascalの3角形に基づくシェルピンスキーのギャスケット(近似)の描画です。実はPascalの3角形、意外と難物?だった。
※『RustにいればRustに従え』関係記事 index はこちら
※動作確認は、Windows11のWSL2上にインストールしたUbuntu20.04LTS上のrustc 1.64.0 (a55dd71d5 2022-09-19) で行っています。
画像をprint? pbm形式
前々回、マンデルブロ集合を「描いた」ときは、テキストファイルでカラー画像を表現できるppmフォーマットを使用させていただきました。今回のシェルピンスキーのギャスケットは、白黒2値で表現できるので、より簡単なpbm形式を使用いたします。これまたUnix世界では古典的なテキストで画像を表現できるフォーマットであります。昔の形式など知らんという画像ビューワーしかない場合、定番の画像処理ツール Imagemagick のconvertコマンドなどがインストールされていれば変換できると思います。
シェルピンスキーのギャスケットとPASCAL三角形
シェルピンスキーのギャスケットは「ありがちな」フラクタル図形なのでご覧になったことがあるのでないかと。なにやら三角形の繰り返しで、フラクタルというには簡単?な印象もうけます。Pascalの三角形との関係でいえば、Pascalの3角形の各段、各項の偶奇を判断して、偶数ならば白、奇数ならば黒という2値変換をすれば描画していくことができます。
しかし、フラクタルはフラクタルです、深淵が隠れておりますで。真のシェルピンスキーのギャスケットを描くには無限段のPascal三角形が必要と。今回のように有限の段数で打ち切って描いたものは、あくまで
近似
でしかありません。
その上、Pascalの3角形から「変換」する方式でそこそこの大きさのシェルピンスキーのギャスケットを描けると思っていたら、大間違いっす。ちょっと考えたら分かることだったのですが、Pascalの3角形の中央付近の項は「倍々ゲーム」で数値が増大していきます。つまり、
i32型を使った前回の方法で32段は描けるけどその後溢れる
のでした。そこで今回のソースではi64型に変更してみましたが、そんなもの焼石に水です。Pascal恐るべし。もっと大きなシェルピンスキーのギャスケット(近似だけれども)を描く場合はPascalの3角形から計算するという方式は諦めた方がよさそうです。
今回実験したRustのソースコード
今回のコードも mut は無ですが、ピクセルを「print」するところでforを3つも使ってます。まあ、forはシンタックス・シュガーみたいだし、printするときはforの方が分かりやすいしいいか。
前回との違いは、前回が数値(文字)で出力したのに対して、今回はピクセル(pbmでは実際は0か1の文字だけれども)であることくらいです。かなり「洗練」されたコードになっているのは@rithmety様のお陰であります。
fn print1line(halfwidth: usize, arg: Vec<i64>) { let fillw : usize = halfwidth - arg.len(); for _x in 0..=fillw { print!("{} ", 0); } for xa in arg.iter() { print!("{} ", if xa % 2 == 0 {0} else {1}); print!("{} ", 0); } for _x in 0..fillw { print!("{} ", 0); } println!(); } fn sub(arg: Vec<i64>) -> Vec<i64> { [1] .iter().cloned() .chain(arg.windows(2).map(|s| s[0] + s[1])) .chain([1].iter().cloned()) .collect() } fn sub2(w: usize, arg: Vec<i64>) -> Vec<i64> { print1line(w, arg.clone()); sub(arg) } fn main() { let pic_size = 64usize; println!("P1"); println!("{} {}", pic_size * 2 + 1, pic_size); print1line(pic_size, vec![1]); let test = vec![1i64, 1]; (2..=pic_size).fold(test, |v, _| sub2(pic_size, v)); }
動作結果
上記のコードを動作させた結果のテキスト出力をsierpinski.pbmにリダイレクトし、画像ビューワーNkVで確認したものが以下に。NkVはWindows上の画像ビューワーですが軽くて、いろいろできるけれどもインタフェースが控えめ、勿論pbm形式にも対応なのでWSL2上のUbuntuからも愛用させていただいております。
それらしい図形(近似)は描けたけれども、この方法では先はないのう。