| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 24106 人关注过本帖, 9 人收藏
标题:C语言从零起步分析《象眼》象棋引擎的源码
取消只看楼主 加入收藏
longswallow2
Rank: 1
等 级:新手上路
帖 子:30
专家分:0
注 册:2016-3-26
结帖率:0
收藏(9)
已结贴  问题点数:20 回复次数:29 
C语言从零起步分析《象眼》象棋引擎的源码
我也是一个c语言初学者,抽业余时间学习C语言;有兴趣的同学可以来交流一下,互相学习,相互促进。
首先来看window窗口的绘制属性的设置。

const int WINDOW_STYLES = WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX;

以上句子设置了一个常数WINDOW_STYLES;
这个常数通过------或运算,计算后,就被初始化了。
以下是后面这些常量的含义。
WS_OVERLAPPED   产生一个层叠的窗口;一个层叠的窗口有一个标题条和一个边框。
WS_SYSMENU 创建一个在标题条上带有窗口菜单的窗口,必须同时设定WS_CAPTION风格。
WS_CAPTION 创建一个有标题框的窗口(包括WS_BORDER风格)。
WS_MINIMIZEBOX 创建一个具有最大化按钮的窗口;该风格不能与WS_EX_CONTEXTHELP风格同时出现,同时必须指定WS_SYSMENU风格。

对于一个初学者,也没有必要看长篇大论,基于自己的水平,做细节上的消化;
象棋小巫师第一阶段cpp源码,在3楼;所有源码在8楼下载;
第一阶段代码的分析,共14小节;
我打算分析完所有,大家共同来探索人工智能的奥秘吧!

[此贴子已经被作者于2016-3-27 12:11编辑过]

搜索更多相关主题的帖子: window C语言 c语言 象棋 
2016-03-26 10:42
longswallow2
Rank: 1
等 级:新手上路
帖 子:30
专家分:0
注 册:2016-3-26
收藏
得分:0 
C语言从零起步分析《象眼》象棋引擎的源码(2)
窗口的创建过程:
1注册窗口类
2构建窗口
3显示窗口

注册窗口类:
RegisterClassEx  为(随后在调用Createwindow函数中使用的)窗口---注册一个窗口类;
ATOM RegisterClassEx(CONST WNDCLASSEX *Ipwcx);
ATOM RegisterClassEx(指向窗口类的指针);

窗口的创建:CreateWindow

