العصف الذهني: كيف ننظر إلى المهام من زاوية مختلفة

العصف الذهني مع تبديل


في بعض الأحيان أتعثر وأبحث عن طرق للتفكير في المهمة من زاوية مختلفة. هناك مهام يمكن عرضها في شكل مصفوفة أو جدول. يبدو هيكلها شيء مثل هذا:

ABCDE
1A1B1C1D1E1
2A2B2C2D2E2
3A3B3C3D3E3
4A4B4C4D4E4
5A5B5C5D5E5

الخلايا التي أعمل معها مرتبة في أعمدة وصفوف. لنأخذ مثالا من لعبة بسيطة:

هجومالدفاعخاص
مقاتلسيفدرعضربة عنيفة
بركهكرة ناريةتعكستجمد
لصخنجرمراوغةنزع سلاح

خطوط هي فئات شخصية: المحارب ، ماجى ، اللص.

الأعمدة هي أنواع من الإجراءات: الهجوم والدفاع والإجراء الخاص.

تحتوي المصفوفة على كل رمز معالجة كل نوع من أنواع الإجراءات لكل نوع من الأحرف.

كيف تبدو الكود؟ عادة ، يتم تنظيم هذه الهياكل في هذه الوحدات:

  1. سوف يحتوي Fighter على رمز للتعامل مع ضربات السيف ، وتقليل الأضرار بالدروع وضربة قوية خاصة.
  2. سوف تحتوي Mage على رمز التعامل مع كرة النار ، انعكاسات الأضرار وهجوم التجميد الخاص.
  3. سيحتوي Thief على رمز للتعامل مع هجمات الخنجر ، وتجنب أضرار المراوغة ، وهجوم نزع سلاح خاص.

من المفيد في بعض الأحيان تبديل المصفوفة. يمكننا ترتيبها على محور آخر :

مقاتلبركهلص
هجومسيفكرة ناريةخنجر
الدفاعدرعتعكسمراوغة
خاصضربة عنيفةتجمدنزع سلاح

  1. سوف يحتوي Attack على رمز للتعامل مع التقلبات ، الكرات النارية وهجمات الخنجر.
  2. سوف يحتوي Defend على رمز للتعامل مع الحد من الضرر ، مما يعكس الضرر وتجنب الضرر.
  3. سوف الإرادة Special تحتوي على ضربة قوية ، وتجميد ونزع رمز التعامل مع.

لقد علمت أن أحد الأساليب "جيد" والآخر "سيء". لكن ليس من الواضح لي لماذا يجب أن يكون كل شيء بهذه الطريقة. السبب هو الافتراض بأننا سنضيف غالبًا فئات جديدة من الأحرف (الأسماء) ، ونادراً ما نضيف أنواعًا جديدة من الإجراءات (الأفعال). بهذه الطريقة يمكنني إضافة رمز باستخدام الوحدة النمطية الجديدة دون لمس جميع تلك المتاحة. في لعبتك ، يمكن أن يكون كل شيء مختلفًا. بالنظر إلى المصفوفة المنقولة ، أنا على دراية بوجود الافتراض ويمكنني أن أشك في ذلك. بعد ذلك سوف أفكر في نوع المرونة التي أحتاج إليها ، وعندها فقط سأختار بنية الشفرة.

دعنا ننظر إلى مثال آخر.

تحتوي ترجمة لغات البرمجة على أنواع مختلفة من العقد المقابلة للأولويات: الثوابت ، المشغلات ، الحلقات ، المتفرعة ، الدوال ، الأنواع ، إلخ. نحن بحاجة إلى إنشاء رمز لهم جميعا.

توليد رمز
ثابت
عامل
أنشوطة
فرع
وظيفة
نوع

! ممتاز يمكنك إنشاء فئة واحدة لكل نوع من العقدة ، ويمكنهم أن يرثوا جميعًا من Node الفئة الأساسية. لكننا نعتمد على افتراض أننا سنضيف صفوفًا وأقل عددًا من الأعمدة. ما يحدث في المترجم الأمثل؟ نضيف تمريرات التحسين الجديدة. وكل واحد منهم هو عمود جديد.

