I. Introduction▲
Code d'un Puissance 4 en pure Windows API (avec une IA sommaire).

II. Code complet▲
Sélectionnez
#include <windows.h>
#include <time.h>
#include <stdio.h>
#define LARG 64
#define NB_COL 7
#define NB_LINE 6
#define NB_ALIGN 4
#define RED_PLAYER 1 // Ordi
#define BLUE_PLAYER -1 // Human
#define DEPTH 6
/* menu ID */
#define IDM_QUIT 1
#define IDM_NEW 2
#define IDM_ABOUT 3
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
//#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
/******************************************************************************/
/** Play :
return le nombre de pions alignés sur le coup joué.
return -1 pour colonne pleine.
**/
int Play(char tab[][NB_COL], int col, int player)
{
int i, j;
int i1, j1;
int cpt[NB_ALIGN];
int raw=0;
while(raw < NB_LINE && tab[raw][col]!=0) raw++;
if(raw>=NB_LINE) return -1; //Colonne peine.
tab[raw][col]=player;
//Test Lignes
i=col;
j=col;
while(i>=0 && tab[raw][i]==player) i--;
while(j<NB_COL && tab[raw][j]==player) j++;
cpt[0] = j-i-1;
//Test Colonnes
i=raw;
while(i>=0 && tab[i][col]==player) i--;
cpt[1] = raw-i;
// Diagonale decendente
i=raw;
i1=raw;
j=col;
j1=col;
while(i>=0 && j<NB_COL && tab[i][j]==player) i--, j++;
while(i1<NB_LINE && j1>=0 && tab[i1][j1]==player) i1++, j1--;
cpt[2] = i1-i-1;
// Diagonale montante
i=raw;
i1=raw;
j=col;
j1=col;
while(i>=0 && j>=0 && tab[i][j]==player) i--, j--;
while(i1<NB_LINE && j1<NB_COL && tab[i1][j1]==player) i1++, j1++;
cpt[3] = i1-i-1;
for(i=1; i<NB_ALIGN; i++) if(cpt[i]>=cpt[0]) cpt[0]=cpt[i];
return cpt[0];
}
/******************************************************************************/
/** alea tire un nombre aléatoire entre 0 et x exclu. **/
int alea(int x)
{
return rand()%x;
}
/******************************************************************************/
/** Eval Evalue le coup. **/
int Eval(char tab[][NB_COL], int col, int player, int depth)
{
int pts;
int tmp=0;
int result=0;
if(player==RED_PLAYER) pts=4000;
else pts=-2000;
//copie du tableau dans tabcpy
char tabcpy[NB_LINE][NB_COL];
memcpy(tabcpy, tab, sizeof(tabcpy));
//joue sur la copie
result=Play(tabcpy, col, player);
if(result>=NB_ALIGN && player==RED_PLAYER) pts = 3000 + depth;
if(result>=NB_ALIGN && player==BLUE_PLAYER) pts = -3000 - depth;
if(result==-1 && player==RED_PLAYER) pts=-5000-depth;
if(result==-1 && player==BLUE_PLAYER) pts=1000+depth;
if(result>0 && result<NB_ALIGN && depth>0)
{
int i;
player = -player; // chgt de player
for(i=0; i<NB_COL; i++)
{
if(player==RED_PLAYER && tmp >= 3000 + depth) break;
if(player==BLUE_PLAYER && tmp <= -3000 - depth) break;
tmp = Eval(tabcpy, i, player, depth-1);
if(player==RED_PLAYER && tmp>pts) pts=tmp;
if(player==BLUE_PLAYER && tmp<pts) pts=tmp;
}
}
return pts;
}
/******************************************************************************/
/** Test retourne la meilleure colonne **/
int Test(char tab[][NB_COL], int player, int depth)
{
int i;
int j=0;
int pts;
int col=0;
int tabpts[NB_COL];
int tabcol[NB_COL];
for(i=0; i<NB_COL; i++) tabpts[i] = Eval(tab, i, player, depth);
pts=tabpts[0];
tabcol[0]=0;
for(i=1; i<NB_COL; i++)
{
if(tabpts[i]>pts)
{
j=0;
pts = tabpts[i];
tabcol[0]=i;
}
if(tabpts[i]==pts)
{
j++;
tabcol[j]=i;
}
}
j++;
col=tabcol[alea(j)];
return col;
}
/******************************************************************************/
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static char tab[NB_LINE][NB_COL];
static int jeuEnCours;
switch (uMsg)
{
case WM_CREATE:
srand(time(NULL));
jeuEnCours=1;
return 0;
case WM_COMMAND:
if(LOWORD(wParam) == IDM_QUIT) PostMessage(hwnd, WM_CLOSE,0,0);
if(LOWORD(wParam) == IDM_ABOUT)
MessageBox(hwnd, "P4 par CGi - © 2015", "A Propos !", MB_OK);
if(LOWORD(wParam) == IDM_NEW)
{
ZeroMemory(tab, sizeof(tab));
jeuEnCours=1;
InvalidateRect(hwnd, NULL, FALSE);
}
return 0;
case WM_LBUTTONUP:
{
static int result;
int colonne = GET_X_LPARAM(lParam)/LARG;
if(jeuEnCours==0) return 0;
result=Play(tab, colonne, BLUE_PLAYER);
if(result>=NB_ALIGN)
{
InvalidateRect(hwnd, NULL, TRUE);
MessageBox(hwnd, "Gagné !", "Puissance 4", MB_OK);
jeuEnCours=0;
}
if(result==-1)
{
MessageBox(hwnd,
"Colonne pleine !\nRejouez dans une autre colonne !",
"Puissance 4", MB_OK);
}
else
{
int col;
if(jeuEnCours==0) return 0;
col = Test(tab, RED_PLAYER, DEPTH);
result=Play(tab, col, RED_PLAYER);
if(result>=NB_ALIGN)
{
InvalidateRect(hwnd, NULL, TRUE);
MessageBox(hwnd, "Ordi à gagné !", "Puissance 4", MB_OK);
jeuEnCours=0;
}
if(result==-1) // Pour test ne devrait pas ce produire.
{
MessageBox(hwnd,
"Colonne pleine !\nSur un jeu ordi !", "Alerte", MB_OK);
}
}
InvalidateRect(hwnd, NULL, TRUE);
return 0;
}
case WM_PAINT:
{
int i, j;
HPEN hpen;
HDC hdc, hdcDB;
HBITMAP bmDB;
HGDIOBJ hobjold;
PAINTSTRUCT ps;
RECT rect;
HBRUSH hbcase = CreateSolidBrush(0x00FFFFFF);
HBRUSH hbred = CreateSolidBrush(0x00FF0000);
HBRUSH hbblue = CreateSolidBrush(0x000000FF);
hpen = CreatePen(PS_SOLID, 1, 0x00AFAFAF);
GetClientRect(hwnd, &rect);
hdc = BeginPaint(hwnd, &ps);
hdcDB = CreateCompatibleDC(hdc);
bmDB = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
hobjold = SelectObject(hdcDB, bmDB);
SelectObject(hdcDB,hpen);
for(j=0; j<NB_LINE; j++)
for(i=0; i<NB_COL; i++)
{
SelectObject(hdcDB, hbcase);
Rectangle(hdcDB, i*LARG, (NB_LINE-j-1)*LARG,
(i+1)*LARG, (NB_LINE-j)*LARG);
if(tab[j][i]==BLUE_PLAYER)
{
SelectObject(hdcDB, hbred);
Ellipse(hdcDB, i*LARG, (NB_LINE-j-1)*LARG,
(i+1)*LARG, (NB_LINE-j)*LARG);
}
if(tab[j][i]==RED_PLAYER)
{
SelectObject(hdcDB, hbblue);
Ellipse(hdcDB, i*LARG, (NB_LINE-j-1)*LARG,
(i+1)*LARG, (NB_LINE-j)*LARG);
}
}
BitBlt(hdc, 0, 0, rect.right, rect.bottom, hdcDB, 0, 0, SRCCOPY);
DeleteDC(hdcDB);
DeleteObject(bmDB);
EndPaint(hwnd, &ps);
DeleteObject(hbcase);
DeleteObject(hbred);
DeleteObject(hbblue);
DeleteObject(hpen);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
/******************************************************************************/
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASS wc;
HMENU hMenu, hSousMenu;
RECT winRect;
wc.style = 0;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "MaWinClass";
RegisterClass(&wc);
hSousMenu = CreateMenu();
AppendMenu(hSousMenu, MF_STRING, IDM_NEW, "Nouvelle partie");
AppendMenu(hSousMenu, MF_MENUBREAK, -1, NULL);
AppendMenu(hSousMenu, MF_STRING, IDM_ABOUT, "A propos");
AppendMenu(hSousMenu, MF_STRING, IDM_QUIT, "Quitter");
hMenu = CreateMenu();
AppendMenu(hMenu,MF_POPUP,(UINT)hSousMenu,"Fichier");
SetRect(&winRect, 0, 0, LARG*NB_COL, LARG*NB_LINE);
AdjustWindowRect(&winRect, WS_CAPTION, TRUE);
hwnd = CreateWindow("MaWinClass", "Puissance4",
WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT,
winRect.right-winRect.left, winRect.bottom-winRect.top,
NULL, hMenu, hinstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
A vos compilateurs.