jubing = CreateWindow("XQWLIGHT", "象棋小巫师", WINDOW_STYLES,
      CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
      CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

绿色的WINDOW_STYLES上一节的常量
  CW_USEDEFAULT是指窗口的大小位置等位默认值;

jubing = CreateWindow(窗口类名称,窗口标题, 窗口格式风格,
      初始 x 坐标, 初始 y 坐标, 宽,
      高, 父窗口句柄, 窗口菜单句柄, 程序实例句柄, 创建参数);

显示窗口:
ShowWindow(jubing, nCmdShow)
ShowWindow(窗口句柄,指定窗口如何显示);
参数nCmdShow----第一次调用ShowWindow函数时,该值应为在函数WinMain中nCmdShow参数;

本节分析了基本的创建窗口的粗略过程;
2016-03-26 22:25
longswallow2
Rank: 1
等 级:新手上路
帖 子:30
专家分:0
注 册:2016-3-26
收藏
得分:0 
象棋小巫师第一阶段cpp源码
程序代码:
/**

 * XiangQi Wizard Light - A Very Simple Chinese Chess Program

 * Designed by Morning Yellow, Version: 0.1, Last Modified: Mar. 2008

 * Copyright (C) 2004-2008 www.*

 * 象棋小巫师 0.1 的目标:

 * 一、制作一个可操作的图形界面。

 */

#include <windows.h>
#include "resource.h"

// 版本号
const LPCSTR cszAbout = "象棋小巫师 0.1\n象棋百科全书 荣誉出品\n\n"
    "欢迎登录 www.\n免费下载PC版 象棋巫师";

// 窗口和绘图属性
const int WINDOW_STYLES = WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX;
const int MASK_COLOR = RGB(0, 255, 0);
const int SQUARE_SIZE = 56;
const int BOARD_EDGE = 8;
const int BOARD_WIDTH = BOARD_EDGE + SQUARE_SIZE * 9 + BOARD_EDGE;
const int BOARD_HEIGHT = BOARD_EDGE + SQUARE_SIZE * 10 + BOARD_EDGE;

// 棋盘范围
const int RANK_TOP = 3;
const int RANK_BOTTOM = 12;
const int FILE_LEFT = 3;
const int FILE_RIGHT = 11;

// 棋子编号
const int PIECE_KING = 0;
const int PIECE_ADVISOR = 1;
const int PIECE_BISHOP = 2;
const int PIECE_KNIGHT = 3;
const int PIECE_ROOK = 4;
const int PIECE_CANNON = 5;
const int PIECE_PAWN = 6;

// 棋盘初始设置
static const BYTE cucpcStartup[256] = {
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0, 20, 19, 18, 17, 16, 17, 18, 19, 20,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0, 21,  0,  0,  0,  0,  0, 21,  0,  0,  0,  0,  0,
  0,  0,  0, 22,  0, 22,  0, 22,  0, 22,  0, 22,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0, 14,  0, 14,  0, 14,  0, 14,  0, 14,  0,  0,  0,  0,
  0,  0,  0,  0, 13,  0,  0,  0,  0,  0, 13,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0, 12, 11, 10,  9,  8,  9, 10, 11, 12,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
};

// 获得格子的横坐标
inline int RANK_Y(int sq) {
  return sq >> 4;
}

// 获得格子的纵坐标
inline int FILE_X(int sq) {
  return sq & 15;
}

// 根据纵坐标和横坐标获得格子
inline int COORD_XY(int x, int y) {
  return x + (y << 4);
}

// 翻转格子
inline int SQUARE_FLIP(int sq) {
  return 254 - sq;
}

// 纵坐标水平镜像
inline int FILE_FLIP(int x) {
  return 14 - x;
}

// 横坐标垂直镜像
inline int RANK_FLIP(int y) {
  return 15 - y;
}

// 获得红黑标记(红子是8,黑子是16)
inline int SIDE_TAG(int sd) {
  return 8 + (sd << 3);
}

// 获得对方红黑标记
inline int OPP_SIDE_TAG(int sd) {
  return 16 - (sd << 3);
}

// 获得走法的起点
inline int SRC(int mv) {
  return mv & 255;
}

// 获得走法的终点
inline int DST(int mv) {
  return mv >> 8;
}

// 根据起点和终点获得走法
inline int MOVE(int sqSrc, int sqDst) {
  return sqSrc + sqDst * 256;
}

// 局面结构
struct PositionStruct {
  int sdPlayer;                   // 轮到谁走,0=红方,1=黑方
  BYTE ucpcSquares[256];          // 棋盘上的棋子

  void Startup(void) {            // 初始化棋盘
    sdPlayer = 0;
    memcpy(ucpcSquares, cucpcStartup, 256);
  }
  void ChangeSide(void) {         // 交换走子方
    sdPlayer = 1 - sdPlayer;
  }
  void AddPiece(int sq, int pc) { // 在棋盘上放一枚棋子
    ucpcSquares[sq] = pc;
  }
  void DelPiece(int sq) {         // 从棋盘上拿走一枚棋子
    ucpcSquares[sq] = 0;
  }
  void MovePiece(int mv);         // 搬一步棋的棋子
  void MakeMove(int mv) {         // 走一步棋
    MovePiece(mv);
    ChangeSide();
  }
};

// 搬一步棋的棋子
void PositionStruct::MovePiece(int mv) {
  int sqSrc, sqDst, pc;
  sqSrc = SRC(mv);
  sqDst = DST(mv);
  DelPiece(sqDst);
  pc = ucpcSquares[sqSrc];
  DelPiece(sqSrc);
  AddPiece(sqDst, pc);
}

static PositionStruct pos; // 局面实例

// 与图形界面有关的全局变量
static struct {
  HINSTANCE hInst;                              // 应用程序句柄实例
  HWND hWnd;                                    // 主窗口句柄
  HDC hdc, hdcTmp;                              // 设备句柄,只在"ClickSquare"过程中有效
  HBITMAP bmpBoard, bmpSelected, bmpPieces[24]; // 资源图片句柄
  int sqSelected, mvLast;                       // 选中的格子,上一步棋
  BOOL bFlipped;                                // 是否翻转棋盘
} Xqwl;

// TransparentBlt 的替代函数,用来修正原函数在 Windows 98 下资源泄漏的问题
static void TransparentBlt2(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
    HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, UINT crTransparent) {
  HDC hImageDC, hMaskDC;
  HBITMAP hOldImageBMP, hImageBMP, hOldMaskBMP, hMaskBMP;

  hImageBMP = CreateCompatibleBitmap(hdcDest, nWidthDest, nHeightDest);
  hMaskBMP = CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL);
  hImageDC = CreateCompatibleDC(hdcDest);
  hMaskDC = CreateCompatibleDC(hdcDest);
  hOldImageBMP = (HBITMAP) SelectObject(hImageDC, hImageBMP);
  hOldMaskBMP = (HBITMAP) SelectObject(hMaskDC, hMaskBMP);

  if (nWidthDest == nWidthSrc && nHeightDest == nHeightSrc) {
    BitBlt(hImageDC, 0, 0, nWidthDest, nHeightDest,
        hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
  } else {
    StretchBlt(hImageDC, 0, 0, nWidthDest, nHeightDest,
        hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, SRCCOPY);
  }
  SetBkColor(hImageDC, crTransparent);
  BitBlt(hMaskDC, 0, 0, nWidthDest, nHeightDest, hImageDC, 0, 0, SRCCOPY);
  SetBkColor(hImageDC, RGB(0,0,0));
  SetTextColor(hImageDC, RGB(255,255,255));
  BitBlt(hImageDC, 0, 0, nWidthDest, nHeightDest, hMaskDC, 0, 0, SRCAND);
  SetBkColor(hdcDest, RGB(255,255,255));
  SetTextColor(hdcDest, RGB(0,0,0));
  BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
      hMaskDC, 0, 0, SRCAND);
  BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
      hImageDC, 0, 0, SRCPAINT);

  SelectObject(hImageDC, hOldImageBMP);
  DeleteDC(hImageDC);
  SelectObject(hMaskDC, hOldMaskBMP);
  DeleteDC(hMaskDC);
  DeleteObject(hImageBMP);
  DeleteObject(hMaskBMP);
}

