win32象棋

这里只用了少数简单的gdi画图,来展示一下最近几个月学习win32的成果吧。。
在这里插入图片描述
下面展示代码,有哪里需要修改的可以指出来。

#include <windows.h>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include <cmath>

#define BLACK_PLAYER 	0
#define RED_PLAYER 		1

struct Point {
	long x, y;
	Point(long i=0,long j=0):x{i}, y{j} {}
	bool operator==(const Point& p) const {return x==p.x && y==p.y;}
	bool operator!=(const Point& p) const {return !(*this==p);}
	bool operator<=(const Point& p) const {return x<=p.x && y<=p.y;}
	bool operator>=(const Point& p) const {return x>=p.x && y>=p.y;}
};

struct Color {
	static COLORREF black;
	static COLORREF red;
};
COLORREF Color::black = RGB(0,0,0);
COLORREF Color::red = RGB(255,0,0);

struct ChessMan {

	Point pt;	//棋盘数组对应位置,并不是中心位置 
	int size;
	std::string name;
	COLORREF color;
	bool isKill = false;
	bool isFoucs = false;
	
	ChessMan(const Point& p,const std::string& n,COLORREF col,int sz=25): pt{p}, name{n}, color{col}, size{sz} {}
	
	bool operator==(const ChessMan& cm) const {return pt==cm.pt && name==cm.name && color==cm.color;}
	
	Point getCenterPos(int rowLength,int colLength) const;
	int getChessPlayer() const {return color==Color::black ? BLACK_PLAYER : RED_PLAYER;}
	bool isAllow(std::vector<ChessMan>& vec, std::map<std::string,int>& paraMap, const Point& p, bool isChessMan=false) const;
	
	private:
		bool isAllowForCannon(std::vector<ChessMan>& vec, const Point& p,bool isChessMan) const;
		bool isAllowForSoldier(const Point& p) const;
		bool isAllowForVehicle(std::vector<ChessMan>& vec, const Point& p) const;
		bool isAllowForHorse(std::vector<ChessMan>& vec, const Point& p) const;
		bool isAllowForElephant(std::vector<ChessMan>& vec, const Point& p) const;
		bool isAllowForBodyGuad(const Point& p) const;
		bool isAllowForGeneral(const Point& p) const;
 		int getCountForTwoChessMan(std::vector<ChessMan>& vec,const Point& p) const;	//获取两个棋子之间有多少个棋子 
};
//辅助函数
bool isInChess(std::vector<ChessMan>& vec,const Point& p) 
{
	for(auto cm : vec)
	{
		if (cm.isKill) continue;
		if (cm.pt == p)
			return true;
	}
	return false;
}

Point ChessMan::getCenterPos(int rowLength,int colLength) const
{
	return {25+pt.x*colLength, 25+pt.y*rowLength};
}

