皆さん、こんにちは!YumePro/iTeen北上校 教室長のゆめとです。
「ゆめと教室長とプログラミング!」第2弾は、推理力をぐんぐん鍛える 「ヒット&ブロー」 の数当てゲームをPythonで作ります。
「プログラミングが初めての人」もワクワクできて、「分かる人」も学びが深まるように、丁寧に・専門用語も噛み砕いて解説していきます。
⸻
ヒット&ブローってなに?
コンピューターが 1〜9 の数字を使って桁数 n の“答え” を決めます(同じ数字は1回しか使いません)。
あなたは n 桁の数字を入力して、“答え”を推理します。
・ヒット(HIT)…「数字も場所も一致」した数
・ブロー(BLOW)…「数字は含まれるけど場所が違う」数
例(4桁のゲーム)
・コンピューターの答え:[1, 2, 3, 4]
・あなたの推理:[1, 3, 2, 9]
・ヒット:1(1桁目が同じ)→ 1 HIT
・ブロー:2 と 3 は含まれているけど場所が違う → 2 BLOW
・9 は含まれていない → 0
・結果:HIT=1, BLOW=2
このヒント(H/B)を手掛かりに、何回かの推理で正解を目指すゲームです。
※ 今回のルール:0は使わない/数字の重複なし。
⸻
ゲームのロードマップ(作る順番)
1. 難易度設定:当てる数の桁数 n を決める
2. 正解の数をランダム生成(遊ぶたびに変わる!)
3. 推理を入力:n 桁の数字をキーボードで入力
4. 判定:HIT と BLOW を計算してヒントを表示
5. 結果発表:当たったらクリア&回数(スコア)を表示
⸻
今回学ぶこと(ねらい)
・whileループ:終わりが“分からない”繰り返しに使う
・標準ライブラリ:random を使って複雑な処理を楽に
・関数:処理を部品化して読みやすく・直しやすく
・読みやすい書き方:docstring、f-string、コメント
・基礎データ構造:データ型、リスト、インデックス、.append()、len()
⸻
完成コード(基礎版)
⸻
コードを「徹底」解説
標準ライブラリとモジュール
・モジュール:便利機能をまとめた“部品箱”。
・標準ライブラリ:Pythonに最初から入っているモジュール集。
import random
random は “疑似乱数(ランダムっぽい値)” を作るモジュール。
今回は 重複なしで n 個の数字 を引く random.sample() を使います。
secret_numbers = random.sample([1,2,3,4,5,6,7,8,9], n)
※ ポイント:0は使わない/重複しない → ゲームとして推理がしやすい!
データ型(Data Type)
・int(整数):1, 2, 3
・str(文字列):"123" ← input() は文字列で返る
・list(リスト):[1, 2, 3] ← 複数の値を順番に並べる箱
・bool(真偽):True / False ← 条件式の結果
今回よく出るのは str → intの変換 と list の扱いです。
推理を受け取る:input と リスト&.append()
guess_number = input(f'{n} 桁の数字を入力してください') # 例: "1234"(str)
guess_list = []
for char in guess_number: # '1','2','3','4' と1文字ずつ取り出す
guess_list.append(int(char)) # 文字→整数にしてリストに追加
・.append(x):リストの末尾に要素 x を追加。
・こうして "1234"(str)→ [1,2,3,4](list of int) に変換します。
※ 補足:慣れてきたら内包表記でもOK
guess_list = [int(c) for c in guess_number](今回は .append() を学ぶ目的で上の書き方)
f-string(読みやすい文字列フォーマット)
print(f'{trial_count} 回目の回答です。')
f'...' の中で {} で変数を埋め込める。
'回目: ' + str(trial_count) のような文字列連結より読みやすい!
関数と docstring(説明書つきの部品)
def check_hit_and_blow(secret, guess):
"""ユーザーの推測値と正解を比較して、ヒットとブローの数を返す"""
...
return hit, blow
・関数:処理を「名前のついた部品」にまとめる。
・引数(secret, guess):関数へ渡す材料。
・戻り値(hit, blow):関数の結果。
・docstring:関数の最初に書く説明文。役割が一目で分かる+エディタのヘルプにも表示されます。
リストとインデックス(0番から始まる!)
for i in range(len(secret)):
if secret[i] == guess[i]:
hit += 1
・インデックス:リスト内の位置。Pythonは0番から。
・len(secret):リストの長さ(=桁数 n)。
・同じ位置 i の数字を比べて、完全一致(HIT) を数えます。
HIT と BLOW をどう数える?
# 1) HIT を数える(位置も数字も同じ)
for i in range(len(secret)):
if secret[i] == guess[I]:
hit += 1
# 2) 「両方に含まれる数字の総数」を数える(位置は無視)
hit_and_blow = 0
for num in secret:
if num in guess:
hit_and_blow += 1
# 3) BLOW = (両方に含まれる総数) - HIT
blow = hit_and_blow - hit
こうすることで、重複なし前提なら正しくHIT/BLOWが出ます。
※ アルゴリズム的には各桁を一度ずつ見るので計算量は O(n)。n が桁数なら十分速いです。
whileループ(終わりが来るまで続ける)
while True:
...
if hit == n: # すべて一致!
break # 終了
・for は「回数が決まっている」繰り返し
・while は「いつ終わるか分からない」繰り返し
正解するまで何度でも推理を受け付けたいので while が最適。
len() で長さを測る(安全対策にも効く)
・len(secret):答えの桁数
・len(guess_list):推理の桁数
本気で作り込む際は、桁数が合っているかもチェックしましょう(改良版で紹介)。
⸻
デバッグ&テストのコツ
途中経過を観察する(見える化)
print(f'[DEBUG] secret={secret_numbers}, guess={guess_list}, hit={hit}, blow={blow}')
・試作時だけ出す「デバッグ出力」。
・どこで値が想定外になっているか、状態を可視化して発見。
よくあるエラー
・ValueError: 数字以外を int() に変換しようとした
・IndexError: 入力桁数が足りず guess[i] が存在しない
・ロジックミス:hit と blow の定義がごっちゃになる
→ 入力チェックと丁寧な出力で防げます(下の改良版)。
⸻
改良版(入力バリデーション&親切UI)
ポイント
・入力関数を分離して、メイン処理が読みやすい
・isdigit(), len(), set() で安全性チェック
・if __name__ == '__main__': は「このファイルを直接実行した時だけ main() を動かす」Pythonの定番パターン
⸻
ここまでの学びを整理
・データ型:str と int の変換、list の操作、bool の条件
・whileループ:正解が出るまで繰り返す「終わり未定」構造
・リスト & インデックス:secret[i] と guess[i] を位置で比較(0始まりに注意)
・標準ライブラリ:random.sample() で重複なしのランダム生成
・f-string:f'...{変数}...' で読みやすい出力
・.append():1文字ずつ int にしてリストへ追加(内包表記も紹介)
・関数:責務ごとに部品化(判定、入力、main)
・docstring:関数の役割を冒頭に記述して“未来の自分”に優しく
・len():桁数やリストの長さを測って安全なループや検査に活用
⸻
親御さまへ(教育的価値)
・論理的思考:ヒント(H/B)から条件を絞り込む
・問題分解:難易度設定/判定/入力などを関数で分割
・堅牢性の感覚:入力の検証・エラー予防・デバッグの習慣
・アルゴリズム入門:位置一致と集合的一致(含有)の違いを体験
⸻
次回予告
次は 「声の高さを自由自在に!『いつでも声変わり機』」。
音の世界に踏み込んで、音声処理×Python に挑戦します。お楽しみに!