水曜日, 9月 14, 2011

devquiz 2011 Go!の解答

devquizのGo!の問題で提出した解答。
問題文は以下の通り。
Go 言語で、PNG 画像を入力として受け取り、その画像が何色使っているかを返す関数

func CountColor(png io.Reader) int
を実装してください。PNG 画像は io.Reader 型で与えられます。
なお、入力の画像は R G B の各色の値が 0 から 255 までの 256 段階のいずれかであり、不透明(アルファチャンネルの値が常に 255)であることが保証されています。

答えとして送ったもの(ただし変数名は多少整理した)。素直にスキャンしているだけです。
package main

import (
 "fmt"
 "io"
 "strings"
 "image"
 "image/png"
)

func CountColor(r io.Reader) int {
 colormap := map[uint32]int{}
 image, _ := png.Decode(r)
 bounds := image.Bounds()
 w, h := bounds.Max.X, bounds.Max.Y
 var colorNum uint32 = 0
 for i := 0; i < w; i++ {
  for j := 0; j < h; j++ {
   colorNum = colorCheck(image.At(i, j))
   colormap[colorNum] = colormap[colorNum] + 1
  }
 }
 return len(colormap)
}

func colorCheck(color image.Color) uint32 {
 r, g, b, _ := color.RGBA()
 var num uint32
 num = uint32(uint8(r))
 num = num << 8
 num = num + uint32(uint8(g))
 num = num << 8
 num = num + uint32(uint8(b))
 return num
}

/* これらの関数は提出時に自動挿入されます。 */
func main() {
 png := GetPngBinary()
 cnt := CountColor(png)
 fmt.Println(cnt)
}

func GetPngBinary() io.Reader {
 // img_strの中身は提出するたびに変化します。
 // 省略
}

以下は、後から考えたgoroutine使用版。

package main

import (
 "fmt"
 "io"
 "strings"
 "image"
 "image/png"
)

func CountColor(r io.Reader) int {
 colormap := map[uint32]int{}
 img, _ := png.Decode(r)
 bounds := img.Bounds()
 w, h := bounds.Max.X, bounds.Max.Y
 result := make(chan uint32)
 go colorCheck(img, w, h, result)
 for i := 0; i < w*h; i++ {
  colormap[<-result]++
 }
 return len(colormap)
}

func colorCheck(img image.Image, w, h int, result chan uint32) {
 var num uint32
 for x := 0; x < w; x++ {
  for y := 0; y < h; y++ {
   r, g, b, _ := img.At(x, y).RGBA()
   num = uint32(uint8(r))
   num = num << 8
   num = num + uint32(uint8(g))
   num = num << 8
   num = num + uint32(uint8(b))
   result <- num
  }
 }
}

/* これらの関数は提出時に自動挿入されます。 */
func main() {
 png := GetPngBinary()
 cnt := CountColor(png)
 fmt.Println(cnt)
}

func GetPngBinary() io.Reader {
 // img_strの中身は提出するたびに変化します。
 // 省略
}
goっぽさという点ではgoroutine版のが良いのだろうけど、いきなりこれを書くのは今の私には無理でした。

改めて見ると、後者ではImageをスキャンしている部分(colorCheck)と、色数を数える部分(CountColor)が分離出来ているので、すっきりしているかも。

土曜日, 8月 27, 2011

「小さな哲学者たち」という映画を見てきた

小さな哲学者たちというドキュメンタリー映画を見てきた。
これは、フランスはパリ近郊のZEP(教育優先地区)の幼稚園で行われた、3歳から5歳の子供に向けてなされた哲学の授業の様子を追いかけたドキュメンタリーで、原題は「Ce n'est qu'un début」。日本語だと「これは始まりに過ぎない」という意味になるみたい。
(ガンダムF91のラストの字幕のようだけど、全く関係ない)

哲学の授業といっても、哲学史ではなく、愛とは何か、死とは何かといった内容を、子供たち同士が意見を言い合い、互いの言葉に耳を傾け、時に反論し、時に賛成する。そういう態度を身につけさせるものらしい。話し合いだけでなく、それをフォローするように、テーマに沿った絵を描いたりもするらしい。

その一番最初の授業では「大人と子供の違い」について先生が質問することで始めるのだけど、しばらくすると子供たちは黙りこんでしまう。それだけでなく、まったく関係ない話を先生に語ろうとしたり、隣の子とおしゃべりしたりと、授業の体を為さないまま終わってしまう。
ZEPとされる地域は「恵まれない」とされる家庭が多く、また移民(二世も含む)の家族が多い土地で、教育レベルが高くないところだそうだけど、3歳児の教育レベルなんて、どこだろうとこんなものだろう。3歳の頃の自分にこの質問をしても「大きいのが大人で、小さいのが子供」以上のことは言えないと思う。先生は「大人がやっても良くて、子供がやってはいけないこと」は何か?とか、大人目線で見ればうまい質問をして、子供が考えるのを助けるのだけど、それでもやっぱり難しいらしい。

それでも何回か授業を繰り返すうちに、自分や家族の実体験を元に具体例を提示した上で、「だから○○と思う」という議論の下地のような物を子供たち自身が獲得していく。子供の体験した事なので、提示される例は「チョコレートを出しっぱなしにしたから溶けちゃった」とか「お父さんとお母さんが喧嘩したけど、最後は謝っていた」みたいにささいだけど、ものすごく具体的。
それと小さくても流石フランス人というべきか、女の子が好きな男の子と一緒にいる絵を描いていて、それを見たその男の子が「君とはもう別れたんだからそんな絵を描くな」と言ったりとか、子供たちの恋愛絡みの光景が多く映されている。知らないだけで日本の子もそんな感じかも知れないけど。

