الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

لعبة Connect 4 مع عقل اصطناعي باستخدام MiniMax Algorithm

بدأه أحمد عصام في 28 ديسمبر 2013 · 6 رد · 2,559 مشاهدة · في لغة C و ++C
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم :)  اسف لو الموضوع مش في مكانه ... لو كان فضلا نقله لاني جديد هنا

لعبة connect 4 من تصميمي باستخدام ال Minimax algorithm بطريقة ال NegaMax

لجعله اكثر ذكاءا يمكنك جعل قيمة Depth اكبر في

if(Depth <= 6)
#include <iostream>#include <cstdlib>#include <conio.h>#include <ctime>using namespace std;bool provocation = false; // used to display a provocative screenchar input[43]; // There are 42 places to play in the board .. this array represent themvoid Board();int PlayOut = 0;int EVA = 0;// EVA and PlayOut are working while NegaMax Function is working .. in NegaMax's way it will definitely make any winning move// as it goes deep so when this happens PlayOut increases by 1 and EVA increases by 1 if its a winnning move or decreases by 1 if it the opposite// so we can evaluate neutral moves for MiniMax by dividing EVA / PlayOut * 100 so we get a percentageint winning();int GetValue(int t);int AIManager();int NegaMax(int Depth);void clean(){    provocation = false;    for(int i = 0 ; i<= 80 ; i++)        input=' ';}int GetValue(int column) // pass this function a column that you want to play in and it will return its value in input array ..{    if(column > 7)        return 0;    int n;    for(int i = 0 ; i<= 6 ; i++)    {        if( input[column+7*i] == ' '  )        {            n = column+7*i;            break;        }    }    if ( n > 42 )        return 0;    return n;}int winning() // Winning algorithm{    int temp=0;    for(int i = 1 ; i<= 42 ; i++)    {        if(input != ' ')        {            temp++;            if( i - int((i-1)/7) * 7 <= 4  )                if( input == input [i+1] && input == input[i+2] && input == input[i+3] )                    if(input == 'X' )                        return 1 ;                    else                        return 2;            if( i <= 21 )                if ( input == input[i+7] && input == input[i+14] && input == input[i+21]  )                    if(input == 'X' )                        return 1 ;                    else                        return 2;            if( i - int((i-1)/7) * 7 <= 4 && i<=18  )                if(input == input[i+8] && input == input[i+16] && input==input[i+24])                    if(input == 'X' )                        return 1 ;                    else                        return 2;            if( i - int((i-1)/7) * 7 >= 4 && i <= 21   )                if(input == input[i+6] && input == input[i+12] && input==input[i+18])                    if(input == 'X' )                        return 1 ;                    else                        return 2;        }    }    if (temp == 42)        return 3;    return 0;}void Board() // Draw board{    cout<<endl<<"    1   "<<"    2   "<<"    3   "<<"    4   "<<"    5   "<<"    6   "<<"    7   "<<endl;    int j = 42;    for(int i = 0 ; i<= 23 ; i++)    {        if(i % 4 == 0)            cout<<string(57,'-');        else        {            if( (i - 2) % 4 == 0)            {                j=42-(0.25*i+0.5)*6-((0.25*i+0.5)-1) ;                for(int i = 0 ; i<=6 ; i++)                {                    cout<<"|"<<"   "<<input[j]<<"   ";                    j++;                }                cout<<"|";            }            else            {                for(int i = 0 ; i<=6 ; i++)                    cout<<"|"<<string(7,' ');                cout<<"|";            }        }        cout<<endl;    }    cout<<string(57,'-');    if(provocation == true)        cout<<endl<<"Hehe I'm sure of my winning :D "<<endl;}void PlayPosition(char XO) // Function that asks you to enter where you like to play{    int sth;    cout<<endl<<"where would you like to play"<<endl;    while(true)    {        cin>>sth;        sth=GetValue(sth);        if( sth != 0 )        {            input[sth] = XO;            return ;        }        else            cout<<"ERROR"<<endl;    }}int main() // main function{    srand(time(0));    clean();    while(true)    {        input[AIManager()]='O';        system("cls");        Board();        int winningtemp = winning();        if(winningtemp!=0)        {            if(winningtemp == 1)                cout<<endl<<"Player 2 WON !";            else if (winningtemp == 2)                cout<<endl<<"Player 1 WON ! " ;            else if (winningtemp == 3)                cout<<"You Tie ! ";            getch();            clean();        }        else            PlayPosition('X');    }}int AIManager() // AI Algorithm{    float chance[2] = {9999999 , 0 };    for(int column = 1 ; column <= 7 ; column ++)    {        PlayOut = 0;        EVA=0;        int PlayNumber = GetValue(column);        if( PlayNumber != 0 )        {            input[PlayNumber] = 'O';            if(winning()==2)               {                   input[PlayNumber]=' ';                   return PlayNumber ;               }            float temp = -(100*NegaMax(1));            if(PlayOut != 0)                temp -= ((100*EVA)/PlayOut);            if(-temp >= 100)                provocation = true;            if( chance[0] > temp  )            {                chance[0] = temp  ;                chance[1] = PlayNumber;            }             //  cout<<endl<<-temp<<"   "<<EVA << "   " <<PlayOut;            input[PlayNumber] = ' ';        }    }    return chance[1];}int NegaMax(int Depth) // MiniMax algorithm in NegaMax form{    char XO;    int PlayNumber[8] = {0,0,0,0,0,0,0,0}; // The values of the input[] for every column    int chance=0;    if(Depth % 2 != 0)        XO='X';    else        XO='O';    for(int column = 1 ; column <= 7 ; column ++)        PlayNumber[column]=GetValue(column);    for(int column = 1 ; column <= 7 ; column++)    {        if(PlayNumber[column] != 0)        {            input[PlayNumber[column]]=XO;            if( winning() != 0 )            {                PlayOut ++;                if(XO=='O')                    EVA ++;                else                    EVA --;                input[PlayNumber[column]]=' ';                return -1;            }            input[PlayNumber[column]]=' ';        }    }    if(Depth <= 6)    {        for(int column = 1 ; column <= 7 ; column ++)        {            int temp=0;            if( PlayNumber[column] != 0 )            {                input[PlayNumber[column]]=XO;                temp = NegaMax(Depth+1);                if(column == 1)                    chance = temp;                if(chance < temp)                    chance = temp;                input[PlayNumber[column]]=' ';            }        }    }    return -chance;}