توليد رمزتدفق البياناتطي ثابتحلقة الانصهار...
ثابت
عامل
أنشوطة
فرع
وظيفة
نوع

إذا كنت أرغب في إضافة تصريح تحسين جديد ، فسوف أحتاج إلى إضافة طريقة جديدة لكل فئة ، وسيتم توزيع رمز مرور التحسين بالكامل على وحدات مختلفة. أريد تجنب مثل هذا الموقف! لذلك ، في بعض الأنظمة ، تتم إضافة طبقة أخرى فوق هذا. باستخدام نمط الزائر ، يمكنني تخزين كل الشفرة لدمج الحلقات في وحدة واحدة ، بدلاً من تقسيمها إلى ملفات متعددة.

إذا نظرت إلى المصفوفة المنقولة ، فسوف نفتح طريقة أخرى:

ثابتعاملأنشوطةفرعوظيفةنوع
توليد رمز
تدفق البيانات
طي ثابت
SSA
حلقة الانصهار

الآن ، بدلاً من الفئات مع الأساليب ، يمكنني استخدام مطابقة النقوش والمطابقة (غير مدعومة في جميع لغات البرمجة). نتيجةً لذلك ، سيتم تخزين الشفرة الكاملة لكل ممر تحسين معًا ويمكنها الاستغناء عن عدم مباشرة نمط الزائر.

من المفيد غالبًا إلقاء نظرة على المشكلة من وجهة نظر المصفوفة. إذا قمت بتطبيقه على بنية موجهة للكائنات يفكر فيها الجميع ، فقد يؤدي ذلك بي إلى شيء آخر ، على سبيل المثال ، إلى النموذج "نظام الكيان المكون" أو قواعد البيانات ذات الصلة أو البرمجة التفاعلية.

وهذا لا ينطبق فقط على الكود. فيما يلي مثال لتطبيق هذه الفكرة على المنتجات. افترض أن هناك أشخاص لهم اهتمامات مختلفة:

شقفنغسيدأليس
السياراتXX
سياسةXX
الرياضياتXX
سفرXX

إذا كنت أقوم بتطوير موقع للتواصل الاجتماعي ، فقد أسمح للناس بمتابعة أخبار الآخرين. يمكن لـ Nick الاشتراك في Alice لأنهما مهتمان بالسيارات و Fenya لأنهما مهتمان بالسفر. لكن نيك سيتلقى أيضًا منشورات أليس في الرياضيات ووظائف فينيا في السياسة. إذا كنت أفكر في مصفوفة منقولة ، فقد أسمح للأشخاص بالاشتراك في الموضوعات . يمكن أن ينضم نيك إلى مجموعة من محبي السيارات ، فضلاً عن مجموعة من المسافرين. بدأ كل من Facebook و Reddit في نفس الوقت تقريبًا ، لكنهما عبارة عن مصفوفات منقولة عن بعضها البعض. يتيح لك Facebook متابعة الأشخاص ؛ رديت يسمح لك بالاشتراك في المواضيع.

عندما وصلت إلى طريق مسدود أو عندما أرغب في دراسة البدائل ، ألق نظرة على المشكلة وابحث عن محاور ترتيب مختلفة فيها. في بعض الأحيان ، يمكن أن يوفر النظر إلى مشكلة من زاوية مختلفة حلاً أفضل.

التحلل العصف الذهني


أنا استخدم تقنية أخرى تسمى التحلل.

في الجبر ، تحول عملية التحلل متعدد الحدود من النموذج 5x² + 8x - 21 إلى (x + 3) · (5x - 7). لحل المعادلة 5x² + 8x - 21 = 0 ، يمكننا أولاً أن نعالجها في (x + 3) · (5x - 7) = 0. ثم يمكننا القول أن x + 3 = 0 أو 5x - 7 = 0. التوسع يتحول مهمة صعبة إلى عدد قليل من المهام أسهل.

س3
5X5x²15X
-7-7x-21

