نحن اليوم أمام موضوع من أهم المواضيع التي تلزم أي مبرمج ، أن نحصل على عدد ما بشكل عشوائي وبشروط معينة . ما هي اللعبة التي يتم برمجتها دون استخدام الأرقام العشوائية ؟ كيف تتخيل لعبة تتكرر بتفاصيلها في كل مرة ، وكم من الملل سيواجه اللاعب حينها ؟ حتى في لعبة XO سيواجه الكمبيوتر طريقين لهما نفس احتمال الفوز ، أي الطريقين سيختار وعلى أي أساس ؟ تلك هي الأرقام العشوائية .
لكي تستطيع توليد generating رقم عشوائي ، ستستخدم اقتران ()rand ، وظيفته إرجاع رقم عشوائي بين 0 و RAND_MAX ، الأخير هو ثابت يختلف من مترجم لآخر ، وهو على الأغلب 32767 ، أعلى قيمة يمكن أن يرجعها الاقتران المذكور .
الكود التالي لطباعة قيمة RAND_MAX ومن ثم طباعة رقم عشوائي .
#include<stdlib.h> // For srand()
#include<iostream.h>
void main()
{
cout << "The value of RAND_MAX is : " << RAND_MAX << endl;
cout << "This is a random integer : " << rand() << endl;
}الرقم الناتج من جملة الطباعة الثانية تعطي رقماً عشوائياً ، لكن ما الفائدة إن كان الرقم نفسه سيطبع في كل مرة ينفذ فيها البرنامج . لحل المشكلة نستخدم الاقتران ()srand ، والذي سيجعل توليد الارقام العشوائية يعتمد على قيمة موجبة يستقبلها ، تلك القيمة ينبغي أن تكون متغيرة باستمرار ، ولتكن ساعة النظام system clock ، ليصبح البرنامج كالتالي :
#include<stdlib.h> // For srand()
#include<ctime.h> // For time()
#include<iostream.h>
void main()
{
srand(time(0)); // Initialize random number generator
cout << "This is a random integer : " << rand() << endl;
}تحتاج لتضمين مكتبة cstdlib المعرف بها ذلك الاقتران ، وبهذه الطريقة سنحصل على قيمة عشوائية مختلفة في كل مرة .
ولكي نحصر تلك القيمة بحيث لا تتجاوز عدداً معيناً نستخدم فكرة باقي القسمة ، إذ أن باقي قسمة العدد a على b يساوي صفراً إن كان من مضاعفات b ، ويزداد تدريجياً بازدياد a إلى أن نعود إلى الصفر من جديد عند وصولنا إلى المضاعف التالي ، كأننا في حلقة دائرية .

مما تقدم ، فإن باقي قسمة أي عدد على n ، يبدأ من الصفر ثم ينمو تدريجياً حتى يصل n-1 وهي أعلى قيمة له ، ثم يعود مجدداً إلى الصفر .
الكود التالي يقوم بطباعة رقم عشوائي من 0 إلى 9 .
cout << rand()%10 << endl;
لاحظ أنه إذا أردنا أعلى قيمة للرقم العشوائي أن تكون n حينها نكتب :
cout << rand()%(n+1) << endl;
ماذا لو احتجنا توليد قيم عشوائية من 3 إلى 8 ؟ البداية هنا لم تكن من الصفر ، الارقام المحتمل الحصول عليها هي 3 4 5 6 7 8 وعددها ستة ، لاحظ أن عددها يساوي 1 + 3 - 8 ، سنقوم بتوليد رقم عشوائي من 0 إلى 5 ثم نضيف 3 على الناتج ليصبح الرقم من 3 إلى 8 .

cout << rand()%6 + 3 << endl; cout << rand()%(last - first + 1) + first << endl;
جملة الطباعة الثانية تعطيك الحالة العامة لطباعة أي رقم عشوائي بين العددين first و last .

◄ اكتب برنامجاً لطباعة رقم عشوائي بين -5 و 5 .
نطبق العلاقة العامة : first = -5 ، last = 5 ، last - first + 1 = 11 ومنه فإن الكود المطلوب :
cout << rand()%11 - 5 << endl;

◄ اكتب برنامجاً لطباعة رقمين موجبين بشكل عشوائي مجموعهما 10 .
في هذا البرنامج نقوم بتوليد العدد الأول بشكل عشوائي ، والثاني ببساطة يساوي مطروحه من العدد 10 .
int a = rand()%11; cout << a << " " << 10 - a << endl;

◄ اكتب برنامجاً لطباعة عدد زوجي من 0 إلى 100 بشكل عشوائي .
نعلم أن العدد الزوجي يمكننا كتابته على الصورة 2n ، وكون العدد من 0 إلى 100 ، قيمة n ستكون من 0 إلى 50 ، فيقوم البرنامج بتوليد قيمة n بشكل عشوائي بينما يطبع 2n
int n = rand()%51; cout << 2*n << endl;
◄ اكتب برنامجاً لطباعة عدد فردي من 1 إلى 99 بشكل عشوائي .
العدد الفردي يمكن كتابته على الصورة 2n+1 ، وكون العدد من 1 إلى 99 ، فإن n ستكون من 0 إلى 49 ، حيث 99=1+49*2
int n = rand()%50; cout << 2*n + 1 << endl;

