Python(4桁数字当てゲーム)

python

今回は受講生(K氏)から届いたお題を深堀りしていこう。
どうやってデータを持つか。。。悩ましい問題だ。

問題

****に隠された4桁の数字を当てるゲーム。
答えには0000~9999のランダムな数字が入る。
8回解答が可能。5回以内の解答でクリアーできると神認定。
正答した桁は、*の代わりに正解の数字が表示される処理を作成せよ。

実行例

実行例(8回で当てられず失敗)

1回目(1/8):****
4桁の数字を当ててね>>0000
2回目(2/8):****
4桁の数字を当ててね>>1111
3回目(3/8):****
4桁の数字を当ててね>>2222
4回目(4/8):****
4桁の数字を当ててね>>3333
5回目(5/8):****
4桁の数字を当ててね>>4444
2Hit!!
6回目(6/8):*4*4
4桁の数字を当ててね>>5454
7回目(7/8):*4*4
4桁の数字を当ててね>>6464
8回目(8/8):*4*4
4桁の数字を当ててね>>7474
残念...答えは9484でした

実行例2(6~8回目で成功)

1回目(1/8):****
4桁の数字を当ててね>>0000
2回目(2/8):****
4桁の数字を当ててね>>1111
3回目(3/8):****
4桁の数字を当ててね>>2222
1Hit!!
4回目(4/8):***2
4桁の数字を当ててね>>3332
5回目(5/8):***2
4桁の数字を当ててね>>4442
1Hit!!
6回目(6/8):*4*2
4桁の数字を当ててね>>5452
1Hit!!
7回目(7/8):54*2
4桁の数字を当ててね>>5462
8回目(8/8):54*2
4桁の数字を当ててね>>5472
1Hit!!
ゲームクリア
5回以内のクリアを目指そう!

実行例3(5回以内で成功)

1回目(1/8):****
4桁の数字を当ててね>>0000
2回目(2/8):****
4桁の数字を当ててね>>1111
3回目(3/8):****
4桁の数字を当ててね>>2222
1Hit!!
4回目(4/8):**2*
4桁の数字を当ててね>>3323
1Hit!!
5回目(5/8):**23
4桁の数字を当ててね>>4423
2Hit!!
ゲームクリア
爆速クリア!凄すぎる!もはや君に勝てる者はいない!

注意点

一度オープンされた数字が再び*になることはない。

1回目(1/8):****
4桁の数字を当ててね>>0000
1Hit!!
2回目(2/8):**0*
4桁の数字を当ててね>>1111 (ここで3桁目の入力を間違えているが0が*に戻ることはない)
3回目(3/8):**0*
4桁の数字を当ててね>>

Let’s challenge

さあ、どうする?人の数分だけやり方がある感じだ。やはりポイントはデータをどう持つかという点だ。

解答例

桁ごとに当てたかそうでないかを管理しなければならないので以下のようなデータ構造で行うのはどうだろうか?

ans=[[4,False],[2,False],[8,False],[2,False]]

2次元リストを用意して正しい数字と当てたか?をペアに持たせる構造だ。
やってみよう。

import random
ans=[[random.randint(0,9),False] for i in range(4)]
# **2*のようなステータス表示関数
def show_status():
    s=str()
    for n in ans:
        s += str(n[0]) if n[1] == True else '*'
    return s

# クリアーしたかを判定する関数
def check_clear():
    for n in ans:
        if n[1]==False:
            return False
    return True

for i in range(8):
    print(f'{i+1}回目({i+1}/{MAX_COUNT}):{show_status()}')
    user=[ int(n) for n in input('4桁の数字を当ててね>>')]
    hit_count=0
    for idx in range(len(user)):
        if ans[idx][1]==False and user[idx]== ans[idx][0]:
            hit_count+=1
            ans[idx][1]=True
    if hit_count>0:
        print(f'{hit_count}ヒット!')
        if check_clear():
            if i > 5:
                print('ゲームクリア!5回以内のクリアを目指そう!')
            else:
                print('爆速クリア!すごすぎる!もはや君に勝てるものはいない!')
            break
else:
    ans_str=''.join([str(n[0]) for n in ans])
    print(f'残念...答えは{ans_str}でした')

