Hatena::ブログ(Diary)

shi3zの長文日記 RSSフィード Twitter

2014-04-13

プログラマーの道具 05:31

 アスキーの遠藤諭さんが、「たまには飯でも食おう」というので地図を頼りに飯田橋まで出かけて行くと、ほぼ廃墟みたいな見た目の中華料理店にぶちあたった。


 「これは昭和・・・というよりも満州か・・・」


 恐る恐る古めかしいドアを押すと、明るく活気ある店内に入り込んだ。


 「エンドーさん、で予約してると思うのですが」


 「エンドーさん?誰それ?」


 女将らしい女性が中国訛りの日本語でそっけなく答えた。


 「ええと、遠藤諭さん・・・」


 「わかんない。そのへんに適当に座ってて」


 と促されて、本当に適当に座る。


 ほどなくして現れた遠藤さん。

 女将はそれを見るなり


 「アイヤー、エンドーさんね」


 と笑った。


 遠藤さんは紹興酒をオーダーすると、「これやるよ」と一台の電卓を取り出した。


https://scontent-a.xx.fbcdn.net/hphotos-frc3/t1.0-9/1531535_10153051579650752_278219723229954701_n.jpg

 

 TIことテキサス・インスツルメンツの、その名もプログラマーと名付けられた電卓。


 「これ、プログラマーの憧れだったんだよ」


 と笑う。