int ChessMan::getCountForTwoChessMan(std::vector<ChessMan>& vec,const Point& p) const
{
	int cnt = 0;
	if (pt.x == p.x)	//同在垂直方向 
	{
		for(auto cm : vec)
		{
			if (cm.pt.x == pt.x)
				if (cm.pt.y>std::min(pt.y,p.y) && cm.pt.y<std::max(pt.y,p.y))
					cnt++;
		}
	} else if (pt.y == p.y) {	//同在水平方向 
		for(auto cm : vec)
		{
			if (cm.pt.y == pt.y)
				if (cm.pt.x>std::min(pt.x,p.x) && cm.pt.x<std::max(pt.x,p.x))
					cnt++;
		}
	}
	return cnt;
}
//炮 
bool ChessMan::isAllowForCannon(std::vector<ChessMan>& vec,const Point& p,bool isChessMan) const
{
	bool bResult = true;
	if (pt.x!=p.x && pt.y!=p.y)		//必须水平或垂直在一条线上 
		bResult = false;
	if (!isChessMan) {					//没有棋子,则中间不能有别的棋子
		if (getCountForTwoChessMan(vec, p) > 0) bResult = false;
	} else {
		if (getCountForTwoChessMan(vec, p) != 1) bResult = false;	//中间只能有一个棋子 
	}
	return bResult;
}
//兵
bool ChessMan::isAllowForSoldier(const Point& p) const 
{
	bool bResult = true;
	if ((name == "兵" && p.y > pt.y) || (name == "卒" && p.y<pt.y))		//不能倒走 
		bResult = false;
	if (std::abs(pt.x-p.x) !=1 && std::abs(pt.y-p.y) !=1) bResult = false;
	//如果没有过河只能往前走
	if (name == "兵" && pt.y>4 && pt.x!=p.x) 	bResult = false;
	if (name == "卒" && pt.y<5 && pt.x!=p.x)	bResult = false;
	return bResult;
}
//车
bool ChessMan::isAllowForVehicle(std::vector<ChessMan>& vec, const Point& p) const
{
	bool bResult = true;
	if (pt.x!=p.x && pt.y!=p.y)		//必须水平或垂直在一条线上 
		bResult = false;
	if (getCountForTwoChessMan(vec, p) > 0) bResult = false;	//中间不能有别的棋子
	return bResult;
}
//马
bool ChessMan::isAllowForHorse(std::vector<ChessMan>& vec, const Point& p) const
{
	bool bResult = true;
	if (pow(std::abs(pt.x-p.x),2) + pow(std::abs(pt.y-p.y),2) !=5)  bResult = false;	//如果不是日
	//是否憋马腿
	if (p.x > pt.x)
	{
		if (p.y < pt.y)
		{
			if (pt.y-p.y == 2 && isInChess(vec, {pt.x,pt.y-1})) bResult = false;
			if (pt.y-p.y == 1 && isInChess(vec, {pt.x+1,pt.y}))	bResult = false;
		} else {
			if (p.y-pt.y == 2 && isInChess(vec, {pt.x,pt.y+1})) bResult = false;
			if (p.y-pt.y == 1 && isInChess(vec, {pt.x+1,pt.y}))	bResult = false;
		}
	} else {
		if (p.y < pt.y)
		{
			if (pt.y-p.y == 2 && isInChess(vec, {pt.x,pt.y-1})) bResult = false;
			if (pt.y-p.y == 1 && isInChess(vec, {pt.x-1,pt.y}))	bResult = false;
		} else {
			if (p.y-pt.y == 2 && isInChess(vec, {pt.x,pt.y+1})) bResult = false;
			if (p.y-pt.y == 1 && isInChess(vec, {pt.x-1,pt.y}))	bResult = false;
		}
	}
	return bResult;
}
//象
bool ChessMan::isAllowForElephant(std::vector<ChessMan>& vec, const Point& p) const
{
	bool bResult = true;
	if (std::abs(pt.x-p.x)!=2 || std::abs(pt.y-p.y)!=2) bResult = false;	//如果不为田
	if ((name=="象" && p.y>4) || (name=="相" && p.y<5)) bResult = false;		//不能过河
	//是否憋象腿
	if (p.x > pt.x)
	{
		if (p.y < pt.y && isInChess(vec, {pt.x+1,pt.y-1})) bResult = false;
		if (p.y > pt.y && isInChess(vec, {pt.x+1,pt.y+1})) bResult = false;
	} else {
		if (p.y < pt.y && isInChess(vec, {pt.x-1,pt.y-1})) bResult = false;
		if (p.y > pt.y && isInChess(vec, {pt.x-1,pt.y+1})) bResult = false;
	}
	return bResult;
}
//士
bool ChessMan::isAllowForBodyGuad(const Point& p) const
{
	bool bResult = true;
	if (std::abs(pt.x-p.x)!=1 || std::abs(pt.y-p.y)!=1) bResult = false;
	//是否在田字格内
	if (color == Color::black)
	{
		if (p.x<3 || p.x>5 || p.y<0 || p.y>2) bResult = false;
	} else {
		if (p.x<3 || p.x>5 || p.y<7 || p.y>9) bResult = false;
	}
	return bResult;
}
//将
bool ChessMan::isAllowForGeneral(const Point& p) const
{
	bool bResult = true;
	if (pt.x!=p.x && pt.y!=p.y)	bResult = false;	//必须水平或垂直在一条线上
	if (std::abs(pt.x-p.x) + std::abs(pt.y-p.y) !=1) bResult = false;	//相隔为1
	//是否在田字格内
	if (color == Color::black)
	{
		if (p.x<3 || p.x>5 || p.y<0 || p.y>2) bResult = false;
	} else {
		if (p.x<3 || p.x>5 || p.y<7 || p.y>9) bResult = false;
	}
	return bResult;
} 