تم تعديل هذه المشاركة بواسطة C++er في 29 ديسمبر 2013 في 02:39 — السبب: code=css -> code

2
#2

بارك الله فيك اخي

 

لكن ماهي المدة التي استغرقتها لصنعها ؟؟؟

#3

يوم واحد لكل شئ عدا ال AI
في البداية كان المنطق لل AI هو :

1- لعب لعبة تجعله يفوز

2 - يصد لعبة تجعل المنافس يفوز

3- يلعب لعبة تقوم بعمل 3 في صف

4- يصد 2 في صف

5 - يلعب 2 في صف

6 - يلعب عشوائيا ولا تقوم بجعل المنافس يفوز

ولكني بهذا ال logic ال AI غبي جدا ولذلك قرات عن MiniMax Algorithm حتي تعلمت مفاهيمها وقمت بتطبيقها

#4

السلام عليكم

 

ملاحظاتي ع السريع :

  • كان يجب عليك أن تكتب الكود وفقا لمنهج الـ OOP ما دمت اخترت لغة السي++ لبرمجة اللعبة.
  • conio.h هو أحد الـ header files الخاصة بلغة سي, كان يُستخدم في التسعينيات من القرن الماضي حيث كان يتواجد أساسا في المترجمات التي تعمل في بيئة الويندوز غير أنه لم يرد في الكتاب الأب The C Programming Language و لا ينتمي إلى المكتبة القياسية للغة السي كما أن المعيار POSIX أيضا لا يدعمه.
  • في الدالة GetValue لم تدرس الحالة التي يكون فيها column أقل من الصفر.
  • كان من الأفضل أن تجعل المتغير column من نوع char و تمسح محتوى الـ buffer في كل مرة (عند إدخال character سيدخل برنامجك في حلقة غير منتهية ..).
  • بدلا من أن تطلب من المستخدم أن يدخل رقم العمود, كان من الأفضل أن تتيح له إمكانية التنقل بين الخانات باستخدام أسهم لوحة المفاتيح (راجع هذا الموضوع - انظر المرفقات)
  • بالنسبة لخوارزمية Minimax Algorithm, راجع هذا الموضوع.

 

 

بالتوفيق.

تم تعديل هذه المشاركة بواسطة Snack3r في 29 ديسمبر 2013 في 19:02

2
#5
اقتباس
  • كان يجب عليك أن تكتب الكود وفقا لمنهج الـ OOP ما دمت اخترت لغة السي++ لبرمجة اللعبة.
للأسف لم اتعلم ال OOP حتي الان ولكني بالتأكيد سأتعلمه حيث ان هذا البرنامج مجرد تطبيق للقواعد الاساسية لل c++ ثم تطور ليصبح تطبيق لدالة ال minimax
اقتباس
  • conio.h هو أحد الـ header files الخاصة بلغة سي, كان يُستخدم في التسعينيات من القرن الماضي حيث كان يتواجد أساسا في المترجمات التي تعمل في بيئة الويندوز غير أنه لم يرد في الكتاب الأب The C Programming Language و لا ينتمي إلى المكتبة القياسية للغة السي كما أن المعيار POSIX أيضا لا يدعمه.