http://www.datamath.org/Sci/MAJESTIC/IMAGES/Programmer.jpg

 1977年に発売が開始されたベストセラー電卓。

 16進モードと8進モードを備え、ビット演算も可能。


 確かにこれは便利そうだ。


 コンピュータを使ってると、ちょっとした計算をしたくなることは良くある。

 そのような場合、僕はOpenOfficeの表計算を立ち上げるか、MacOSに搭載された電卓か、ダッシュボードの電卓を使うことが多い。


 しかし、PCのデスクトップから電卓を呼び出して使うというのがどうも、なにか居心地が悪い。画面の中にある電卓の形をしたソフトのボタンにトラックパッドで狙いを定めてクリックするのがなにか滑稽だし、それはiPhoneで動いてる電卓で多少はマシになるけれども、本質的には変わらない。そこにあるのは電卓のイミテーションであって、電卓ではない。


 時たま、物理的な電卓が恋しくなることがある。クリック感が欲しい。


 ちょっと凝った計算をするなら表計算しか選択肢がないけれども、シンプルな計算を繰り返すなら物理的な電卓があったほうがいい。


 ただ、16進数の計算やビット演算をするとなると専用の電卓が必要になる。


 そういうものはたいがい高価なので、さすがにそこまで用意するという発想は僕にはなかったけれども、このTI Programmerは僕のそういうニーズに答えてくれる。


 16進数の計算なんていつ必要になるのか、たいがいの人には想像もつかないかもしれないけど、本格的なプログラミングをしていると今でもたまに必要になることがあるのだ。


 たとえばenchantMOON S-IIでは、指で適当に囲んだ図形が、自動的に長方形や楕円や三角形として認識される。


 このアルゴリズムの元になるコードは僕が書いたんだけど、そのとき、様々な仮説をビット演算で表現してる。

 例えば長方形かどうか判定しているのは以下のような部分だ

	//長方形かな?
	if(inside(x,y,left,top,acceptable*0.5,acceptable*0.5))box|=1;
	if(inside(x,y,right-acceptable*0.5,top,acceptable*0.5,acceptable*0.5))box|=2;
	if(inside(x,y,left,bottom-acceptable*0.5,acceptable*0.5,acceptable*0.5))box|=4;
	if(inside(x,y,right-acceptable*0.5,bottom-acceptable*0.5,acceptable*0.5,acceptable*0.5))box|=8;

	 //それ以外の変な形なのかな? (♡など)
	if(inside(x,y, center_x-width*0.2,center_y-height*0.2,
			width*0.4,height*0.4)){
			box|=16;
	}

 ここではboxという変数に論理演算で仮説の妥当性を検証している。

 四隅にあるバウンディングボックスを点が通過するかどうかで、それぞれの四隅に1ビットずつ割り当てている。

 ただし、真ん中付近を通る場合は、それは長方形ではなく、ハート形などのヘンな形である、と判定する。それが16の位(5ビット目)だ。

 boxの値が15なら、その形は長方形の可能性が高いと判定するわけだ。


 長方形はまだ簡単だけれども、三角形の判定は少し複雑だ。

 原理は同じだが

	//直角三角形かな?
	if(inside(x,y,left,top,acceptable,acceptable))triangle|=1;
	if(inside(x,y,right-acceptable,top,acceptable,acceptable))triangle|=2;
	if(inside(x,y,left,bottom-acceptable,acceptable,acceptable))triangle|=4;
	if(inside(x,y,right-acceptable,bottom-acceptable,acceptable,acceptable))triangle|=8;

	//二等辺三角形かな?
	if(inside(x,y,left+width/2-acceptable*0.5,top,acceptable,acceptable*0.5))isoscelesTri|=32;
	if(inside(x,y,right-acceptable*0.5,top+height/2-acceptable*0.5,acceptable*0.5,acceptable))isoscelesTri|=64;
	if(inside(x,y,left,top+height/2-acceptable*0.5,acceptable*0.5,acceptable))isoscelesTri|=128;
	if(inside(x,y,left+width/2-acceptable*0.5,bottom-acceptable*0.5,acceptable,acceptable*0.5))isoscelesTri|=256;

 

 triangleとisoscelesTriの二つの変数でビットが重ならないようになっている。

 これを判定している部分は以下のようになる


	//三角形、または二等辺三角形、直角三角形を認識する
	var composite = isoscelesTri|triangle;
	if( (triangle & 16)!=0 ){
		//二等辺三角形ならそれを作る
		if( composite == (1|2|16|32|256)){
			vertices = [	{x:left,y:top},
							{x:right,y:top},	
							{x:left+width/2,y:bottom}];
			
		}else
		if( composite == (1|4|16|64|128)){
			vertices = [	{x:left,y:top},
							{x:left,y:bottom},	
							{x:right,y:top+height/2}];
		}else
		if( composite == (2|8|16|64|128)){
			vertices = [	{x:right,y:top},
							{x:right,y:bottom},	
							{x:left,y:top+height/2}];
		}else
		if( composite == (4|8|16|32|256)){
			vertices = [	{x:left,y:bottom},
							{x:right,y:bottom},	
							{x:left+width/2,y:top}];
		}
		else{
			//直角三角形以外なら自由図形
			if(!((triangle == (1|2|4|16))||
				(triangle == (1|2|8|16))||
				(triangle == (1|4|8|16))||
				(triangle == (2|4|8|16))))vertices=[];
		}
	}

 与えられた図形が二等辺三角形である可能性は、4パターンある。

 それぞれ上下左右方向に向いた形になっている。


 このアルゴリズムをデバッグするとき、triangleとisoscelesTriの値だけを表示させても、それがどのように判定されてるのか瞬時にはわからない。

 

 このようなとき、ビット演算ができる電卓があると便利だ。なくても困らないが、あると頼もしい。


 このビット演算によって仮説を管理する、というテクニックは、プログラミングをしているとごく当たり前のように出て来るが、ビット演算を使わないと大変面倒くさいことになる。


 まあもうちょっと読み易くするには、数字を直接書くのではなく、TOPLEFT=1,TOPRIGHT=2のようにしてTOPLEFT|TOPRIGHTのような書き方をするべきだと思うが、この時は時間がなかったのでハードコーディングしてしまった。実際にこのアルゴリズムを作ったのはサンフランシスコから戻る飛行機の中のわずかな時間しかなかったのだ。


 

 「この電卓、いくらくらいするんですか?」


 「まあそう高価なもんじゃないよ。eBayで調べてみようか・・・2000円くらいだね」


 「なるほど」


 「オークションで落札したはいいんだけど、僕はヒューレット・パッカード派でね。そっちのほうを愛用してるからTIのはいらないのよ。だからあげるよ。プログラミングの本も書いた記念にね」


 「ありがとうございます」


 ちなみに今回のアルゴリズムで僕が苦労したのは、認識した図形にモーフィング(滑らかなアニメーション)する機能だ。


 最初、このモーフィング機能はなく、パッと図形が切り替わるようになっていたんだけど、それだとどうしても違和感があってモーフィング機能をできれば入れたい、と思うようになった。しかしこの時もやはり時間がなくて、慌てて書いたんだけど、


	//二直線の交点を求める
	crossLine = function(x1, y1, x2, y2, x3, y3, x4, y4){
		if(x1==x2){
		}
		if(x3==x4){
			var y = (y2-y1)/(x2-x1)*(x3-x1)+y1
			return {x:x3,y:y};
		}
		var a1 = (y2-y1)/(x2-x1)
		var a3 = (y4-y3)/(x4-x3)
		var x = (a1*x1-y1-a3*x3+y3)/(a1-a3)
		var y = (y2-y1)/(x2-x1)*(x-x1)+y1
		return {x:x, y:y};
	}
	var m=0.1;
	for(j=0;j<clip.length-3*2;j+=3){
		var x = clip[j];
		var y = clip[j+1];
			
		var x1=dstClip[0],y1=dstClip[1];
		var distance=1000;
		var goal={x:x,y:y};
		for(var i=3;i<dstClip.length;i+=3){
			var x2=dstClip[i];
			var y2=dstClip[i+1];
							
			//交点を求める	
			var cross = crossLine(x,y,gx,gy,x1,y1,x2,y2);
				
			//交点との距離を求める
			var d = getDistance(x,y,cross.x,cross.y);
			if(d<distance){
				//交点との距離が最も近い点を求める
				goal = {x:cross.x,y:cross.y};
				distance=d;
			}
			x1=x2;y1=y2;
		}
			
		var px = (goal.x-x)*m+x;
		var py = (goal.y-y)*m+y;
		clipAnimVel.push((goal.x-x)*m);
		clipAnimVel.push((goal.y-y)*m);
		clipAnimVel.push(0);
	}

 これは全ての点に対して、最寄りの直線との交点を求め、その点が10フレームでぴったり交点に達するようなスピード(clipAnimVel)を求める。

 パッと見ると計算量は多いが、dstClipは長方形などのシンプルな図形であり、見た目ほどはループ回数は多くない。この計算は一度行っておけばあとは毎フレームごとにclipAnimVelを足し込んで行けば自動的にアニメーションが開始され完了する。