bool ChessMan::isAllow(std::vector<ChessMan>& vec, std::map<std::string,int>& paraMap, const Point& p, bool isChessMan) const
{
	if (pt == p)	//目标棋子为源棋子 
		return false;
	if (name == "炮")
		return isAllowForCannon(vec, p, isChessMan);
	else if (name == "兵" || name == "卒")
		return isAllowForSoldier(p);
	else if (name == "车")
		return isAllowForVehicle(vec, p);
	else if (name == "马")
		return isAllowForHorse(vec, p);
	else if (name == "象" || name == "相")
		return isAllowForElephant(vec, p);
	else if (name == "士")
		return isAllowForBodyGuad(p);
	else if (name == "将" || name == "帅")
		return isAllowForGeneral(p);
}

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow)
{
	static TCHAR szAppName[] = TEXT("Chess");
	HWND hwnd;
	MSG msg;
	WNDCLASS wndclass;
	
	wndclass.style = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc = WndProc;
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hInstance;
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName = NULL;
	wndclass.lpszClassName = szAppName;
	
	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL, TEXT("This program requires windows NT!"), szAppName, MB_ICONERROR);
		return 0;
	}
	hwnd = CreateWindow(
		szAppName, TEXT("Chess"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT,
		850, 950,
		NULL, NULL, hInstance, NULL
	);
	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);
	while (GetMessage(&msg,NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

HFONT GetFont(HDC hdc,LPCTSTR face,int width,int height,int angle)
{
	HFONT hFont;
	hFont = CreateFont(height, width, angle, 0, FW_REGULAR, FALSE, FALSE, FALSE, GB2312_CHARSET,
					OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, FIXED_PITCH|FF_MODERN, face);
	return hFont; 
}

void DrawChessBoard(HDC hdc,std::map<std::string,int>& paraMap)
{
	int i;
	RECT blackRect, redRect;
	HFONT hPrevFont, hFont;
	POINT pt[8];
	HPEN hPrevPen, hPen;
	std::vector<POINT> vec;
	int iChessXStart = paraMap["iChessXStart"];
	int iChessXEnd = paraMap["iChessXEnd"];
	int iChessYStart = paraMap["iChessYStart"];
	int iChessYEnd = paraMap["iChessYEnd"];
	int iRow = paraMap["iRow"];
	int iCol = paraMap["iCol"];
	
	for(i=0; i<=9; i++)
	{
		MoveToEx(hdc, iChessXStart, iChessYStart+i*iRow, NULL);
		LineTo(hdc, iChessXEnd, iChessYStart+i*iRow);
	}
	for(i=0; i<=8; i++)
	{
		MoveToEx(hdc, iChessXStart+i*iCol, iChessYStart, NULL);
		LineTo(hdc, iChessXStart+i*iCol, iChessYEnd);
		if (i!=0 && i!=8)
		{
			vec.push_back({iChessXStart+i*iCol, iChessYStart+4*iRow});
			vec.push_back({iChessXStart+i*iCol, iChessYStart+5*iRow});
		}
	}
	
	pt[0] = {iChessXStart+3*iCol, iChessYStart};
	pt[1] = {iChessXStart+5*iCol, iChessYStart+2*iRow};
	pt[2] = {iChessXStart+5*iCol, iChessYStart};
	pt[3] = {iChessXStart+3*iCol, iChessYStart+2*iRow};
	pt[4] = {iChessXStart+3*iCol, iChessYStart+7*iRow};
	pt[5] = {iChessXStart+5*iCol, iChessYStart+9*iRow};
	pt[6] = {iChessXStart+5*iCol, iChessYStart+7*iRow};
	pt[7] = {iChessXStart+3*iCol, iChessYStart+9*iRow};
	for(i=0; i<8; i+=2)
		Polyline(hdc, pt+i, 2);
	
	hPrevPen = (HPEN)SelectObject(hdc, GetStockObject(WHITE_PEN));
	for(i=0; i<vec.size(); i+=2)
	{
		MoveToEx(hdc, vec[i].x, vec[i].y, NULL);
		LineTo(hdc, vec[i+1].x, vec[i+1].y);
	}
	SelectObject(hdc, hPrevPen);
	
	hFont = GetFont(hdc, TEXT("楷体"), 30, 30, 0);
	hPrevFont = (HFONT)SelectObject(hdc, hFont);
	SetRect(&blackRect, iChessXStart+0*iCol, iChessYStart+4*iRow, iChessXStart+4*iCol, iChessYStart+5*iRow);
	SetRect(&redRect, iChessXStart+4*iCol, iChessYStart+4*iRow, iChessXStart+8*iCol, iChessYStart+5*iRow);
	SetTextColor(hdc, Color::black);
	DrawText(hdc, TEXT("楚河"), -1, &blackRect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
	SetTextColor(hdc, Color::red);
	DrawText(hdc, TEXT("汉界"), -1, &redRect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
	SelectObject(hdc, hPrevFont);
	DeleteObject(hFont);	//删除GDI对象 
}

void DrawSingleChessMan(HDC hdc,const ChessMan& cm,std::map<std::string,int>& paraMap)
{
	RECT rect;
	
	HFONT hPrevFont, hFont;
	HBRUSH hPrevBrush, hBrush;
	HPEN hPrevPen, hPen;
	int focusSize = cm.size-5;
	
	if (cm.isKill) return;
	
	hBrush = CreateSolidBrush(RGB(239,215,189));
	hFont = GetFont(hdc, TEXT("微软雅黑"), 10, 20, 0);
	SetBkColor(hdc, RGB(239,215,189));
	hPrevBrush = (HBRUSH)SelectObject(hdc, hBrush);
	hPrevFont = (HFONT)SelectObject(hdc, hFont);
	SetTextColor(hdc, cm.color);
	Point center = cm.getCenterPos(paraMap["iRow"], paraMap["iCol"]);
	Ellipse(hdc, center.x-cm.size, center.y-cm.size, center.x+cm.size, center.y+cm.size);
	if (cm.isFoucs)
	{
		hPen = CreatePen(PS_SOLID, 1, cm.color);
		hPrevPen = (HPEN)SelectObject(hdc, hPen);
		Ellipse(hdc, center.x-focusSize, center.y-focusSize, center.x+focusSize, center.y+focusSize);
		SelectObject(hdc, hPrevPen);
		DeleteObject(hPen);
	}
	SetRect(&rect, center.x-cm.size, center.y-cm.size, center.x+cm.size, center.y+cm.size);
	DrawText(hdc, TEXT(cm.name.c_str()), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	
	SelectObject(hdc, hPrevBrush);
	SelectObject(hdc, hPrevFont);
	DeleteObject(hBrush);	//删除GDI对象
	DeleteObject(hFont);
}

void DrawChessMan(HDC hdc,std::map<std::string,int>& paraMap,std::vector<ChessMan>& vec)
{
	for(int i=0; i<vec.size(); i++)
		DrawSingleChessMan(hdc, vec[i], paraMap);
}

void DrawChess(HDC hdc,std::map<std::string,int>& paraMap,std::vector<ChessMan>& vec)
{
	DrawChessBoard(hdc, paraMap);
	DrawChessMan(hdc, paraMap, vec);
}

int getChessManByPos(std::vector<ChessMan>& vec, const Point& pt, std::map<std::string,int>& paraMap)
{
	for(int i=0; i<vec.size(); i++)
	{
		if (vec[i].isKill)
			continue;
		Point center = vec[i].getCenterPos(paraMap["iRow"], paraMap["iCol"]);
		Point leftTop{center.x-vec[i].size, center.y-vec[i].size};
		Point rightBottom{center.x+vec[i].size, center.y+vec[i].size};
		if (pt>=leftTop && pt<=rightBottom)
			return i;
	}
	return -1;
}

void fillParam(std::map<std::string,int>& paraMap,int cxClient,int cyClient)
{
	int iChessXStart = 25;
	int iChessXEnd = cxClient - 25;
	int iChessYStart = 25;
	int iChessYEnd = cyClient - 25;
	int iRow = (iChessYEnd-iChessYStart) / 9;
	int iCol = (iChessXEnd-iChessXStart) / 8;
	
	paraMap["iChessXStart"] = iChessXStart;
	paraMap["iChessXEnd"] = iChessXEnd;
	paraMap["iChessYStart"] = iChessYStart;
	paraMap["iChessYEnd"] = iChessYEnd;
	paraMap["iRow"] = iRow;
	paraMap["iCol"] = iCol;
	paraMap["cxClient"] = cxClient;
	paraMap["cyClient"] = cyClient;
}

Point getChessManPos(std::map<std::string,int>& paraMap,const Point& pt)
{
	int x = (pt.x-paraMap["iChessXStart"])/paraMap["iCol"];
	int y = (pt.y-paraMap["iChessYStart"])/paraMap["iRow"];
	Point leftTop{paraMap["iChessXStart"]+x*paraMap["iCol"], paraMap["iChessYStart"]+y*paraMap["iRow"]};
	Point rightTop{paraMap["iChessXStart"]+(x+1)*paraMap["iCol"], paraMap["iChessYStart"]+y*paraMap["iRow"]};
	Point leftBottom{paraMap["iChessXStart"] + x*paraMap["iCol"], paraMap["iChessYStart"] + (y+1)*paraMap["iRow"]};
	Point rightBottom{paraMap["iChessXStart"]+(x+1)*paraMap["iCol"], paraMap["iChessYStart"]+(y+1)*paraMap["iRow"]};
	
	if (pt.x>=leftTop.x && pt.x<=leftTop.x+25 && pt.y>=leftTop.y && pt.y<=leftTop.y+25)
		return {x, y};
	else if (pt.x>=rightTop.x-25 && pt.x<=rightTop.x && pt.y>=rightTop.y && pt.y<=rightTop.y+25)
		return {x+1, y};
	else if (pt.x>=leftBottom.x && pt.x<=leftBottom.x+25 && pt.y>=leftBottom.y-25 && pt.y<=leftBottom.y)
		return {x, y+1};
	else if (pt.x>=rightBottom.x-25 && pt.x<=rightBottom.x && pt.y>=rightBottom.y-25 && pt.y<=rightBottom.y)
		return {x+1, y+1};
	else
		return {-1,-1};
}

std::vector<ChessMan> getChessMen()
{
	return std::vector<ChessMan> {
			{{0,0},"车",Color::black}, {{1,0},"马",Color::black}, {{2,0},"象",Color::black}, {{3,0},"士",Color::black},
			{{8,0},"车",Color::black}, {{7,0},"马",Color::black}, {{6,0},"象",Color::black}, {{5,0},"士",Color::black},
			{{4,0},"将",Color::black},
			{{1,2},"炮",Color::black}, {{7,2},"炮",Color::black},
			{{0,3},"卒",Color::black}, {{2,3},"卒",Color::black}, {{4,3},"卒",Color::black},
			{{6,3},"卒",Color::black}, {{8,3},"卒",Color::black},
			
			{{0,9},"车",Color::red}, {{1,9},"马",Color::red}, {{2,9},"相",Color::red}, {{3,9},"士",Color::red},
			{{8,9},"车",Color::red}, {{7,9},"马",Color::red}, {{6,9},"相",Color::red}, {{5,9},"士",Color::red},
			{{4,9},"帅",Color::red},
			{{1,7},"炮",Color::red}, {{7,7},"炮",Color::red},
			{{0,6},"兵",Color::red}, {{2,6},"兵",Color::red}, {{4,6},"兵",Color::red},
			{{6,6},"兵",Color::red}, {{8,6},"兵",Color::red}
		};
}

LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	static int currentChessPlayer = RED_PLAYER;
	static int cxClient, cyClient, idFoucs=-1;
	static std::map<std::string,int> paraMap;
	static std::vector<ChessMan> vec{getChessMen()};
	int iChessXStart, iChessXEnd, iChessYStart, iChessYEnd, iRow, iCol;
	HDC hdc;
	PAINTSTRUCT ps;
	TEXTMETRIC tm;
	RECT rect;
	int i, currentId;
	Point pt;
	
	switch (message)
	{
		case WM_CREATE:
			hdc = GetDC(hwnd);
			GetClientRect(hwnd, &rect);
			cxClient = rect.right - rect.left;
			cyClient = rect.bottom - rect.top;
			ReleaseDC(hwnd, hdc);
			fillParam(paraMap, cxClient, cyClient);
			return 0;
		case WM_SIZE:
			cxClient = LOWORD(lParam);
			cyClient = HIWORD(lParam);
			fillParam(paraMap, cxClient, cyClient);
			return 0;
		case WM_LBUTTONDOWN:
			pt.x = LOWORD(lParam);
			pt.y = HIWORD(lParam);

			if (idFoucs != -1)	//已选中棋子 
			{
				currentId = getChessManByPos(vec, pt, paraMap);
				if (currentId == -1) {								//空白地方 
					pt = getChessManPos(paraMap, pt);
					if (pt == Point{-1,-1})
						MessageBeep(0);
					else {
						if (vec[idFoucs].isAllow(vec,paraMap,pt))
						{
							vec[idFoucs].pt = pt;
							currentChessPlayer ^= 1;
						} else
							MessageBeep(0);
						vec[idFoucs].isFoucs = false;
						idFoucs = -1;
					}
				} else {
					if (vec[idFoucs].color == vec[currentId].color)	//己方 
					{
						if (idFoucs == currentId)
						{
							vec[idFoucs].isFoucs = false;
							idFoucs = -1;
						}
						else
							MessageBeep(0);
					}
					else {											//对方
						if (vec[idFoucs].isAllow(vec,paraMap,vec[currentId].pt,true))
						{
							vec[currentId].isKill = true;
							vec[idFoucs].pt = vec[currentId].pt;
							currentChessPlayer ^= 1;
							if (vec[currentId].name == "将" || vec[currentId].name == "帅")
							{
								InvalidateRect(hwnd, NULL, TRUE);
								MessageBeep(0);
								if (vec[idFoucs].color == Color::red)
									MessageBox(hwnd, TEXT("红方获胜!"), TEXT("结果"), MB_OK);
								else 
									MessageBox(hwnd, TEXT("黑方获胜!"), TEXT("结果"), MB_OK);
								//复原棋盘
								vec = getChessMen();
							}
						} else 
							MessageBeep(0);
						vec[idFoucs].isFoucs = false;
						idFoucs = -1;
					}
				}
			} else {	
				currentId = getChessManByPos(vec, pt, paraMap);
				if (currentId == -1)
					MessageBeep(0);
				else {
					if (vec[currentId].getChessPlayer() == currentChessPlayer)
					{
						idFoucs = currentId;
						vec[idFoucs].isFoucs = true;
					} else 
						MessageBeep(0);
				}
			}
			InvalidateRect(hwnd, NULL, TRUE);
			return 0;
		case WM_PAINT:
			hdc = BeginPaint(hwnd, &ps);
			DrawChess(hdc, paraMap, vec);
			EndPaint(hwnd, &ps);
			return 0;
		case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
	}
	return DefWindowProc(hwnd,message,wParam,lParam);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值