20120519 inverse fizzbuzz を解いてみよう

27
Inverse FizzBuzz を解いてみよう! 2012/5/19 @quassia88

Upload: hirosuga

Post on 27-May-2015

3.282 views

Category:

Documents


6 download

DESCRIPTION

2012年5月19日に開催された、「第一回関数型言語勉強会 大阪」での発表資料です。コードとか:https://github.com/quassia88/InverseFizzBuzz/まとめとか:http://togetter.com/li/306278

TRANSCRIPT

Page 1: 20120519 inverse fizzbuzz を解いてみよう

Inverse FizzBuzz を解いてみよう!2012/5/19

@quassia88

Page 2: 20120519 inverse fizzbuzz を解いてみよう

自己紹介

Twitter: @quassia88

過去に、「Scalaで圏論入門」を翻訳https://github.com/scalajp/introduction-to-category-theory-in-scala-jp/wiki

Page 3: 20120519 inverse fizzbuzz を解いてみよう

Inverse FizzBuzz って何?

Krishnan Raman氏のブログ「just another scala quant」に5月3日付でアップロード。翌々週あたりから拡散。

原文http://www.jasq.org/2/post/2012/05/inverse-fizzbuzz.html

日本語訳http://d.hatena.ne.jp/matarillo/20120515/p1

コードゴルフhttp://golf.shinh.org/p.rb?Invert+FizzBuzz

Page 4: 20120519 inverse fizzbuzz を解いてみよう

Inverse FizzBuzz のあらすじ

時は2016年、関数型言語がプログラム言語界のメインストリームとなっていた。すでに、FizzBuzz問題はおばあちゃんでも解けるほどに陳腐化。Googleは採用試験に、Inverse FizzBuzzと呼ばれる最新の問題を出題しようとしていた・・・

毒舌な妹さんも安心です

Page 5: 20120519 inverse fizzbuzz を解いてみよう

Inverse FizzBuzz 問題の定義

問題:逆FizzBuzz問題

あるリストが与えられたときに、FizzBuzzを実行するとそのリストを出力するような最短の連続数列を求めよ。

Page 6: 20120519 inverse fizzbuzz を解いてみよう

なんのこっちゃ?

要は、FizzBuzzの逆問題!つまり、結果から原因を推定する問題。

FizzBuzz問題の復習:非負の整数列が与えられたとき、3の倍数ならばFizz、5の倍数ならばBuzz、3の倍数かつ5の倍数ならば、FizzBuzzを出力せよ。

Page 7: 20120519 inverse fizzbuzz を解いてみよう

FizzBuzzの例

数列 { 3, 4, 5, 6 } が与えられたとする。この数列にFizzBuzz を適用すると、

3 ⇒ Fizz4 ⇒5 ⇒ Buzz6 ⇒ Fizz

となり、文字列の列 { Fizz,Buzz,Fizz } がえられる。

Page 8: 20120519 inverse fizzbuzz を解いてみよう

Inverse FizzBuzzの例

では、文字列の列 { Fizz,Buzz,Fizz } が与えられたとする。この列と同じ列を出力する数列のうち、もっとも短いものは何か?

条件:● 解は一意ではないが、最短のものであればどれでもよい

Page 9: 20120519 inverse fizzbuzz を解いてみよう

Inverse FizzBuzzの例

先ほどのFizzBuzzの回答から、 { Fizz,Buzz,Fizz } を出力する数列は、 

{ 3, 4, 5, 6 }

だと分かる。では、他の例は?

{ Fizz, Buzz } ⇒ { 3, 4, 5 } ではなく、{ 9, 10 }{ Buzz, Fizz } ⇒ { 5, 6 }{ Buzz, Buzz, Buzz } ⇒ 解なし!

Page 10: 20120519 inverse fizzbuzz を解いてみよう

再度 Inverse FizzBuzz の定義

Fizz,Buzz,FizzBuzz からなる、文字列の列が与えられたとする。FizzBuzz を適用した時、この列と同じ列を出力する数列のうち、もっとも短いものは何か?

条件:● 解は一意ではないが、最短のものであればどれでもよい。● 解が存在しない場合もある。何らかの対処を行うこと。

Page 11: 20120519 inverse fizzbuzz を解いてみよう

現在の心象

     ノ´⌒`\           ∩___∩    ━┓     /  γ⌒´     \          | ノ\     ヽ.   ┏┛   / .// ""´ ⌒\ \       /  ●゛  ● |   ・    /.    ___   ━┓ .i /  \   ,_ i )\      | ∪  ( _●_) ミ     /     / ―  \  ┏┛  i   (・ )゛ ´( ・) i,/ \    彡、   |∪|   |    /     /  (●)  \ヽ ・ l u   (__人_).  | .   \ /     ∩ノ ⊃  ヽ /     /   (⌒  (●) /_\  ∩ノ ⊃ /  ━┓\  ∧∧∧∧∧∧∧/     /      ̄ヽ__) /(  \ / _ノ |  |.  ┏┛  \<         >    /´     ___/.\ “  /__|  |  ・     <   ━┓   >    |        \―――――――――――――<.   ┏┛   >―――――――――――――      ___    ━┓     <    ・     >.          ____     ━┓    / ―\   ┏┛     <         >        / ―   \    ┏┛  /ノ  (●)\  ・       /∨∨∨∨∨∨\      /ノ  ( ●)  \   ・. | (●)   ⌒)\      /            \     | ( ●)   ⌒)   |. |   (__ノ ̄  |    /    / ̄ ̄ヽ  ━┓  \   |   (__ノ ̄   /  \        /   /    / (●) ..(● ┏┛   \  |            /    \     _ノ  /      |   'ー=‐' i  ・      \ \_   ⊂ヽ∩\    /´     `\/        >     く          \  /´    (,_ \.\     |      /      _/ ,/⌒)、,ヽ_         \ |  /     \_ノ     |     /         ヽ、_/~ヽ、__)  \        \

Page 12: 20120519 inverse fizzbuzz を解いてみよう

どうするの?

● 整数列から出力される FizzBuzz 列は当然無限列。無限列に対して探索しろって?停止する保証は?● 見つからなかったら、永遠に探し続けるの?● 解が得られたとして、それが最短の数列であることはどうやって保証する?● それ以前に、FizzBuzz 列をどうやって数に戻すのよ?

Page 13: 20120519 inverse fizzbuzz を解いてみよう

困った時はどうしよう?

手段その1:力ずくで解く!有限の数列から得られた FizzBuzz 列の部分列をすべて列挙して、与えられた FizzBuzz 列と同じものがないか探す。

→ 出題者がもうやってます

手段その2:とにかく観察してみよう

Page 14: 20120519 inverse fizzbuzz を解いてみよう

FizzBuzz 列を図示してみた

観察すると・・・

Page 15: 20120519 inverse fizzbuzz を解いてみよう

図示すると分かること

これって循環してない?

Fizz, Buzz, Fizz, Fizz, Buzz, Fizz, FizzBuzz

がただ繰り返しているだけ?

考えてみりゃそりゃそーだ。倍数の出力を繰り返してるだけなんだから。(数論、群論、数学的帰納法なんかで証明できるかな・・・)

Page 16: 20120519 inverse fizzbuzz を解いてみよう

糸口を掴む

ある「有限の周期」で循環する列に対する探索の問題と考えればいいのでは?

循環列なので、十分な長さの列に対して探索を行えば

● 有限の時間で終了できることが保証できる● 解が得られたとして、それが最短の数列であることが保証できる● 解が得られなかった場合は、解がないことを保証できる

Page 17: 20120519 inverse fizzbuzz を解いてみよう

問題を分割してみる

● 循環する FizzBuzz 列を作成する● 循環する FizzBuzz 列と、与えられた FizzBuzz 列を比較し、一致する列を列挙する● FizzBuzz 列を数列に戻す● 数列のなかで、最短のものを選択する

もちろん、もっとエレガントな方法もあるはず!

でも、とりあえず上に従って分割した問題を解いてみる

Page 18: 20120519 inverse fizzbuzz を解いてみよう

分割された問題を解いてみよう

Page 19: 20120519 inverse fizzbuzz を解いてみよう

変形 Inverse FizzBuzz 問題1

ある非負整数 n から始まる数列があったとする。

この数列にFizzBuzz を適用した時、最初に Fizz/Buzz/FizzBuzz が出力される数は何か?

例: 3で始まる数列で、最初の Buzz を出力する数は?

Page 20: 20120519 inverse fizzbuzz を解いてみよう

変形 Inverse FizzBuzz 問題1回答例

/** * satisfies を満たす start から最も近い数を返す * start が satisfies を満たさなかった場合、 * next によって次の数が与えられる */def nearestNumber( satisfies:Int => Boolean, next:Int => Int, start:Int):Int = {   if(satisfies(start)) start   else nearestNumber(satisfies,next,next(start)) }

Page 21: 20120519 inverse fizzbuzz を解いてみよう

変形 Inverse FizzBuzz 問題1回答例

/** * FizzBuzz の逆写像を返す */def inverseMapOfFB(str:String):Int => Int = str match { case "fizz" => nearestNumber(x=> x%3==0 && x%5!=0 && x >= 3, _+1, _) case "buzz" => nearestNumber(x=> x%5==0 && x%3!=0 && x >= 5, _+1, _) case "fizzbuzz" => nearestNumber(x=> x%15==0 && x >= 15, _+1, _) }

inverseMapOfFB("buzz")(3) // 5が得られる

Page 22: 20120519 inverse fizzbuzz を解いてみよう

変形 Inverse FizzBuzz 問題2

ある長さのFizzBuzz列が与えられたとする。

このFizzBuzz列 を生成した数列が n から始まるのが分かっている時、FizzBuzz 列を数列に直せ

例: { Fizz, FizzBuzz } を出力する12で始まる数列は?

Page 23: 20120519 inverse fizzbuzz を解いてみよう

変形 Inverse FizzBuzz 問題2回答例

/** * 関数列 funcs に start を順に適用した数列を返す */ def chainSeq( start:Int, funcs:List[Int=>Int]):List[Int] = funcs match { case Nil => Nil case _ => funcs.head(start) :: chainSeq(funcs.head(start)+1,funcs.tail) }

chainSeq( 12, List("fizz","fizzbuzz").map(inverseMapOfFB) )

Page 24: 20120519 inverse fizzbuzz を解いてみよう

変形 Inverse FizzBuzz 問題2回答例

/** * 連続数列を返す */def contiguousSeq(xs:List[Int]):List[Int]=xs match { case Nil => Nil case x => (x.head to x.last).toList }

contiguousSeq(chainSeq( 12, List("fizz","fizzbuzz").map(inverseMapOfFB) ))

Page 25: 20120519 inverse fizzbuzz を解いてみよう

あとは自分で解いてみよう!

でも、注意事項を少々・・・

Page 26: 20120519 inverse fizzbuzz を解いてみよう

Inverse FizzBuzz の注意点

できた!と思ったら以下のことをテストしてみよう

● 最短になっているか?{ Fizz, Buzz } を与えた時に長さ2の列が返るか?

● 解のない FizzBuzz 列を与えた時、クラッシュしないか?

● 空の列(Nil)を与えた時、クラッシュしないか?正しい結果が返るか?(「解なし」じゃないよ!)

● 長いFizzBuzz列に対しても、解を与えるか?

Page 27: 20120519 inverse fizzbuzz を解いてみよう

Let’s solve Inverse FizzBuzz!

 ご静聴ありがとうございました