https://fbcdn-sphotos-f-a.akamaihd.net/hphotos-ak-prn1/t1.0-9/10264556_10153061035495752_6063236333560146293_n.jpg

 こういうアルゴリズムを考えるときは、どうしても紙とペンのようなものが必要になる。

 今回はenchantMOONをその代わりに使うことにした。数式を書いたり、図を書いたりして検証するには、悪くない端末だ。その目的に関して言えば、enchantMOONは僕にとって完全に紙とペンの代替となった。いわば電卓ともう一つ、僕が考えをまとめるときに必要な機能を持った機械というわけだ。ないと絶対に困るわけではないが、あると頼もしい。


 プログラムを書くとき、なにか新しいことを考えるとき、そういうときほど、こういう道具が必要になる。MOONにする利点は、暗闇でも使えることと、Evernoteに入れておくとあとで読み返すのがラクということだ。


 人間は複雑な思考をまとめるとき、情報をどこかに集約しつつ推敲するというプロセスが必要になる。

 電卓も、MOONも、そういう思考を補助する道具であろうとする。


 まあ究極のところは、そういう複雑なアルゴリズムもMOONBlockだけで記述できるようになることなんだけど、まだなかなかそこまでは行かない。そのためにはMOONBlock自体の研究が必要だと思うし、MOONBlockはまだ生まれたばかりの言語だ。

 

 あるプログラミング言語が産声を上げてから、何もかもそれでできるようになるまでには相当な時間を要する。MOONBlock自体も研究が必要だし、そのためにはもっと時間がかかるだろうと思う。

Kindle本が売れすぎて驚いた。そして気付いたロングテールの罠 06:33

 なんか中央公論の吉岡さんが「Kindle版が大変なことになってる」と騒いでいるので何事かと思ってよくよく見ると、Kindle本が新書ランキングの1位になっていた。