◄ اكتب برنامجاً لطباعة حرف capital بشكل عشوائي ، ومن ثم طباعة حرف small كذلك .
كل رمز symbol يحمل قيمة عددية تسمى ascii code ، لا يشترك رمزان في تلك القيمة . أسهل طريقة لمعرفة تلك القيمة هي وضع علامة + قبل ذلك الرمز عند طباعته ، كالآتي :
cout << +'A' << " " << +'Z' << " " << +'a' << " " << +'z' << endl;
The output is : 65 90 97 122
إذن في البداية علينا توليد رقم عشوائي من 65 إلى 90 ، وآخر من 97 إلى 122 ، ثم نحول الرقم إلى رمز مباشرة كالآتي :
char CH = rand()%('Z' - 'A' + 1) + 'A';
char ch = rand()%('z' - 'a' + 1) + 'a';
cout << CH << " " << ch << endl;
للاختيار بين أمرين بشكل عشوائي ، نولد قيمة عشوائية إما 0 أو 1 ، نحصل عليها من باقي القسمة على 2 ، ثم بجملة شرطية نختار بين الأمرين ، كالآتي :
◄ اكتب برنامجاً يطبع إما Hello أو Bye بشكل عشوائي .
int x = rand()%2; if(x==1) cout << "Hello" << endl; else cout << "Bye" << endl;
◄ اكتب برنامجاً يطبع إما 7 أو 12 بشكل عشوائي .
int x = rand()%2; if(x==1) cout << 7 << endl; else cout << 12 << endl;
حركة تكتيكية بسيطة إذا جعلنا البرنامج يختار ما بين 7+0*5 أو 7+1*5 ، لاحظ أن الذي يتغير هو فقط معامل العدد 5 ، لنحصل في النهاية على 7 أو 12 ، كما يلي :
cout << 7 + 5*(rand()%2) << endl;
◄ اكتب برنامجاً يطبع إما T أو F بشكل عشوائي .
char CH = 'F' + ('T' - 'F')*(rand()%2);
cout << CH << endl;◄ اكتب برنامجاً يطبع حرف capital أو small بشكل عشوائي .
الفرق بين القيمة العددية لحرف capital وآخر small هو 32 ، لذا فإن الكود التالي يسند إلى المتغير CH حرف capital مضافاً إليه 0*32 أو 1*32 أي إما يبقى capital أو يزيده 32 ليصبح small
char CH = rand()%('Z' - 'A' + 1) + 'A' + 32*(rand()%2);
◄ اكتب برنامجاً يطبع 3 أعداد موجبة مجموعها 10 بشكل عشوائي .
int n1 = rand()%11; int n2 = rand()%(11 - n1); int n3 = 10 - n1 - n2; cout << n1 << " " << n2 << " " << n3 << endl;

◄ اكتب برنامجاً يطبع عدداً أقل من 100بشكل عشوائي يقبل القسمة على 7 .
أكبر عدد ينطبق عليه الشرط هو 98 حيث 14*7=98 ، نكتب برنامجاً يختار عدداً n من 0 إلى 14 بشكل عشوائي ثم يطبع 7*n
cout << rand()%15*7 << endl;
◄ اكتب برنامجاً يطبع مربعاً كاملاً أقل من 100 .
int x = rand()%10; cout << x*x << endl;
◄ اكتب برنامجاً يطبع عدداً أولياً أقل من 100بشكل عشوائي .
هنا في هذه الحالة لا يمكننا التنبؤ بالعدد الأولي لعدم وجود قاعدة ثابتة تحكم الأعداد الأولية ، حينها سنلجأ إلى اسلوب التجربة والخطأ
do
{
int p = rand()%100;
} while(!isPrime(p));
cout << p << endl;انظر إلى تعريف الاقتران ()isPrime في موضوع الأعداد الأولية ، لن يخرج البرنامج من الدوران ما لم يحصل على عدد أولي ، وهنا يبقى التخوف من دوران البرنامج لعدد هائل من المرات ، لا أحد يعلم ! من هنا أتتني فكرة أن نخزن الأعداد الأولية الأقل من 100 في مصفوفة ثم طباعة أحد عناصرها بشكل عشوائي ، حينها نضمن أنه أولي من أول مرة . وإن كنت لا تدري كم عدداً أوليا هناك أقل من 100 ، اعتبرها 30 كحد أقصى .
int primes[30];
primes[0] = 2; // since 2 is a special case
int counter = 1; // since 2 has been stored in the array
for(int i=3; i<100; i+=2)
if(isPrime(i))
primes[counter++] = i;
cout << primes[rand()%counter] << endl;◄ أكتب برنامجاً لإسناد القيم إلى مصفوفة منطقية بشكل عشوائي .
bool b[10];
for(int i=0; i<10; i++)
b = (rand()%2 == 1);◄ قم بالتعديل على البرنامج السابق بحيث يكون احتمال false ضعف احتمال true
bool b[10];
for(int i=0; i<10; i++)
b = (rand()%3 == 1);
◄ اكتب برنامجاً يطبع جميع الأعداد من 0 إلى 5 بشكل عشوائي دون تكرار .
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int main()
{
srand(time(0));
int num[6] = {0, 1, 2, 3, 4, 5};
for(int c=6; c>0; c--)
{
swap(&num[c-1], &num[rand()%c]);
cout << num[c-1] << endl;
}
return 0;
}وهذه الصورة هي جزء توضيحي لسيناريو محتمل . لاحظ أنه في كل مرة يتم استبدال العنصر في الموقع c - 1 من المصفوفة بعنصر يختاره بشكل عشوائي من بين المواقع من 0 وحتى c - 1 ، أي أنه يمكن استبدال العنصر بنفسه وفي هذه الحالة يبقى في موقعه الأصلي ، أو بأحد العناصر على يساره ، وبما أن قيمة c تنقص في كل مرة بمقدا 1 ، سنحصل في النهاية على مصفوفة بنفس العناصر لكن بعد تغيير مواقعها عشوائياً :

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

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

