tkinterで簡単なゲームを作っています。
内容としては、二人のプレイヤーで行い、順番にゲームに指定された範囲で好きな数字を入力、ゲームがそれらをリストに保存しておき、その中からランダムに何番目かの数字を思い出させ、正しく答えられなかった方の負け、と言うゲームです。勝敗が決まるまでターンを交代して行います。
質問はゲーム内容に直接は関係ないですが、
現在の設計ではゲームの進行をする部分と、playerとのインターフェース(inputを受け取ったり、質問をしたり)の部分を同じMyGameクラスが担っていますが、これらの機能は別々のクラスに分けた方が、ソフトウェア設計的にはよいですか? つまり、勝ち負けを判定したり、数字を保存したりする部分と入力を受け取ったり表示したりする部分を分けた方がよいですか?
(また、何かソフトウェア設計的にまずそうなところにお気づきになれば教えていただけると幸いです。)
python
1import sys 2import tkinter 3import random 4import time 5import sys 6from tkinter.font import Font 7 8 9class Player: 10 def __init__(self, name): 11 self.name = name 12 self.numbers = [] 13 def __eq__(self, other): 14 return self.name == other 15 16 17class MyGame: 18 def __init__(self, main_label, name_label_1, name_label_2, entry_1, entry_2, button): 19 self.main_label = main_label 20 self.name_label_1 = name_label_1 21 self.name_label_2 = name_label_2 22 self.entry_1 = entry_1 23 self.entry_2 = entry_2 24 self.button = button 25 26 self.idx = None 27 self.rand = None 28 self.done = False 29 self.seed = int(time.time()) 30 random.seed(self.seed) 31 32 # playerの名前をentryから取得, それを元にplayerをインスタンス化 33 def get_names(self): 34 self.button.bind('<Button-1>', self.get_new_number) # 以後はボタンを押すとget_new_numberが呼ばれる 35 root.bind("<Return>", self.get_new_number) 36 self.button.config(text="OK") 37 name_1, name_2 = self.entry_1.get(), self.entry_2.get() 38 self.entry_1.delete(0, "end") 39 self.entry_2.delete(0, "end") 40 self.name_label_1.config(text=name_1, font=Font(family="Courier", size=24)) 41 self.name_label_2.config(text=name_2, font=Font(family="Courier", size=24)) 42 self.player_1 = Player(name_1) 43 self.player_2 = Player(name_2) 44 self.players = [self.player_1, self.player_2] 45 self.cur_player = None 46 self.input_from_player = None 47 48 # どっちのentryに名前を書いても順番がランダムになるように 49 def decide_order(self): 50 if random.uniform(0, 1) < 0.5: 51 self.players = [self.player_2, self.player_1] 52 self.cur_player = self.players[0] 53 54 # 新たな数字の入力を促す 55 def ask_new_number(self): 56 self.rand = int(random.uniform(0, 100)) 57 self.main_label.config( 58 text=f"{self.cur_player.name}のターンです!\n新しい数字を入力してください: {self.rand-4} ~ {self.rand+4}", 59 font=Font(family="Helvetica", size=18)) 60 self.button.bind('<Button-1>', self.get_new_number) 61 root.bind("<Return>", self.get_new_number) 62 63 # 入力の範囲が誤っていた時にもう一度取得 64 def get_correct_new_number(self, event): 65 if self.cur_player == self.player_1: 66 input_1 = entry_1.get() 67 self.entry_1.delete(0, "end") 68 self.input_from_player = int(input_1) 69 else: 70 input_2 = entry_2.get() 71 self.entry_2.delete(0, "end") 72 self.input_from_player = int(input_2) 73 74 # 新たに入力された数字を取得する 75 def get_new_number(self, event): 76 if self.cur_player == self.player_1: 77 input_1 = entry_1.get() 78 self.entry_1.delete(0, "end") 79 self.input_from_player = int(input_1) 80 else: 81 input_2 = entry_2.get() 82 self.entry_2.delete(0, "end") 83 self.input_from_player = int(input_2) 84 85 # TODO: make it not freeze... 86 if self.input_from_player < self.rand-4 or self.rand+4 < self.input_from_player: 87 self.main_label.config( 88 text=f"範囲外です。もう一度入力してください: {self.rand-4} ~ {self.rand+4}\n", 89 font=Font(family="Helvetica", size=18)) 90 self.button.bind('<Button-1>', self.get_correct_new_number) 91 root.bind("<Return>", self.get_correct_new_number) 92 93 self.cur_player.numbers.append(self.input_from_player) 94 95 self.idx = random.choice(range(1, len(self.cur_player.numbers)+1)) 96 self.main_label.config(text=f"{self.idx}番目に入力した数字はなんでしたか?\n",font=Font(family="Helvetica", size=18)) 97 98 self.button.bind('<Button-1>', self.get_past_number) 99 root.bind("<Return>", self.get_past_number) 100 101 # 過去の数字に関する質問の答えを取得し、勝ち負け判断。 102 # 決まらなければ、次のplayerに新たな数字を聞く。以下繰り返し。 103 def get_past_number(self, event): 104 if self.cur_player == self.player_1: 105 input_1 = entry_1.get() 106 self.entry_1.delete(0, "end") 107 self.input_from_player = int(input_1) 108 else: 109 input_2 = entry_2.get() 110 self.entry_2.delete(0, "end") 111 self.input_from_player = int(input_2) 112 113 true = self.cur_player.numbers[self.idx-1] 114 if self.input_from_player != true: 115 self.main_label.config( 116 text=f"{self.cur_player.name}の負けです:(\n\n正しい答えは{true}ですが、{self.cur_player.name}は{self.input_from_player}と答えました:(", 117 font=Font(family="Helvetica", size=18)) 118 self.done = True 119 120 if self.done: 121 #self.main_label.config(text=f"Finished!", font=Font(family="Courier", size=18)) 122 self.button.config(text="Exit", font=Font(family="Courier", size=15)) 123 self.button.bind('<Button-1>', self.exit) 124 else: 125 126 self.cur_player = [self.player for self.player in self.players if self.player != self.cur_player][0] 127 self.set_focus_on_entry() 128 self.ask_new_number() 129 130 # windowを閉じる 131 def exit(self, event): 132 sys.exit() 133 134 # 回答を求めるプレイヤーのentryにファーカスを当てる 135 def set_focus_on_entry(self): 136 if self.cur_player == self.player_1: 137 entry_1.focus_set() 138 else: 139 entry_2.focus_set() 140 141 def main(self, event): 142 self.get_names() 143 self.decide_order() 144 145 self.set_focus_on_entry() 146 self.rand = int(random.uniform(0, 100)) 147 self.main_label.config( 148 text=f"{self.cur_player.name}のターンです!\n新しい数字を入力してください: {self.rand-4} ~ {self.rand+4}", 149 font=Font(family="Helvetica", size=18)) 150 151 152if __name__ == '__main__': 153 # 箱を用意 154 root = tkinter.Tk() 155 root.title("kazuoboe") 156 root.geometry("700x500") 157 158 # 各widgetを用意 159 main_label = tkinter.Label(root, text="Welcome to Kazuoboe!", font=Font(family="Courier", size=24)) 160 main_label.place(x=350, y=100, anchor="center") 161 162 name_label_1 = tkinter.Label(root, text="Enter your name :)", font=Font(family="Courier", size=18)) 163 name_label_1.place(x=200, y=200, anchor="center") 164 165 name_label_2 = tkinter.Label(root, text="Enter your name :)", font=Font(family="Courier", size=18)) 166 name_label_2.place(x=500, y=200, anchor="center") 167 168 entry_1 = tkinter.Entry(root, width=10) 169 entry_1.place(x=200, y=250, anchor="center") 170 entry_1.focus_set() 171 172 entry_2 = tkinter.Entry(root, width=10) 173 entry_2.place(x=500, y=250, anchor="center") 174 175 button = tkinter.Button(root, text=u'Start', width=10, font=Font(family="Courier", size=15)) 176 button.place(x=350, y=350, anchor="center") 177 178 # widgetを持ったgameインスタンスを作成 179 mygame = MyGame(main_label, name_label_1, name_label_2, entry_1, entry_2, button) 180 181 # startボタンが押されたらgameインスタンスのmain()が呼ばれて開始 182 button.bind('<Button-1>', mygame.main) 183 root.bind("<Return>", mygame.main) 184 root.mainloop()
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/05/05 03:20