https://fbcdn-sphotos-g-a.akamaihd.net/hphotos-ak-frc1/t1.0-9/10176024_10153058764965752_5217332018232230475_n.jpg

 で、「新刊なんだから当たり前じゃないの?」と思っていたんだけど、どうもそういうことではなく、紙の本を含むすべての新書の中の1位がKindle版の「教養としてのプログラミング講座」である、ということだった。



 とりあえず、このブログからも数百名の方が買っていただいたようで、本当にありがとうございます。


 で、これってまあ確かに売れてなくはないんだけど、Kindleの場合品切れがないので売れ続けるけど、紙の本は在庫にどうしても限りがあるので、売切れてしまう→ランキングが下がる、ということなんだと思う。


 実際、「教養としてのプログラミング講座」の紙の本の場合も、なんどかランキング上位まで行っては、売り切れになってランキングを下降するというのを繰り返していた。


 過去、enchantMOONもそうだし、enchant.js関係の本を何冊かAmazonで売ったことがあるんだけど、いずれもカテゴリーのランキングで1位をとるものの、すぐに品切れになって在庫が補充されるまで編集部と一緒になってヤキモキすることが多かった。

 で、編集部と僕の間では「この本は確実に○○部は売れるはずだ」というヨミがあっても、出版社の営業に言わせれば「そんなわけのわからない本が売れるワケないし」と相手にされない。


 ちなみに「教養としてのプログラミング講座」も例外ではなく、編集と営業の間で初版部数についてせめぎ合いがあったという。まあプログラミングについて書かれた新書が売れるなんて普通誰も思わない。


 その結果、初版はつねに少なめに設定され、Amazonにはごく少量(数百部)しか入荷されない。

 そんなもんだから、売り切れになったあとの再入荷がつらい。


 で、Amazonで売切れるということは他のサービス(紀伊国屋ブックwebとか)に流れるということなのかな、とも思うんだけど、結局書店を除けばAmazonが一番売れるような気がする。


 Amazonはロングテールに対応するため、大量の製品の品揃えがあるのだけれども、実は在庫として確保する量は限られている。下手すると、全く売れるかわからない新製品は1個だけしか扱わない、ということもある。


 そして在庫を確保してもらうために倉庫代もこちらが払わないといけない。これは出版社ごとに全体の枠が決まってる。

 だから結局、ちょっと変わった本ばかり作ってる我々は少ししか在庫を置けないということになってしまう。


 で、そこでスマッシュヒットが出ても、在庫が瞬間的に蒸発してしまって、そこから次の在庫が入るまでにタイムラグがある。


 この機会損失を、僕も編集も、いつも「ギギギギ・・・」と歯ぎしりしながら見ていたのだ。


 営業の無理解というギャップは常に埋めるのが難しい。



 そこにKindle版だ。

 実はこの本が、僕の初めてのKindle本ということになる。だからKindle本がどのように売れて行くのか、実感として知らなかった。


 たぶんこのブログの読者に、そもそもKindleを日常的に使ってる人が多いのだろう。

 Kindleのメリットは、読みたいと思ったものを読みたいタイミングで買い、どこにでも持ち歩けることだ。


 先日、Kindle本でお勧めの本を何冊か紹介したけれども、それも飛ぶように売れた。

 つまりこのブログとKindle本はとても相性がいいのだ、ということになる。


 実際、たとえばちょっと古いマンガとか、マニアックなマンガとかは紙の本で揃えるのは面倒だし、読み終わった後邪魔になってどうせ捨ててしまうならKindleで買いたい、という心理は凄く理解できる。


 また、新書も似たようなもので、読んでみて、つまらなかったらそのまま読むのをやめてしまえばいいけど、面白かったらどこにでも持ち歩きたい。スマートフォンでもタブレットでも読みたい、となれば、Kindle本がいいのだ。



 そういえば僕も「もしドラ」は紙の本を持ってない。Kindleで読んだ。


 最初は文章に違和感があるが気がつくと泣いてしまう。ドラッカーについては特に学べないが、意味もわからず涙がこぼれるというのはすごい構成力だと思う。


 Kindleで読んだ、といえば「統計学が最強の学問である」