قمت بالاستغناء عنها واستخدمت system("pause >nul");
اقتباس
  • كان من الأفضل أن تجعل المتغير column من نوع char و تمسح محتوى الـ buffer في كل مرة (عند إدخال character سيدخل برنامجك في حلقة غير منتهية ..).
قمت بتغير طريقة الادخال في الدالة PlayPosition حيث يطلب ان تقوم بادخال string ثم اقوم بتحويلها لقيمة عددية لتفادي اي اخطاء
اقتباس
  • بدلا من أن تطلب من المستخدم أن يدخل رقم العمود, كان من الأفضل أن تتيح له إمكانية التنقل بين الخانات باستخدام أسهم لوحة المفاتيح (راجع هذا الموضوع - انظر المرفقات)
لكن كيف سأقوم بفعل هذا بدون دالة getch الني توجد في مكتبة conio.h ؟

للأسف لا أستطيع التعديل علي الموضوع لذلك قمت بوضع الكود في تعليق

شكرا علي تعليقك .. انظر للكود الجديد وأتمني المزيد من الملاحظات المفيدة :)

تم تعديل هذه المشاركة بواسطة أحمد عصام في 30 ديسمبر 2013 في 13:22

#6

#include <iostream>

#include <cstdlib>

#include <ctime>

#include <string>

using namespace std;

bool provocation = false; // used to display a provocative screen

char input[43]; // There are 42 places to play in the board .. this array represent them

void Board();

int PlayOut = 0;

int EVA = 0;

// EVA and PlayOut are working while NegaMax Function is working .. in NegaMax's way it will definitely make any winning move

// as it goes deep so when this happens PlayOut increases by 1 and EVA increases by 1 if its a winnning move or decreases by 1 if it the opposite

// so we can evaluate neutral moves for MiniMax by dividing EVA / PlayOut * 100 so we get a percentage

int winning();

int GetValue(int t);

int AIManager();

int NegaMax(int Depth);

void clean()

{

provocation = false;

for(int i = 0 ; i<= 80 ; i++)

input=' ';

}

int GetValue(int column) // pass this function a column that you want to play in and it will return its value in input array ..

{

if( column <= 0 || column > 7 )

return 0;

int n;

for(int i = 0 ; i<= 6 ; i++)

{

if( input[column+7*i] == ' ' )

{

n = column+7*i;

break;

}

}

if ( n > 42 )

return 0;

return n;

}

int winning() // Winning algorithm

{

int temp=0;

for(int i = 1 ; i<= 42 ; i++)

{

if(input != ' ')

{

temp++;

if( i - int((i-1)/7) * 7 <= 4 )

if( input == input [i+1] && input == input[i+2] && input == input[i+3] )

if(input == 'X' )

return 1 ;

else

return 2;

if( i <= 21 )

if ( input == input[i+7] && input == input[i+14] && input == input[i+21] )

if(input == 'X' )

return 1 ;

else

return 2;

if( i - int((i-1)/7) * 7 <= 4 && i<=18 )

if(input == input[i+8] && input == input[i+16] && input==input[i+24])

if(input == 'X' )

return 1 ;

else

return 2;

if( i - int((i-1)/7) * 7 >= 4 && i <= 21 )

if(input == input[i+6] && input == input[i+12] && input==input[i+18])

if(input == 'X' )

return 1 ;

else

return 2;

}

}

if (temp == 42)

return 3;

return 0;

}

void Board() // Draw board

{

cout<<endl<<" 1 "<<" 2 "<<" 3 "<<" 4 "<<" 5 "<<" 6 "<<" 7 "<<endl;

int j = 42;

for(int i = 0 ; i<= 23 ; i++)

{

if(i % 4 == 0)

cout<<string(57,'-');

else

{

if( (i - 2) % 4 == 0)

{

j=42-(0.25*i+0.5)*6-((0.25*i+0.5)-1) ;

for(int i = 0 ; i<=6 ; i++)

{

cout<<"|"<<" "<<input[j]<<" ";

j++;

}

cout<<"|";

}

else

{

for(int i = 0 ; i<=6 ; i++)

cout<<"|"<<string(7,' ');

cout<<"|";

}

}

cout<<endl;

}

cout<<string(57,'-');

if(provocation == true)

cout<<endl<<"Hehe I'm sure of my winning :D "<<endl;

}

void PlayPosition(char XO) // Function that asks you to enter where you like to play