دعنا نلقي نظرة على مثال: لدي ستة فئات: File ، EncryptedFile ، GzipFile ، EncryptedGzipFile ، BzipFile ، EncryptedBzipFile . يمكنني تحليلها إلى مصفوفة:

غير مضغوطغزيبBzip
غير مشفرةملفGzip (ملف)بزيب (ملف)
مشفرةتشفير (ملف)تشفير (Gzip (ملف))تشفير (Bzip (ملف))

باستخدام نمط "الديكور" (أو الشوائب) ، حولت ستة أنواع مختلفة من الملفات إلى أربعة مكونات: عادي ، gzip ، bzip ، تشفير. لا يبدو أن هذا يوفر الكثير ، لكن إذا أضفت المزيد من الاختلافات ، فستزداد المدخرات. يحول التحلل مكونات O (M * N) إلى مكونات O (M + N).

مثال آخر: في بعض الأحيان يسألني الناس أسئلة مثل "كيفية كتابة الاستيفاء الخطي في C #؟" . يمكنني كتابة العديد من البرامج التعليمية المحتملة:

C ++الثعبانجافاC #جافا سكريبتصدأإدريس...
استيفاء
الجيران
الاستطلاعية
المسافات
خرائط النهر
متساوي القياس
Voronoi
التحويلات
...

إذا كانت هناك مواضيع M ولغات N ، فيمكنني كتابة دروس M * N. ومع ذلك ، هذا كثير من العمل. بدلاً من ذلك ، سأكتب تعليميًا عن الاستيفاء ، وسيقوم شخص آخر بكتابة تعليمي حول C # ، ثم يجمع القارئ معرفة C # مع معرفة الاستيفاء ، ويكتب نسختهم من الاستيفاء في C #.

مثل النقل ، التحلل لا يساعد دائمًا ، لكن إن أمكن ، قد يكون مفيدًا جدًا.

العصف الذهني المتخلف


في الجزءين السابقين ، تحدثت عن الطريقة التي أتناول بها المهمة في بعض الأحيان ، وأحاول ترتيبها في مصفوفة. هذا لا يساعد في بعض الأحيان ، ثم أحاول أن أنظر إلى المهمة في الاتجاه المعاكس. دعونا نلقي نظرة على إنشاء الخريطة الإجرائية ، على سبيل المثال. غالبًا ما أبدأ بوظيفة الضوضاء ، ثم أضف أوكتافات ، واضبط المعلمات ، وأضيف طبقات. أفعل ذلك لأنني بحاجة إلى بطاقات لها خصائص معينة.


من الممكن تمامًا البدء بالتجارب مع المعلمات ، لكن مساحة المعلمة كبيرة جدًا ، ولا يُعرف ما إذا كنت سأعثر على المعلمات الأكثر ملاءمة لمتطلباتي. لذلك ، بعد أن جربت قليلًا ، أتوقف وأبدأ في التفكير بالترتيب العكسي: إذا كان بإمكاني وصف ما أحتاج إليه ، فإن هذا يمكن أن يساعد في العثور على المعلمات.

كان هذا الدافع هو الذي جعلني أدرس علم الجبر. إذا كانت لدينا معادلة للشكل 5x² + 8x - 21 = 0 ، فما هو x ؟ عندما لا أعلم الجبر ، سأحل هذه المعادلة ، وأحاول استبدال قيم مختلفة من x ، أولاً باختيارها عشوائيًا ، ثم ضبطها عندما أشعر بأنني اقتربت من الحل. الجبر يعطينا أداة للذهاب في اتجاه مختلف. بدلاً من تخمين الإجابات ، تعطيني جهازًا (تحلل أو معادلات من الدرجة الثانية أو الطريقة النيوتونية للبحث التكراري عن الجذور) ، والتي يمكنني استخدامها بوعي أكبر للبحث عن قيم x (-3 أو 7/5).

