それなりに高機能なライフゲーム

ライフゲームとは

Wikipediaからのコピペですが、ライフゲームはこういうものです。

  • セルオートマトンの一種
  • セルの上に生命体をつくり、誕生から死亡をシミュレートする
  • 生命のステータスは4つ(以下)
誕生
死んでいるセルに隣接する生きたセルがちょうど3つあれば、次の世代が誕生する。
生存
生きているセルに隣接する生きたセルが2つか3つならば、次の世代でも生存する。
過疎
生きているセルに隣接する生きたセルが1つ以下ならば、過疎により死滅する。
過密
生きているセルに隣接する生きたセルが4つ以上ならば、過密により死滅する。

この単純なルールで生命体を表現するのがライフゲームです。
とりあえずそれを作ってみました。

デモ

グライダー

まずは”グライダー”をご覧ください。Runをクリックしてください。
このページへ

ほかの物体はリンク先の下のほうにあるリンクで辿れます。

銀河

こんなのもいいですね。
このページへ

Numを押して生命数の表示を有効化すると、セルの周りの生命体数が表示され、ルールと照らし合わせて確認できます。が!ブラウザによっては固まってしまうことも・・・。重いようです。

ほかにはこういうのも

パルサーといわれるようです。たしかに、天体の一種に見えなくもない。
このページへ

グライダーを量産するグライダー銃

グライダーを製造しまくります。
幅が広いので、このページで見てください。

ほかに・・・

というわけで、いろいろ作れます。セルをクリックすると生命体を作れるので、やってみてください。一つや二つのセルに生命を置いても、過疎で死んでしまいますし、4つ以上を隣接させるとそれはそれで過密で死にます。

more..

see wikipedia
たくさんあります。なにか新しいものを作ったら、リンクをGetURIで生成して、コメントにでも書き込んでくださいね。

プログラムの工夫

  • とりあえずHTML5です
  • セルの内容をURIにシリアライズできます。
    URIの後ろの#以降は、実は生命体の座標が入っています。いい感じの生命ができたら、GetURIでURIを作成して共有できるというわけ。
    上のサンプルのリンクへいくと、URIが長いのが分かります。

Shallow copy / Deep Copy

さて、このライフゲームを作っているときに、JavaScriptの代入で困っていました。たとえば、tmp = obj.aのようなことをすると、tmpにはobj.aの参照が入ります。これはShallow Copyというものです。これに対して、丸ごとコピーすることをDeep Copyといいます。
Deep Copyをする方法はググればいろいろなライブラリがあるようです。

Base64

URI生成でシリアライズはJSONとBase64URLを利用しました。JSON+encodeURIComponentだとどうしても大きくなるからです。Base64URLとは、Base64で利用する文字種について、URIでディレクトリセパレータなどになってしまう文字を置き換えたりしたものです。

code review

Kinetic.jsをつかってみましたが、何か遅いです。newが重いのか、描画が重いのか定かではありません。ブラウザ別で早かった順で行くと、IE10, Chrome, Safari==Firefoxくらいになりました。
requestAnimationFrameを利用して垂直同期と同じくらいの間隔でレンダリングをしようと思ったのですが、最速のIE10でもワンステップのシミュレーションに20msほどかかるので、setTimeoutにて行っています。
Kinetic.jsでリフレッシュにstage.draw()を使うと遅かったので、layerごとにdraw()しています。この場合、枠のレイヤーはレンダリングされません。

WebRTCで複数台監視可能なカメラをつくる

WebRTC
WebRTCはブラウザからカメラやマイクを使える楽しいAPIです。というわけで、WebRTC+Canvas+WebSocket+node.jsと豪華な最新ラインナップで監視カメラを作りましょう。
サーバには、node.jsをインストールします。
npm install wsでwsパッケージもいれておきます。
そして、以下のコードを書きます。

var WebSocketServer = require('ws').Server
, wss = new WebSocketServer({port: 8080});
var slot = [];
var maxid = 0;
wss.on('connection', function(ws) {
var id = maxid;
console.log('connection open #%d',id);
ws.on('message', function(data) {
broadcast('DAT',id,data);
});
ws.on('close', function() {
console.log('connection closed #%d',id);
// 接続切れのソケットを配列から除外
slot = slot.filter(function (conn, i) {
return (conn === ws) ? false : true;
});
broadcast('CTL','close',id);
});
slot[id] = ws;
++maxid;
});

function broadcast(type,id,data) {
var buf = '';
slot.forEach(function(socket,i){
buf = type + ' ' + id + ' ';
buf += data;
try {
socket.send(buf);
}
catch (e) {};
});
}

https://github.com/keiya/WebRTC-CCTV/blob/master/server.js

HTMLを書きます。
https://github.com/keiya/WebRTC-CCTV/blob/master/rtc.htm
※jQueryが必要です

まとめてダウンロード
iPadからも当然見れます!
CCTV on iOS

サーバにアクセスし、カメラの動作を許可すれば、データがWebSocketにより送信され、Canvas上のあたらしい表示領域が自動で作られます。
動作するブラウザはChrome、Firefoxで、Windows/OSX/Ubuntuで動作を確認しています。
UVC対応カメラであればどのOSでもデバイスドライバのインストールなしにブラウザに認識されます。

こちらではUbuntu上のChromeで数週間の連続稼働を確認しています。

手書き文字認識APIをテスト運用中

Zinniaを利用した高速な手書き文字認識APIを実装しました。
http://hwr.missinglink.co.jp/vec.html にてデモが使えます。
利用方法は、 http://hwr.missinglink.co.jp/v1/? へ以下のようなJSONをGETにて送信します。(?以降のQUERY_STRINGにそのままJSONをつなげます)

[
{
"canvas_size":[300,300]
},
{
"strokes_points":[
[
[x,y], ...
], ...
]

canvas_size は手書き認識エリアのサイズのx,yです。
stroke_pointsは、pointsを格納します。pointsは、strokeの集合です。strokeはx,yから成り、ストロークの座標です。始点/終点だけとは限りません。デモ画面では、スムージングした座標を利用しています。
送信すると、JSONPで返却されます。
コールバック関数は _mlHWRCallback です。
「知」を書いたときの結果は以下のようになっています。

{"result":[{"value":"知","score":0.192947},{"value":"肴","score":-0.376623},{"value":"刹","score":-0.540289},{"value":"氛","score":-0.600198},{"value":"頚","score":-0.652695},{"value":"午","score":-0.663520},{"value":"帥","score":-0.690676},{"value":"竍","score":-0.710740},{"value":"剥","score":-0.762234},{"value":"朋","score":-0.766667},]}

サーバサイドは、C++で実装されています。spawn-fastcgiとnginxにより、高速なレスポンスが期待出来ます。混雑していない場合は、都内から30ms程度で認識結果が返ります。(DNS解決にかかる時間は除く。また、サーバはEC2 micro instanceのため、複数のアクセスがあると急激にレスポンスが低下します)
ソースコードはgithubにあります。予告なく非公開にする場合があります。