// 绘制透明图片
inline void DrawTransBmp(HDC hdc, HDC hdcTmp, int xx, int yy, HBITMAP bmp) {
  SelectObject(hdcTmp, bmp);
  TransparentBlt2(hdc, xx, yy, SQUARE_SIZE, SQUARE_SIZE, hdcTmp, 0, 0, SQUARE_SIZE, SQUARE_SIZE, MASK_COLOR);
}

// 绘制棋盘
static void DrawBoard(HDC hdc) {
  int x, y, xx, yy, sq, pc;
  HDC hdcTmp;

  // 画棋盘
  hdcTmp = CreateCompatibleDC(hdc);
  SelectObject(hdcTmp, Xqwl.bmpBoard);
  BitBlt(hdc, 0, 0, BOARD_WIDTH, BOARD_HEIGHT, hdcTmp, 0, 0, SRCCOPY);
  // 画棋子
  for (x = FILE_LEFT; x <= FILE_RIGHT; x ++) {
    for (y = RANK_TOP; y <= RANK_BOTTOM; y ++) {
      if (Xqwl.bFlipped) {
        xx = BOARD_EDGE + (FILE_FLIP(x) - FILE_LEFT) * SQUARE_SIZE;
        yy = BOARD_EDGE + (RANK_FLIP(y) - RANK_TOP) * SQUARE_SIZE;
      } else {
        xx = BOARD_EDGE + (x - FILE_LEFT) * SQUARE_SIZE;
        yy = BOARD_EDGE + (y - RANK_TOP) * SQUARE_SIZE;
      }
      sq = COORD_XY(x, y);
      pc = pos.ucpcSquares[sq];
      if (pc != 0) {
        DrawTransBmp(hdc, hdcTmp, xx, yy, Xqwl.bmpPieces[pc]);
      }
      if (sq == Xqwl.sqSelected || sq == SRC(Xqwl.mvLast) || sq == DST(Xqwl.mvLast)) {
        DrawTransBmp(hdc, hdcTmp, xx, yy, Xqwl.bmpSelected);
      }
    }
  }
  DeleteDC(hdcTmp);
}

// 播放资源声音
inline void PlayResWav(int nResId) {
  PlaySound(MAKEINTRESOURCE(nResId), Xqwl.hInst, SND_ASYNC | SND_NOWAIT | SND_RESOURCE);
}

// "DrawSquare"参数
const BOOL DRAW_SELECTED = TRUE;

// 绘制格子
static void DrawSquare(int sq, BOOL bSelected = FALSE) {
  int sqFlipped, xx, yy, pc;

  sqFlipped = Xqwl.bFlipped ? SQUARE_FLIP(sq) : sq;
  xx = BOARD_EDGE + (FILE_X(sqFlipped) - FILE_LEFT) * SQUARE_SIZE;
  yy = BOARD_EDGE + (RANK_Y(sqFlipped) - RANK_TOP) * SQUARE_SIZE;
  SelectObject(Xqwl.hdcTmp, Xqwl.bmpBoard);
  BitBlt(Xqwl.hdc, xx, yy, SQUARE_SIZE, SQUARE_SIZE, Xqwl.hdcTmp, xx, yy, SRCCOPY);
  pc = pos.ucpcSquares[sq];
  if (pc != 0) {
    DrawTransBmp(Xqwl.hdc, Xqwl.hdcTmp, xx, yy, Xqwl.bmpPieces[pc]);
  }
  if (bSelected) {
    DrawTransBmp(Xqwl.hdc, Xqwl.hdcTmp, xx, yy, Xqwl.bmpSelected);
  }
}