{

string enter;

cout<<endl<<"where would you like to play"<<endl;

while(true)

{

cin>>enter;

char temp = enter[0];

int value = 0;

if(enter.length() == 1)

value=GetValue(atoi(&temp));

if( value != 0 )

{

input[value] = XO;

return ;

}

else

cout<<"ERROR"<<endl;

}

}

int main() // main function

{

srand(time(0));

clean();

while(true)

{

input[AIManager()]='O';

system("cls");

Board();

int winningtemp = winning();

if(winningtemp!=0)

{

if(winningtemp == 1)

cout<<endl<<"Player 2 WON !";

else if (winningtemp == 2)

cout<<endl<<"Player 1 WON ! " ;

else if (winningtemp == 3)

cout<<"You Tie ! ";

system( "pause >nul" );

clean();

}

else

PlayPosition('X');

}

}

int AIManager() // AI Algorithm

{

float chance[2] = {9999999 , 0 };

for(int column = 1 ; column <= 7 ; column ++)

{

PlayOut = 0;

EVA=0;

int PlayNumber = GetValue(char(column));

if( PlayNumber != 0 )

{

input[PlayNumber] = 'O';

if(winning()==2)

{

input[PlayNumber]=' ';

return PlayNumber ;

}

float temp = -(100*NegaMax(1));

if(PlayOut != 0)

temp -= ((100*EVA)/PlayOut);

if(-temp >= 100)

provocation = true;

if( chance[0] > temp )

{

chance[0] = temp ;

chance[1] = PlayNumber;

}

// cout<<endl<<-temp<<" "<<EVA << " " <<PlayOut;

input[PlayNumber] = ' ';

}

}

return chance[1];

}

int NegaMax(int Depth) // MiniMax algorithm in NegaMax form

{

char XO;

int PlayNumber[8] = {0,0,0,0,0,0,0,0}; // The values of the input[] for every column

int chance=0;

if(Depth % 2 != 0)

XO='X';

else

XO='O';

for(int column = 1 ; column <= 7 ; column ++)

PlayNumber[column]=GetValue(column);

for(int column = 1 ; column <= 7 ; column++)

{

if(PlayNumber[column] != 0)

{

input[PlayNumber[column]]=XO;

if( winning() != 0 )

{

PlayOut ++;

if(XO=='O')

EVA ++;

else

EVA --;

input[PlayNumber[column]]=' ';

return -1;

}

input[PlayNumber[column]]=' ';

}

}

if(Depth <= 6)

{

for(int column = 1 ; column <= 7 ; column ++)

{

int temp=0;

if( PlayNumber[column] != 0 )

{

input[PlayNumber[column]]=XO;

temp = NegaMax(Depth+1);

if(column == 1)

chance = temp;

if(chance < temp)

chance = temp;

input[PlayNumber[column]]=' ';

}

}

}

return -chance;

}

#7

رجاء لكل من يفهم Minimax algorithm

شرح لما قمت بفعله حتي اعلم ان كان صحيحا ام لا ... باقي الكود غير مهم حيث اني ان شاء الله ساتعلم ما استطيع تعلمه عن ال classes و ال oop ثم ساتعلم القليل عن برمجة الواجهات الرسومية لاعيد برمجة البرنامج ...

المهم

الدالة تقوم بالبحث حتي عمق ٧ لعبات اول لعبة يقوم بتطبيقها AiManager والباقي يقوم بتطبيقه NegaMax

ومن المعلوم ان عمق سبع لعبات من المستحيل ان تصل لخطة للفوز حيث ان ذلك يحتاج لعمق كبير سياخذ وقت مهول ليقوم الكمبيوتر بتنفيذه ...

لذلك فان دالة minimax ستقوم بارجاع قيم كالاتي في اللعبة الاولي

playing in all columns = 0 (neutral)

ولذلك قمت بعمل متغير اسميته PlayOut واخر اسميته EVA

في كل مرة تقابل فيها الدالة لعبة فوز يزداد PlayOut ويتغير EVA ان كانت فوز لل AI فبالزيادة والعكس صحيح

وبتلك الطريقة اقوم بحساب نسبة مئوية

EVA / PlayOut. * 100

وبذلك قمت بحساب اللعبات المحايدة

وقمت باضافة بعض الاستفزاز بمتغير يسمي provocation عندما يقوم Minimax بارجاع لعبة فوز ( علي مدي بعيد طبعا فهو ينظر ٧ لعبات ) تظهر تلك العبارة المستفزة

السؤال هو ... هل تلك الطريقة صحيحة ؟

اسف يبدو انه كان ينبغي من البداية ان ارفق شرح لما فعلت

( بقولي minimax اعني الدالتين AIManager و NegaMax في البرنامج )

مواضيع مشابهة