Processingとビット演算

[Processing Advent Calendar 2020](https://adventar.org/calendars/4953)の11日目です。

# 自己紹介

H1ronoです。時々[つぶやきProcessing](https://twitter.com/hau_kun/status/1136299935618351105)に投稿しています。基本的にp5.jsです。

# この記事でやること

この記事では、ビット演算をProcessingに取り入れる簡単な方法を紹介します。大きく次の2つに分けて説明します。

1. グラフィック×ビット演算のテンプレート
2. 実際の利用例

分かりづらいところなどがあれば何でも言って下さい。

# テンプレート

私の場合、ビット演算を用いて得た情報をグラフィックにアウトプットするというのが基本的な流れです。具体的には次のようなコードになります。

```JavaScript
// 扱うビット長
const bit_len = 8;
// データ
const data = 255;

for (let i = 0; i < bit_len; i++) {
    if (data & 1<<i) {
        /* 何かする */
    }
}
```

`data & 1<<i`では「整数`data`を2進数で現したとき、その`i`ビット目が`1`かどうか」を判定しています。`1`であれば短絡評価で`true`[^1]になります。これだけだと情報量が足りないので、整数の配列にします。

[^1]: 正確には`int`型です。`bool`型に明示的に変換する場合、` != 0`を後ろにつけてください。

```JavaScript
// 配列の長さ, 扱うビット長
const arr_len = 8, bit_len = 8;
// データ
const data = [34, 108, 232, 5, 46, 202, 165, 71];

for (let i = 0; i < arr_len; i++) {
    for (let j = 0; j < bit_len; j++) {
        if (data[i] & 1<<j) {
            /* 何かする */
        }
    }
}
```

ここまでがテンプレです。私はこれをもう少し応用してつぶやいています。

# ビット演算の利用例

この作品を例に、ビット演算の利用方法を紹介します。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"></p><a href="https://twitter.com/h1rono_k/status/1301380605649666050?s=21">Saito-inspired</a></blockquote>

Koji Saito([@KojiSaito](https://twitter.com/KojiSaito))さん考案の生き物が動く作品です。

ビット演算の利用で最初に思いつくのはドット絵かなと思います。ツイートのコードを見やすく整形するとこのようになります。

```JavaScript
// ドット絵の1行または1列あたりのマスの数 (ドット絵は正方形)
const cell_len = 8;
// ドット絵の1セルのサイズ, 生き物の大きさの半分
const cell_size = 10, half_size = cell_size * cell_len / 2;
// データ
const data = ["ļłƩƁǃžĤĢ", "ļłƕƁǃžĤń"];
// 生き物の左上の座標を返す関数
const pos = (f) => f(frameCount/60) * 100 + width/2 - half_size;

function setup() {
    createCanvas(360, 360);
}

function draw() {
    background(0);
    let source = data[floor(frameCount/9%2)];
    // 生き物の左上の座標
    let x = pos(cos), y = pos(sin);
    for (let i = 0; i < cell_len; i++) {
        for (let j = 0; j < cell_len; j++) {
            if (source.charCodeAt(i) & 1<<j) {
                rect(x + j*cell_size, y + i*cell_size, cell_size, cell_size);
            }
        }
    }
}
```

様変わりしましたが、基本的なロジックは(おそらく)変わっていません。

最初に気になるのは変数`data`の中身ですね。この文字列からunicodeとビット演算を用いてあの生き物を生み出しています。例として、`data[0]`の文字列`ļłƩƁǃžĤĢ`を見てみましょう。この文字列のそれぞれのunicode番号とその2進数表現を並べると次のようになります。

```
ļ : 316 : 0b100111100
ł : 322 : 0b101000010
Ʃ : 425 : 0b110101001
Ɓ : 385 : 0b110000001
ǃ : 451 : 0b111000011
ž : 382 : 0b101111110
Ĥ : 292 : 0b100100100
Ģ : 290 : 0b100100010
```

ここで大事なのは、2進数の`1`のみに注目することです。`0`を空白にします。

```
1  1111  
1 1    1 
11 1 1  1
11      1
111    11
1 111111 
1  1  1  
1  1   1 
```

これを見ると、2つのことに気がつくと思います。

1. 9ビット目が`1`であること
2. 9ビット目を無視すると、あの生き物が現れること

このように、この作品では2進数をそのままプロットしてドット絵を出しています。ただし、上記コードでは2進数を右から読み、それを左からプロットしているため、左右反転した絵が出力されます。

9ビット目の`1`はドット絵には関係ありませんが、こうなっているのには少し事情があります。例として`129`(`0b10000001`)という数字を文字に変換することを考えましょう。実際にJavaScriptで変換するにはこのコードを実行します。

```JavaScript
console.log(String.fromCharCode(129));
```

実行すると分かりますが、コンソールには何も表示されません。このようになるのは、unicodeでは、`129`には印字できない特殊文字が割り当てられているためです。プログラム上でこの文字を表現するには`\x81`と書く必要があります。`"ab\x81c"`といった具合です。これだとつぶやきにする上で文字数の効率が悪くなります。そこで、ドット絵に影響しない9ビット目を`1`にして`385`(`0b110000001`)とし、これを文字に変換します。

```JavaScript
console.log(String.fromCharCode(385));
// Ɓ
```

無事に1文字[^2]になってくれました。`\x81`から`Ɓ`に変換したので3文字縮まったことになります。たった3文字と言ってしまえばそれまでなんですが、つぶやきにする上で文字数はできるだけ減らしておきたいのでこのようにしています。

[^2]: `Ɓ`は2バイトなので2文字分使っているのでは、といった疑問も考えられます。しかし、twitterでは1文字とカウントされているようなので1文字としています。

長々と書きましたが、要するに「`["ļłƩƁǃžĤĢ", "ļłƕƁǃžĤń"]`には2枚のドット絵の情報が入っている」ということです。それでは`draw`関数を見てみましょう。

```JavaScript
function draw() {
    background(0);
    // ドット絵に使う文字列。定期的に切り替わる
    let source = data[floor(frameCount/9%2)];
    // 生き物の左上の座標
    let x = pos(cos), y = pos(sin);
    for (let i = 0; i < cell_len; i++) {
        for (let j = 0; j < cell_len; j++) {
            // sourceのi文字目のunicode番号のjビット目が1かどうか判定
            if (source.charCodeAt(i) & 1<<j) {
                // セルを描画
                rect(x + j*cell_size, y + i*cell_size, cell_size, cell_size);
            }
        }
    }
}
```

ドット絵はこのような方法で描いています。頑張れば下のツイートのようなこともできちゃいます。正直なところ、ドット絵から2進数に変換するのがすごく面倒ですが...

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"></p><a href="https://twitter.com/h1rono_k/status/1303164373368672256?s=21">mario</a></blockquote>

ですが、8x8であればドット絵から文字列を得るツールがあります。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"></p><a href="https://twitter.com/naoto_hieda/status/1301953126665203713?s=21">8x8-dot-editor</a></blockquote>

これ最高です。

もう1つ書いたんですが長くなったので折り畳みました。よかったらどうぞ。

<details><summary>おまけ</summary>
<div>

7セグメントを使った作品を紹介します。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"></p><a href="https://twitter.com/h1rono_k/status/1300924132373049351?s=21">7segment</a></blockquote>

7セグメントは棒7本のON/OFFなので、表現する文字(数字)1つにつき7ビットの情報量で表現できます。まずはコードを整形します。

```JavaScript
// 各セグメントの情報
// 長方形の長い方の長さ、短い方の長さ
const seg_longer = 160, seg_shorter = 50;
// データ
const data = "ŷĔŮľĝĻŻĖſĿ";

function setup() {
    createCanvas(720, 720);
    colorMode(HSB, 10);
    noFill();
}

function draw() {
    background(0);
    // translateで使う
    let p = - seg_longer / 2;
    // 表示する番号
    let n = floor(frameCount / 60 % 10);
    translate(width / 2, height / 2);
    stroke(n, 9, 9);
    for(let i = 0; i < 7; i++) {
        translate(p, p);
        if (i != 3) {
            rotate(HALF_PI);
        } else {
            rotate(-HALF_PI);
        }
        if (data.charCodeAt(n) & 1<<i) {
            rect(p, -seg_shorter/2, seg_longer, seg_shorter);
        }
    }
}
```

まずは文字列`ŷĔŮľĝĻŻĖſĿ`ですね。各文字のunicode番号とその2進数表現を並べます。

```
ŷ : 375 : 0b101110111
Ĕ : 276 : 0b100010100
Ů : 366 : 0b101101110
ľ : 318 : 0b100111110
ĝ : 285 : 0b100011101
Ļ : 315 : 0b100111011
Ż : 379 : 0b101111011
Ė : 278 : 0b100010110
ſ : 383 : 0b101111111
Ŀ : 319 : 0b100111111
```

先程の例と同様、こちらも9ビット目を`1`にして特殊文字を避けています。下7ビットのみを抜き出し、`0`を空白にします。

```
111 111
  1 1  
11 111 
 11111 
  111 1
 111 11
1111 11
  1 11 
1111111
 111111
```

これだけ見せられても何がなんだかさっぱりですね。`draw`関数を読んでいくと、`translate`と`rotate`で座標軸を動かしていることが分かるかと思います。実際、座標軸はこのように動いています。

![7seg.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497362/bacffc64-f1fe-3a21-43fa-715288a84f63.gif)


<details>
<summary>上の動画用に書いたコード</summary>
<div>
需要があるかなと思って置いておきます。解説とかは何も書いてません。

```JavaScript
const seg_longer = 160, seg_shorter = 50;

function setup() {
    createCanvas(720, 720);
    textSize(40);
    stroke(0);
}

function draw_axis() {
    push();

    stroke(255, 0, 0);
    line(-10, 0, 50, 0);
    triangle(50, 0, 40, -10, 40, 10);

    stroke(0, 255, 0);
    line(0, -10, 0, 50);
    triangle(0, 50, -10, 40, 10, 40);

    pop();
}

function draw() {
    background(255);
    let p = - seg_longer / 2;
    let n = floor(frameCount / 60) % 7;
    fill(0);
    text(`i = ${n}`, 50, 50);
    noFill();
    translate(width / 2, height / 2);
    for(let i = 0; i < 7; i++) {
        translate(p, p);
        if (i != 3) {
            rotate(HALF_PI);
        } else {
            rotate(-HALF_PI);
        }
        rect(p, -seg_shorter/2, seg_longer, seg_shorter);
        if (i == n) {
            push();
        }
    }
    pop();
    draw_axis();
}
```

</div>
</details>

矢印は`i`がその値の時の座標軸です。赤色がx軸、緑色がy軸です。`i`に応じて座標軸を動かし、そのときの対応するビットが`1`かどうかに応じてセグメントを描いています。

少し余談ですが、unicode文字を使うというアイデアを採用したのは(私は)この作品が初めてなんです。採用する前は文字数の制約がかなり大きい状態でやってました。ちょうどこのツイートのような感じです。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"></p><a href="https://twitter.com/h1rono_k/status/1297432915152789505?s=21">pchj03</a></blockquote>

この作品は今年の8月に行われたpchj03([YouTube](https://www.youtube.com/watch?v=aM7-Bu0LeiI))に投稿しました。動画上でNaoto HIÉDA([@naoto_hieda](https://twitter.com/naoto_hieda))さんが文字コードが使えるのではとおっしゃってたのを参考にして、今の形になりました。

</div></details>

# 最後に

ここまで、Processingでのビット演算の使用方法を紹介しました。他にも、[この記事で紹介した方法とはべつのやり方でドット絵を描いたり](https://twitter.com/nagayama/status/1332604496954806273)、[ビット演算でグラフのようなものを描いたり](https://twitter.com/H1rono_K/status/1328297836333604864)と、様々な使い方ができます。まだ発見されていない使い方もあると思うので、是非一度使ってみてはいかがでしょうか。

<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>