// 点击格子事件处理
static void ClickSquare(int sq) {
  int pc;
  Xqwl.hdc = GetDC(Xqwl.hWnd);
  Xqwl.hdcTmp = CreateCompatibleDC(Xqwl.hdc);
  sq = Xqwl.bFlipped ? SQUARE_FLIP(sq) : sq;
  pc = pos.ucpcSquares[sq];

  if ((pc & SIDE_TAG(pos.sdPlayer)) != 0) {
    // 如果点击自己的子,那么直接选中该子
    if (Xqwl.sqSelected != 0) {
      DrawSquare(Xqwl.sqSelected);
    }
    Xqwl.sqSelected = sq;
    DrawSquare(sq, DRAW_SELECTED);
    if (Xqwl.mvLast != 0) {
      DrawSquare(SRC(Xqwl.mvLast));
      DrawSquare(DST(Xqwl.mvLast));
    }
    PlayResWav(IDR_CLICK); // 播放点击的声音

  } else if (Xqwl.sqSelected != 0) {
    // 如果点击的不是自己的子,但有子选中了(一定是自己的子),那么走这个子
    Xqwl.mvLast = MOVE(Xqwl.sqSelected, sq);
    pos.MakeMove(Xqwl.mvLast);
    DrawSquare(Xqwl.sqSelected, DRAW_SELECTED);
    DrawSquare(sq, DRAW_SELECTED);
    Xqwl.sqSelected = 0;
    PlayResWav(pc == 0 ? IDR_MOVE : IDR_CAPTURE); // 播放走子或吃子的声音
  }
  DeleteDC(Xqwl.hdcTmp);
  ReleaseDC(Xqwl.hWnd, Xqwl.hdc);
}

// 初始化棋局
static void Startup(void) {
  pos.Startup();
  Xqwl.sqSelected = Xqwl.mvLast = 0;
}

// 窗体事件捕捉过程
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  int x, y;
  HDC hdc;
  RECT rect;
  PAINTSTRUCT ps;
  MSGBOXPARAMS mbp;

  switch (uMsg) {
  // 新建窗口
  case WM_CREATE:
    // 调整窗口位置和尺寸
    GetWindowRect(hWnd, &rect);
    x = rect.left;
    y = rect.top;
    rect.right = rect.left + BOARD_WIDTH;
    rect.bottom = rect.top + BOARD_HEIGHT;
    AdjustWindowRect(&rect, WINDOW_STYLES, TRUE);
    MoveWindow(hWnd, x, y, rect.right - rect.left, rect.bottom - rect.top, TRUE);
    break;
  // 退出
  case WM_DESTROY:
    PostQuitMessage(0);
    break;
  // 菜单命令
  case WM_COMMAND:
    switch (LOWORD(wParam)) {
    case IDM_FILE_RED:
    case IDM_FILE_BLACK:
      Xqwl.bFlipped = (LOWORD(wParam) == IDM_FILE_BLACK);
      Startup();
      hdc = GetDC(Xqwl.hWnd);
      DrawBoard(hdc);
      ReleaseDC(Xqwl.hWnd, hdc);
      break;
    case IDM_FILE_EXIT:
      DestroyWindow(Xqwl.hWnd);
      break;
    case IDM_HELP_HOME:
      ShellExecute(NULL, NULL, "http://www.", NULL, NULL, SW_SHOWNORMAL);
      break;
    case IDM_HELP_ABOUT:
      // 弹出带象棋小巫师图标的对话框
      MessageBeep(MB_ICONINFORMATION);
      mbp.cbSize = sizeof(MSGBOXPARAMS);
      mbp.hwndOwner = hWnd;
      mbp.hInstance = Xqwl.hInst;
      mbp.lpszText = cszAbout;
      mbp.lpszCaption = "关于象棋小巫师";
      mbp.dwStyle = MB_USERICON;
      mbp.lpszIcon = MAKEINTRESOURCE(IDI_APPICON);
      mbp.dwContextHelpId = 0;
      mbp.lpfnMsgBoxCallback = NULL;
      mbp.dwLanguageId = 0;
      MessageBoxIndirect(&mbp);
      break;
    }
    break;
  // 绘图
  case WM_PAINT:
    hdc = BeginPaint(Xqwl.hWnd, &ps);
    DrawBoard(hdc);
    EndPaint(Xqwl.hWnd, &ps);
    break;
  // 鼠标点击
  case WM_LBUTTONDOWN:
    x = FILE_LEFT + (LOWORD(lParam) - BOARD_EDGE) / SQUARE_SIZE;
    y = RANK_TOP + (HIWORD(lParam) - BOARD_EDGE) / SQUARE_SIZE;
    if (x >= FILE_LEFT && x <= FILE_RIGHT && y >= RANK_TOP && y <= RANK_BOTTOM) {
      ClickSquare(COORD_XY(x, y));
    }
    break;
  // 其他事件
  default:
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
  }
  return FALSE;
}

