اذهب إلى المحتوى

كل الأنشطة

تحدث تلقائيًا

  1. الساعة الماضية
  2. اليوم
  3. سنشرح في هذا المقال نوع البيانات المسمى بالقاموس dictionary، الذي يوفر طريقة مرنة للوصول إلى البيانات وتنظيمها، ثم سنتعلم كيفية كتابة لعبة إكس-أو عبر دمج ما تعلمناه في المقالات السابقة من هذه السلسلة مع القواميس. نوع البيانات dictionary القواميس تشبه القوائم في أنها مجموعة قابلة للتعديل mutable من القيم، لكن بدلًا من وجود الفهارس الرقمية للعناصر كما في القوائم، يمكن استخدام مختلف أنواع البيانات في القواميس. نسمي المفاتيح في القواميس بالمفاتيح keys، وكل مفتاح مرتبط بقيمة، ونسمي ذلك زوجًا من المفاتيح والقيم key-value pair. نكتب القواميس في بايثون بإحاطها بقوسين مجعدين أو معقوصين {}: >>> myCat = {'size': 'fat', 'color': 'gray', 'disposition': 'loud'} السطر السابق يسند قاموسًا إلى المتغير myCat، ومفاتيح هذا القاموس هي 'size' و 'color' و 'disposition'، والقيم المرتبطة بتلك المفاتيح هي 'fat' و 'gray' و 'loud' على التوالي وبالترتيب. يمكنك الوصول إلى هذه القيم عبر مفاتيحها: >>> myCat['size'] 'fat' >>> 'My cat has ' + myCat['color'] + ' fur.' 'My cat has gray fur.' ما يزال بالإمكان استخدام الأعداد الصحيحة مفاتيحًا لقيم القواميس، لكن ليس من الضروري أن تبدأ من الصفر 0 ويمكنك استخدام أي رقم: >>> spam = {12345: 'Luggage Combination', 42: 'The Answer'} مقارنة القواميس والقوائم على خلاف القوائم، لا تكون القواميس مرتبةً، فأول عنصر في قائمة اسمها spam سيكون spam[0]‎، لكن لا يوجد «أول» عنصر في القاموس. سيكون ترتيب العناصر مهمًا في حال أردنا تحديد إن كانت قائمتان متساويتين، بينما لا يفرق ترتيب كتابة أزواج المفاتيح-القيم في القواميس: >>> spam = ['cats', 'dogs', 'moose'] >>> olive = ['dogs', 'moose', 'cats'] >>> spam == olive False >>> eggs = {'name': 'Zophie', 'species': 'cat', 'age': '8'} >>> steak = {'species': 'cat', 'age': '8', 'name': 'Zophie'} >>> eggs == steak True ولأن القواميس غير مرتبة، فلا يمكن تقسيمها كما في القوائم. محاولة الوصول إلى مفتاح غير موجود في قاموس ما سيؤدي إلى حدوث الخطأ KeyError، وهي تشبه رسالة الخطأ IndexError في القوائم حين محاولة الوصول إلى قيمة خارج مجال فهارس القائمة. لاحظ رسالة الخطأ الآتية التي تظهر لعدم وجود المفتاح 'color': >>> spam = {'name': 'Zophie', 'age': 7} >>> spam['color'] Traceback (most recent call last): File "<pyshell#1>", line 1, in <module> spam['color'] KeyError: 'color' وصحيحٌ أن القواميس غير مرتبة، لكن إمكانية استخدام أي قيمة تريدها للمفاتيح يسمح لنا بترتيب البيانات بطرائق رائعة! لنقل أننا نريد كتابة برنامج يخزن معلومات حول أعياد ميلاد أصدقائك، يمكنك أن تكتب الشيفرة الآتية birthdays.py التي تستخدم القواميس وتجعل أسماء أصدقائك مفاتيحًا للقيم: ➊ birthdays = {'Alice': 'Apr 1', 'Bob': 'Dec 12', 'Carol': 'Mar 4'} while True: print('Enter a name: (blank to quit)') name = input() if name == '': break ➋ if name in birthdays: ➌ print(birthdays[name] + ' is the birthday of ' + name) else: print('I do not have birthday information for ' + name) print('What is their birthday?') bday = input() ➍ birthdays[name] = bday print('Birthday database updated.') أنشأنا قاموسًا وخزناه في المتغير birthdays ➊، ثم تحققنا إن كان الاسم المدخل موجودًا في القاموس عبر الكلمة المحجوزة in ➋ كما كنا نفعل مع القوائم. إذا كان الاسم موجودًا في القاموس فيمكنك الوصول إلى القيمة المرتبطة به عبر استخدام الأقواس المربعة ➌، وإلّا فيمكنك إضافتها باستخدام صيغة الأقواس المربعة مع عامل الإسناد ➍: Enter a name: (blank to quit) Alice Apr 1 is the birthday of Alice Enter a name: (blank to quit) Eve I do not have birthday information for Eve What is their birthday? Dec 5 Birthday database updated. Enter a name: (blank to quit) Eve Dec 5 is the birthday of Eve Enter a name: (blank to quit) للأسف ستحذف كل المعلومات التي أدخلتها في هذا البرنامج حين انتهاء تنفيذه. ستتعلم كيفية حفظ الملفات على القرص في مقال لاحق من هذه السلسلة. القواميس المرتبة في بايثون 3.7 صحيح أن القواميس غير مرتبة ولا يوجد فيها عنصر «أول»، لكن القواميس في الإصدار 3.7 من بايثون وما يليه ستتذكر ترتيب أزواج القيم الموجودة فيها حين إنشاء متسلسل sequence منها. فمثلًا لاحظ أن ترتيب العناصر في القائمتين المنشأتين من القاموسين eggs و steak يطابق ترتيب إدخالها: >>> eggs = {'name': 'Zophie', 'species': 'cat', 'age': '8'} >>> list(eggs) ['name', 'species', 'age'] >>> steak = {'species': 'cat', 'age': '8', 'name': 'Zophie'} >>> list(steak) ['species', 'age', 'name'] ستبقى القواميس غير مرتبة، ولا يمكنك أن تصل إلى العناصر فيها عبر فهرس رقمي مثل eggs[0]‎ أو steak[2]‎، لا يجدر بك الاعتماد على هذا السلوك لأن بايثون لا تتذكر ترتيب إدخال العناصر في الإصدارات القيمة منها، فلاحظ المثال الآتي الذي لا يطابق ترتيب عناصر القاموس الناتج النهائي الترتيبَ الذي أدخلتها به، ناتج التنفيذ الآتي على إصدار بايثون 3.5: >>> spam = {} >>> spam['first key'] = 'value' >>> spam['second key'] = 'value' >>> spam['third key'] = 'value' >>> list(spam) ['first key', 'third key', 'second key'] التوابع keys()‎ و values()‎ و items()‎ هنالك ثلاثة توابع خاصة بالقواميس التي تعيد قيمًا شبيهة بالقوائم list-like من مفاتيح القواميس أو قيمها أو كلًا من المفاتيح والقيم معًا وهي التوابع keys()‎ و values()‎ و items()‎ بالترتيب. القيم المعادة من هذه التوابع ليست قوائم حقيقيةً، فلا يمكننا تعديلها وليس لها التابع append()‎، لكن أنواع البيانات المعادة (وهي dictkeys و dictvalues و dict_items بالترتيب) يمكن أن تستخدم في حلقات التكرار for: >>> spam = {'color': 'red', 'age': 42} >>> for v in spam.values(): ... print(v) red 42 ستمر حلقة for هنا على كل قيمة في القاموس spam، يمكن لحلقة for المرور على المفاتيح فقط، وعلى المفاتيح والقيم معًا: >>> for k in spam.keys(): ... print(k) color age >>> for i in spam.items(): ... print(i) ('color', 'red') ('age', 42) حين استخدامنا للتوابع keys()‎ و values()‎ و items()‎ فيمكن للحلقة for المرور على قيم المفاتيح أو قيم العناصر أو قيم أزواج المفتاح-القيمة على التوالي. لاحظ أن القيم المعادة من items()‎ هي صفوف tuples تحتوي على المفتاح ثم قيمته. إذا أردتَ قائمةً حقيقية من ناتج أحد تلك التوابع، فيمكننا تمرير القيمة الشبيهة بالقوائم إلى الدالة list()‎ كما يلي: >>> spam = {'color': 'red', 'age': 42} >>> spam.keys() dict_keys(['color', 'age']) >>> list(spam.keys()) ['color', 'age'] يأخذ السطر list(spam.keys())‎ القيمة ذات النوع dict_keys المعادة من التابع keys()‎ ويمررها إلى الدالة list()‎، والتي تعيد بدورها قائمةً فيها ['color', 'age']. يمكنك استخدام الإسناد المتعدد مع حلقة for لإسناد المفتاح والقيمة إلى متغيرات منفصلة: >>> spam = {'color': 'red', 'age': 42} >>> for k, v in spam.items(): ... print('Key: ' + k + ' Value: ' + str(v)) Key: age Value: 42 Key: color Value: red التحقق من وجود مفتاح أو قيمة في قاموس نتذكر من المقال السابق أن العاملين in و not in يمكن أن يستخدما للتحقق من وجود قيمة في قائمة. ويمكننا استخدام نفس العاملين للتحقق من وجود قيمة ما في مفتاح أو قيمة في قاموس: >>> spam = {'name': 'Zophie', 'age': 7} >>> 'name' in spam.keys() True >>> 'Zophie' in spam.values() True >>> 'color' in spam.keys() False >>> 'color' not in spam.keys() True >>> 'color' in spam False لاحظ أن كتابة ‎'color' in spam هي مطابقة لكتابة ‎'color' in spam.keys()‎. فإذا أردت التحقق من وجود (أو عدم وجود) مفتاح ما في قاموس فاستعمل الكلمة المحجوزة in (أو not in) مع القاموس نفسه. التابع get()‎ من الرتيب أن نتحقق من وجود مفتاح ما في القاموس قبل الوصول إلى القيمة المرتبطة به، لكن لحسن الحظ هنالك تابع باسم get()‎ يأخذ وسيطين: الأول هو المفتاح الذي نريد الوصول إلى قيمته، والثاني هو قيمة افتراضية ستعاد إن لم يكن المفتاح موجودًا: >>> picnicItems = {'apples': 5, 'cups': 2} >>> 'I am bringing ' + str(picnicItems.get('cups', 0)) + ' cups.' 'I am bringing 2 cups.' >>> 'I am bringing ' + str(picnicItems.get('eggs', 0)) + ' eggs.' 'I am bringing 0 eggs.' ولعدم وجود المفتاح 'eggs' في القاموس picnicItems فستعاد القيمة 0 من التابع get()‎، وإن لم نستعمل التابع get()‎ في المثال السابق فستظهر رسالة خطأ كما يلي: >>> picnicItems = {'apples': 5, 'cups': 2} >>> 'I am bringing ' + str(picnicItems['eggs']) + ' eggs.' Traceback (most recent call last): File "<pyshell#34>", line 1, in <module> 'I am bringing ' + str(picnicItems['eggs']) + ' eggs.' KeyError: 'eggs' التابع setdefault()‎ الحاجة إلى ضبط قيمة في القاموس مرتبطة بمفتاح معين إن لم يكن ذاك المفتاح موجودًا مسبقًا هو أمرٌ شائع، وتكون الشيفرة بالشكل الآتي: spam = {'name': 'Pooka', 'age': 5} if 'color' not in spam: spam['color'] = 'black' يوفر التابع setdefault()‎ طريقة أسهل لفعل ذلك بسطر برمجي وحيد، فأول وسيط يمرر إلى التابع هو المفتاح الذي سنتحقق من وجوده، والوسيط الثاني هو القيمة التي ستُضبَط إن لم يكن المفتاح موجودًا. إذا كان المفتاح موجودًا فسيعيد التابع setdefault()‎ قيمة ذاك المفتاح: >>> spam = {'name': 'Pooka', 'age': 5} >>> spam.setdefault('color', 'black') 'black' >>> spam {'color': 'black', 'age': 5, 'name': 'Pooka'} >>> spam.setdefault('color', 'white') 'black' >>> spam {'color': 'black', 'age': 5, 'name': 'Pooka'} حينما استدعينا التابع setdefault()‎ أول مرة، فتغيرت قيمة القاموس spam إلى ‎{'color': 'black', 'age': 5, 'name': 'Pooka'}‎، وسيعيد التابع setdefault()‎ القيمة 'black' لأنها القيمة المضبوطة للمفتاح 'color' حاليًا. لكن حين استدعاء spam.setdefault('color', 'white')‎ فإن القيمة لن تتغير إلى 'white' لأن القاموس spam يحتوي على مفتاح باسم 'color'. التابع setdefault()‎ هو اختصار جميل للتأكد من وجود مفتاح معين وضبط قيمته. هذا مثال عن برنامج يعدّ عدد مرات وجود كل حرف في سلسلة نصية. احفظ المثال الآتي باسم characterCount.py: message = 'It was a bright cold day in April, and the clocks were striking thirteen.' count = {} for character in message: ➊ count.setdefault(character, 0) ➋ count[character] = count[character] + 1 print(count) سيمر البرنامج على كل محرف في السلسلة النصية المخزنة في المتغير message، ويعد كم مرة يظهر فيها كل محرف. استدعاء الدالة setdefault()‎ ➊ سيضمن وجود المفتاح في القاموس count ويضبط قيمته الافتراضية إلى 0، وبالتالي لا يرمي البرنامج الخطأ KeyError حين تنفيذ التعبير البرمجي count[character] = count[character] + 1 ➋. سيبدو الناتج كما يلي: {' ': 13, ',': 1, '.': 1, 'A': 1, 'I': 1, 'a': 4, 'c': 3, 'b': 1, 'e': 5, 'd': 3, 'g': 2, 'i': 6, 'h': 3, 'k': 2, 'l': 3, 'o': 2, 'n': 4, 'p': 1, 's': 3, 'r': 5, 't': 6, 'w': 2, 'y': 1} سترى من الناتج السابق أن الحرف c الصغير مكرر 3 مرات، بينما الفراغ مكرر 13 مرة، والحرف A الكبير يظهر مرة واحدة. سيعمل البرنامج السابق على جميع السلاسل النصية بغض النظر عن محتويات المتغير message حتى لو كان يحتوي على مليون حرف! تجميل الطباعة إذا استوردت الوحدة pprint في برامجك، فيمكنك الوصول إلى الدالتين pprint()‎ و pformat()‎ التي «تجمل طباعة» pretty print قيم القواميس، ستستفيد من هذه الدوال إن أردت عرض قيم القواميس عرضًا أجمل من طريقة عرض الدالة print()‎، لنعدل المثال السابق: import pprint message = 'It was a bright cold day in April, and the clocks were striking thirteen.' count = {} for character in message: count.setdefault(character, 0) count[character] = count[character] + 1 pprint.pprint(count) سيظهر لنا الناتج الجميل الآتي: {' ': 13, ',': 1, '.': 1, 'A': 1, 'I': 1, --snip-- 't': 6, 'w': 2, 'y': 1} سنستفيد فعليًا من الدالة pprint.pprint()‎ عندما يحتوي القاموس على قوائم أو قواميس متشعبة داخله nested. إذا أردت الحصول على قيمة النص المجمّل بدلًا من طباعته على الشاشة مباشرةً، فاستدعِ الدالة pprint.pformat()‎. السطران الآتيان متكافئان تمامًا: pprint.pprint(someDictionaryValue) print(pprint.pformat(someDictionaryValue)) استخدام بنى المعطيات لنمذجة عناصر حقيقية كان بإمكاننا لعب الشطرنج مع شخص آخر عن بعد قليل ظهور الإنترنت، فكان يعد كل لاعب رقعة الشطرنج في منزله، ثم يبادلان الرسائل البريدية يصف كل منهما خطوته، ولكي يستطيعوا فعل ذلك كان لاعبو الشطرنج بحاجة إلى وصف حالة رقعة الشطرنج والحركات التي يجريها وصفًا لا لبس فيه. تمثل الفراغات في رقعة الشطرنج في التأشير الجبري Algebraic chess notation بإحداثيات تتألف من حرف ورقم كما في الشكل 5-1. الشكل 5-1: إحداثيات رقعة الشطرنج في التأشير الجبري تُعرّف قطع الشطرنج بالأحرف: K للملك king، و Q للملكة queen (يسميها البعض بالوزير)، و R للقلعة rook، و B للفيل bishop، و N للحصان knight. أما الجنود فلا رمز لهم. يكون وصف الحركات متألفًا من الحرف الذي يمثل القطعة، وإحداثيات الوجهة. وزوج من تلك الحركات يصف ما يحدث في دورٍ واحد (بفرض أن صاحب اللون الأبيض يبدأ أولًا)؛ فمثلًا التأشير 2‎. Nf3 Nc6 يعني أن الأبيض حرك الحصان إلى f3 والأسود حرك الحصان إلى c6 في الدور الثاني من اللعبة. هنالك المزيد من القواعد للتأشير الجبري للشطرنج، لكن الفكرة التي أحاول إيصالها هي أننا نستطيع وصف لعبة الشطرنج دون الحاجة إلى أن نكون أمام رقعة، ويمكن أن يكون خصمك في الطرف الثاني من الكوكب، وإذا كانت لديك ذاكرة ومخيلة جيدة فلا تحتاج إلى رقعة شطرنج حقيقية من الأساس: فيمكنك أن تقرأ الحركات من الرسائل البريدية وتحدِّث الرقعة الموجودة في مخيلتك! تمتلك الحواسيب ذواكر رائعة، فيمكن أن يخزن الحاسوب مليارات السلاسل النصية من الشكل ‎'2. Nf3 Nc6'‎، وبهذا يمكن أن تلعب الحواسيب الشطرنج دون لوحة حقيقية؛ فما تفعله الحواسيب هو نمذجة البيانات لتمثيل رقعة الشطرنج، ويمكنك كتابة شيفرة تفعل ذلك بنفسك. هنا تلعب القوائم والقواميس دورها، فمثلًا القاموس ‎{'1h': 'bking', '6c': 'wqueen', '2g': 'bbishop', '5h': 'bqueen', '3e': 'wking'}‎ يمثل الرقعة في الشكل 5-2: الشكل 5-2: رقعة شطرنج منمذجة وفق قيمة قاموس لكن لمثالنا القادمة سنستعمل لعبة أسهل وأبسط من الشطرنج وهي لعبة إكس-أو. لعبة إكس-أو لعبة إكس-أو (تسمى بالإنكليزية tic-tac-toe) تشبه رمز # كبير فيه 9 خانات يمكن أن تكون قيمها X أو O أو أن تكون فارغة. لتمثيل هذه الرقعة بقاموس، فيجب أن نسند لكل خانة زوجًا من المفتاح-القيمة كما في الشكل 5-3. الشكل 5-3: خانات رقعة إكس-أو مع المفاتيح الموافقة لها يمكنك استخدام القيم النصية لتمثيل ما هو موجود في كل خانة في الرقعة: 'x' أو 'o' أو ' ' (فراغ)، وبالتالي نحتاج إلى تسع سلاسل نصية، يمكنك استخدام قاموس من القيم لهذا الأمر، فالقيمة النصية المرتبطة مع المفتاح 'top-R' تمثل القيمة في الركن العلوي الأيمن، والسلسل النصية المرتبطة مع المفتاح 'low-L' تمثل الركن السفلي الأيسر، والسلسلة النصية المرتبطة مع المفتاح 'mid-m' تمثل المنتصف، وهلم جرًا للبقية. هذا القاموس هو بنية معطيات تمثل رقعة لعبة إكس-أو، ولنخزن هذا القاموس في متغير باسم theBoard، ولنحفظ الشيفرة الآتية في ملف باسم ticTacToe.py: theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ', 'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ', 'low-L': ' ', 'low-M': ' ', 'low-R': ' '} بنية المعطيات المخزنة في المتغير theBoard تمثل رقعة إكس-أو الموضحة في الشكل 5-4. الشكل 5-4: لوحة إكس-أو فارغة ولما كانت قيمة كل مفتاح في القاموس theBoard هي فراغ واحد فيمثل ذاك القاموس رقعةً فارغةً تمامًا. وإذا بدأت اللاعب X واختار الخانة في المنتصف تمامًا فسيصبح القاموس الذي يمثل الرقعة على الشكل: theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ', 'mid-L': ' ', 'mid-M': 'X', 'mid-R': ' ', 'low-L': ' ', 'low-M': ' ', 'low-R': ' '} أصبحت بنية المعطيات theBoard تمثل الرقعة الموضحة في الشكل 5-5. الشكل 5-5: الحركة الأولى وتكون رقعة ربح فيها اللاعب O بوضع الشكل O في الصف العلوي كما يلي: theBoard = {'top-L': 'O', 'top-M': 'O', 'top-R': 'O', 'mid-L': 'X', 'mid-M': 'X', 'mid-R': ' ', 'low-L': ' ', 'low-M': ' ', 'low-R': 'X'} وهي ممثلة في الشكل 5-6. الشكل 5-6: ربح اللاعب O وبالتأكيد لا يستطيع أن يرى اللاعب إلا ما يطبع على الشاشة أمامه، ولا يعرف محتويات المتغيرات، فلننشئ دالةً تطبع القاموس الذي يحتوي على الرقعة على الشاشة. أضف ما يلي إلى ملف ticTacToe.py: theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ', 'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ', 'low-L': ' ', 'low-M': ' ', 'low-R': ' '} def printBoard(board): print(board['top-L'] + '|' + board['top-M'] + '|' + board['top-R']) print('-+-+-') print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R']) print('-+-+-') print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R']) printBoard(theBoard) حينما تشغل هذا البرنامج فستطبع رقعة إكس-أو فارغة: | | -+-+- | | -+-+- | | يمكن أن تتوالى الدالة printBoard()‎ أي بنية معطيات تمثل رقعة إكس-أو تمررها إليها، جرب تغيير الشيفرة إلى ما يلي: theBoard = {'top-L': 'O', 'top-M': 'O', 'top-R': 'O', 'mid-L': 'X', 'mid-M': 'X', 'mid-R': ' ', 'low-L': ' ', 'low-M': ' ', 'low-R': 'X'} def printBoard(board): print(board['top-L'] + '|' + board['top-M'] + '|' + board['top-R']) print('-+-+-') print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R']) print('-+-+-') print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R']) printBoard(theBoard) ستعرض الرقعة الآتية على الشاشة: O|O|O -+-+- X|X| -+-+- | |X ولأنك أنشأت بنية معطيات تمثل لوحة إكس-أو وكتبت الشيفرة في printBoard()‎ التي تفسر بنية المعطيات وتظهر الرقعة، فأنت كتبت برنامجًا «ينمذج» models رقعة إكس-أو. كان بإمكانك تنظيم البيانات في بنية المعطيات بطريقة مختلفة، فمثلًا يمكنك استخدام المفتاح 'TOP-LEFT' بدلًا من 'top-L'، لكن طالما كانت شيفرتك تعمل مع بنية المعطيات التي لديك، فأنت كتبت عملية النمذجة بشكل صحيح. فمثلًا تتوقع الدالة printBoard()‎ أن بنية المعطيات التي تمثل الرقعة هي قاموس فيه مفاتيح لجميع الخانات التسع، لكن إن كان في قاموسك مفتاحٌ ناقص وليكن 'mid-L' فلن يعمل برنامجك: O|O|O -+-+- Traceback (most recent call last): File "ticTacToe.py", line 10, in <module> printBoard(theBoard) File "ticTacToe.py", line 6, in printBoard print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R']) KeyError: 'mid-L' لنضف الآن الشيفرة التي تسمح للاعبين بإدخال حركاتهم. لنعدل برنامجنا ليبدو كما يلي: theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ', 'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ', 'low-L': ' ', 'low-M': ' ', 'low-R': ' '} def printBoard(board): print(board['top-L'] + '|' + board['top-M'] + '|' + board['top-R']) print('-+-+-') print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R']) print('-+-+-') print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R']) turn = 'X' for i in range(9): ➊ printBoard(theBoard) print('Turn for ' + turn + '. Move on which space?') ➋ move = input() ➌ theBoard[move] = turn ➍ if turn == 'X': turn = 'O' else: turn = 'X' printBoard(theBoard) الشيفرة الجديدة تطبع اللوحة في بداية كل دور ➊ ثم تطلب المدخلات من اللاعب الحالي ➋ ثم تحدث الرقعة وفقًا لذلك ➌ ثم تبدل اللاعب الحالي ➍ قبل الانتقال إلى الدور القادم. | | -+-+- | | -+-+- | | Turn for X. Move on which space? mid-M | | -+-+- |X| -+-+- | | --snip-- O|O|X -+-+- X|X|O -+-+- O| |X Turn for X. Move on which space? low-M O|O|X -+-+- X|X|O -+-+- O|X|X صحيحٌ أن البرنامج ليس لعبة إكس-أو كاملة، فلن يتحقق إن ربح أحد اللاعبين مثلًا؛ لكنه كافٍ لمعرفة كيفية استخدام بنى المعطيات في برامج حقيقية. القواميس والقوائم المتشعبة نمذجة لوحة إكس-أو هو أمر سهل: تحتاج اللوحة إلى قاموس فيه 9 مفاتيح تمثل خاناتها. لكن إن أردت نموذج أمور أكثر تعقيدًا فستجد أنك تحتاج إلى القواميس والقوائم التي تحتوي على قواميس وقوائم أخرى داخلها. تناسب القوائم تخزين سلسلة مرتبة من القيم، بينما تفيد القواميس بتخزين قواميس التي ترتبط فيها المفاتيح مع القيم. هذا مثال يستعمل قاموسًا يحتوي على قواميس داخله فيها الأغراض التي أتى بها الضيوف إلى الرحلة. يمكن أن تقرأ الدالة totalBrought()‎ بنية المعطيات وتحسب العدد الكلي للعناصر المجلوبة من كل الضيوف: allGuests = {'Alice': {'apples': 5, 'pretzels': 12}, 'Bob': {'steak sandwiches': 3, 'apples': 2}, 'Carol': {'cups': 3, 'apple pies': 1}} def totalBrought(guests, item): numBrought = 0 ➊ for k, v in guests.items(): ➋ numBrought = numBrought + v.get(item, 0) return numBrought print('Number of things being brought:') print(' - Apples ' + str(totalBrought(allGuests, 'apples'))) print(' - Cups ' + str(totalBrought(allGuests, 'cups'))) print(' - Cakes ' + str(totalBrought(allGuests, 'cakes'))) print(' - Steak Sandwiches ' + str(totalBrought(allGuests, 'steak sandwiches'))) print(' - Apple Pies ' + str(totalBrought(allGuests, 'apple pies'))) داخل الدالة totalBrought()‎ هنالك حلقة for تدور على أزواج مفتاح-قيمة في المتغير guests ➊، وسنسند داخل الحلقة اسم كل ضيف إلى المتغير k، وسنسند القاموس الذي يحتوي على قائمة الأغراض التي سيجلبها معه إلى الرحلة إلى المتغير v. إذا كان أحد المعامل item موجودة في القاموس، فستضاف قيمته (كمية الأغراض المجلوبة) إلى المتغير numBrought ➋، لكن إذا لم يكن المفتاح موجودًا فيسعيد التابع get()‎ القيمة 0 لإضافتها إلى numBrought. سيكون ناتج تنفيذ البرنامج كما يلي: Number of things being brought: - Apples 7 - Cups 3 - Cakes 0 - Steak Sandwiches 3 - Apple Pies 1 قد يبدو لك أن حالة الاستخدام السابقة بسيطة ولا حاجة إلى نمذجتها، لكن فكر أن الدالة totalBrought()‎ يمكن أن تتعامل بسهولة مع قاموس يحتوي على آلاف الضيوف، وكل ضيف يجلب آلاف العناصر، وتنظيم هذه المعلومات في بنية معطيات واضحة ووجود الدالة totalBrought()‎ سيوفر عليك وقتًا كثيرًا. يمكنك أن تنمذج العناصر في بنى المعطيات بالطريقة التي تراها مناسبة، لطالما كانت بقية الشيفرة في برنامج قادرةً على التعامل مع بنية المعطيات المنشأة. حينما تبدأ البرمجة فلا تقلق أن تنمذج البيانات بالطريقة «الصحيحة»، فكلما ازدادت خبرتك أصبحت تخطر ببالك طرائق أكثر فاعلية وكفاءة للنمذجة، لكن أهم ما في الأمر أن تعمل بنية المعطيات مع احتياجات برنامجك. الخلاصة يمكن أن تحتوي القوائم والقواميس على عدّة قيم، بما فيها قوائم وقواميس أخرى. القواميس مفيدة لأنك تستطيع ربط مفتاح معين مع قيمة، على عكس القوائم التي هي سلسلة من القيم المرتبة. يمكن الوصول إلى القيم داخل القاموس عبر استخدام الأقواس المربعة كما في القوائم، لكن بدلًا من استخدام فهرس رقمي فيمكن أن تكون المفاتيح في القواميس من مختلف القيم سواءً كانت أعدادًا صحيحةً أو أعدادًا عشريةً أو سلاسل نصية أو صفوف tuples. يمكنك تمثيل الكائنات الحقيقية بتنظيم قيم البرنامج في بنى المعطيات، ورأينا مثال ذلك عمليًا على لعبة إكس-أو. مشاريع تدريبية لكي تتدرب، اكتب برامج لتنفيذ المهام الآتية. مدقق لقواميس الشطرنج استعملنا في هذا المقال قيمةً مثل ‎{'1h': 'bking', '6c': 'wqueen', '2g': 'bbishop', '5h': 'bqueen', '3e': 'wking'}‎ لتمثيل رقعة الشطرنج. اكتب دالةً باسم isValidChessBoard()‎ التي تقبل وسيطًا هو قاموس وتعيد القيمة True أو False اعتمادًا إن كان القاموس صالحًا لتمثيل رقعة الشطرنج. تحتوي الرقعة السليمة على ملك أسود واحد وملك أبيض واحد. ويمكن لأيٍ من اللاعبين امتلاك 16 قطعة كحد أقصى، و 8 جنود كحد أقصى، ويجب أن تكون جميع القطع في المجال بين 1a و 8h، أي لا يمكن أن تكون القطعة في المكان 9z. يجب أن تبدأ أسماء القطع بحرف w أو b لتمثيل اللونين الأبيض أو الأسود، متبوعًا بإحدى الكلمات pawn أو knight أو bishop أو rook أو queen أو king. قائمة الأدوات في لعبة نحن نعمل على لعبة فيها قائمة أدوات يمكن أن يمتلكها اللاعب، والتي سننمذجها باستخدام بنية معطيات تتألف من قاموس تكون فيه مفاتيحه هي سلاسل نصية تصف القيمة الموجودة في قائمة الأدوات، وقيمتها هي عدد نصي يمثل عدد الأدوات التي يمتلكها اللاعب مثلًا القاموس ‎{'rope': 1, 'torch': 6, 'gold coin': 42, 'dagger': 1, 'arrow': 12}‎ تعني أن اللاعب يملك حبلًا واحدًا، و 6 شعلات، و 42 قطعة ذهبية …إلخ. اكتب دالةً باسم displayInventory()‎ التي تأخذ أي قاموس يمثل قائمة أدوات ويعرضه بالشكل: Inventory: 12 arrow 42 gold coin 1 rope 6 torch 1 dagger Total number of items: 62 تلميح: يمكنك استخدام حلقة for للمرور على جميع المفاتيح في القاموس: # inventory.py stuff = {'rope': 1, 'torch': 6, 'gold coin': 42, 'dagger': 1, 'arrow': 12} def displayInventory(inventory): print("Inventory:") item_total = 0 for k, v in inventory.items(): # أكمل الشيفرة هنا print("Total number of items: " + str(item_total)) displayInventory(stuff) دالة تحويل قائمة إلى قاموس في لعبة لنفترض أن لاعبنا في اللعبة السابقة قد حصل على غنيمة ممثلة في القائمة الآتية: playerLoot = ['gold coin', 'dagger', 'gold coin', 'gold coin', 'ruby'] اكتب دالةً باسم addToInventory(inventory, addedItems)‎ حيث أن المعامل inventory هو قاموس يمثل قائمة أدوات اللاعب (كما في المثال السابق) والمعامل addedItems يشبه المتغير playerLoot. يجب أن تعيد الدالة addToInventory()‎ قاموسًا يمثل قائمة الأدوات المحدثة. لاحظ أن القائمة الموجودة في addedItems قد تحتوي على عدة نسخ من نفس الأداة. يفترض أن تكون شيفرتك شبيهة بما يلي: def addToInventory(inventory, addedItems): # اكتب الدالة هنا inv = {'gold coin': 42, 'rope': 1} dragonLoot = ['gold coin', 'dagger', 'gold coin', 'gold coin', 'ruby'] inv = addToInventory(inv, dragonLoot) displayInventory(inv) يجب أن يظهر البرنامج السابق (مع الدالة displayInventory()‎ من المثال السابق) الناتج الآتي: Inventory: 45 gold coin 1 rope 1 ruby 1 dagger Total number of items: 48 ترجمة -بتصرف- للفصل Dictionaries And Structuring DATA من كتاب Automate the Boring Stuff with Python. اقرأ أيضًا المقال السابق: القوائم Lists في لغة بايثون أنواع البيانات والعمليات الأساسية في لغة بايثون تعلم لغة بايثون النسخة العربية الكاملة لكتاب البرمجة بلغة بايثون
  4. في البداية بدون دراية برمجية لن تتمكن من التعديل والتطوير، يجب الإلمام بلغة PHP لفعل ذلك بجانب لغات الويب HTML, CSS, JS. أولاً، عليك تثبيت Smarty: composer require smarty/smarty ثم قم بتهيئة Smarty في ملف PHP الرئيسي، ولنفترض أن ملفك الرئيسي هو index.php. <?php require_once 'vendor/autoload.php'; $smarty = new Smarty(); $smarty->setTemplateDir(__DIR__ . '/template'); $smarty->setCompileDir(__DIR__ . '/template_c'); $smarty->setCacheDir(__DIR__ . '/cache'); $smarty->setConfigDir(__DIR__ . '/configs'); ثم لنقم بكتابة كود PHP لقراءة القوالب المتاحة في مجلد القوالب. <?php // تابع للخطوة 2 $templateDir = __DIR__ . '/template'; $templateFolders = array_filter(glob($templateDir . '/*'), 'is_dir'); $templates = []; foreach ($templateFolders as $folder) { $templateName = basename($folder); $templates[] = $templateName; } $smarty->assign('templates', $templates); $smarty->display('admin.tpl'); بعد ذلك إنشاء ملف قالب Smarty يسمى admin.tpl لعرض القوالب في جدول. <!-- admin.tpl --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Admin Panel - Templates</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"> </head> <body> <div class="container"> <h1>Available Templates</h1> <table class="table table-bordered"> <thead> <tr> <th>Template Name</th> <th>Action</th> </tr> </thead> <tbody> {foreach from=$templates item=template} <tr> <td>{$template}</td> <td> <form method="post" action="install_template.php"> <input type="hidden" name="template_name" value="{$template}"> <button type="submit" class="btn btn-primary">Install Template</button> </form> </td> </tr> {/foreach} </tbody> </table> </div> </body> </html> ثم إنشاء ملف PHP يسمى install_template.php لتنفيذ عملية تركيب القالب. <?php if ($_SERVER['REQUEST_METHOD'] === 'POST') { $templateName = $_POST['template_name']; // نفذ عملية تركيب القالب هنا // تستطيع نسخ الملفات إلى مجلد آخر أو تحديث إعدادات قاعدة البيانات echo "Template '{$templateName}' has been installed!"; } else { echo "Invalid request."; } بذلك ستتمكن من عرض القوالب المتاحة في مجلد template على شكل جدول في صفحة لوحة التحكم، مع زر لتركيب كل قالب، وعند النقر على زر "تركيب القالب"، سيتم إرسال طلب POST إلى install_template.php لتنفيذ عملية التركيب، تستطيع تعديل عملية التركيب حسب متطلباتك.
  5. في البداية ستحتاج بالطبع إلى إنشاء حساب مطور على Google Cloud Vision API أو Amazon Rekognition. ثم ضبط إعدادات متغيرات البيئة في المشروع في ملف .env وأهما مفاتيح الـ API، عليك إضافة إعدادات Google Cloud Vision API أو Amazon Rekognition فقط، وإليك كلاهما: GOOGLE_CLOUD_VISION_API_KEY=google_api_key AWS_ACCESS_KEY_ID=aws_access_key AWS_SECRET_ACCESS_KEY=aws_secret_key AWS_REGION=aws_region ثم أنشئ نموذج وقاعدة بيانات لتخزين بيانات الصور: php artisan make:model Image -m في ملف التهجير: Schema::create('images', function (Blueprint $table) { $table->id(); $table->string('image_path'); $table->json('features'); // لتخزين بيانات الميزات (features) $table->timestamps(); }); أيضًا اعتمد على مكتبة مثل intervention/image لمعالجة الصور وضغط حجمها قبل إرسالها. ثم استخدام مكتبة google/cloud-vision أو aws/aws-sdk-php للتواصل مع المنصة. وإليك مثال لكلاهما اختر ما تريد: // ImageController.php use Illuminate\Http\Request; use Intervention\Image\Facades\Image; use Google\Cloud\Vision\V1\ImageAnnotatorClient; // or Aws\Rekognition\RekognitionClient; public function uploadImage(Request $request) { $image = $request->file('image'); // Process and resize the image $image->resize(300, 300); // Analyze the image using Google Cloud Vision API or Amazon Rekognition $visionClient = new ImageAnnotatorClient(); // or $rekognitionClient = new RekognitionClient(); $response = $visionClient->annotateImage(file_get_contents($image->getPathname()), ['LABEL_DETECTION']); // or $rekognitionClient->detectLabels(['Image' => ['Bytes' => file_get_contents($image->getPathname())]]); $features = $response->getLabelAnnotations(); // or $response->getLabels(); // Store the features in the database $imageFeatures = new ImageFeatures(); $imageFeatures->features = json_encode($features); $imageFeatures->save(); return response()->json(['message' => 'Image uploaded and analyzed successfully']); } بعد ذلك اعتمد على مكتبة doctrine/dbal للتفاعل مع قاعدة البيانات، حيث تتوفر cosine similarity أو Euclidean distance لقياس التشابه بين ميزات الصور. use App\ImageFeatures; use Illuminate\Http\Request; public function searchByImage(Request $request) { $searchImage = $request->file('image'); $searchFeatures = $this->analyzeImage($searchImage); // Query the database to find similar images $similarImages = ImageFeatures::all()->filter(function ($imageFeature) use ($searchFeatures) { $storedFeatures = json_decode($imageFeature->features, true); return $this->cosineSimilarity($searchFeatures, $storedFeatures) > 0.5; }); return response()->json(['similar_images' => $similarImages]); } private function analyzeImage($image) { // هنا يجب أن تضع الكود الخاص بتحليل الصورة والحصول على الميزات // سأضع مثال بسيط لتحليل الصورة return [/* array of features */]; } private function cosineSimilarity($features1, $features2) { $dotProduct = 0; $magnitude1 = 0; $magnitude2 = 0; foreach ($features1 as $index => $feature1) { $dotProduct += $feature1 * $features2[$index]; $magnitude1 += $feature1 * $feature1; $magnitude2 += $features2[$index] * $features2[$index]; } $magnitude1 = sqrt($magnitude1); $magnitude2 = sqrt($magnitude2); if ($magnitude1 * $magnitude2 == 0) { return 0; } return $dotProduct / ($magnitude1 * $magnitude2); } لتحسين الأداء، باستطاعتك استخدام تقنيات مثل الفهرسة المكانية أو مكتبات متخصصة في البحث عن الصور مثل Elasticsearch.
  6. افتحي مشروع Unity الذي تريدين تصديره كمكتبة، وانتقلي إلى File > Build Settings، وفي نافذة Build Settings، اختاري المنصة المستهدفة (Android أو iOS). وفي حال تستهدفي Android، اختاري Android من القائمة. ثم اضغطي على Player Settings في الزاوية السفلية اليسرى من نافذة Build Settings، وضبط الإعدادات اللازمة مثل اسم الحزمة (Package Name) وغيرها. وفي نافذة Build Settings، تأكدي من اختيار المنصة الصحيحة ثم اضغطي على Export في الزاوية اليمنى السفلى. وعندما تظهر نافذة التصدير، عليك تحديد خيار Export as a Library (أو خيار مشابه يعبر عن تصدير كمكتبة)، ثم اختيار مكان حفظ المجلد الذي سيحتوي على مكتبة Unity والضغط على Export لبدء عملية التصدير. بعد اكتمال التصدير، ستجدي مجلد يحتوي على مكتبة Unity في المسار الذي اخترتيه، باستطاعتك الآن دمج تلك المكتبة في مشروع Flutter كما هو موضح في الخطوات التي شرحها سابقًا.
  7. يمكنك ربط Python بلغة JavaScript .و هناك عدة طرق لتحقيق ذلك، ولكن الطريقة الأكثر شيوعًا هي استخدام واجهات برمجة التطبيقات (APIs). يمكنك إنشاء واجهة برمجة تطبيقات (API) باستخدام إطار عمل مثل Flask أو Django في Python كما بالعليق السابق . حيث ستقوم هذه الواجهة بتعريف نقاط نهاية تتيح لك الوصول إلى الدوال التي كتبتها في Python. بعد ذلك، يمكنك استدعاء هذه النقاط النهائية من جانب العميل (Client-side) باستخدام JavaScript وإجراء طلبات HTTP مثل GET أو POST لتمرير البيانات والحصول على النتائج. على سبيل المثال، إذا كتبت دالة في Python لحساب المتوسط الحسابي لمجموعة من الأرقام، يمكنك إنشاء نقطة نهائية في واجهة برمجة التطبيقات تسمح لك بإرسال الأرقام كبيانات JSON وتستدعي دالة Python لحساب المتوسط وإرجاع النتيجة. هناك أيضًا طرق أخرى مثل استخدام WebAssembly أو إطارات عمل مثل Transcrypt أو Brython التي تتيح لك كتابة كود Python يمكن تشغيله مباشرة في المتصفح. ومع ذلك، فإن استخدام واجهات برمجة التطبيقات هو الأكثر شيوعًا وفعالية.
  8. ملحوظة: يرجى كتابة عنوان واضح حتى تعم الفائدة على الجميع. بخصوص استخدام لغة البايثون من خلال الجافاسكريبت، فيمكن ذلك عن طريق إنشاء واجهات برمجية التطبيقات APIs ثم استدعاؤها من خلال الجافاسكريبت، وفي الحقيقة هذا يتم مع كل لغات البرمجة وليس مع البايثون فقط. ووجهة برمجة التطيبقات API هي عبارة عن وظائف يتم كتابتها بلغة برمجة معينة على الخادم، ثم تهيئتها لتكون متاحة لاستدعائها بواسطة أي لغة أخرى. بالنسبة لبايثون، فإن أطر عمل مثل الفلاسك والجانجو Flask & Django يوفران بيئة تطوير جاهزة تُمكن المبرمج من البدء في كتابة الواجهات البرمجية بكل سهولة ويسر.
  9. هل استطيع ربط بايثون بلغة الجافا سكريبت بحيث استخدم ال Functions التي اكتبها بالبايثون في الجافا سكريبت واضيفهم الى موقعي؟
  10. وعليكم السلام ورحمة الله وبركاته . مرحبا محمد . نعتذر عن المشكلة التي تواجاهك حاليا . من المفترض حين الإشتراك فإن قسم دوراتى يظهر فوريا بعد الإشتراك ويمكنك الدخول ومشاهدة الدورة دون أى مشاكل . ولكن يبدوا أنه حدثت مشكلة لديك تمنع ظهور القسم لديك.لذلك الحل هو التواصل مع الدعم كما فعلت وسيتم الرد عليك في أسرع وقت إن شاء الله . لا تقلق من التأخير في الرد فسوف يتم حل المشكلة لديك إن شاء الله . إذا لم يتم الرد عليك بحلول نهاية اليوم الحالي من فضلك أخبرنى . شكرا لتفهمك وبالتوفيق إن شاء الله
  11. السلام عليكم أود الاستفسار عن الوقت اللازم حتى أتمكن من الوصول لمحتوى الدورة التي اشتركت بها؟؟ حيث أني قمت بالاشتراك بدورة الذكاء الاصطناعي منذ صباح الأمس و تمت عملية الدفع بنجاح وإلى الآن لم أتمكن من الوصول إلى محتوى الدورة ولم يظهر لي خيار (دوراتي) على شريط المهام الرئيسي على صفحة الحساب الخاص بي!!! مع العلم اني قمت بالتواصل مع المساعدة الخاصة بموقع الأكاديمية عبر المحادثة المباشرة و عبر البريد الالكتروني ولم يتم الرد حتى الآن!!! هل هناك أي طريقة أخرى للتواصل لحل المشكلة؟ مع الشكر
  12. وعليكم السلام، إذا لم تكن باحثا في الذكاء الاصطناعي، فهذا ليس اختصاصك، لأن تطوير المعادلات شيء معقد، ومعظم ما سيأتي في بالك من تطويرات ستجد أن هناك من سبقك وقام بها على أغلب الظن. لذلك، فالنماذج الموجودة في مكتبات تعلم الآلة هي أكثر النماذج التي تمت مراجعتها ويمكنك أن تضمن أنها تعمل بشكل صحيح ويمكنك الاعتماد عليها. بينما لو طورت نموذجا خاصا بك فهناك احتمالية كبيرة في أن تقع في خطأ ما ويتسبب في إعطائك نتائج خاطئة يصعب إصلاحها. عندما تفهم كيف تعمل نماذج الآلة على الأمثلة التي تدرسها، يمكنك بعدها تطبيقها على مواضيع مختلفة لم يتم تدريسها، وقد يكون بعضها جديدا كليا لم يقم به أحد من قبلك. وهذا ممكن جدا، لأن المواضيع تختلف باختلاف الأماكن والأزمنة. فقد يكون هناك مشكل محدد في بلادك لا يوجد في البلدان الأخرى، وهنا يمكنك البحث عن كيفية الحصول على المعلومات اللازمة من بلادك، ثم معالجتها واستخدامها في نموذج تعلم آلة لحل ذلك المشكل. وربما تتمكن بعدها من نشر هذا النموذج كخدمة مدفوعة، أو شيء مشابه. هذا يعتبر إبداعا في المجال.
  13. وعليكم السلام لنبدأ أولا بالتكلم عن فهم المعادلات المقصود هنا هو أنك تفهم كيف تعمل المعادلات المستخدمة في النماذج، مثل معادلات الانحدار الخطي أو الشبكات العصبية. هذا الفهم يساعدك على استخدام هذه النماذج بفعالية وتحديد متى يكون النموذج مناسبا للمشكلة التي تعمل عليها. فهمك للمعادلات يساعدك أيضًا في تحسين النماذج واكتشاف الأخطاء. ثم تطوير المعادلات هذا يتطلب مستوى أعلى من الفهم والابتكار. يعني أنك تقوم بابتكار وتطوير معادلات جديدة أو تحسين المعادلات الحالية بشكل مبتكر. هذا يتطلب معرفة عميقة بالرياضيات والخوارزميات. فالخطوة الأولى هي فهم كيف تعمل الأشياء الموجودة، ثم بعد ذلك يمكنك محاولة تطوير أشياء جديدة.
  14. السلام عليكم هل المقصود ان اطور المعادالات الموجود في النماذج ؟ والا المقصود ان افهم المعادالات وسعاتها اقدر ان ابداع في المجال ؟ انا كا مطور في المجال ده اقصد كده
  15. وعليكم السلام، في مجال تعلم الآلة سوف تجد أن معظم الوقت يذهب في الجزء النظري والتفكير في الحل، وليس في كتابة الحل. عندما تكون عندك بيانات، فسوف تحتاج إلى معرفة ما هي المدخلات وما هي المخرجات، وكيف تقوم بتحويل المدخلات لتناسب النموذج، وما هو النموذج المختار وما هي إعداداه وكيف يعمل، وكيف تقوم بتقسيم البينات وما الذي تستخدمه للتدريب وما الذي تبقيه للاختبار، وكيف تحسب جودة النموذج. كل هذا عندما يتم تحويله إلى كود بالشكل الصحيح وعند استخدام مكتبة جيدة مثل Scikit-learn سوف ترى أنك قد تستطيع كتابته أحيانا في 10 سطور! مما يجعل قارئ تلك السطور يظن أن البرنامج بسيط. لكن الوصول إلى تلك 10 سطور يتطلب فهما عميقا يحتاج إلى ساعات أو أيام من العمل.
  16. البارحة
  17. أجل كما قلت لي أولا شكرا على كلامك ففي بعض المشاكل أجلس بالساعات وأسأل هنا وهناك وأبحث وحتى أستخدم الذكاء الاصطناعي ولكن لا يساعدني دائما بل يزيد المشاكل فعندما أستسلم أسأل أحد المدربين وأحيانا أخرى أتكاسل قليلا عن البحث وأسأل المدربين شكرا على كلامك الطيب وأيضا لا أكذب ولكن أصبحت أكثر للأحطاء التي تأتي إلي وأفهم أين المشكلة فهذا شيئ جيد ويساعدني كثيرا وفي أحد المشاكل التي واجهتني من البحث استطعت حل مشكلة في جهازي مما أدت إلى مساعدتي في لغات البرمجة وهي مشكلة الpath موضوع يطال شرحه ولكن عرفت ما هو الحل أيها المدربون شكرا لكم جدا على مساعدتكم لي ومن الدربين الذين يعرفونني مشاكل القوية والثقيلة والصعبة جدا فأشكركم وبشدة على جهدكم لمساعدتي 😅
  18. بالطبع لا، قد أديت ما عليك، هناك أخطاء بحاجة إلى خبرة مكتسبة تتأتى من التعلم من الأخطاء بمرور الوقت وتطور المستوى من خلال تنفيذ المشاريع والممارسة العملية والتعرض لأفكار وأخطاء مختلفة، لذا في البداية أنت بحاجة إلى من يرشدك لتوفير الوقت عليك وتوجيهك للطريق الصحيح. ليس المطلوب منك حل جميع المشاكل، بل المطلوب هو بذل جهدك ومحاولة اكتشاف ما المشكلة وفهم السبب، وإن تعذر ذلك عليك بالسؤال فمن لا يسأل لا يصل وتلك خصلة ليست جيدة فالسؤال بعد أن إتمام جانبك من المجهود هو الصحيح. المقال التالي سيفيدك:
  19. وعليكم السلام ورحمة الله وبركاته . نعم صحيح إن الأخطاء هى ما ستعلمك أكثر من أى شئ . حيث في بداية مسيرتى وبداية التعلم حينما كنت أقع في خطأ ما فإنى أقوم بالبحث عنه وحينما أجد الإجابة فإنها تظل في ذاكرتى ومن الصعب أن أخطا نفس الخطأ مرة أخرى أو إذا تكرر معى فسأستطيع حله بسهوله . ولكن توجد بعض الأخطاءالتي من المستحيل أن تستطيع حلها بنفسك فبعد المحاولات الكثيرة التى من الممكن أن تستمر لأيام ستجد أنك لم تستطع حلها فهنا لا بئس في سؤال أى شخص أو حتى نحن المدربون هنا سعداء بحل أى مشكلة تواجه أى طالب. لذلك فإن هذا ليس تقصيرا منك بل هذا هو المسار الصحيح للتعلم حاول حل الأخطاء نفسك أولا وإذا وجدت صعوبة فلا تتردد في السؤال وحاول فهم لما حدثت المشكلة وفهم الحل الخاص بها . حيث إذا لم تقم بالمحاولة بنفسك فستستهل الأمور و إذا واجهتك أى مشكلة فلن تستطيع حلها حيث أول شئ ستقوم به هو سؤال أى شخص ولن تحاول حتى فهم الخطأ و الحل .
  20. السلام عليكم! سمعت كثيرا عن موضوع تعلم البرمجة والأخطاء وسمعت عن أنه إذا واجهتك مشكلة قم بالبحث بنفسك وما إلى ذلك فهل بأنني أسأل المدربين بارك الله فيهم هل هذا تقصير مني وفي نفس الوقت بعض المشاكل أبحث عنها بكقرة وعنما أستسلم أسأل المدرب
  21. تعلم الآلة يعد مجالًا واسعًا ومعقدًا، ولكنه بالطبع أكثر سهولة عند البدء بالمفاهيم الأساسية وتتقدم بشكل تدريجي، وبما أنك تدرس حاليًا الـ Regression الانحدار، فتلك نقطة جيدة للبدء. وتتوفر العديد من المكتبات والأدوات مثل Scikit-Learn، TensorFlow، و PyTorch التي تسهل عملية بناء نماذج تعلم الآلة، فتلك المكتبات توفر واجهات برمجية سهلة الاستخدام وأدوات جاهزة للانحدار، التصنيف، التجميع، وغيرها. المجال الذي اخترته ليس بالسهل فهو بحاجة إلى وقت أطول وصبر كذلك، لذا عليك البدء بالأساسيات ثم التدرج ولا تنتظر نتائج سريعة، لذا مفتاح النجاح هو الاستمرار والصبر. فلا تنظر للأمر بصورته الكلية فتحبط، بل حاول تخطي جزء جزء لتصل، فمع تقدمك في تعلم الآلة ومحاولتك لحل مشكلات أكثر تعقيدًا، فإن تعقيد الكود يزيد بشكل كبير، وسيتطلب منك ذلك القيام بالعديد من المهام الإضافية، مثل: معالجة البيانات Preprocessing وتشمل تنظيف البيانات، معالجة القيم الناقصة، تحويل البيانات النصية إلى رقمية، وغيرها، وذلك أمرًا مرهقًا ويستغرق وقتًا طويلًا. هندسة الميزات Feature Engineering من خلال إنشاء ميزات جديدة من البيانات الحالية بشكل إبداعي لزيادة دقة النموذج، وتلك العملية تتطلب تفكيرًا إبداعيًا وفهمًا عميقًا للبيانات.
  22. السلام عليكم انا هنا بتكلم فقط علي مجال تعلم الاله مش تعلم العميق الان انا بتدرس مجال تعلم الاله لسه في اول حاجه وهي الRegression فا هل مجال تعليم الاله سهل من حيث بناء الكود ؟
  23. هل إصدار Gradle المستخدم في مشروعك متوافق مع إصدار Android Gradle Plugin (AGP) المذكور في الخطأ (7.3.0)، عليك العثور على ملف gradle-wrapper.properties وتحققي من تعيين إصدار Gradle بشكل صحيح. distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.0-all.zip أيضًا هل مشروع Unity تم تصديره بشكل صحيح كـ Android Library، عليك القيام بذلك من خلال الذهاب إلى File > Build Settings وتحديد Android كمنصة الهدف، ثم التأكد من تمكين خيار Export Project إذا كان موجودًا. وفي مشروع Flutter، تأكدي من أن لديك إعدادات Gradle الصحيحة لاستيراد مشروع Unity، من خلال فتح ملف settings.gradle في مشروع Flutter وتأكد من إضافة مشروع Unity بشكل صحيح. include ':app' include ':unityLibrary' project(':unityLibrary').projectDir = new File('../UnityExport/unityLibrary') ثم افتحي ملف build.gradle لمشروع Flutter وإضافة تبعية مشروع Unity بشكل صحيح. dependencies { implementation project(':unityLibrary') } ثم تفقد هل إعدادات Kotlin متوافقة مع إصدارات الأدوات الأخرى، توجهي إلى ملف build.gradle وتفقدي هل تم إضافة الإعدادات الصحيحة. buildscript { ext.kotlin_version = '1.5.31' repositories { google() mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:7.3.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } بعد تطبيق جميع التعديلات، قومي بإعادة مزامنة المشروع من خلال Android Studio أو استخدام أمر flutter pub get لإعادة جلب الحزم والتبعيات.
  24. تسمح لك الإدارة المرئيّة للمشاريع برؤية حجم العمل والمهامّ معروضةً في صورة مرئيّة. وييسّر هذا تبسيط الجهود تبسيط الجهود بين أفراد الفريق، والبقاء على المسار، وتفادي حالات عنق الزّجاجة المحتملة. وعادةً ما يتمّ ذلك على شكل جدول مخطّط للمشروع، أو رزنامة، أو ألواح كانبان Kanban boards. تختلف الطّريقة الّتي يعالج بها كلّ منا المعلومات، لكنّنا نشترك في أنّ رسم العمل بصورة مرئية في عقولنا أمر مهمّ لنا جميعًا. والإدارة المرئيّة هنا للمشاريع هي طريقة لإدارة هذه المشاريع، حيث تجمع تقنيات إدارة المهام التّقليديّة، وأدوات التّقرير، والتّواصل بالجانب المرئيّ لعملك. ماهية الإدارة المرئية للمشاريع الإدارة المرئيّة للمشاريع هي طريقة تتظّم بها العمل وتديره في قوالب مرئيّة مثل المخطّطات الزّمنيّة، وألواح كانبان Kanban boards، والرّزنامات. توظّف طرائق الإدارة المرئيّة هذه نفس الجوانب الّتي تغطّيها نظيراتها غير المرئيّة، مثل المهامّ، وآجال التّسليم، وأفراد الفريق، ولكن بطريقة تجعلها أسهل رؤيةً واستعمالًا، وتتبّعًا. لذا إذا كنت ترسل في السابق قائمة مهامّ إلى فردٍ في الفريق، فإنّك في الإدارة المرئيّة قد تضيفه إلى مخطّط زمني مرئيّ مع إرفاق مهامّه إلى اسمه. فوائد استعمال الإدارة المرئية للمشاريع توفّر الإدارة المرئيّة للمشاريع في لمحة واحدة رؤيةً عميقةً لما يعمل عليه كلّ فرد من الفرق، ومتى يجب تسليم مخرجات المشروع، وما هي معالم الإنجاز، وأكثر. وهي بهذا تُعَد نمط إدارة أعمال أكثر تفاعليّةً يسهّل التّعاون. هناك العديد من الأسباب الّتي تدفع إلى التحوّل إلى الإدارة المرئيّة أو على الأقلّ دمجها في إدارة مشاريعك، نذكر منها: تحصيل رؤية أسرع: يمكنك بسرعة وسهولة الإلمام بالمعلومات حين تكون وضعيّة المشروع ومقاييسه ومهامّه كلّها في مكان واحد. تقليل حالات عنق الزّجاجة: يمكن لأعضاء الفريق وأصحاب المصلحة الحصول على المعلومات الّتي يحتاجونها، في الوقت المناسب، ممّا يخفّض من حالات عنق الزّجاجة. متابعة دورة حياة المشروع: بدءًا من تعيين مهامّ المشروع، مرورًا بالتّواصل عبر أدوات التّواصل، وانتهاءً بالتّقارير؛ يمكنك استعمال أنواع مختلفة من طرائق الإدارة المرئيّة للمشاريع من البداية إلى النّهاية. تنسيق عمل الفريق: التّمكين للتّعاون بين الأقسام المختلفة بجمع كلّ أجزاء العمل في مكان واحد واضح للعيان. تسهيل الاطّلاع على العمل: إعطاء القادة وأصحاب المصلحة التّنفيذيّين اطّلاعًا عميقًا على عمل فريقك دون الحاجة إلى إضجارهم بالتّفاصيل. التعرّف على معيقات العمل المحتملة باكرًا: تصوّر تبعيّات المشروع، ومعالمه الإنجازيّة، ومعيقاته حتّى تتمكّن من معالجة المشاكل قبل حدوثها. ثلاث طرائق لتصور تقدم المشروع هناك ثلاث طرائق شهيرة لإنشاء أداتك الخاصّة في الإدارة المرئيّة للمشروع: المخطّطات الزّمنية Timelines: أو مخطّطات غانت Gantt charts. ألواح كانبان Kanban boards. رزنامات المشروع Project calendars لكلّ واحدة من هذه الطّرائق حسناتها وعيوبها، لذا يعتمد اختيار أيّها أنسب لك على نوع المشروع الّذي تخطّط له، وكيفيّة استخدامك لها. وبغضّ النّظر عن أيِّها اخترت، فإنّها جميعًا تعمل بامتياز ضمن برمجيّة إدارة مشاريع (برنامج حاسوب). واعتمادًا على البرمجيّة الّتي تستعملها، يمكنك تخصيص أيّ من تلك الطّرائق تخصيصًا شاملًا، وإضافة الأتمتة، واستخدام المزايا البديهيّة مثل السّحب والإفلات drag and drop. وفيما يلي نشرح كيفيّة عمل كلّ طريقة، وأنواع المشاريع الّتي تناسبها. 1. المخططات الزمنية يمكنك إعطاء خطّة مشروعك صورةً مرئيّةً بإنشاء مخطّط زمني أو مخطّط غانت للجدول الزّمني لمشروعك. ويمكنك عبر إدارة المخطّط الزّمني تنظيم تفاصيل المشروع في مخطّط أعمدة بيانيّة لإظهار متى يجب إنهاء كلّ مهمّة أو مُخرج في مشروع، وكم سيستغرق كلّ منها. حالات استخدام المخططات يمكنك استخدام والاستفادة من المخطّطات في المشاريع المحدودة بوقت، والّتي تحتاج التزام مهامّها بآجال تسليم نهائيّة، وذلك لأنّ المخطّطات تظهر لك متى يجب بدء المهمّة، وكم من الوقت ستستغرق. وبتجميعك لكلّ شيء في مخطّط زمنيّ فإنّك تسهّل على نفسك توزيع الموارد، وتعيين أعضاء الفريق على الخطوات المختلفة، وتصوّر المهامّ الاعتماديّة (المهامّ المعتمدة على إنهاء أخرى). يمكنك باستعمال إدارة المخطّطات الزّمنية إنشاء خطّة مشروع تظهر كيف تتفاعل كلّ جوانب المشروع مع بعض، ويساعدك هذا في إجراء التّغييرات اللاّزمة لمنع المشاكل من الحدوث. وهذه المخطّطات ممتازة في حالات: إدارة الحملات. إطلاق المنتجات. تخطيط التّظاهرات. حالات عدم استخدام المخططات تُعَد المخطّطات الزّمنيّة كما أسلفنا مفيدةً عندما يكون لكلّ مهمّة تاريخ بداية وتاريخ نهاية معروفان، أمّا إن لم تكن تلك التّواريخ معروفةً فليس هنالك ما تصوّره مرئيًّا، لذا عندما تخطّط لمشروع تكثر فيه المهامّ اليوميّة، أو المهامّ الّتي آجالها النّهائيّة مرنة كما هو الحال في إدارة مشاريع آجايل، فإنّ من الأفيد تصوّر عملك في رزنامة مشروع، أو لوحة كانبان. مثال مخطط زمني لنفترض أنّك تخطّط لإطلاق منتج، وتحتاج قصد تحقيق أهدافك بنجاح إلى العمل كفريق ديناميكيّ متعدّد الوظائف. عندها تجمع فريقك من أقسام المنتج، والهندسة، والتسويق، والمبيعات، والدعم الفنّيّ لإنجاح إطلاق المنتج؛ وبما أنّك تعمل مع الكثير من أصحاب المصلحة، فإنّ المشروع سيكون معقّدًا لا محالة. يعطي المخطّط الزّمني صورةً مرئيّةً للجميع حول تقدّم المشروع، وخارطة طريقه ليكون الجميع في مسار واحد. ويمكنك نتيجةً لذلك تنسيق إدارة الموارد، وتوقّع أوقات الوصول إلى المعالم الإنجازيّة، ورؤية المهامّ الاعتماديّة لفكّها قبل وقوعها، ورؤية تواريخ البداية والنّهاية جميعها في مكان واحد. وبهذه الطّريقة يملك لكلّ فرد في فريق المشروع رؤيةً واضحةً لخطّة الإطلاق، وما هو مطلوب لإنجاحه من البداية إلى النّهاية. بعد أن تحضّر مخطّطا زمنيًّا لمشروعك، لا تنسَ مشاركته مع زملائك وأصحاب المصلحة، وتحديث التّفاصيل عند كلّ تغيير. وذلك أنّ مشاركة مصدر حقيقة واحد مع الجميع يعطي كلّ فرد رؤية واقعيّة محدّثة على عمل الفريق. 2. ألواح كانبان Kanban boards ألواح كانبان هي نظام مرئيّ لتنظيم المشاريع تعطي فيه كلّ جزء تنفيذيّ من العمل بطاقة. ترتّب هذه البطاقات في أعمدة يمثّل كلّ منها مرحلة من المشروع، أو مرحلة من عمليّة، أو المعنيّ بالمهمّة، أو أولويّتها، أو أشياء أخرى بما يناسب عمل فريقك. وكلّما تقدّم العمل على المهمّة أو المُخرَج تحرّك بطاقتها من عمود إلى عمود آخر يناسب وضعها الجديد ليتمكّن من رؤيته الجميع. حالات استعمال ألواح كانبان يناسب نظام ألواح كانبان المشاريع الّتي تنقسم إلى مراحل. سواءً كانت تلك المراحل بسيطةً وتتدرّج من "مهمّة للتّنفيذ"، إلى "مهمّة قيد التّنفيذ"، وتنتهي بـ "مهمّة منتهية"؛ أو كانت أكثر تعقيدًا. المهمّ في الأمر أن تكون المراحل متدرّجة، بحيث تنتقل المهمّة بينها من واحدة إلى التّالية، لذا فإنّ ألواح كانبان ممتازة لفرق آجايل الّتي تعمل في دورات تطوير أو ما يعرف بالسبرنت sprint لأنّها توفّر رؤيةً واضحةً لتقدّم العمل. ومن أمثلة ذلك: تتبّع الأخطاء bug tracking. تخطيط دورة التطوير. جلسات دورات التطوير الاسترجاعيّة. اجتماعات أجايل اليوميّة المختصرة. إدارة إنتاج الويب. طلبات العمل. ألواح سكرام scrum boards. مثال مشروع ألواح كانبان تدفّق العمل في تتبّع الأخطاء مثال عن مشروع يمكن إدارته باستخدام ألواح كانبان لأنّ كلّ مهمّة فيه تحتاج إلى المرور بعدّة مراحل قبل أن تعدّ منتهية. فعندما تحصل مثلا على مهمّة لخطأ جديد، فإنّه يحتاج أوّلا إلى إعطائه رقم تعريف، وتدوينه في في سجلّ الأعمال التّراكميّة، ثمّ يجري العمل عليه، وأخيرًا الانتهاء منه. فتجهّز لوحة كانبان بالأعمدة الممثّلة لما يلي: أخطاء جديدة (من سجلّ أعمالك التّراكميّة). جاهزة للعمل عليها. في طور العمل. في ضمان الجودة. منتهية ولكلّ خطأ جديد يبلَّغ عنه، يمكن لفريقك بسهولة إنشاء بطاقة جديدة ثمّ نقلها من عمود إلى الآخر بتقدّم العمل، منشئين بفعالية قائمة مهام لكلّ مرحلة مع تحديثها دوريًّا. غالبًا ما تُصنع ألواح كانبان من ألواح فعليّة مع بطاقات لاصقة، ولكن بإمكانك إنشاؤها افتراضيًّا على الإنترنت عبر وسائل مثل: أنا و Hygger و Asana و Trello. ويعطيك هذا إمكانيات كثيرة، مثل تخصيص المجالات، والأوصاف، والملفات؛ مع إضافة المتعاونين على كلّ بطاقة لتتمكّن بسهولة من جمع معلومات إضافيّة حول المشروع تساعد بها فريقك على العمل معًا لتحقيق النّجاح. 3. رزنامة المشروع تعمل المخطّطات الزّمنيّة وألواح كانبان بامتياز في الكثير من المشاريع، ولكنّك أحيانًا لا تحتاج إلى أكثر من رزنامة تقليديّة. رغم بساطة الرّزنامات وسلاستها إلا أنّها قد تكون مثاليّةً في التّخطيط لبعض المشاريع. حالات استعمال رزنامة المشروع تختلف الرزنامة عن سابقتيها بتميّزها في التّخطيط للمشاريع الّتي بها مهامّ كثيرة مع آجال نهائيّة مختلفة، وذلك أنّ معرفة متى عليك تحقيق معلم إنجاز، أو تسليم أحد الأصول في أسبوع معيّن، أو شهر، أو سنة يمكنه مساعدتك على التخطيط المسبق لتنفيذ المطلوب في وقته المناسب. وتساعدك رزنامة المشروع تحديدًا في إدارة: رزنامة التّحرير. رزنامة محتوى التواصل الاجتماعي. حالات عدم استعمال رزنامة المشروع تساعدك رزنامة المشروع على التّخطيط المسبق للأسبوع أو الشّهر أو الرّبع أو حتّى السّنة، ولكنّها أقلّ فائدةً عند كثرة المهامّ اليوميّة. وفي تلك الحالة الّتي تستدعي الانهماك في العمل الّذي يقوم به فريقك كلّ يوم فإنّ لوحة كانبان أو حتّى قائمة مهامّ قد تكون أنسب لك ولفريقك. مثال رزنامة مشروع إذا كنت تخطّط لمشروع فإنّ الرّزنامة تمنحك صورة مرئيّة للعمل المستحقّ خلال الأيّام والأسابيع القادمة. وتتجلّى فائدة الرّزنامة عندما يشمل المشروع الكثير من الفرق وأصحاب المصلحة المختلفين. إذا امتلكت مثلًا رزنامةً تحريريّةً شاملة، فإنّ كلّ من في الشّركة يعرف المحتوى المخطّط والمنشور، ومتى تنشر مواضيع بعينها. وبهذا يمكن لفريق المبيعات إرسال المقالات المعنيّة إلى العملاء المحتملين، وللمديرين توزيع الأصول على فرقهم، ولفريق التّحرير معرفة من يعمل على كلّ موضوع. يمكنك باستخدام أدوات إدارة المشاريع المرئيّة (مثل أنا المقدمة من شركة حسوب، وAsana وTrello وغيرها) إنشاء قائمة مهام المشروع، وجدولة المواعيد النّهائيّة، ويمكنك تحريك المهام في الرزنامة عند الحاجة إلى تغيير الأجل النّهائيّ أو إضافة ملفات إلى المشروع للمزيد من التّعاون. الصور المرئية للمعلومات يُعَد تصوّر المعلومات جانبًا مهمًّا آخر من إدارة المشروع البصريّة. لأنّك متى احتجت لكتابة التّقارير أو إرسال عروض حال، فإنّ عرضها في نمط تصوّري أكثر فاعليّة. على سبيل المثال، يمكنك إرسال تقرير نصّيّ إذا كنت تتابع إطلاق موقع إلكتروني: "أنهينا 70% من المهامّ المستهدفة." أو يمكنك إظهار تلك المعلومات في نمط بصريّ كما يلي: لكلّ من الطّريقتين استعمالاتها بالطّبع، ولكنّ أصحاب المصلحة صاروا يفضّلون البيانات البصريّة أكثر لأنّها أسهل فهمًا، وأسرع مشاركةً. أفضل أداة إدارة مرئية للمشاريع لا يمكن القول بأنّ هناك أداة أفضل من جميع منافساتها، بل هناك الأداة الأفضل بالنّسبة لك ولحجم العمل الحاليّ. استعمالك المخطّطات الزّمنية، وألواح كانبان، والرّزنامة كلّها طرائق ممتازة في تصوّر كلّ الخطوات في مشروعك لتتمكّن من رؤية الصّورة الأكبر دون المخاطرة بتجاوز أيّة تفاصيل. ترجمة -وبتصرّف- للمقال ‎.3 types of visual project management: Timelines, calendars, and boards (with examples) اقرأ أيضًا ما هي إدارة المشاريع؟ دليلك الشامل إلى عرض برمجيات إدارة المشاريع أساسيات إطار الإدارة الاستثنائية للمشاريع XPM دليل المبتدئين لمنهجية أجايل Agile مقارنة بين مدير المنتج ومدير المشروع
  25. بالفعل هناك عالم من التقنيات والمفاهيم التي تقع خلف الكود كما أنه هناك الكثير من الشركات ولكن كما أخبرك عمر في التعليق السابق فإن التقنيات والمهاارات التي ذكرتها هي مجالات منفصله ومع ذلك كـ Full Stack Web Developer، تعلم هذه المهارات بشكل بسيط يضيف قيمة كبيرة لمهاراتك ويجعلك أكثر كفاءة واستقلالية في العمل على المشاريع . لذلك لا يفترض أن تتعلم هذه المجالات بشكل متعمق كمطور مواقع ولكن يفضل لو تتعلم بعض الأشياء البسيطة أو فكره عامة عن المجال وبالنسبة لما يجب تعلمه فهو ما تحتاجه بالفعل مثل تعلم عن أنواع السيرفرات المختلفة (مشتركة، خاصة، VPS) وفهم مزايا وعيوب كل نوع. معرفة شركات استضافة الموثوقة، تأخذ بعين الاعتبار سرعة الاتصال، موثوقية الخدمة، ودعم العملاء. يفضل تعلم أساسيات إدارة السيرفر، مثل تثبيت البرامج، تحديثات الأمان، وإدارة ملفات الموقع. تعلم أساسيات أمن الموقع وبالنسبة لتعلم المفاهيم والتقنيات السابقة لا تحتاج لدورة معينة إنما عند تقف عن مفهوم ما قم بالبحث عنه وقراءة المقالات وبعدها ستعرف ما يجب عليك تعلمه أو المصادر يفضل الإطلاع على المقالات الموجودة بالرابط التالي https://academy.hsoub.com/devops/general/
  1. عرض المزيد
×
×
  • أضف...