統計学が最強の学問である

統計学が最強の学問である


 これはもともと、今回の「教養としての〜」を書く時に、「こういう本にしたい」と編集の吉岡さんに読めと言われて買ったのだった。


 ああ、あと、東浩紀の出版記念イベントに呼ばれたので、「一般意志2.0」もKindleで読んだ。微妙にハードカバーな本なので、Kindleはありがたかった。

[asin:B009YG88QO:detail]

 そして気がつくと動物化するポストモダンもKindle版が出てる

動物化するポストモダン オタクから見た日本社会 (講談社現代新書)

動物化するポストモダン オタクから見た日本社会 (講談社現代新書)


 個人的には2の方がお勧めだ。「こんなものの見方があったのか」と思う。

[asin:B00APB8H86:detail]

 副読本として「物語消費論改」もお勧め。

 あらゆる物語を構造的に解説していて、これも目からウロコだった。


人類最古の哲学 カイエ・ソバージュ(1) (講談社選書メチエ)

人類最古の哲学 カイエ・ソバージュ(1) (講談社選書メチエ)


 カイエ・ソバージュもKindle版あるかなーと思ったら、なかった。残念。

 このシリーズこそ大きくてかさばって、しかも長いからKindleで読みたいのに。

煙か土か食い物 (講談社文庫)

煙か土か食い物 (講談社文庫)

 舞城王太郎の傑作、「煙か土か食い物

 これもときどき、繰り返して読みたくなるのでKindleで読むのがいい。



 もしかすると紙の本とKindle本は相乗効果で売れるのかもしれない。

 発売のタイミングを同時にしたら、もっと売れるのではないか。

 だぶって買ってもらう、みたいなセコい売り方ではなくて、普通に面白い本を紙で入手するか、Kindleで入手するか、あるいはその両方か、読者に選んでもらうほうが売り方として誠実なのではないか、と思った。


 結局、気分が悪いのは、売切れるとすぐによくわからない業者が定価よりも高い価格でマーケットプレイスに出品すること。当然ながらそのぶんの印税は入らないし、出版社も損をする。少なくとも出版されてから半年以内の本の場合、Amazonはそうした業者が定価よりも高い価格で本を売ろうとするのを規制すべきだと思う。


 しかし実感として、「本が売れてる」というのがこんなによくわからないものだとはちょっと思わなかった。


 もしかして、「本を書いた」という感動を感じるには、僕は本を書きすぎてしまったのかもしれない。

https://fbcdn-sphotos-h-a.akamaihd.net/hphotos-ak-prn2/t1.0-9/1798624_10153042962130752_1830385626_n.jpg


 でもなんか、書店に立ち寄るとずらっと並んでるし、「ああ、これが一般書の世界なのか」という感じ。


 でも正直、今読み返すと縦書きでプログラミングの説明するのってわかりにくいなと思ったりする。

 まあでも、入り口としてはこれでいいのだろうか。


 さっそく続編の話もでてきているんだけど、これを読んだ人は、次にどんな本が読みたいのだろう。と思うと、なかなか企画も進まない。


 そのへんのフィードバックを貰う方法が、結局、紙だろうがKindleだろうがあまりないのは残念。Amazonだと書評になっちゃうしね(それでもAmazonに書評が載るのは嬉しい)。

 

 しかし驚きました。本当に。


 そうそう。火曜日(4/15) 18:00からのニコニコ超会議「仁義なきプレゼンバトル」にenchantMOONで出場します。

https://scontent-a.xx.fbcdn.net/hphotos-ash3/t1.0-9/10175038_10153058848380752_7624286091703796984_n.jpg

【出展企業抗争】仁義なきプレゼンバトル -予選篇- |niconico プレゼンをチェックして投票しよう!

http://www.chokaigi.jp/2014/jingi/


 ローソンさんやグリコさんに森永さんにスクエニさん、ガンホーさんに岩手県さんといった、スーパー大企業&地方自治体を相手に、零細企業である僕たちユビキタスエンターテインメントがどんな戦いぶりをするのか、ぜひ見届けて下さい。