|   | 
      
                
        
           | 
          【程序】贪吃蛇 | 
         
                
          
            
                         一派掌門 二十級              | 
          
            
            
            
                       | 
         
                
          
            
                         一派掌門 二十級              | 
          
            
            
             
              【代码】 【头文件main.h】 #ifndef _MAIN_H #define _MAIN_H
  void StartTimer(HWND hWnd); void CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT iTimerID, DWORD dwTime); LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  #endif 【头文件snake.h】 #ifndef _SNAKE_H #define _SNAKE_H
  #define WALL_WIDTH 15 #define WALL_HEIGHT 15 #define BLOCK_SIZE 16 #define OVERLAP_MAX 5
  #define GAP_SIZE 4
  typedef struct tagSNAKE {     int x;     int y;     struct tagSNAKE *pPrev;     struct tagSNAKE *pNext; } SNAKE, *PSNAKE;
  typedef struct tagFOOD {     int x;     int y;     char ch; // 食物的字符表示 } FOOD, *PFOOD;
  int AvoidOverlap(PSNAKE pHead, PFOOD pFood); void CreateFood(PFOOD pFood); void DestroySnake(PSNAKE pHead); void InitSnake(PSNAKE pSnake); BOOL LoadSnake(LPSTR szFileName, PSNAKE pHead, PSNAKE *ppRear, PFOOD pFood, PINT pDirection); BOOL MeetFood(PSNAKE pSnake, PFOOD pFood); void ResetFoodLocation(PSNAKE pHead, PFOOD pFood, int direction); BOOL SaveSnake(LPSTR szFileName, PSNAKE pHead, PFOOD pFood, PINT pDirection); BOOL SnakeAteItself(PSNAKE pHead); PSNAKE SnakeGrow(PSNAKE pHead); void SnakeMove(PSNAKE pHead, PSNAKE pRear, int direction, PBOOL pbGameOver); void UpdateFood(PSNAKE pSnake, PFOOD pFood, int direction);
  #endif              
             |  |
 
         
                
          
            
                         一派掌門 二十級              | 
          
            
            
             
              【源文件main.c】 #include <tchar.h> #include <time.h> #include <Windows.h> #include "snake.h" #include "main.h"
  #define IDR_TIMER1 1
  BOOL bGameOver = FALSE; int direction = VK_RIGHT; // 蛇的移动方向 FOOD food = {5, 8, 'A'}; SIZE size; // 画布大小 SNAKE snake; // 蛇头 PSNAKE pRear;
  void StartTimer(HWND hWnd) {     SetTimer(hWnd, IDR_TIMER1, 500, TimerProc); }
  void CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT iTimerID, DWORD dwTime) {     SnakeMove(&snake, pRear, direction, &bGameOver);     if (MeetFood(&snake, &food))     {         pRear = SnakeGrow(&snake);         UpdateFood(&snake, &food, direction);     }     if (!bGameOver && SnakeAteItself(&snake))         bGameOver = TRUE;     if (bGameOver)         KillTimer(hWnd, IDR_TIMER1); // 当游戏结束时关闭计时器
      InvalidateRect(hWnd, NULL, FALSE); // 刷新游戏画面 }
  LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {     BOOL bDrawn;     char szText[2];     HBITMAP hbmp;     HDC hdc, hdcMem;     int x, y;     PAINTSTRUCT ps;     RECT rect, rcClient, rcText;
      PSNAKE pSnake;
      switch (uMsg)     {     case WM_CHAR:         // 字符输入检测         switch (wParam)         {         case 's':             // 保存到文件             if (!bGameOver)                 SaveSnake("game.dat", &snake, &food, &direction);             break;         case 'l':             if (LoadSnake("game.dat", &snake, &pRear, &food, &direction))             {                 if (bGameOver)                 {                     bGameOver = FALSE;                     StartTimer(hWnd);                 }                 InvalidateRect(hWnd, NULL, FALSE);             }         }         break;     case WM_CREATE:         srand((UINT)time(NULL));         InitSnake(&snake);         pRear = &snake;         StartTimer(hWnd);         break;     case WM_DESTROY:         KillTimer(hWnd, IDR_TIMER1);         DestroySnake(&snake);         PostQuitMessage(0);         break;     case WM_ERASEBKGND:         // 防止窗口闪烁         break;     case WM_KEYDOWN:         // 按键检测         if (direction == VK_UP || direction == VK_DOWN)         {             if (wParam == VK_LEFT || wParam == VK_RIGHT)                 direction = wParam;         }         else if (direction == VK_LEFT || direction == VK_RIGHT)         {             if (wParam == VK_UP || wParam == VK_DOWN)                 direction = wParam;         }         break;     case WM_PAINT:         hdc = BeginPaint(hWnd, &ps);                  hdcMem = CreateCompatibleDC(hdc);         hbmp = CreateCompatibleBitmap(hdc, size.cx, size.cy);         SelectObject(hdcMem, hbmp);         SetBkMode(hdcMem, TRANSPARENT);                  SelectObject(hdcMem, GetStockObject(WHITE_PEN));         SelectObject(hdcMem, GetStockObject(NULL_BRUSH));                  SetRect(&rcText, 2, 2, 4 + WALL_WIDTH * (BLOCK_SIZE + GAP_SIZE), 4 + WALL_HEIGHT * (BLOCK_SIZE + GAP_SIZE));         Rectangle(hdcMem, rcText.left, rcText.top, rcText.right, rcText.bottom);
          SetTextColor(hdcMem, RGB(255, 255, 255));         for (x = 0; x < WALL_WIDTH; x++)         {             for (y = 0; y < WALL_HEIGHT; y++)             {                 rect.left = 5 + x * (BLOCK_SIZE + GAP_SIZE);                 rect.top = 5 + y * (BLOCK_SIZE + GAP_SIZE);                 rect.right = rect.left + BLOCK_SIZE;                 rect.bottom = rect.top + BLOCK_SIZE;
                  bDrawn = FALSE;                 pSnake = &snake;                 while (pSnake != NULL)                 {                     if (x == pSnake->x && y == pSnake->y)                     {                         if (pSnake == &snake)                             FillRect(hdcMem, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));                         else                             Rectangle(hdcMem, rect.left, rect.top, rect.right, rect.bottom);                         bDrawn = TRUE;                         break;                     }                     pSnake = pSnake->pNext;                 }                 if (!bDrawn)                 {                     if (x == food.x && y == food.y)                     {                         szText[0] = szText[1] = food.ch;                         TextOutA(hdcMem, rect.left, rect.top, szText, 2);                     }                 }             }         }
          if (bGameOver)         {             SetTextColor(hdcMem, RGB(240, 235, 200));             DrawText(hdcMem, TEXT("GAME OVER"), 9, &rcText, DT_CENTER | DT_VCENTER | DT_SINGLELINE);         }
          GetClientRect(hWnd, &rcClient);         StretchBlt(hdc, 0, 0, rcClient.right, rcClient.bottom, hdcMem, 0, 0, size.cx, size.cy, SRCCOPY);
          DeleteDC(hdcMem);         DeleteObject(hbmp);         EndPaint(hWnd, &ps);         break;     default:         return DefWindowProc(hWnd, uMsg, wParam, lParam);     }     return FALSE; }
  int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {     HWND hWnd;     MSG msg;     RECT rcClient;     WNDCLASSEX wcex;
      wcex.cbSize = sizeof(WNDCLASSEX);     wcex.cbClsExtra = wcex.cbWndExtra = 0;     wcex.hbrBackground = NULL;     wcex.hCursor = LoadCursor(NULL, IDC_ARROW);     wcex.hIcon = wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);     wcex.hInstance = hInstance;     wcex.lpfnWndProc = WndProc;     wcex.lpszClassName = TEXT("MainWindow");     wcex.lpszMenuName = NULL;     wcex.style = CS_HREDRAW | CS_VREDRAW;     RegisterClassEx(&wcex);          size.cx = 6 + WALL_WIDTH * (BLOCK_SIZE + GAP_SIZE);     size.cy = 6 + WALL_HEIGHT * (BLOCK_SIZE + GAP_SIZE);     SetRect(&rcClient, 0, 0, size.cx, size.cy);     AdjustWindowRect(&rcClient, WS_OVERLAPPEDWINDOW, FALSE);
      hWnd = CreateWindow(wcex.lpszClassName, TEXT("贪吃蛇"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, NULL, NULL, hInstance, NULL);     if (!hWnd)         return 0;     ShowWindow(hWnd, nCmdShow);     UpdateWindow(hWnd);
      while (GetMessage(&msg, NULL, 0, 0))     {         TranslateMessage(&msg);         DispatchMessage(&msg);     }     return msg.wParam; }              
             |  |
 
         
                
          
            
                         一派掌門 二十級              | 
          
            
            
             
              【源文件snake.c】 #include <stdio.h> #include <Windows.h> #include "snake.h"
  int AvoidOverlap(PSNAKE pHead, PFOOD pFood) {     int nTimes = 0;     BOOL bFlag = TRUE;     PSNAKE pSnake;     while (bFlag && nTimes <= OVERLAP_MAX)     {         bFlag = FALSE;         nTimes++;
          pSnake = pHead;         while (pSnake)         {             if (MeetFood(pSnake, pFood))             {                 bFlag = TRUE;                 CreateFood(pFood); // 如果重叠, 则再次生成食物                 break;             }             pSnake = pSnake->pNext;         }     }     return nTimes; }
  void CreateFood(PFOOD pFood) {     pFood->x = rand() % WALL_WIDTH;     pFood->y = rand() % WALL_HEIGHT;     pFood->ch = 'A' + rand() % 26; // 随机大写字母 }
  // 将蛇身全部删除并释放内存,仅保留蛇头 void DestroySnake(PSNAKE pHead) {     PSNAKE pSnake = pHead->pNext; // 无需删除蛇头     PSNAKE pTemp;     while (pSnake != NULL)     {         pTemp = pSnake->pNext;         free(pSnake);         pSnake = pTemp;     }     pHead->pNext = NULL; }
  void InitSnake(PSNAKE pSnake) {     pSnake->x = pSnake->y = 1;     pSnake->pPrev = pSnake->pNext = NULL; }
  BOOL LoadSnake(LPSTR szFileName, PSNAKE pHead, PSNAKE *ppRear, PFOOD pFood, PINT pDirection) {     FILE *fp;     PSNAKE pSnake = NULL;     fopen_s(&fp, szFileName, "rb");     if (fp == NULL)         return FALSE;     DestroySnake(pHead);     fread(pFood, sizeof(FOOD), 1, fp);     fread(pDirection, sizeof(*pDirection), 1, fp);     while (fgetc(fp), !feof(fp))     {         fseek(fp, -1, SEEK_CUR);         if (pSnake != NULL)         {             pSnake->pNext = (PSNAKE)malloc(sizeof(SNAKE));             pSnake->pNext->pPrev = pSnake;             pSnake = pSnake->pNext;         }         else             pSnake = pHead;         fread(&pSnake->x, sizeof(pSnake->x), 1, fp);         fread(&pSnake->y, sizeof(pSnake->y), 1, fp);     }     pSnake->pNext = NULL; // 最后一个节点的pNext必须为NULL     *ppRear = pSnake;     fclose(fp);     return TRUE; }
  BOOL MeetFood(PSNAKE pSnake, PFOOD pFood) {     return (pSnake->x == pFood->x && pSnake->y == pFood->y); }
  void ResetFoodLocation(PSNAKE pHead, PFOOD pFood, int direction) {     switch (direction)     {     case VK_LEFT:         pFood->x = pHead->x - 1;         pFood->y = pHead->y;         break;     case VK_UP:         pFood->x = pHead->x;         pFood->y = pHead->y - 1;         break;     case VK_RIGHT:         pFood->x = pHead->x + 1;         pFood->y = pHead->y;         break;     case VK_DOWN:         pFood->x = pHead->x;         pFood->y = pHead->y + 1;         break;     }
      if (pFood->x < 0)         pFood->x = WALL_WIDTH - 1;     if (pFood->x >= WALL_WIDTH)         pFood->x -= WALL_WIDTH;     if (pFood->y < 0)         pFood->y = WALL_HEIGHT - 1;     if (pFood->y >= WALL_HEIGHT)         pFood->y -= WALL_HEIGHT; }
  BOOL SaveSnake(LPSTR szFileName, PSNAKE pHead, PFOOD pFood, PINT pDirection) {     FILE *fp;     PSNAKE pSnake = pHead;     fopen_s(&fp, szFileName, "wb");     if (fp == NULL)         return FALSE;     fwrite(pFood, sizeof(FOOD), 1, fp);     fwrite(pDirection, sizeof(*pDirection), 1, fp);     while (pSnake != NULL)     {         fwrite(&pSnake->x, sizeof(pSnake->x), 1, fp);         fwrite(&pSnake->y, sizeof(pSnake->y), 1, fp);         pSnake = pSnake->pNext;     }     fclose(fp);     return TRUE; }
  BOOL SnakeAteItself(PSNAKE pHead) {     PSNAKE pSnake = pHead->pNext;     while (pSnake != NULL)     {         if (pHead->x == pSnake->x && pHead->y == pSnake->y)             return TRUE; // 当蛇头碰到蛇身, 游戏结束         pSnake = pSnake->pNext;     }     return FALSE; }
  PSNAKE SnakeGrow(PSNAKE pHead) {     PSNAKE pNew = (PSNAKE)malloc(sizeof(SNAKE));     PSNAKE pRear = pHead;     while (pRear->pNext != NULL)         pRear = pRear->pNext;     pNew->pPrev = pRear;     pRear->pNext = pNew;     pNew->pNext = NULL;     return pNew; }
  void SnakeMove(PSNAKE pHead, PSNAKE pRear, int direction, PBOOL pbGameOver) {     // 移动身体     PSNAKE pSnake = pRear;     while (pSnake != pHead)     {         pSnake->x = pSnake->pPrev->x;         pSnake->y = pSnake->pPrev->y;         pSnake = pSnake->pPrev;     }
      // 移动蛇头     switch (direction)     {     case VK_LEFT:         if (pHead->x > 0)             pHead->x--;         else             *pbGameOver = TRUE;         break;     case VK_UP:         if (pHead->y > 0)             pHead->y--;         else             *pbGameOver = TRUE;         break;     case VK_RIGHT:         if (pHead->x + 1 < WALL_WIDTH)             pHead->x++;         else             *pbGameOver = TRUE;         break;     case VK_DOWN:         if (pHead->y + 1 < WALL_WIDTH)             pHead->y++;         else             *pbGameOver = TRUE;         break;     } }
  void UpdateFood(PSNAKE pSnake, PFOOD pFood, int direction) {     int nOverlap;     CreateFood(pFood);     nOverlap = AvoidOverlap(pSnake, pFood);     if (nOverlap > OVERLAP_MAX)         ResetFoodLocation(pSnake, pFood, direction); }              
             |  |
 
         
                
          
            
                         一派掌門 二十級              | 
          
            
            
             
              【说明】 这是一个用C语言编写出来的窗口程序。 游戏中按S键可存档,按L键可读档。              
             |  |
 
         
                 
                 | 
      
        
                
                       | 
        |