追記:最新作『アルセウス』までのポケモンで数え直してみました
追記ここまで
はじめに
開発・公開中の『ポケモンしりとり』は、ポケモンの名前を使ったしりとりです。ルールは通常のしりとりと同じなので、名前の語尾が「ン」で終わるポケモンを回答すると負けになってしまいます。
現在、ポケモンは809種類いて、しりとりゲームを成立させるには十分な数ですが、「"ン"で終わる名前のポケモンって結構いるイメージだけど、何匹いるんだろ?」と思い立ち、せっかくなので、Ruby2.7から追加される新機能Enumerable#tally
を使って調べてみることにしました。
Enumerable#tally
とは
Enumerable#tally
は、Ruby2.7から追加される「各要素の出現回数を数える」メソッドです。各要素の値がkeyに、各要素の数がvalueとなるハッシュを返します。
["a", "b", "c", "b"].tally #=> {"a"=>1, "b"=>2, "c"=>1}
ちなみに、tally
は日本語で「集計」という意味だそうです。
ソースコード
と、いうことで、さっそく書いてみました。Rubyのバージョンは2.7.0-preview1
です。
簡単に説明すると、
- 全ポケモンの情報が記述されているJSONファイルを読み取る
- 読み取ったデータをもとに、名前の語尾だけを格納した配列をつくる
- つくった配列に対して
tally
を呼び出す - その結果を
sort
で昇順にソートする
というやり方です。tally
はハッシュを返しますが、最後にsort
しているため、最終的には配列が返ります。
『ポケモンしりとり』のルールに則り、語尾が長音の場合はその直前の文字(「フリーザー」は「ザ」)で、小文字の場合は大文字に変換(「フェローチェ」は「エ」)してカウントします。
また、ついでに語尾だけでなく、頭文字の数も調べてみました。
# JSONファイルを読み込む require 'json' json_data = open('pokemon_data.json') do |io| JSON.load(io) end # 語尾変換用ハッシュ conversion = {'ァ' => 'ア', 'ィ' => 'イ', 'ゥ' => 'ウ', 'ェ' => 'エ', 'ォ' => 'オ', 'ャ' => 'ヤ', 'ュ' => 'ユ', 'ョ' => 'ヨ', 'ッ' => 'ツ', '2' => 'ツ', 'Z' => 'ト', '♂' => 'ス', '♀' => 'ス'} puts '---語尾を数える---' p json_data.map { |data| if data['name'][-1] == 'ー' # 語尾が長音の場合 data['name'][-2] elsif data['name'][-1] =~ /[ァィゥェォャュョッ2Z♂♀]/ # 語尾が小文字・特殊文字の場合 data['name'][-1].sub(/./,conversion) else data['name'][-1] end }.tally.sort puts '---頭文字を数える---' p json_data.map { |data| data['name'][0] }.tally.sort
ソースコードはGithubにも公開しました。
出力結果
こんな感じ↓になりました!ブログに張り付けるにあたって、見やすいように(そもそもが見づらいけど......)改行を入れています。
---語尾を数える--- [["ア", 17], ["イ", 21], ["ウ", 15], ["エ", 1], ["オ", 15], ["カ", 5], ["ガ", 14], ["キ", 17], ["ギ", 2], ["ク", 18], ["グ", 16], ["ケ", 1], ["ゲ", 5], ["コ", 18], ["ゴ", 5], ["サ", 2], ["ザ", 2], ["シ", 23], ["ジ", 3], ["ス", 80], ["ズ", 5], ["ゼ", 1], ["ソ", 1], ["ゾ", 1], ["タ", 12], ["ダ", 9], ["チ", 11], ["ツ", 7], ["テ", 4], ["デ", 5], ["ト", 32], ["ド", 25], ["ナ", 16], ["ニ", 5], ["ヌ", 1], ["ネ", 6], ["ノ", 6], ["バ", 4], ["パ", 10], ["ヒ", 1], ["ビ", 3], ["ピ", 4], ["フ", 4], ["ブ", 5], ["プ", 10], ["ベ", 2], ["ホ", 1], ["ボ", 7], ["ポ", 1], ["マ", 21], ["ミ", 6], ["ム", 22], ["メ", 6], ["モ", 8], ["ヤ", 6], ["ユ", 7], ["ヨ", 3], ["ラ", 38], ["リ", 18], ["ル", 77], ["レ", 3], ["ロ", 12], ["ワ", 1], ["ン", 102]] ---頭文字を数える--- [["ア", 33], ["イ", 10], ["ウ", 11], ["エ", 20], ["オ", 22], ["カ", 28], ["ガ", 12], ["キ", 18], ["ギ", 8], ["ク", 15], ["グ", 8], ["ケ", 10], ["ゲ", 4], ["コ", 26], ["ゴ", 19], ["サ", 15], ["ザ", 1], ["シ", 18], ["ジ", 17], ["ス", 13], ["ズ", 5], ["セ", 1], ["ゼ", 5], ["ソ", 4], ["ゾ", 2], ["タ", 10], ["ダ", 12], ["チ", 15], ["ツ", 6], ["テ", 6], ["デ", 14], ["ト", 13], ["ド", 25], ["ナ", 10], ["ニ", 19], ["ヌ", 7], ["ネ", 7], ["ノ", 3], ["ハ", 18], ["バ", 23], ["パ", 9], ["ヒ", 16], ["ビ", 9], ["ピ", 8], ["フ", 25], ["ブ", 12], ["プ", 7], ["ヘ", 3], ["ベ", 6], ["ペ", 6], ["ホ", 7], ["ボ", 5], ["ポ", 11], ["マ", 31], ["ミ", 16], ["ム", 9], ["メ", 16], ["モ", 10], ["ヤ", 16], ["ユ", 8], ["ヨ", 6], ["ラ", 19], ["リ", 8], ["ル", 10], ["レ", 11], ["ロ", 5], ["ワ", 7]]
「ン」で終わるポケモンは102匹
でした。
1割ちょっとのポケモンが「ン」で終わるポケモンということですね。ちなみに、全文字中、1位が「ン」の102、2位が「ス」の80、3位が「ル」の77でした。
CPUに勝つには「ル」と「ス」を使え!(確信)
こちらの記事でも書いたのですが、「ル」もしくは「ス」で終わるポケモンをできるだけ回答し、「ル」「ス」で始まるポケモンを枯渇させることがCPUに勝つ最善の方法だということが、今回の分析で改めて分かりました。
というのも、「ス」で終わるポケモンは80匹と多く、かつ「ス」で始まるポケモンは13匹と少ないです。つまり、「ス」で始まるポケモンは枯渇させやすいです。同じく、「ル」で終わるポケモンは77匹、「ル」で始まるポケモンは10匹で、枯渇させやすいです。
CPUに勝ちたければ、「ス」と「ル」のポケモンをたくさん覚えましょう!
「レックウザ」と「フリーザー」で必勝!?
たとえば、「ヤ」で終わるポケモンが何種類かいて、かつ「ヤ」で始まるポケモンが1種類もいないとすると、「ヤ」で終わるポケモンを答えた時点で勝利が確定します。...が、そんな必勝ポケモンはいませんでした。(たぶん)
しかし!
「ザ」で始まるポケモンは「ザングース」だけなのに対し、「ザ」で終わるポケモンは「レックウザ」と「フリーザー」の2匹います。つまり、「レックウザ」と「フリーザー」をどちらも回答してしまえばCPUに勝つことができます。これは大発見(!?)です!
おわりに
Ruby2.7の新機能Enumerable#tally
を使って遊んでみました。新機能は楽しいですね。
Enumerable#tally
は「競技プログラミングで便利そうだな~~」という印象を受けましたが、AtCoderのRubyのバージョンは2.3.3なので、使えません。残念~。