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 !
\n
Rejouez 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 !
\n
Sur 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.