أشعر أنني غالبًا ما أواجه هذا الموقف من البرمجة. أثناء العمل على إنشاء خرائط إجرائية ، بعد تجربة المعلمات لبعض الوقت ، توقفت وأعدت قائمة بما ينبغي أن يكون في عوالم ألعاب مشروع واحد :

  1. يجب أن يبدأ اللاعبون اللعبة بعيدًا عن الساحل.
  2. عند التسوية ، يجب على اللاعبين الصعود شاقة.
  3. يجب ألا يتمكن اللاعبون من الوصول إلى حافة الخريطة.
  4. مع نمو المستوى ، يجب أن ينضم اللاعبون إلى مجموعات.
  5. يجب أن يكون هناك وحوش بسيطة على السواحل دون اختلاف كبير.
  6. على السهول يجب أن يكون هناك مجموعة واسعة من الوحوش من الصعوبة المتوسطة.
  7. في المناطق الجبلية يجب أن يكون هناك وحوش مدرب معقدة.
  8. يجب أن يكون هناك نوع من المعالم التي تسمح للاعبين بالبقاء على نفس المستوى من الصعوبة ، ومعلمًا آخر يسمح لك بالارتفاع أو الهبوط في مستوى الصعوبة.

أدى تجميع هذه القائمة إلى إنشاء القيود التالية:

  1. يجب أن تكون عوالم الألعاب جزرًا بها العديد من السواحل وقمة صغيرة في الوسط.
  2. يجب أن يتوافق الارتفاع مع تعقيد الوحوش.
  3. في الارتفاعات المنخفضة والعالية ، يجب أن يكون هناك تقلب أقل في المناطق الأحيائية مقارنة بالارتفاعات المتوسطة.
  4. يجب أن تظل الطرق على نفس مستوى الصعوبة.
  5. يجب أن تتدفق الأنهار من المرتفعات إلى الصغيرة ، وتوفر للاعبين القدرة على التحرك لأعلى / لأسفل.

أدت هذه القيود لي لتصميم مولد خريطة. وأدى إلى إنشاء مجموعة من البطاقات أفضل بكثير من تلك التي تلقيتها من خلال ضبط المعلمات ، كما أفعل عادةً. وأثار المقال الناتج اهتمام كثير من الناس في إنشاء خرائط تستند إلى مخططات فورونوي.

اختبارات الوحدة هي مثال آخر. يقترح أن أتوصل إلى قائمة من الأمثلة للاختبار. على سبيل المثال ، بالنسبة لشبكات السداسي ، قد أعتقد أنني بحاجة إلى التحقق من add(Hex(1, 2), Hex(3, 4)) == Hex(4, 6) الحالة add(Hex(1, 2), Hex(3, 4)) == Hex(4, 6) . ثم أستطيع أن أتذكر أنك تحتاج إلى التحقق من الأصفار: add(Hex(0, 1), Hex(7, 9)) == Hex(7, 10) . ثم يمكنني أن أتذكر أنك تحتاج إلى التحقق من القيم السلبية: add(Hex(-3, 4) + Hex(7, -8)) == Hex(4, -4) . حسنا ، عظيم ، لدي بعض الاختبارات وحدة.

ولكن إذا كنت تفكر أكثر من ذلك بقليل ، فقد قمت بالفعل بالتحقق من add(Hex(A, B), Hex(C, D)) == Hex(A+C, B+D) . توصلت إلى الأمثلة الثلاثة الموضحة أعلاه بناءً على هذه القاعدة العامة. أنا ذاهب في الاتجاه المعاكس من هذه القاعدة من أجل الوصول إلى اختبارات الوحدة. إذا تمكنت من ترميز هذه القاعدة مباشرة في نظام اختبار ، فسيكون النظام نفسه قادرًا على العمل بترتيب عكسي لإنشاء أمثلة للاختبار. وهذا ما يسمى اختبار الملكية. (انظر أيضا: اختبار التحول )

مثال آخر: حل المعوقات. في مثل هذه الأنظمة ، يصف المستخدم ما يريد رؤيته في المخرجات ، ويجد النظام طريقة لتلبية هذه القيود. اقتباس من كتاب جيل المحتوى الإجرائي ، الفصل الثامن :

