数字を当てるHit and Blow。ある桁の数字を取り出す処理が何か所にもあるし、いちいち割り算をしなければならないというのはイケてないので、改良します。
配列なら一部分を取り出すのも簡単
文字列は配列のように操作できます。配列の添え字(インデックス)は0から始まるので、文字列の最初の文字は0番目になります。
4桁の数字を文字列にすれば、千の位の数字は0番目、百の位は1番目、十の位は2番目、一の位は3番目です。なので、hitを数える部分は
と書き換えられます。hitは桁(位置)と数字が一致している個数なので、添え字(変数 i)を0から3まで変化させて、コンピュータが選んだ数字(com_num)のi番目とプレーヤーが入力した数字(player_num)のi番目が同じかどうか、比較しています。
com_numとplayer_numの型ヒントをstrにすることも忘れないようにしましょう。
「含まれている」はinを使う
次はblowを見てみましょう。
コンピュータが決めた値に含まれている数字を数えればいいので、プレーヤーの入力した値から1つ数字を取り出して、コンピュータが決めた値(文字列)に含まれているかを確認します。
count_blow()、前のバージョンでは30行を超えていましたが、10行弱で同じ処理を行えるようになりました。
入力チェックができていなかった
プレーヤーが数値を入力する部分も見直しましょう。
わざわざint(input())として数値に直していましたが、文字列として扱うならint()は不要です。
しかし、入力したのが4つの数字(3桁か4桁の数字)でなかった場合の対策をしていません。他の部分は4桁の数字(長さが4の文字列)であるものとして作っているので、ここで何とかしてしまいましょう。
後ろから4文字を使う
5桁以上の数字が入力された場合、コンピュータが決めた数字は4桁なので、絶対にあたりません。エラーとして再入力させてもいいのですが、今回は、文字列の後ろから4文字分を使うようにしましょう。
文字列から(より短い)文字列として抜き出すには、[開始位置:終了位置]のように指定します。「最後まで」であれば、終了位置は指定しません。
のようにします。
0パディング
入力された数字が4桁に満たない場合を考えます。
「ちゃんと0も入力してください」なんですけど、まぁ、入力すべき0が省かれたと見なしましょう。「0123」と入力すべきところを「123」と入力したと。
「書式指定で4桁として…」と考えるところですが、便利な関数zfill()がありました。
ぴったり!なんですが、ここでは使いません。せっかく5桁以上入力された場合の対策をしたので、それをうまく使いましょう。
最終的に4文字使うので、左側に0を4つ加えてから後ろ(右)から4文字使えば、入力された数字が1桁でも2桁でも、5桁6桁でも、いい感じに処理できます。
改良完了
今回の修正を行った結果のプログラムがこちら。
パッと見て冗長だと思うところは片付けました。is_number_correct()とか、そもそもコンピュータが数字を決める処理は、まだまだ改良できるでしょう。ですが、今回はここまで。