الآن وبعد أن أعدنا ترتيب عناصر المصفوفة بشكل عشوائي ، نستطيع أن نضع العناصر من 0 إلى 4 في فريق ، والعناصر من 5 إلى 9 في الفريق المقابل . انظر الكود :
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int main()
{
srand(time(0));
int num[10];
int teamA[5], teamB[5];
// initializin the array with 0 -> 9
for(int i=0 ; i<10 ; i++)
{
num = i;
}
// rearranging elements randomly
for(int c=10; c>0; c--)
{
swap(&num[c-1], &num[rand()%c]);
}
// dividing the array into two teams
for(int k=0; k<5; k++)
{
teamA[k] = num[k];
teamB[k] = num[9-k];
cout << teamA[k] << " " << teamB[k] << endl;
}
return 0;
}
◄ اكتب برنامجاً لاختيار 10 أسئلة من بين 100 سؤال في مسابقة ثقافية بشكل عشوائي .
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int main()
{
srand(time(0));
int num[100];
int Q[10];
for(int i=0; i<100; i++)
num = i;
for(int c=100; c>90; c--)
{
swap(&num[c-1], &num[rand()%c]);
Q[100-c] = num[c-1];
}
for(int k=0; k<10; k++)
cout << Q[k] << " ";
return 0;
}إذن تم اختيار 10 عناصر من بين الـ 100 عنصر في المصفوفة num بشكل عشوائي ونقلها إلى يمين المصفوفة كما في البرنامج السابق ، وفي الوقت نفسه نسخ تلك العناصر ( 90 - 99 ) إلى المصفوفة Q التي أصبحت تحوي مواقع 10 أسئلة من بين الـ 100 سؤال وبشكل عشوائي .

◄ اكتب برنامجاً لتوليد أرقام عشوائية من 1 إلى 9 دون تكرار ووضعها في مصفوفة 3x3 ثم طباعتها .
نقوم بعمل دوران من 9 إلى 1 ، ونضع كل واحد منها في الموقع العشوائي [a] حيث نقوم بتوليد رقم عشوائي x من 0 إلى 8 ، بحيث a=x/3 و b=x%3 . لما x تساوي 0 فنحن في الموقع [0][0] من المصفوفة ، ولما x تساوي 8 فنحن في الموقع [2][2] منها .
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int main()
{
srand(time(0));
int arr[3][3];
int num[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
int a, b, c;
for(c=9 ; c>0 ; c--)
{
swap(&num[c-1], &num[rand()%c]);
a = num[c-1]/3;
b = num[c-1]%3;
arr[a] = c;
}
for(int i=0; i<3; i++, cout<<endl)
for(int j=0; j<3; j++)
cout << arr[j] << " ";
return 0;
}نفس النتيجة يمكن الحصول عليها لكن بدلاً من تعبئة الأرقام من 9 إلى 1 بشكل منتظم وجعل المواقع بشكل عشوائي ، هنا سنمر على مواقع المصفوفة الثنائية بالترتيب لكن المحتوى هو الذي سيكون بشكل عشوائي هذه المرة
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int main()
{
srand(time(0));
int arr[3][3];
int num[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
for(int c=9 ; c>0 ; c--)
{
swap(&num[c-1], &num[rand()%c]);
}
for(int i=0; i<3; i++, cout<<endl)
{
for(int j=0; j<3; j++)
{
arr[j] = num[i*3 + j] + 1;
cout << arr[j] << " ";
}
}
return 0;
}◄ سبحانك لا علم لنا إلا ما علمتنا إنك أنت العليم الحكيم
◄ للأمانة العلمية يرجى ذكر المصدر عند النقل
الموضوع الأصلي : http://psd-development.com/vb/t502.html#post3186


