質問投稿の直前に自己解決したが、後から同じ問題に直面した人のために投稿し、解決方法を記す。
実現したいこと
- あるカードゲームのデッキをtxtファイルから読み込みたい。
- カードデータをディクショナリの形に変換し、ゲーム内で個別に参照・操作できるようにしたい。
前提
Pythonでカードゲームのプログラムを作っており、ゲームに用いるデッキをtxtファイルから読み込む機能を実装しようとしています。
ファイルパスの指定およびメッセージの表示にtkinterのfiledialogモジュールを使用しています。
カード情報には色とカード名があり、txtファイルではそれらのカード情報、およびカード枚数を指定しています。
発生した問題
該当コードの114行目の操作で問題が起こりました。
デッキMAIN_deck
に格納される情報は以下のようになっています。
Python
1MAIN_deck = [{"name":"カード名", "color":色, "tap":カードの状態(T/F), "select":選択中か否か(T/F), "position":カードの座標}, 2 {"name":"カード名", "color":色, "tap":カードの状態(T/F), "select":選択中か否か(T/F), "position":カードの座標}, 3 ...]
例えば、MAIN_deck
の0番目から3番目が同じ名前のカードのとき、0番目のカードに対して
Python
1MAIN_deck[0]['position'] = [100,0]
のように操作をした場合、MAIN_deck[0]
からMAIN_deck[3]
までのすべてについて、キー'position'
の値が[100,0]
に変更されてしまいます。
MAIN_deck[0]
以外のカードの情報を変えることなくMAIN_deck[0]
の情報を操作できるのが理想です。
該当のソースコード
Python
1from tkinter import filedialog 2from tkinter import messagebox 3 4# 色の設定 5# 原色 6red = (255, 0, 0) 7green = (0, 255, 0) 8blue = (0, 0, 255) 9yellow = (255, 255, 0) 10purple = (255, 0, 255) 11black = (0, 0, 0) 12white = (255, 255, 255) 13# 各文明 14light = (255, 255, 120) 15water = (120, 120, 255) 16darkness = (120, 120, 120) 17fire = (255, 120, 120) 18nature = (120, 255, 120) 19zero = white 20 21# txtファイル内の文字と色を対応させる関数 22def color_read(color): 23 if color in ["白", "光"]: 24 return light 25 elif color in ["青", "水"]: 26 return water 27 elif color in ["黒", "闇"]: 28 return darkness 29 elif color in ["赤", "火"]: 30 return fire 31 elif color in ["緑", "自然"]: 32 return nature 33 elif color in ["無", "零", "ゼロ"]: 34 return white 35 else: 36 return purple 37 38# txtファイルからデッキを読み取る関数 39def deck_read(): 40 # ファイルパスを格納する変数 41 # tkinter の filedialog によってブラウズウィンドウを表示、ファイル名を参照 42 file = filedialog.askopenfilename() 43 44 45 # ファイルが指定されなかったら空のデッキを返す 46 if file == "": 47 return [] 48 # txt ファイルでなければエラーメッセージを表示して空のデッキを返す 49 elif file[-3:] != "txt": 50 messagebox.showerror("Duel Masters", "txtファイルを選択してください") 51 return [] 52 53 # txt ファイルなら開く 54 else: 55 f = open(file,"r",encoding="utf-8") 56 57 # カードを入れるリスト 58 MAIN_deck = [] 59 60 61 # 1行ずつ処理 62 for line in f: 63 # 全角空白を半角空白に置換 64 line = line.replace("\n","") 65 66 # その行が空でなければ処理 67 if line != "": 68 # 最初の文字がカードの文明なら処理 69 if line[:1] in ("白", "青", "黒", "赤", "緑", "無", "光", "水", "闇", "火", "自", "零", "ゼ") and line[:2] != "零龍": 70 # その行を半角空白で分割、カード情報のリストにする 71 card_info_list = line.replace("\u3000"," ").split(" ") 72 # カード名を入れる変数 73 card_name = "" 74 # カードの枚数を入れる変数 75 card_value = 0 76 # カードの枚数が入力されていなかったら処理 77 if card_info_list[-1].isdigit() == False: 78 # カード情報が文明のみになるまで名前を結合 79 # カード名に空白が含まれている場合の処理 80 while len(card_info_list)>=2: 81 card_name += card_info_list[1] 82 card_info_list.pop(1) 83 # カード枚数を1枚に指定 84 card_value = 1 85 # カードデータの完成 86 card_info = {"name":card_name, "color":color_read(card_info_list[0]), "tap":False, "select":False, "position":[], "reverse":False} 87 else: 88 # カード情報が文明のみになるまで名前を結合 89 # カード名に空白が含まれている場合の処理 90 while len(card_info_list)>=3: 91 card_name += card_info_list[1] 92 card_info_list.pop(1) 93 # カード枚数を入力通りに指定 94 card_value = int(card_info_list[-1]) 95 # カードデータの完成 96 card_info = {"name":card_name, "color":color_read(card_info_list[0]), "tap":False, "select":False, "position":[], "reverse":False} 97 98 for i in range(card_value): 99 MAIN_deck.append(card_info) 100 101 # ファイルを閉じる 102 f.close() 103 104 #登録完了のメッセージ 105 messagebox.showinfo("Notice","デッキを登録しました") 106 # 読み取ったデッキを返す 107 return MAIN_deck 108 109# メイン部分 110# デッキを読み込み 111deck = deck_read() 112# デッキ内のカードそれぞれに番号を割り当てる 113for i in range(len(deck)): 114 deck[i]["card_num"] = i # ここがうまくいかない 115# 読み取ったデッキを表示 116print(deck)
テキストファイルのサンプル
- 色 カード名 枚数 の順に記述
- 全角スペースと半角スペースは区別しない
txt
1青黒緑 カード1 4 2緑 カード2 4 3緑 カード3 3 4青赤緑 カード4 4 5白 カード5 4 6白黒赤 カード6 2 7白青赤 カード7 4 8白黒赤 カード8 4 9黒 カード9 4 10赤緑 カード10 1 11白青 カード11 1 12青黒緑 カード12 1 13黒 カード13 1 14青 カード14 1 15緑 カード15 2
想定していた実行結果
キー'card_num'
の値は0から39、1枚ごとに異なる
[{'name': 'カード1', 'color': (255, 0, 255), 'tap': False, 'select': False, 'position': [], 'reverse': False, 'card_num': 0}, {'name': 'カード1', 'color': (255, 0, 255), 'tap': False, 'select': False, 'position': [], 'reverse': False, 'card_num': 1}, {'name': 'カード1', 'color': (255, 0, 255), 'tap': False, 'select': False, 'position': [], 'reverse': False, 'card_num': 2}, {'name': 'カード1', 'color': (255, 0, 255), 'tap': False, 'select': False, 'position': [], 'reverse': False, 'card_num': 3}, {'name': 'カード2', 'color': (120, 255, 120), 'tap': False, 'select': False, 'position': [], 'reverse': False, 'card_num': 4}, ...]
実際の実行結果
キー'card_num'
の値が同名カードで同じ値になっている
[{'name': 'カード1', 'color': (255, 0, 255), 'tap': False, 'select': False, 'position': [], 'reverse': False, 'card_num': 3}, {'name': 'カード1', 'color': (255, 0, 255), 'tap': False, 'select': False, 'position': [], 'reverse': False, 'card_num': 3}, {'name': 'カード1', 'color': (255, 0, 255), 'tap': False, 'select': False, 'position': [], 'reverse': False, 'card_num': 3}, {'name': 'カード1', 'color': (255, 0, 255), 'tap': False, 'select': False, 'position': [], 'reverse': False, 'card_num': 3}, {'name': 'カード2', 'color': (120, 255, 120), 'tap': False, 'select': False, 'position': [], 'reverse': False, 'card_num': 7}, ...]
試したこと
- より単純な以下のコード
dict_test.py
で実験。正しく処理され、想定通りの結果となった。
Python
1# dict_test.py 2dic_list = [] 3 4for i in range(4): 5 dic_list.append({"name":"a", "grade":1, "student":True}) 6 7for i in range(3): 8 dic_list.append({"name":"b", "grade":1, "student":True}) 9 10for i in range(2): 11 dic_list.append({"name":"c", "grade":3, "student":True}) 12 13for i in range(len(dic_list)): 14 dic_list[i]["num"] = i 15 16print(dic_list)
Python
1# 実行結果 2[{'name': 'a', 'grade': 1, 'student': True, 'num': 0}, {'name': 'a', 'grade': 1, 'student': True, 'num': 1}, {'name': 'a', 'grade': 1, 'student': True, 'num': 2}, {'name': 'a', 'grade': 1, 'student': True, 'num': 3}, {'name': 'b', 'grade': 1, 'student': True, 'num': 4}, {'name': 'b', 'grade': 1, 'student': True, 'num': 5}, {'name': 'b', 'grade': 1, 'student': True, 'num': 6}, {'name': 'c', 'grade': 3, 'student': True, 'num': 7}, {'name': 'c', 'grade': 3, 'student': True, 'num': 8}]
dict_test.py
を少し書き換えたプログラムdict_test2.py
を実行した。今回質問するに至った問題が再現された。
Python
1# dict_test2.py 2dic_list = [] 3a = {"name":"a", "grade":1, "student":True} 4b = {"name":"b", "grade":1, "student":True} 5c = {"name":"c", "grade":3, "student":True} 6 7for i in range(4): 8 dic_list.append(a) 9 10for i in range(3): 11 dic_list.append(b) 12 13for i in range(2): 14 dic_list.append(b) 15 16for i in range(len(dic_list)): 17 dic_list[i]["num"] = i 18 19print(dic_list)
Python
1# 実行結果 2[{'name': 'a', 'grade': 1, 'student': True, 'num': 3}, {'name': 'a', 'grade': 1, 'student': True, 'num': 3}, {'name': 'a', 'grade': 1, 'student': True, 'num': 3}, {'name': 'a', 'grade': 1, 'student': True, 'num': 3}, {'name': 'b', 'grade': 1, 'student': True, 'num': 8}, {'name': 'b', 'grade': 1, 'student': True, 'num': 8}, {'name': 'b', 'grade': 1, 'student': True, 'num': 8}, {'name': 'b', 'grade': 1, 'student': True, 'num': 8}, {'name': 'b', 'grade': 1, 'student': True, 'num': 8}]
補足情報(FW/ツールのバージョンなど)
- Python 3.10.4
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/03/11 08:17