// 装入资源图片
inline HBITMAP LoadResBmp(int nResId) {
  return (HBITMAP) LoadImage(Xqwl.hInst, MAKEINTRESOURCE(nResId), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
}

// 入口过程
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
  int i;
  MSG msg;
  WNDCLASSEX wce;

  // 初始化全局变量
  Xqwl.hInst = hInstance;
  Xqwl.bFlipped = FALSE;
  Startup();

  // 装入图片
  Xqwl.bmpBoard = LoadResBmp(IDB_BOARD);
  Xqwl.bmpSelected = LoadResBmp(IDB_SELECTED);
  for (i = PIECE_KING; i <= PIECE_PAWN; i ++) {
    Xqwl.bmpPieces[SIDE_TAG(0) + i] = LoadResBmp(IDB_RK + i);
    Xqwl.bmpPieces[SIDE_TAG(1) + i] = LoadResBmp(IDB_BK + i);
  }

  // 设置窗口
  wce.cbSize = sizeof(WNDCLASSEX);
  wce.style = 0;
  wce.lpfnWndProc = (WNDPROC) WndProc;
  wce.cbClsExtra = wce.cbWndExtra = 0;
  wce.hInstance = hInstance;
  wce.hIcon = (HICON) LoadImage(hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 32, 32, LR_SHARED);
  wce.hCursor = (HCURSOR) LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
  wce.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
  wce.lpszMenuName = MAKEINTRESOURCE(IDM_MAINMENU);
  wce.lpszClassName = "XQWLIGHT";
  wce.hIconSm = (HICON) LoadImage(hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 16, 16, LR_SHARED);
  RegisterClassEx(&wce);

  // 打开窗口
  Xqwl.hWnd = CreateWindow("XQWLIGHT", "象棋小巫师", WINDOW_STYLES,
      CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
  if (Xqwl.hWnd == NULL) {
    return 0;
  }
  ShowWindow(Xqwl.hWnd, nCmdShow);
  UpdateWindow(Xqwl.hWnd);

  // 接收消息
  while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}


[此贴子已经被作者于2016-3-27 10:03编辑过]

2016-03-26 22:26
longswallow2
Rank: 1
等 级:新手上路
帖 子:30
专家分:0
注 册:2016-3-26
收藏
得分:0 
C语言从零起步分析《象眼》象棋引擎的源码(3)
窗口类结构体WNDCLASSEX:

结构体参数:
1--cbSize:   WNDCLASSEX 的大小,即结构体本身的大小;
2--style:从这个窗口类派生的窗口具有的风格;
3--lpfnWndProc:窗口处理函数的指针;
4--cbClsExtra:指定紧跟在窗口类结构后的附加字节数;
5--cbWndExtra:指定紧跟在窗口实例的附加字节数;
6--hInstance:模块的实例句柄;
7--hIcon:图标的句柄;
8--hCursor:光标的句柄;
9--hbrBackground:背景画刷的句柄;
10--lpszMenuName:指向菜单的指针;
11--lpszClassName:指向类名称的指针;
12--hIconSm:和窗口类关联的小图标;如果该值为NULL则把hIcon中的图标转换成大小合适的小图标;

这是象棋窗口类的设置代码:
程序代码:
  WNDCLASSEX wce;
// 设置窗口类
  wce.cbSize = sizeof(WNDCLASSEX);
  wce.style = 0;
  wce.lpfnWndProc = (WNDPROC) WndProc;// 窗体事件捕捉(窗口事件将触发这个函数)
  wce.cbClsExtra = wce.cbWndExtra = 0;
  wce.hInstance = hInstance;
  wce.hIcon = (HICON) LoadImage(hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 32, 32, LR_SHARED);
  wce.hCursor = (HCURSOR) LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
  wce.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
  wce.lpszMenuName = MAKEINTRESOURCE(IDM_MAINMENU);
  wce.lpszClassName = "XQWLIGHT";
  wce.hIconSm = (HICON) LoadImage(hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 16, 16, LR_SHARED);
  RegisterClassEx(&wce);

当移动鼠标,按下鼠标,释放鼠标,按下键盘,释放键盘,等事件发生时;
操作系统将调用本程序中的回调函数-------lpfnWndProc:窗口处理函数的指针;
这个函数即wce.lpfnWndProc = (WNDPROC) WndProc;// 窗体事件捕捉(窗口事件将触发这个函数);

这一节,分析了窗口类的设置

[此贴子已经被作者于2016-3-27 11:06编辑过]

2016-03-26 22:26
longswallow2
Rank: 1
等 级:新手上路
帖 子:30
专家分:0
注 册:2016-3-26
收藏
得分:0 
C语言从零起步分析《象眼》象棋引擎的源码(4)

因为,源码很长,所以,采用分块的方法,来消化;
把注册窗口类,这个过程,剪切掉,放入一个头文件中;
然后,仅使用一条语句,就可以调用它,加强了可读性,便于我们理解;
注册窗口类中的这个变量WNDCLASSEX wce,
是个传递参数的变量,仅仅使用1次,因此完全可以把它放入函数内部;

剪切并稍微修改后的代码是这个样子的:
程序代码:
//ATOM MyRegisterClass(HINSTANCE hInstance);
ATOM MyRegisterClass(HINSTANCE hInstance)
{
  WNDCLASSEX wce;
  wce.cbSize = sizeof(WNDCLASSEX);
  wce.style = 0;
  wce.lpfnWndProc = (WNDPROC) WndProc;
  wce.cbClsExtra = wce.cbWndExtra = 0;
  wce.hInstance = hInstance;
  wce.hIcon = (HICON) LoadImage(hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 32, 32, LR_SHARED);
  wce.hCursor = (HCURSOR) LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
  wce.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
  wce.lpszMenuName = MAKEINTRESOURCE(IDM_MAINMENU);
  wce.lpszClassName = "XQWLIGHT";
  wce.hIconSm = (HICON) LoadImage(hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 16, 16, LR_SHARED);
  return RegisterClassEx(&wce);
}

然后在使用时,就MyRegisterClass(hInstance);就可以了;

这一节,使用剪切法,来提高代码的可读性;

[此贴子已经被作者于2016-3-27 11:07编辑过]

2016-03-26 22:27
longswallow2
Rank: 1
等 级:新手上路
帖 子:30
专家分:0
注 册:2016-3-26
收藏
得分:0 
C语言从零起步分析《象眼》象棋引擎的源码(5)
程序代码:
// 接收消息
  while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }

总之,这是一个消息循环;
GetMessage----接受消息
只接受自己的消息;而不接受其他线程或应用程序的消息;
从消息队列里取得一个消息并将其放于指定的结构(msg中);
如果取得WM_QUIT之外的其他消息,返回非零值;
如果取得WM_QUIT消息,返回零;(即退出这个循环;)

TranslateMessage
将虚拟键消息转换为字符消息;
DispatchMessage
调度一个消息给窗体;
窗体将会调用----回调函数(WndProc);

现在把主函数整理一下:
使用原有的句柄变量-------Xqwl.hWnd;
全局变量定义:
程序代码:
// 与图形界面有关的全局变量
static struct {
  HINSTANCE hInst;                              // 应用程序句柄实例
  HWND hWnd;                                    // 主窗口句柄
  HDC hdc, hdcTmp;                              // 设备句柄,只在"ClickSquare"过程中有效
  HBITMAP bmpBoard, bmpSelected, bmpPieces[24]; // 资源图片句柄
  int sqSelected, mvLast;                       // 选中的格子,上一步棋
  BOOL bFlipped;                                // 是否翻转棋盘
} Xqwl;

主函数:
程序代码:
int WINAPI WinMain(
                   HINSTANCE hInstance, 
                   HINSTANCE hPrevInstance, 
                   LPSTR lpCmdLine, 
                   int nCmdShow) 
{
  MSG msg;
  // 设置窗口,注册窗口类
  MyRegisterClass(hInstance);
  // 打开窗口
  Xqwl.hWnd = CreateWindow("XQWLIGHT", "象棋小巫师", WINDOW_STYLES,
      CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
      NULL, NULL, hInstance, NULL);
  if (Xqwl.hWnd == NULL) {return 0;}//如果建窗口失败就退出
  ShowWindow(Xqwl.hWnd, nCmdShow);//显示
  UpdateWindow(Xqwl.hWnd);//刷新
  // 接收消息-----主循环
  while (GetMessage(&msg, NULL, 0, 0)) {//取消息
    TranslateMessage(&msg);//转换为字符消息
    DispatchMessage(&msg);//把消息给窗体
  }
  return msg.wParam;
}

这一节,整理了主函数中的窗口构建,与消息循环;
主函数中,也只需要有这些内容;
关于画图和事件相应,都在回调函数(WndProc)中实现;

[此贴子已经被作者于2016-3-27 11:10编辑过]

2016-03-26 22:28
longswallow2
Rank: 1
等 级:新手上路
帖 子:30
专家分:0
注 册:2016-3-26
收藏
得分:0 
俺用的是Vc6.0
这个源码共有6个开发阶段;
我使用的是VC6.0;当然其他的也行,如VS等;
在这个附件里下载吧
Win32.rar (831.62 KB)



[此贴子已经被作者于2016-3-27 10:10编辑过]

2016-03-26 22:30
longswallow2
Rank: 1
等 级:新手上路
帖 子:30
专家分:0
注 册:2016-3-26
收藏
得分:0 
C语言从零起步分析《象眼》象棋引擎的源码(6)
回调函数(WndProc)
函数参数:
HWND hWnd, ---窗口的句柄
UINT uMsg, -----消息
WPARAM wParam, ---附加消息
LPARAM lParam  ---附加消息

参数UINT uMsg消息分类:

WM_CREATE: 创建窗口时发生;产生时间是窗口创建之后显示之前;
WM_PAINT:当需要绘制一部分应用窗口的时候,这个消息被Windows发出;
WM_DESTROY:窗口销毁后(调用DestroyWindow()后)的消息;
WM_COMMAND:这个消息是由窗口控件产生;
--------此时,参数WPARAM wParam:直接对应控件号;

WM_LBUTTONDOWN:鼠标点击;当用户在window客户区域点击鼠标左键的时候发送;
   wParam表示按键状态;以用它判断CTRL或者ATL或者SHIFT之类的按键有没有按下;
   lParam表示鼠标坐标(lParam是4字节整数,高2字节表示Y坐标,低2字节表示X坐标
   X坐标xPos = LOWORD(lParam);
   Y坐标yPos = HIWORD(lParam);

为了简洁,和可读性,外加可试验性;
把回调函数(WndProc)独立到一个H头文件之中;
程序代码:
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, 
                                WPARAM wParam, LPARAM lParam) 
{
  int x, y;
  HDC hdc;
  RECT rect;
  PAINTSTRUCT ps;//绘图信息结构
  MSGBOXPARAMS mbp;
switch(uMsg){
    case WM_PAINT:  // 绘图
        hdc = BeginPaint(Xqwl.hWnd, &ps);//绘画
        EndPaint(Xqwl.hWnd, &ps);
        break;
    case WM_COMMAND: // 菜单命令
        switch (LOWORD(wParam)) {
              case IDM_FILE_EXIT://菜单退出
                  DestroyWindow(Xqwl.hWnd);
                  break;
        }
    case WM_DESTROY:    // 退出
        PostQuitMessage(0);//发送一个退出信号,使主循环退出
        break;
    default://其他事件
        //默认的窗口处理函数,我们可以把不关心的消息都丢给它来处理
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return FALSE;
}

这样,就可以试运行了;
图片附件: 游客没有浏览图片的权限,请 登录注册

 
 这一节,稍微熟悉了回调函数的使用,并且试运行了一个最简单的窗口程序。

[此贴子已经被作者于2016-3-27 11:04编辑过]

2016-03-26 22:31
longswallow2
Rank: 1
等 级:新手上路
帖 子:30
专家分:0
注 册:2016-3-26
收藏
得分:0 
C语言从零起步分析《象眼》象棋引擎的源码(7)

在回调函数(WndProc)的消息选项中,
添加调整窗口尺寸的函数;
程序代码:
//static LRESULT CALLBACK WndProc(...){
//switch(uMsg){
    case WM_CREATE://创建窗口时发生;产生时间是窗口创建之后显示之前;
        tiaozhengchuangkou(hWnd); // 调整窗口位置和尺寸
//    case WM_PAINT:  // 绘图

函数独立出来放入头文件之中;
程序代码:
// 调整窗口位置和尺寸
void tiaozhengchuangkou(HWND hWnd)
{
    int x, y;
    RECT rect;
    GetWindowRect(hWnd, &rect);
    x = rect.left;
    y = rect.top;
    //右=左+棋盘宽度
    rect.right = rect.left + BOARD_WIDTH;
    //底=上+棋盘高度
    rect.bottom = rect.top + BOARD_HEIGHT;
    //计算矩形的大小--微调是为了适应风格(自适应)
    AdjustWindowRect(&rect, WINDOW_STYLES, TRUE);
    //改变窗口的位置和大小
    MoveWindow(hWnd, x, y, rect.right - rect.left, rect.bottom - rect.top, TRUE);
}

关于棋盘的常量设置,也粘贴出来:
程序代码:
// 版本号
const LPCSTR cszAbout = "象棋小巫师 0.1\n象棋百科全书 荣誉出品\n\n"
    "欢迎登录 www.\n免费下载PC版 象棋巫师";

// 窗口和绘图属性

//WS_OVERLAPPED产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。
//WS_SYSMENU创建一个在标题条上带有窗口菜单的窗口,必须同时设定WS_CAPTION风格。
//WS_CAPTION创建一个有标题框的窗口(包括WS_BORDER风格)。
//WS_MINIMIZEBOX创建一个具有最大化按钮的窗口。
//该风格不能与WS_EX_CONTEXTHELP风格同时出现,同时必须指定WS_SYSMENU风格。
const int WINDOW_STYLES = WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX;

//
const int MASK_COLOR = RGB(0, 255, 0);//掩码颜色(绿色)
const int SQUARE_SIZE = 56;//单元的大小(正方形格子的边长)
const int BOARD_EDGE = 8;//棋盘边缘
const int BOARD_WIDTH = BOARD_EDGE + SQUARE_SIZE * 9 + BOARD_EDGE;//棋盘宽度
const int BOARD_HEIGHT = BOARD_EDGE + SQUARE_SIZE * 10 + BOARD_EDGE;//棋盘高度

// 棋盘范围
const int RANK_TOP = 3;//最顶行
const int RANK_BOTTOM = 12;//最底行
const int FILE_LEFT = 3;//最左列
const int FILE_RIGHT = 11;//最右列

// 棋子编号
const int PIECE_KING = 0;//将帅
const int PIECE_ADVISOR = 1;//
const int PIECE_BISHOP = 2;//
const int PIECE_KNIGHT = 3;//
const int PIECE_ROOK = 4;//
const int PIECE_CANNON = 5;//
const int PIECE_PAWN = 6;//卒或兵

 
这一节,分析了窗口的调整部分。
 

[此贴子已经被作者于2016-3-27 11:12编辑过]

2016-03-26 22:32
longswallow2
Rank: 1
等 级:新手上路
帖 子:30
专家分:0
注 册:2016-3-26
收藏
得分:0 
C语言从零起步分析《象眼》象棋引擎的源码(8)

vc6.0如何添加资源到工程?
点击菜单上的
工程------>增加到工程------>选文件------选资源文件(XQWLIGHT.RC)
接下来,需要做的是:1装载资源图片2显示到窗口;
===========================================
1装载资源图片
程序代码:
void zhuangrutupianziyuan()//装入图片资源
{
    Xqwl.bmpBoard = LoadResBmp(IDB_BOARD);//棋盘
    Xqwl.bmpSelected = LoadResBmp(IDB_SELECTED);//选子  
}

全局变量Xqwl下的一个图片句柄的数组;
 HBITMAP bmpBoard, bmpSelected, bmpPieces[24]; // 资源图片句柄
--------------------------------
Xqwl.hInst = hInstance;//记录应用程序的实例句柄
  //Xqwl.hWnd为主窗口句柄;Xqwl.hInst为程序的实例句柄;有区别
  MSG msg;
  zhuangrutupianziyuan();//装入图片资源
  // 设置窗口,注册窗口类
  MyRegisterClass(hInstance);
紫色的代码,添加于WinMain主函数之内;
--------------------------------
// 装入资源图片
程序代码:
inline HBITMAP LoadResBmp(int nResId) {
  return (HBITMAP) LoadImage(Xqwl.hInst, 
      MAKEINTRESOURCE(nResId), IMAGE_BITMAP, 
      0, 0, LR_DEFAULTSIZE | LR_SHARED);
}

这是装入图片函数LoadResBmp,放入另一头文件之中。
===========================================
2显示到窗口
程序代码:
// 绘制棋盘
static void DrawBoard(HDC hdc) {

 // int x, y, xx, yy, sq, pc;
  HDC hdcTmp;

  // 画棋盘
  hdcTmp = CreateCompatibleDC(hdc);
  SelectObject(hdcTmp, Xqwl.bmpBoard);
  BitBlt(hdc, 0, 0, BOARD_WIDTH, BOARD_HEIGHT, hdcTmp, 0, 0, SRCCOPY);
  // 画棋子
  
  DeleteDC(hdcTmp);
}

------------------------
程序代码:
case WM_PAINT:  // 绘图
        hdc = BeginPaint(Xqwl.hWnd, &ps);//绘画
        DrawBoard(hdc);//--------------------------添加
        EndPaint(Xqwl.hWnd, &ps);
        break;

添加于回调函数(WndProc之中)
========================
这样,就完成了棋盘的装载与显示:
图片附件: 游客没有浏览图片的权限,请 登录注册

gongfumi.blog.
 ======================
粘贴一些函数的注释:
===========================
SelectObject(hdcTmp, bmp);//选择一对象到指定的设备上下文环境中
===========================
hdcTmp = CreateCompatibleDC(hdc);//创建一个兼容DC
当不再需要内存设备上下文环境时,可调用DeleteDc函数删除它
===========================
BitBlt   目标hDC,   目标X,   目标Y,   图像高,   图像宽,   源hDC,  源X,   源Y,   光栅运算常数
图片拷贝,从源拷贝到目标;
函数原型:
BOOL BitBlt(HDC hdcDest,//目标DC
  int nXDest,//目标X偏移
  int nYDest,//目标Y偏移
  int nWidth,//宽度
  int nHeight,//高度
  HDC hdcSrc,//源DC
  int nXSrc,//源X起点
  int nYSrc,//源Y起点
  DWORD dwRop);//光栅操作代码

BitBlt(hdc, 0, 0, BOARD_WIDTH, BOARD_HEIGHT, hdcTmp, 0, 0, SRCCOPY);
BitBlt(目标hDC, 目标X, 目标Y,宽, 高, 源hDC, 源X起点, 源y起点, SRCCOPY---拷贝);
===========================
本节分析了资源图片的装载与显示的大略过程。

[此贴子已经被作者于2016-3-27 11:17编辑过]

2016-03-26 22:34
快速回复:C语言从零起步分析《象眼》象棋引擎的源码
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.040172 second(s), 10 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved