もう一回 数当てゲーム

2012/08/09

haskell

t f B! P L
数当て問題 - Hit & Blow -: ツムジのひとりごとで取り上げていただいたので、自分のコードと比べてみる。

このゲームの肝であるHitとBlowを求める処理のうち、まずはBlowから。
Blowは、「数字として当たっているし、場所(桁)も当たり」ということ。

countBlow :: String->String->Int
countBlow [] _ = 0
countBlow _ [] = 0
countBlow (x:xs) (y:ys)
          | x == y    = 1 + countBlow xs ys
          | otherwise = countBlow xs ys
  • 文字列を2つ受け取って、それぞれの先頭を比較する。一致していたら、戻り値に1を加える。
  • 文字列が終わりでなかったら、比較しなかった残りの文字列それぞれを引数にして、自分を呼び出す。
  • 受け取った文字列のうち、どちらかが空だったら、0を返す
で、それを
  • 文字列を2つ受け取って、それぞれの桁について、同じ数字だったらTrue、違ったらFalseにする→受け取った文字列と同じ長さの、Boolのリストができる
  • そのBoolのリストのうち、Trueの数がBlow
と考える。
そうすると、文字(Char)のリストである文字列を2つ受け取って、それぞれの要素に対して関数を適用する→zipWithの出番
また、BoolのリストでTrueを数えるのは
  • filterでリストのうちTrueのものだけにする
  • それからリストの要素数を数える
とすればよいので、

countTrue :: [Bool] -> Int
countTrue = length . filter (== True)

となる。
結局、Blowは

countBlow :: String -> String -> Int
countBlow target = countTrue . zipWith (==) target

で求められると。


次。Hit。
Hitは、「数字としては当たっているけど、場所(桁)は違う」ということ。
単純に「数字として当たっている」ものを数えてしまうと、Blowもカウントしてしまう。でも、Blowも求めるのだから、「数字として当たりの数」- Blow として求めればよい。
ということで、どうやって「数字として当たりの数」を求めるか?

isUsedNum :: Char->String->Int
isUsedNum _ [] = 0
isUsedNum a (x:xs)
             | a == x    = 1 + isUsedNum a xs
             | otherwise = isUsedNum a xs

countUsedNum :: String->String->Int
countUsedNum [] _ = 0
countUsedNum (x:xs) ys = isUsedNum x ys + countUsedNum xs ys

うーん、回りくどい。2つの文字列を引数として受け取って、1つ目の文字列を1文字ずつ、2つ目の文字列の構成要素か見ている(isUsedNum)。これも、文字列を1文字ずつ比較しているから、遅くなるはず。
こっちも、Blowと同様、「構成要素であればTrue」のリストを作って、最後にTrueの数を数えればいいわけだ。

countHit :: String -> String -> Int
countHit target = countTrue . map (`elem` target)

mapが肝かな?関数とリストを受け取って、リストの1つ1つの要素に対して関数を適用する(関数で処理する)。だから、mapの結果のリストって、与えたリストと同じ長さになる
で、mapにどんな関数を与えるかというと、target の構成要素かどうかを返す関数を与える。あとは、Trueの数を数えればOK。


リストの使い方がうまくない。まぁ、もっといろいろプログラム書いて慣れないとね。

楽天で探す
楽天市場
にほんブログ村 IT技術ブログへ

人気の投稿

ブログ アーカイブ

自己紹介

開発からSREにクラスチェンジしました。

アフィリエイト

  • 当ブログ「Hiroaki's blog」は、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、Amazonアソシエイト・プログラムの参加者です。
  • 当ブログでは、第三者配信による広告サービスを利用しています。このような広告配信事業者は、ユーザーの興味に応じた商品やサービスの広告を表示するため、当サイトや他サイトへのアクセスに関する情報 (氏名、住所、メール アドレス、電話番号は含まれません) を使用することがあります。このプロセスの詳細やこのような情報が広告配信事業者に使用されないようにする方法については、ここをクリックしてください。
  • アクセストレードアフィリエイトプログラムに参加しています。
  • A8.netアフィリエイトプログラムに参加しています。
  • バリューコマースアフィリエイトプログラムに参加しています。
  • もしもアフィリエイトプログラムに参加しています。

プライバシーポリシー

当サイトにアクセスされる場合、IPアドレスなどの情報または閲覧状況に関するデータが機械的に生成され、場合によっては個人情報と関連付けられる可能性があります。プライバシー保護に関する適用法に準じて、これらの通信および閲覧に関するデータを収集、処理、および利用することがあります。
当サイトにアクセスされる場合、非個人情報(ブラウザの種類、OSの種類、ドメイン名、訪問数、平均滞在時間、ページ・ビューなど個人を特定できない情報)が自動収集される場合があります。当サイトのパフォーマンスやコンテンツを改善する目的で、これらの情報を利用する場合があります。
アフィリエイトでは成果を把握するためにcookie等を利用しています。それ以外の目的で使用されることはありません。詳しくは各社のページにて確認してください。
本サイトに掲載する情報に関しては、正しいものを提供することを務めていますが、掲載内容から、いかなる損失や損害などの被害が発生しても、当ブログでは責任を追いかねます。

QooQ