حتى الآن كانت اللوحة تُعطى لك جاهزة كقائمة متداخلة. لكن في البرنامج الكامل يجب أن تنشئها بنفسك.
هذا كود يبدو قريبًا من الحل:
__copyable__ __program_indented__
الكود قريب جدًا، لكن توجد مشكلة خفية. تأكد أنك تفهم ما يفعله، وحاول اكتشاف الخطأ إن استطعت. إذا لم تره سريعًا فلا تضيع وقتًا كبيرًا؛ المشكلة دقيقة.
أحسنت!
يمكن حل المشكلة بنقل الحلقة الأولى إلى داخل الحلقة الثانية حتى ننشئ row جديدة في كل مرة:
def make_board(size): board = [] for _ in range(size): row = [] for _ in range(size): row.append(' ') board.append(row) return board
وهناك طريقة أخرى: أن تنشئ نسخة من row في كل مرة. يمكنك إبقاء الكود الأصلي وتغيير سطر واحد فقط إلى:
board.append(row.copy())
ويمكن نسخ row أيضًا باستخدام row[:] أو list(row). لكن من المهم أن تعرف أن هذه الطرق كلها تصنع نسخة سطحية (shallow copy) من القائمة. أي إنها تنسخ القائمة في المستوى الأعلى، ولا تنشئ نسخًا مستقلة من كل عنصر بداخلها. هذا مناسب هنا لأن row تحتوي نصوصًا لا تُعدّل في مكانها، ولذلك لا تحتاج عناصرها إلى نسخ.
لكن إذا كانت العناصر نفسها كائنات قابلة للتعديل مثل القوائم، كما هو الحال مع board، فقد تظهر المشكلة نفسها على مستوى أعمق. انظر إلى هذا المثال:
__copyable__ def make_board(size): row = [] for _ in range(size): row.append(' ') board = [] for _ in range(size): board.append(row.copy()) return board
def make_cube(size): cube = [] board = make_board(size) for _ in range(size): cube.append(board.copy()) return cube
def test(): cube = make_cube(2) print(cube) cube[0][0][0] = 'X' print(cube) print(cube[0] is cube[1]) print(cube[0][0] is cube[0][1]) print(cube[0][0] is cube[1][0])
test()
كل عنصر في cube هنا قائمة مستقلة لأنها نسخة من board. وداخل كل نسخة من board توجد قوائم صفوف. لكن لأننا استخدمنا نسخة سطحية من board، فإن نسخ board المختلفة ما زالت تشترك في كائنات الصفوف الداخلية نفسها: العنصر الأول داخل كل نسخة يشير إلى نسخة row الأولى نفسها، والعنصر الثاني إلى الكائن نفسه في الموضع الثاني، وهكذا.
تعديل make_board وحده لا يحل مشكلة النسخ في cube. لديك حلان عامان:
make_board من جديد في كل مرة لتنشئ board مستقلة تمامًا.deepcopy بدل board.copy() عندما تحتاج إلى نسخ المستويات الداخلية أيضًا. تقوم deepcopy بإنشاء نسخ عبر مستويات الكائنات المتداخلة بدل نسخ المستوى الأعلى فقط.إذا بدت هذه الفكرة مربكة الآن فلا مشكلة. الهدف أن تتعرف مبكرًا على سبب محتمل لسلوك غريب في البرامج التي تحتوي كائنات متداخلة قابلة للتعديل. لست مطالبًا بإتقان النسخ العميق الآن، وما تعلمته في هذا الدرس سيظل مفيدًا.
أصبحنا الآن جاهزين لتجميع اللعبة كاملة.