باستخدام الأساليب البنّاءة من الفصل 3 ، بالإضافة إلى طرق الكسر والضوضاء من الفصل 4 ، يمكننا إنشاء أنواع مختلفة من بيانات المخرجات عن طريق ضبط الخوارزميات حتى نرضى عن بيانات المخرجات الخاصة بهم. ولكن إذا علمنا بالخصائص التي يجب أن يكون للمحتوى الذي تم إنشاؤه ، فسيكون من المناسب أن نشير بشكل مباشر إلى ما نريده من الخوارزمية العامة أن تجد محتوى يفي بمعاييرنا.

يصف هذا الكتاب برمجة مجموعات الإجابات (ASP) ، التي وصف فيها بنية ما نعمل به (البلاط والأرضيات والجدران ، والبلاط يحد بعضنا البعض) ، وهيكل الحلول التي نبحث عنها (مجموعة الأبراج المحصنة هي مجموعة مربعات متصلة مع البداية والنهاية) وخصائص الحلول (يجب ألا تحتوي الممرات الجانبية على أكثر من 5 غرف ، ويجب أن يكون هناك 1-2 حلقة في المتاهة ، ويجب هزيمة ثلاثة مساعدين قبل الوصول إلى الرئيس). بعد ذلك ، يقوم النظام بإنشاء الحلول الممكنة ويسمح لك بتحديد ما يجب القيام به بها.

في الآونة الأخيرة ، تم تطوير محلل قيد ، مما تسبب في اهتمام كبير بسبب اسمه الرائع وعرضه الغريب: Wave Function Collapse. [يوجد مقال حول هذا حلالًا على Habr.] إذا أعطيته أمثلة على الصور للإشارة إلى القيود المفروضة على البلاط المجاور ، فسيقوم بإنشاء أمثلة جديدة تتوافق مع الأنماط المعطاة. يوصف عمله في WaveFunctionCollapse هو قيد القيد في البرية :

تطبق WFC طريقة بحث جشعة دون الرجوع إلى الوراء. يستكشف هذا المقال WFC كمثال أساليب القرار المستندة إلى القيد.

لقد حققت بالفعل الكثير بمساعدة من محللي القيود. كما هو الحال مع الجبر ، قبل أن أتعلم كيفية استخدامها بفعالية ، يجب أن أتعلم الكثير.

مثال آخر: سفينة الفضاء التي قمت بإنشائها . يمكن للمشغل سحب المحركات في أي مكان ، وسيحدد النظام المحركات التي يجب تنشيطها عند النقر فوق W و A و S و D و Q و E. على سبيل المثال ، في هذه السفينة:


إذا كنت تريد الطيران إلى الأمام ، فقم بتضمين محركين خلفيين. إذا كنت تريد الدوران يسارًا ، فقم بتشغيل المحركات الأمامية والخلفية اليمنى. حاولت البحث عن حل ، مما اضطر النظام إلى التكرار على الكثير من المعلمات :


نظام يعمل ، ولكن ليس الكمال. أدركت لاحقًا أن هذا مثال آخر على المكان الذي يمكن أن يساعد فيه الحل في الاتجاه المعاكس. اتضح أنه يمكن وصف حركة المركبات الفضائية بنظام قيود خطي . إذا فهمت هذا ، فيمكنني استخدام مكتبة جاهزة تحل بدقة القيود ، وليس طريقة التجريب والخطأ ، والتي تُرجع تقريبًا.

ومثال آخر: مشروع G9.js ، حيث يمكنك سحب إخراج وظيفة معينة على الشاشة ، ويحدد كيفية تغيير بيانات الإدخال لمطابقة بيانات الإخراج المطلوبة. عروض G9.js تبدو رائعة! تأكد من إلغاء تثبيت السطر "uncomment the السطر التالي" في العرض التوضيحي Rings.

من المفيد في بعض الأحيان التفكير في مهمة بالترتيب العكسي. غالبًا ما يتبين أن هذا يعطيني حلولًا أفضل من التفكير المباشر.

Source: https://habr.com/ru/post/ar453170/


All Articles