I. Introduction▲
Code d'un Sokoban en pure Windows API.
Le code est composé de trois fichiers et quatre images mises dans les ressources du programme. Les grilles seront intégrées à l'exécutable afin de n'avoir qu'un seul fichier à distribuer.

II. Code complet▲
Sélectionnez
main.c
#include <windows.h>
#define LARG 32
#define NBC_X 20
#define NBC_Y 18
/* ID de menu */
#define IDM_QUIT 1
#define IDM_NEW 2
#define IDM_RNIV 3
#define IDM_ABOUT 4
/* pièces de jeu */
#define GP_WALL 1
#define GP_SOKO 2
#define GP_STOCK 4
#define GP_BOX 8
HINSTANCE hinst;
extern char grilles[88][18][20];
POINT Init(char tab[][NBC_X], int niv)
{
int i;
int j;
POINT soko;
for(i=0; i<NBC_X; i++)
for(j=0; j<NBC_Y; j++)
{
tab[j][i]=grilles[niv][j][i];
if(tab[j][i]==GP_SOKO)
{
soko.x=i;
soko.y=j;
}
}
return soko;
}
/******************************************************************************/
BOOL testfin(char tab[][NBC_X])
{
int i;
int j;
for(i=0; i<NBC_X; i++)
for(j=0; j<NBC_Y; j++)
if(tab[j][i]==GP_STOCK||tab[j][i]==(GP_STOCK|GP_SOKO)) return FALSE;
return TRUE;
}
/******************************************************************************/
void move(char tab[NBC_Y][NBC_X], POINT *soko, WPARAM wParam)
{
int x = 0;
int y = 0;
if(wParam==VK_RIGHT) x=1;
if(wParam==VK_LEFT) x=-1;
if(wParam==VK_DOWN) y=1;
if(wParam==VK_UP) y=-1;
if(tab[soko->y+y][soko->x+x]&GP_WALL) return;
if(tab[soko->y+y][soko->x+x]&GP_BOX)
{
if(tab[soko->y+y+y][soko->x+x+x]&(GP_WALL|GP_BOX)) return;
else
{
tab[soko->y+y][soko->x+x]&=GP_STOCK;
tab[soko->y+y+y][soko->x+x+x]|=GP_BOX;
}
}
tab[soko->y][soko->x]&=GP_STOCK;
soko->y+=y;
soko->x+=x;
tab[soko->y][soko->x]|=GP_SOKO;
}
/******************************************************************************/
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static char tab[NBC_Y][NBC_X];
static int niveau;
static POINT soko;
static HBRUSH hbSoko;
static HBRUSH hbWall;
static HBRUSH hbBox;
static HBRUSH hbStock;
static HBRUSH hbPath;
switch (uMsg)
{
case WM_CREATE:
{
niveau = 0;
hbSoko = CreatePatternBrush(LoadBitmap(hinst,"soko"));
hbWall = CreatePatternBrush(LoadBitmap(hinst,"brick"));
hbBox = CreatePatternBrush(LoadBitmap(hinst,"box"));
hbStock = CreatePatternBrush(LoadBitmap(hinst,"stock"));
hbPath = CreateSolidBrush(0x00FFFFFF);
soko=Init(tab, niveau);
return 0;
}
case WM_COMMAND:
if(LOWORD(wParam) == IDM_QUIT)
PostMessage(hwnd, WM_CLOSE,0,0);
if(LOWORD(wParam) == IDM_ABOUT)
MessageBox(hwnd, "Sokoban by CGi !", "A Propos !", MB_OK);
if(LOWORD(wParam) == IDM_NEW)
{
ZeroMemory(tab, sizeof(tab));
niveau = 0;
soko=Init(tab, niveau);
InvalidateRect(hwnd, NULL, FALSE);
}
if(LOWORD(wParam) == IDM_RNIV)
{
ZeroMemory(tab, sizeof(tab));
soko=Init(tab, niveau);
InvalidateRect(hwnd, NULL, FALSE);
}
return 0;
case WM_KEYDOWN:
if(wParam==VK_DOWN) move(tab, &soko, wParam);
if(wParam==VK_UP) move(tab, &soko, wParam);
if(wParam==VK_LEFT) move(tab, &soko, wParam);
if(wParam==VK_RIGHT) move(tab, &soko, wParam);
InvalidateRect(hwnd, NULL, FALSE);
if(testfin(tab))
{
MessageBox(hwnd, "Bravo, on continue !", "Sokoban !", MB_OK);
niveau++;
if(niveau==88)
{
MessageBox(hwnd, "Vous êtes un champion !", "Sokoban !", MB_OK);
niveau=0;
}
ZeroMemory(tab, sizeof(tab));
soko=Init(tab, niveau);
InvalidateRect(hwnd, NULL, FALSE);
}
return 0;
case WM_PAINT:
{
int i, j;
HDC hdc, hdcDB;
HBITMAP bmDB;
PAINTSTRUCT ps;
RECT rect, caserect;
GetClientRect(hwnd, &rect);
hdc = BeginPaint(hwnd, &ps);
hdcDB = CreateCompatibleDC(hdc);
bmDB = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
SelectObject(hdcDB, bmDB);
for(j=0; j<NBC_Y; j++)
for(i=0; i<NBC_X; i++)
{
int value = tab[j][i];
caserect.left = i*LARG;
caserect.right = i*LARG+LARG;
caserect.top = j*LARG;
caserect.bottom = j*LARG+LARG;
if(value&GP_STOCK) FillRect(hdcDB, &caserect, hbStock);
if(value&GP_BOX) FillRect(hdcDB, &caserect, hbBox);
if(value&GP_SOKO) FillRect(hdcDB, &caserect, hbSoko);
if(value==GP_WALL) FillRect(hdcDB, &caserect, hbWall);
if(value==0) FillRect(hdcDB, &caserect, hbPath);
}
BitBlt(hdc, 0, 0, rect.right, rect.bottom, hdcDB, 0, 0, SRCCOPY);
DeleteDC(hdcDB);
DeleteObject(bmDB);
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY:
DeleteObject(hbWall);
DeleteObject(hbBox);
DeleteObject(hbStock);
DeleteObject(hbSoko);
DeleteObject(hbPath);
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;
HMENU hMenu, hSousMenu;
RECT winRect;
WNDCLASS wc;
hinst = hinstance;
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";
if(!RegisterClass(&wc)) return FALSE;
hSousMenu = CreateMenu();
AppendMenu(hSousMenu, MF_STRING, IDM_NEW, "Nouvelle partie");
AppendMenu(hSousMenu, MF_STRING, IDM_RNIV, "Reprendre le niveau");
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*NBC_X, LARG*NBC_Y);
AdjustWindowRect(&winRect, WS_CAPTION, TRUE);
hwnd = CreateWindow("MaWinClass", "Sokoban",
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;
}Le fichier ressources : images.rc
Sélectionnez
brick BITMAP brick.bmp
stock BITMAP stock.bmp
box BITMAP box.bmp
soko BITMAP soko.bmpIII. Téléchargements▲
Les grilles sont dans un fichier nommé grilles.c inclus dans l'archive à télécharger.
Les compilations ont été testées sous MinGW et Visual C.
À vos compilateurs.