実現はできた。。。
ただ、もう少しいい方法がありそうだ。
データにTrue,Falseを持たせるのではなく。****という文字列で直接「当てたかどうか」を管理したほうがいいかもしれない。
また、先程の例では数字をintで管理しているが、今回計算することはないので数字も文字列でやったほうがよさそうだ。
そこらへんを考慮してもう一度やってみよう。

import random
disp=['*' for i in range(4)]
ans=[str(random.randrange(10)) for i in range(4)]
for i in range(8):
    print(f'{i+1}回目({(i+1)}/8):{"".join(disp)}')
    user=[ c for c in input('4桁の数字を当ててね>>')]
    hit_count=0
    for j in range(4):
        if disp[j]=='*' and ans[j]==user[j]:
            hit_count+=1
            disp[j]=ans[j]
    if hit_count>0:
        print(f'{hit_count}Hit!!')
        if disp.count('*') == 0:
            print('ゲームクリア')
            if i>5:
                print('5回以内のクリアを目指そう!')
            else:
                print('爆速クリア!凄すぎる!もはや君に勝てる者はいない!')
            break
else:
    print(f'残念...答えは{"".join(ans)}でした')

OK!!!!
冗長な部分がない。実にご機嫌なコードができた!
最後にマジックナンバーを定数化しておこう。

import random
LENGTH=4 #桁数
MAX_COUNT=8 #最大試行回数
disp=['*'] *LENGTH
ans=[str(random.randrange(10)) for i in range(LENGTH)]
for i in range(MAX_COUNT):
    print(f'{i+1}回目({(i+1)}/{MAX_COUNT}):{"".join(disp)}')
    user=[ c for c in input(f'{LENGTH}桁の数字を当ててね>>')]
    hit_count=0
    for j in range(LENGTH):
        if disp[j]=='*' and ans[j]==user[j]:
            hit_count+=1
            disp[j]=ans[j]
    if hit_count>0:
        print(f'{hit_count}Hit!!')
        if disp.count('*') == 0:
            print('ゲームクリア')
            if i>5:
                print('5回以内のクリアを目指そう!')
            else:
                print('爆速クリア!凄すぎる!もはや君に勝てる者はいない!')
            break
else:
    print(f'残念...答えは{"".join(ans)}でした')

発展

少し推理できる部分も加えよう。入力された答えと正答を比べて「もっと上だよ」と「もっと下だよ」のヒントが表示されるようにする。

実行例

1回目(1/8):****
4桁の数字を当ててね>>5555
もっと下だよ
2回目(2/8):****
4桁の数字を当ててね>>3333
2Hit!!
もっと下だよ
3回目(3/8):*33*
4桁の数字を当ててね>>1335
1Hit!!
もっと下だよ
4回目(4/8):133*
4桁の数字を当ててね>>1332
1Hit!!
ゲームクリア
爆速クリア!凄すぎる!もはや君に勝てる者はいない!
import random
LENGTH=4 #桁数
MAX_COUNT=8 #最大試行回数
disp=['*'] *LENGTH
ans=[str(random.randrange(10)) for i in range(LENGTH)]
for i in range(MAX_COUNT):
    print(f'{i+1}回目({(i+1)}/{MAX_COUNT}):{"".join(disp)}')
    user=
    hit_count=0
    for j in range(LENGTH):
        if disp[j]=='*' and ans[j]==user[j]:
            hit_count+=1
            disp[j]=ans[j]
    if hit_count>0:
        print(f'{hit_count}Hit!!')
        if disp.count('*') == 0:
            print('ゲームクリア')
            if i>5:
                print('5回以内のクリアを目指そう!')
            else:
                print('爆速クリア!凄すぎる!もはや君に勝てる者はいない!')
            break
    if i == MAX_COUNT-1:
        pass
    elif int("".join(ans)) > int("".join(user)):
        print('もっと上だよ')
    else:
        print('もっと下だよ')
else:
    print(f'残念...答えは{"".join(ans)}でした')
python
スポンサーリンク
シェアする
mjpurinをフォローする
ジョイタスネット

コメント

タイトルとURLをコピーしました