印象的だったのは、ある女の子が障害を持った父親の事を「お父さんは自分で歩けないけど、自分で動ける」「自分とは違うけど同じ」と矛盾した言い回しで語っているシーン。他の子たちは、この矛盾を追求するのだけど、女の子はそれにきちんと応答しようと試み、最終的に「障害があるとしても、そのままのお父さんが好きである」事を表明する。矛盾の追求に対する回答にはなっていないのだけど、おそらくその子にとっては、矛盾の解消以上に重要なことに辿り着いたのだと思う。

もう一つ印象に残ったのは、子供たちの多くが「自由」というものは一人で出歩く事であるという意見に同意していたこと。さらに大人が子供を「自由」に歩かせないのは、子供を守るためであることをきちんと認識していること。自分たちが「自由」で無い理由は、大人たちが守ってくれているからという事を理解しながらも、柵を乗り越えて怒られた子供の話や、旅行に行った子が滞在先の家から一人で海まで歩いたことを自慢気に話すのを、わくわくした顔で聞き入っているのが「移動の自由」の原点を表しているようで、微笑ましくも頼もしい。

また、子供たちは哲学の授業から「愛」や「死」といったテーマを持ち帰り、家庭内でも思考が連続していく。両親とも一緒にテーマについて語り、両親もそれに応答していく。幼稚園だけでなく家庭も含めて思考する態度が訓練されていく様子が分かる。

哲学というと抽象的で、虚学の総本山という印象があるけれど、この映画で、様々なバックグラウンドを持つ子供たちが、暴力ではなく言葉と思考によって、相手を説得する態度を学んでいく様子を見ると具体的で実践的なツールとして哲学を使うことが出来るのだと言うことがよく分かる。
移民が多いという背景により「単純な一つの道徳」が暴力に成りうる土地、国において、まずなされるべき対話(これすら暴力かもしれないが、少なくともマシな暴力だ)を構築する上で、哲学の授業が有効に機能している。

私が見た回では、上映後トークショーがあって、移民が少ない日本ではこのような授業の要請はまだ少ないと語られていたけど、例えば北海道と沖縄の子が遠隔で対話するような哲学の授業というのは潜在的に要求されているのではないかと思う。

道を聞かれた 新宿

西新宿のあたりで、初老の女性に十二庵?という場所が無いか聞かれた。
聞いたことが無かったので、知りませんと回答。
他の人にも聞いていたようだけど、他の人も心当たりが無さそう。

後から調べるとニューオータニのあたりに、そういう名前のお店があるらしい。
確かに、あのあたりのお店に行きそうな上品なお金持ち風の格好だったけど、無事辿りつけただろうか。

土曜日, 5月 28, 2011

正規表現 幅ゼロ先読みでよく間違えるのでメモ

正規表現で、いつも混乱するゼロ幅先読みについてメモ。
整理せず思考過程をそのまま記述する。

まず確認として、ゼロ幅とか気にしない正規表現。
具体例が合ったほうが分かりよいので、以下の仕様で考える。

1) aとzだけが使われる
2) 文字列の長さは3以上、10以下

これにマッチする正規表現は^[az]{3,10}$である。ここまでは問題ない。
次に以下の仕様を追加する。

3)zは連続して3つ以上ならんではならない

連続した3つ以上のzとマッチする正規表現は、z{3,}なので、これを幅ゼロ否定先読みしてやればよい。
そして、こう間違える(?!z{3,})^[az]{3,10}$。(※)
この書き方では、zzzaは確かにマッチしないが、aaazzzaaaにはマッチしてしまう。

なぜなら、正規表現のカーソルはマッチした文字列の後ろに移動してしまうから。
aaazzzaaaの場合、文字列の先頭(最初のaの直前)で3連続以上のzを探した後、aaazzzaaaにマッチして、カーソルは文字列の最後に移動してしまう。

正しい正規表現はこうなる(?![az]*z{3,})^[az]{3,10}$
否定先読みの中身だけ取り出すと[az]*z{3,}。つまりaかzが先頭に0個以上あって、その後でzが3つ以上並んでいるかどうかを調べている。

なんで、※のような間違いに至るかについて、自己分析してみる。
人間が文字列を検索するときは基本的に頭から順番に一文字ずつ、対象の文字列と合っているかどうかを調べていく。
対して、正規表現は与えられた個々の正規表現単位で合っているかどうかを調べていく。
aaazzzaaaを^[az]{3,10}$と表す場合、aaazzzaaaで一つの「文字」であり、aaaやzzzという「文字」は存在していない。
この違いを忘れて、人間の検索戦略をそのまま正規表現での検索に当てはめてしまうところに、間違いの原因がある。

ところで、人間であっても実際には正規表現と似たような調べ方を行っている。
例えば「時」という漢字は「日」「寺」に分けられるが、人間が「時」という文字を検索するとき(書体の影響もあるとはいえ)、「日寺」という文字の並びとはマッチさせない。
とはいえ、あえて「時」と「日寺」をマッチさせるような遊びも楽しいのだけど。

金曜日, 3月 11, 2011

かわいいPS1

TwitterでTerminalともっと仲良くなりたいという人と話していて、プロンプトをかわいくすれば仲良くなれるかも、と思ってやってみた。

bashrcでPS1="\w\n(・ᴗ・)?"と設定。
kawaii PS1