from machine import Pin, I2C # GPIOピンとI2C通信を使用するためのモジュール
from lcd1602 import LCD # LCD1602ディスプレイを使用するライブラリ
import random # ランダムな値を生成するためのライブラリ
import time # 時間関連の処理を行うためのライブラリ
# --- LCD 初期化 ---
# I2C通信でLCD1602ディスプレイを操作するために、SDAとSCLピンを設定
i2c = I2C(1, sda=Pin(26), scl=Pin(27), freq=400000)
lcd = LCD(i2c) # LCDオブジェクトを作成して、ディスプレイを制御
# --- キーパッド設定 ---
# 4×4マトリクス型キーパッドに対応する文字の配置を定義
characters = [["1", "2", "3", "A"],
["4", "5", "6", "B"],
["7", "8", "9", "C"],
["*", "0", "#", "D"]]
# キーパッドの行と列に接続するGPIOピンを設定
row_pins = [2, 3, 4, 5] # 行用ピン
col_pins = [6, 7, 8, 9] # 列用ピン
# 行ピンは出力設定、列ピンは入力設定(プルダウン)で定義
row = [Pin(pin, Pin.OUT) for pin in row_pins]
col = [Pin(pin, Pin.IN, Pin.PULL_DOWN) for pin in col_pins]
# --- LED設定 ---
# EAT用(赤LED)とBITE用(緑LED)のGPIOピン設定
red_leds = [Pin(p, Pin.OUT) for p in [18, 17, 16]] # EAT(赤LED)
green_leds = [Pin(p, Pin.OUT) for p in [13, 14, 15]] # BITE(緑LED)
# --- ボタンスイッチ設定 ---
# ボタンが押されたかを確認するためにGPIO11を入力(プルダウン)
button = Pin(11, Pin.IN, Pin.PULL_DOWN)
# --- 数字を入力する関数 ---
# キーパッドから数字(3桁)を入力するための関数
def read_keypad_input():
input_str = "" # 入力された数字を保存する変数
lcd.clear() # LCDをクリア
lcd.message("Enter 3 nums:\n#:Enter *:Clear") # 3桁の数字を入力してください
while True:
key = None
for i in range(4): # 各行を順にスキャン
row[i].high() # 行のピンを高く設定
for j in range(4): # 各列を順にスキャン
if col[j].value() == 1: # ボタンが押されたら
key = characters[i][j] # そのボタンの値を取得
row[i].low() # 行のピンを低く設定
if key: # 押されたキーがあれば
if key == "#": # エンターキー
if len(input_str) == 3: # 3桁の数字が入力されていたら
return input_str # 入力された数字を返す
else: # 3桁未満ならエラーメッセージ
lcd.clear()
lcd.message("Need 3 nums!") # 3桁入力してください
time.sleep(2)
lcd.clear()
lcd.message("Enter 3 nums:\n#:Enter *:Clear")
input_str = "" # 入力をリセット
elif key == "*": # キャンセルキー
input_str = "" # 入力をリセット
lcd.clear()
lcd.message("Cleared\nRe-enter") # 入力クリア
time.sleep(2)
lcd.clear()
lcd.message("Enter 3 nums:\n#:Enter *:Clear")
elif key.isdigit() and len(input_str) < 3: # 数字キーが押されたら
input_str += key # 入力された数字を追加
lcd.clear()
lcd.message("Input:\n" + input_str) # LCDに入力された数字を表示
# ボタンが押されたらリセット
if button.value() == 1:
return "RESET"
time.sleep(0.1) # 少し待って、ノイズを防止
# --- EAT/BITE を計算する関数 ---
# ユーザーの推測と正解を比較して、EATとBITEを計算する
def evaluate_guess(answer, guess):
eat = sum(1 for a, g in zip(answer, guess) if a == g) # 同じ位置の数字が一致する数(EAT)
bite = sum(min(answer.count(d), guess.count(d)) for d in set(guess)) - eat # 同じ数字の数(BITE)
return eat, bite
# --- LEDを表示する関数 ---
# EAT(赤LED)とBITE(緑LED)を表示する
def show_result(eat, bite):
for i in range(3):
red_leds[i].value(1 if i < eat else 0) # EATの数に応じて赤LEDを点灯
green_leds[i].value(1 if i < bite else 0) # BITEの数に応じて緑LEDを点灯
# --- LEDすべてオフ ---
# ゲーム終了時などに、LEDを消灯する
def clear_leds():
for led in red_leds + green_leds:
led.value(0) # すべてのLEDを消灯
# --- 正解時の赤LED点滅 ---
# ゲームに勝った時に赤LEDを点滅させる
def blink_red(times=5):
for _ in range(times): # 点滅回数
for led in red_leds:
led.toggle() # LEDを切り替える
time.sleep(0.3) # 0.3秒の間隔で点滅
clear_leds() # 点滅後にLEDを消灯
# --- ゲーム処理 ---
# ゲームの流れを管理する
def play_game():
num = random.randint(0, 999) # ランダムな0〜999の整数を取得
answer = f"{num:03d}" # 3桁の0埋め文字列に変換
life = 10 # ゲームの試行回数
while life > 0: # 残り試行回数が0でない限りゲームを続ける
lcd.clear()
lcd.message(f"Guess Num!\nLIFE: {life}") # 残りのライフを表示
time.sleep(2)
guess = read_keypad_input() # ユーザーに3桁の数字を入力させる
if guess == "RESET":
lcd.clear()
lcd.message(f"Game Reset! \nAnswer:{answer}") # ゲームリセット
time.sleep(2)
return # ゲームを最初からやり直し
eat, bite = evaluate_guess(answer, guess) # ユーザーの入力を評価
lcd.clear()
lcd.message(f"EAT:{eat} BITE:{bite}") # EATとBITEの結果を表示
show_result(eat, bite) # 結果に応じてLEDを表示
if eat == 3: # 3つの数字が正解したらゲーム終了
lcd.clear()
lcd.message("You Win!\n" + guess) # 正解表示
blink_red() # 赤LED点滅
time.sleep(2)
return # ゲーム終了
life -= 1 # 残りライフを1減らす
time.sleep(2)
# 10回失敗した場合
lcd.clear()
lcd.message("You Lose!\nAns: " + answer) # ゲームオーバー
time.sleep(3)
# --- メインループ ---
try:
while True:
lcd.clear()
lcd.message("Press button \nto start game") # ゲーム開始を促すメッセージ
while button.value() == 0: # ボタンが押されるのを待機
time.sleep(0.1)
play_game() # ゲームを開始
# --- プログラム終了時の処理(終了時にLCDをクリア) ---
finally:
clear_leds() # ゲーム終了時にLEDをすべて消す
lcd.clear() # LCDをクリア
lcd.message("Game ended") # ゲーム終了メッセージ
time.sleep(3) # 3秒待機
lcd.clear() # LCDをクリア