はじめに
今回はヒット&ブローゲームを完成版とさせていく
参考:
- マークダウン記法 : https://qiita.com/kamorits/items/6f342da395ad57468ae3
- 西谷教授Qiita : https://qiita.com/drafts/c0b34f8c6ad82a2443bd
- 前回記事 : https://qiita.com/Bokkun321/private/9113d525cf72e06d0375
ウィンドウ表示
前回作成したコード では、VSCODE上でのみ動作し、プレイヤーからすると非常に扱いにくい。
そこで、ウィンドウ表示というものが登場する。
Pythonにおいてはtkinterをimportすることによってウィンドウ表示が実現される。
import tkinter as tk #tkinterをimport
root = tk.Tk() #window作成
root.geometry("400x150") #windowのサイズ指定
root.title("ヒット&ブロー") #windowのタイトル指定
root.mainloop() #windowの表示
このようにroot . 実行したい操作という形でウィンドウの表示が実現。
また、root.geometry("400x150")の数字を書き換えることによってウィンドウの大きさを変更可能。
実行後に表示されたウィンドウ
メッセージの表示とボタンの配置
これだけだと何もできないように感じるだろう。
そこで、さらに拡張しメッセージを表示してみる。
#coding=utf-8
import tkinter as tk #tkinterをimport
root = tk.Tk() #window作成
root.geometry("400x150") #windowのサイズ指定
root.title("ヒット&ブロー") #windowのタイトル指定
#ここからが書き足したコード
labell = tk.Label(root, text="数を入力してね", font=("Helvetica",14))
labell.place(x = 20, y = 20)
#ここまで
root.mainloop() #windowの表示
このように、tk.Label(root, text="表示させたい文字", font=("フォント名",フォントサイズ)とすることで表示させたいテキストを作製できる。
label.place(x = ~, y = ~)によって文字の表示位置が指定される。
mainloop
はwindowの設定の最後に置くことに注意。
実行結果
入力とボタンの設置
ゲームにおいてはプレイヤーに見えるようにするだけでなく、操作してもらう必要がある。
そこで、このゲームにおける操作である数値の入力を可能にする。
editbox1 = tk.Entry(width = 4, font =("Helvetica", 28)) #入力欄をeditbox1に代入
editbox1.place(x = 120, y=60)
button1 = tk.Button(root, text = "チェック", font=("Helvetica",14), command=ButtonClick) #ボタンをbutton1に代入
button1.place(x = 220, y = 60)
実現したい行動 | コード |
---|---|
入力欄の作成 | tk.Entry(width = 数値, font = ("フォント名", フォントサイズ) |
ボタンの作成 | button1 = tk.Button(root, text = "チェック", font=("Helvetica",14) |
ここで、下の二行は文字の表示で説明したように、それぞれの位置の指定を行っている。
editbox1.place(x = 120, y=60)
button1.place(x = 220, y = 60)
また、この一行は後で登場するButtonClickという関数との関連をつけている。
command=ButtonClick
関数化
前回作成したコードをここでは関数として扱っていく。
関数を定義するためには、def 関数名():実行したい内容
とする必要がある。
ここでは先ほどのbutton1
が押されるとButtunClick関数が実行されるように作っている。
def ButtonClick():
実行したい内容
button1 = tk.Button(root, text = "チェック", font=("Helvetica",14), command=ButtonClick)
button1.place(x = 220, y = 60)
ここで、関数の定義が関数の使用より上に書かれているということは
定義は先に行う必要があるということなのだろうか。
print関数から卒業
これまでのコードでは、print()
というものを用いてきたがそれではプレイヤーからは見にくいだろう。
そこで登場するのがshowinfo
やshowerror
というパッケージだ。
これを使用すると、プレイヤーの入力に対するメッセージを新しいウィンドウとして表示することができる。
またそのためにはtkinter.messageboxをimportする必要がある。
#coding = utf-8
import tkinter as tk
import tkinter.messagebox as tkmbox #省略のため、tkmboxと名を指定してimportする
b = editbox1.get() #入力された文字をbに代入
tkmbox.showinfo("入力されたテキスト" , b) #bを表示
例として、このようにプレイヤーからの入力を新しいウィンドウとして表示することもできる。
また、if文等と組み合わせることによって特定の条件を満たしたときにエラーメッセージを表示させることも可能だ。
tkmbox.showerror("error","4桁にしてください")
数値の生成
前回と同様に数値を生成する。
a = [random.randint(0,9),
random.randint(0,9),
random.randint(0,9),
random.randint(0,9)]
ここで注意しなくてはならないのは、数値の生成は先ほど作成したButtunClick関数
の外側で行われなければならないという点だ。
関数が実行されるたび、つまりプレイヤーがボタンを押すたびに答えが変わってしまうのではたまったものではない。
つまり、数値の生成は一度きりでなくてはならない。
よって、関数が実行される前に一度だけ上記の文が実行される必要がある。
完成
ここまでくれば、あとは組み合わせるだけだ。
今回説明したものと、前回作成したコードを組み合わせ、若干の書き換え(printからshowinfoへ)を行うことによって完成する。
if hit == 4:
tkmbox.showinfo("あたり~","おめでとう!大当たり!")
root.destroy()
これは、最後の条件であるヒット数が4に達したときゲームを終了するコードだ。root.destrooy()
が実行されることによって、ウィンドウが閉じられる。
反省点
- printをshowinfoに書き換えるのを忘れる
- 関数内にwhile文削除し忘れによって入れてしまい、エラーメッセージが無限に表示される。
- mainloop()文を最後に置き忘れてウィンドウの表示に失敗。
- mainloopの綴りをmainroopと間違えることによりエラー
感想
1行1行デバッグを行い、バグが最小限に収まるよう努めるのはもちろんだが、後々修正しやすいよう、見やすいコーディングを心掛けることは大事だとわかった。また、今後自分以外に自身が作ったプログラムを使用、改造されることを考えると、どこになんの内容が書かれており、何を行っているのかを分かりやすくコメントすることも大切だと思った。
完成形
#coding = utf-8
import random
import tkinter as tk
import tkinter.messagebox as tkmbox
#ここからButtonClick関数
def ButtonClick():
b = editbox1.get()
tkmbox.showinfo("入力されたテキスト" , b)
tkmbox.showinfo("答え","こたえは"+str(a)) #テスト時の答え確認用
isok = False
if len(b) != 4 :
tkmbox.showerror("error","4桁にしてください")
else:
kazuok=True
for i in range(4):
if (b[i]<"0") or (b[i]>"9"): #もしすべての桁が数字であったなら、if文は判定だけ行った後、中身は実行されないので,次のif文に進む
tkmbox.showerror("error","数字ではありません")
kazuok = False
break
if kazuok :
isok = True
hit = 0 #初期化
for i in range(4):
if a[i] == int(b[i]):
hit = hit + 1
blow = 0 #初期化
for j in range(4): #b[0]からb[3]まで
for i in range(4): #bのそれぞれの要素とa[0]からa[3]までを比較
if (int(b[j]) == a[i]) and (a[i] != int(b[i])) and (a[j] != int(b[j])):
blow = blow + 1
break #breakすると、jの数が一つ進み、for j に戻り、b[j]がb[3]まで終了するとfor文を抜け出す
if hit == 4:
tkmbox.showinfo("あたり~","おめでとう!大当たり!")
root.destroy()
else:
tkmbox.showinfo("ヒント!", "ヒット数" + str(hit) + "/" + "ブロー数" + str(blow))
a = [random.randint(0,9),
random.randint(0,9),
random.randint(0,9),
random.randint(0,9)]
#ウィンドウ表示に関する
root = tk.Tk()
root.geometry("400x150")
root.title("ヒット&ブロー")
labell = tk.Label(root, text="数を入力してね", font=("Helvetica",14))
labell.place(x = 20, y = 20)
editbox1 = tk.Entry(width = 4, font =("Helvetica", 28))
editbox1.place(x = 120, y=60)
button1 = tk.Button(root, text = "チェック", font=("Helvetica",14), command=ButtonClick) #クリックされない限りはただ表示され続ける
button1.place(x = 220, y = 60)
root.mainloop()