基于MFC实现的人机对战五子棋游戏
基于MFC实现的人机对战五子棋游戏
1、引言
此报告将详细介绍本次课程设计的动机、设计思路及编写技术的详细过程,展现我所学过的C++知识以及我通过本次课程设计所学到例如MFC等知识。在文档最后我也会记录我所编写过程遇到的问题以及解决方案。
1.1 背景
五子棋是起源于中国古代的传统黑白棋种之一,此游戏不仅能增强思维能力,提高智力,而且变化多端,非常富有趣味性和消遣性,伸手人们喜爱。而且人工智能发展迅速,人们不断制造出可以用机器代替人们做一些事的程序,包括五子棋等棋类小游戏。随着经济的快速发展,人们的生活节奏也越来越快,随之而来的便是人们越来越少的空闲时间,而此类小游戏不占空间,占用时间也少,所以成了很多人喜爱的娱乐方式。
传统五子棋的棋具与围棋大致相同,棋子分为黑白两色,棋盘为15×15,棋子放置于棋盘线交叉点上。两人对局,各执一色,轮流下一子,先将横、竖或斜线的5个或5个以上同色棋子连成不间断的一排者为胜(正规比赛中黑棋只能连成5个。6-9个一排算禁手,另外黑棋还有33和44禁手。黑棋禁手判负。白棋没有限制)。 因为传统五子棋在落子后不能移动或拿掉,所以也可以用纸和笔来进行游戏。随着五子棋的发展,逐步发现先行优势非常大,最后得出“先行必胜”即现代五子棋。本游戏为传统无禁手五子棋,适用于初学者。
1.2 动机
五子棋游戏如果开发成功,有以下几个好处:
- 可以增强人们的抽象思维能力、逻辑推理能力、空间想象力、提高人们的记忆力、心算能力等,而且深含哲理,有助于修身养性
- 可以作为人们休闲时的娱乐,容易上手,老少皆宜,而且趣味横生,引人入胜
所以,本系统旨在开发一个传统五子棋小游戏程序。
1.3 要解决的问题
本系统要提供以下几个功能:
- 玩家信息录入功能:在主界面初始化之前,调用对话框的DoModal函数,产生一个对话框即登陆界面,在登录界面录入玩家姓名、年龄和性别,点击登录在对话框结束后,根据结果判断,再进行主界面的初始化,显示玩家信息
- 棋盘绘制:关于棋盘的呈现采用GDI DrawImage 的方法先准备一张15*15的棋盘图片,在OnPaint()函数中从备份DC拷贝到屏的DC里实现图片的显示。再是绘制棋盘中的棋子,本程序根据棋盘坐标定义二维数组,用户在棋盘中放置棋子时,根据鼠标的坐标点获取对应棋子
- 人机对弈:进入主界面后即可进行人机对弈,程序默认为玩家先,可以通过游戏设置,选择人先机后或者机先人后。同时我为计算机设计了一套策略型智能算法,使得在用户每走一步棋后,电脑都要进行一次全盘扫描,然后根据算法选择出得分最高的位置即对对方最有威胁而对自己最有利的位置,选择最佳下棋点下棋,实现人机轮流走棋
- 输赢判断功能:在玩家或计算机每走一步棋后,通过算法判断是否有一方连续的棋子数在“横”、“竖”、“左斜”、“右斜”等于或超过五个棋子,若是则电脑将调用一个函数Messagebox(),弹出对话框提示输赢
- 悔棋功能:在玩家下棋后,如果想返回之前的棋局,则可点“悔棋”使得棋局回到下每步棋之前的棋局
- 错误示功能:如果玩家在下棋时,将棋子落在其它棋子的位置或者在棋盘外的位置时,将会弹出错误提示框,提示请到棋盘内落子
2、系统流程图
五子棋的游戏规则很简单,在玩家登录后开始游戏,在每次玩家或电脑下棋后,系统都要判断是否分出胜负,若否,另一方继续下棋;若是,提示输赢后,可以选择再来一局。下图是此系统的流程图,描述了系统的运行过程,以便大家了解游戏的原理。
3、数据结构设计
棋盘使用二维数组表示,15*15的棋盘就用m_board[15][15]的二维数组表示,第i行,第j列的元素应该是m_board[i][j]。
以下用自定义数据结构类型pos表示棋子位置:
struct pos
{int x,y; //x,y分别行列坐标int flag; //记录xy处下的是白棋还是黑棋;1--白棋
};
玩家信息表如下:
表中内容为数据库表格的三列名称:玩家姓名、年龄和性别,以及各自的数据类型。
4、关键技术
本系统是C++中的MFC基于对话框创建的MFC程序,主要致力于解决如下几个关键问题:
4.1 玩家信息登录
在主界面初始化之前,调用Dialog的DoModal函数,产生另外一个Dialog即登陆界面,玩家在登录界面输入玩家信息(玩家名,年龄,性别),完成后进入主界面,显示玩家信息。
玩家输入的信息
playername=dlg2.m_name; //玩家名
playerage=dlg2.m_age; //年龄
playersex=dlg2.m_sex; //性别
棋盘旁边显示的信息
dlg.m_cname=playername;
dlg.m_csex=playersex;
dlg.m_cage=playerage; //获取对象dlg的信息
dlg.DoModal(); //调用DoModal()函数
4.2 棋盘绘制
关于棋盘的呈现采用GDI DrawImage 的方法先准备一张15*15的棋盘图片,在OnPaint()函数中从源位图拷贝成为目的位图。
void CFivezq::DrawBoard()//画棋盘
{m_pdc->BitBlt(0,0,446,446,m_pboard,0,0,SRCCOPY);
}
4.3 棋子绘制
关于棋子的实现,在于读取鼠标点击的坐标来判断点击位置所在的格子,然后求出该格子的中心位置坐标,以该中心为圆心用GDI画黑色或白色圆,然后用画刷CBrush *brush分别填充黑白色即可。实现代码如下:
//游戏中画棋子
void CFivezq::DrawChess(int px, int py, int type)
//判断下棋次序,如果轮到白棋下
if(m_turn==1)//添加红色中心CPen pen_r(PS_SOLID,2,RGB(255,0,0));
else//如果轮到黑棋下CBrush *brush;
//定义黑色画刷填充黑色
CBrush brush1(RGB(0,0,0));
//窗口无效重画白棋
m_pdc->Ellipse(px*29+7,py*29+7,px*29+34,py*29+34);
CBrush *brush;
//窗口无效重画黑棋子
CBrush brush1(RGB(0,0,0));
4.4 计算机落子
4.4.1 评分算法
为方便后面介绍详细算法先介绍下五子棋相关术语
- 连:2枚以上的同色棋子在一条线上邻接成串
- 五连:五枚同色棋子在一条线上邻接连串
- 成五:五连和长连的统称
- 四:五连去掉1子的棋型
- 活四:有两个威胁的四
- 冲四:只有一个威胁的四
- 死四:不能成五的四连
- 三:可以形成四再形成五的三枚同色棋子组成的棋型
- 活三:再走一着可以形成活四的三
- 连活三:两端都是威胁的连三。简称“连三”
- 眠三:再走一着可以形成冲四的三
- 死三:不能成五的三
- 二:可以形成三、四直至五的两枚同色棋子组成的棋型
- 活二:再走一着可以形成活三的二
- 连活二:连的活二。简称“连二”
- 眠二:再走一着可以形成眠三的二
- 死二:不能成五的二
- 先手:对方必须应答的着法,相对于活三先手而言,冲四称为“绝对先手”
- 三三:一子落下同时形成两个活三。也称“双三”
- 四四:一子落下同时形成两个冲四。也称“双四”
- 四三:一子落下同时形成一个冲四和一个活三
电脑落子之前要对棋局进行判断,那就需要告诉电脑什么时候的局势最好,我们可以通过给不同局势时不同分值的办法来让电脑明白。评分的基本规则及实现代码如下:
//评分函数
void CFivezq::Evaluater(int (&flag)[2][2], int &n, int &score,int turn);
判断是否能成5,如果是电脑方给予100000分,如果是控制者方给予-100000分;
//五连以上,得最高分
else if(n>=5) if(turn==1)score=100000;elsescore=50000;
判断是否能成活4或者是双死4或者是死4活3,如果是电脑方给予10000分,如果是控制方给予-10000分;若成双活3,如果是电脑方给予5000分,如果是控制者方给予-50 00分;若成死3活3,如果是电脑方给予1000分,如果是控制者方给予-1000分;
//活四+****+
if(flag[1][1]&&flag[0][1])if(turn==1)score=10000;elsescore=4000;
判断是否能成死4,如果是电脑方给予500分,如果是控制者方给予-500;
//死四
if(flag[1][0]&&flag[0][0])score=500;
if((flag[1][0]&&flag[0][1])||(flag[1][1]&&flag[0][0]))//冲四o****+ 轮到己方下子冲四>活三if(turn==1)score=4000; elsescore=2500;
判断是否能成单活3,如果是电脑方给予200分,如果是控制者方给予-200分;
//o**---|---**o 眠三
if((flag[1][0]&&flag[0][1])||(flag[1][1]&&flag[0][0]))score=200;
判断是否已成双活2,如果是电脑方给予100分,如果是控制者方给予-100分;若成死3,如果是电脑方给予50分,如果是控制者方给予-50分;
//死三o***o
if(flag[1][0]&&flag[0][0])score=120;
if(flag[1][1]&&flag[0][1])if(turn==1)//活三+***+score=3000; elsescore=2000;
判断是否成眠2,如果是电脑房给予20分,如果是控制者方给予-20分;
//o**---|---**o 眠二
if((flag[1][0]&&flag[0][1])||(flag[1][1]&&flag[0][0]))score=20;
判断是否能成双活2,如果是电脑方给予10分,如果是控制者方给予-10分;判断是否能成活2,如果是电脑方给予5分,如果是控制者方给予-5分;
//活二
if(flag[1][1]&&flag[0][1]) if(turn==1)score=50;elsescore=40;
判断是否能成死2,如果是电脑方给予3分,如果是控制者方给予-3分。
//死二
if(flag[1][0]&&flag[0][0])score=3;
4.4.2 判断最佳落子点核心算法
要使电脑落子必须令计算机知道自己及对方的棋型才行。先来分析己方的棋型,我们从棋盘左上角出发,向右逐行搜索,当碰到一个空白点时,以它为中心向左挨个查找,假如碰到己方的子则记录然后继续,假如碰到对方的子、空白点或边界就停止查找。左边完成后再向右进行同样的操作;最后把左右两边的记录合并起来,得到的数据就是该点横向上的棋型,然后把棋型的编号填入到Computer[x][y][n]中就行了(x、y代表坐标,n=0、1、2、3分别代表横、竖、左斜、右斜四个方向)。而其他三个方向的棋型也可用同样的方法得到,当 搜索完整张棋盘后,己方棋型表也就填写完毕了。然后再用同样的方法填写对方棋型表。
实现代码如下:
//核心算法
void CFivezq::ChessExpert(CPoint &best)
//应全部初始化为零
int computer[15][15][4]={0},player[15][15][4]={0};
//标志数组:标志该空位两端是否到达边界(遇到对方棋子)/遇到空位
int flag[2][2]={0};
int count=0,i,j,k,m;
//(x,y)存储向右搜索时遇到边界/空位/对方棋子时的前一个坐标,向左搜索的起点
int x=0,y=0;
横向向左搜索
//横向--->
for(k=1;k<5;k++)
{//横向右遇到边界if(i+k>14){flag[0][0]=1;break;}//横向右遇到对方棋子+***oif(m_board[i+k][j]==-m_turn){flag[0][0]=1;break;}//横向右遇到空位++*++if(m_board[i+k][j]==0){flag[0][1]=1;break;}
}
横向向右搜索
//横向<---
for(m=0;m>-5;m--)
{//横向左遇到边界if(x+m<0){flag[1][0]=1;break;}if(m_board[x+m][y]==m_turn)count++;//横向左遇到对方棋子o***+if(m_board[x+m][y]==-m_turn){flag[1][0]=1;break;}//横向左遇到空位++*++if(m_board[x+m][y]==0){flag[1][1]=1;break;}
}
纵向向下搜索
//纵向下遇到边界
if(j+k>14)
{flag[0][0]=1;break;
}
//纵向下 遇到对方棋子+***o
if(m_board[i][j+k]==-m_turn)
{flag[0][0]=1;break;
}
//纵向下遇到空位++*++
if(m_board[i][j+k]==0)
{flag[0][1]=1;break;
}
纵向向上搜索
//纵向上遇到界
if(y+m<0)
{flag[1][0]=1;break;
}
if(m_board[x][y+m]==m_turn)count++;
//纵向上遇到对方棋子o***+
if(m_board[x][y+m]==-m_turn)
{flag[1][0]=1;break;
}
//纵向上遇到空位++*++
if(m_board[x][y+m]==0)
{flag[1][1]=1;break;
}
45度向下搜索
//45°向下遇到边界
if(i+k>14||j+k>14)
{flag[0][0]=1;break;
}
//45°向下遇到对方棋子+***o
if(m_board[i+k][j+k]==-m_turn)
{flag[0][0]=1;break;
}
//45°向下遇到空位++*++
if(m_board[i+k][j+k]==0)
{flag[0][1]=1;break;
}
45度向上搜索
//45°向上遇到边界
if(x+m<0||y+m<0)
{flag[1][0]=1;break;
}
//45°向上遇到对方棋子o***+
if(m_board[x+m][y+m]==-m_turn)
{flag[1][0]=1;break;
}
//45°向上遇到空位++*++
if(m_board[x+m][y+m]==0)
{flag[1][1]=1;break;
}
135度向下搜索
//135°向下遇 到边界
if(i-k<0||j+k>14)
{flag[0][0]=1;break;
}
//135°向下遇到对方棋子+***o
if(m_board[i-k][j+k]==-m_turn)
{flag[0][0]=1;break;
}
//135°向下遇到空位++*++
if(m_board[i-k][j+k]==0)
{flag[0][1]=1;break;
}
135度向上搜索
//135°向上遇到边界
if(x-m>14||y+m<0)
{flag[1][0]=1;break;
}
//135°向上遇到对方棋子o***+
if(m_board[x-m][y+m]==-m_turn)
{flag[1][0]=1;break;
}
//135°向上遇到空位++*++
if(m_board[x-m][y+m]==0)
{flag[1][1]=1;break;
}
4.4.3 计算机落子函数
有了上面填写的两张棋型表,现在要作的就是让电脑知道在哪一点下子了。其中最简单的计算方法就是遍历棋型表computer[15][15][4]和player[15][15][4],在通过评分算法找出其中数值最大的一点,在该点下子即可。实现代码如下:
//电脑得分,玩家得分;初始化为0;
int cpscore[15][15],plscore[15][15];
//求每一可能下子的交叉点得分
for(i=0;i<15;i++)
从电脑角度求出最佳下棋点:
//从电脑角度 最好的点(cpx,cpy)
int cpmax=0,cpx=0,cpy=0;
cpmax=cpscore[0][0];
if(cpmax<cpscore[i][j])
{cpmax=cpscore[i][j];cpx=i;cpy=j;
}
从玩家角度选出最佳下棋点:
//从玩家角度 最好的点(cpx,cpy)
int plmax=0,plx=0,ply=0;
plmax=plscore[0][0];
if(plmax<plscore[i][j])
{plmax=plscore[i][j];plx=i;ply=j;
}
4.5 判断输赢
当棋盘中出现连续五个或以上同色棋子相连时,即可判定输赢。实现代码如下:
// 判赢函数
int CFivezq::WhoWin(int nx,int ny)
判断水平行还是否连成五个子,只要够了5个就返回1,否则返回0.
for(i=0;i>-5;i--)
{if(nx+i<0)continue;if(m_board[nx+i][ny]==m_turn){count++;if(count>=5)return m_turn;}elsebreak;
}//向右判断
for(i=1;i<5;i++)
{if(nx+i>14)break;if(m_board[nx+i][ny]==m_turn){count++;if(count>=5)return m_turn;}elsebreak;
}
判断竖行是否连成五个子:
//向下判断
for(i=0;i>-5;i--)
{if(ny+i<0)continue;if(m_board[nx][ny+i]==m_turn){count++;if(count>=5)return m_turn;}elsebreak;
}
//向上判断
for(i=1;i<5;i++)
{if(ny+i>14)break;if(m_board[nx][ny+i]==m_turn){count++;if(count>=5)return m_turn;}elsebreak;
}
判断从左上到右下是否连成五个子:
//向135度判断
for(i=0;i>-5;i--)
{if(nx+i<0||ny+i<0)continue;if(m_board[nx+i][ny+i]==m_turn){count++;if(count>=5)return m_turn;}elsebreak;
}
//向45度判断
for(i=1;i<5;i++)
{if(nx+i>14||ny+i>14)break;if(m_board[nx+i][ny+i]==m_turn){count++;if(count>=5)return m_turn;}elsebreak;
}
判断从右上到右下是否连成五个子:
//向135度判断
for(i=0;i>-5;i--)
{if(ny+i<0)continue;if(nx-i>14)break;if(m_board[nx-i][ny+i]==m_turn){count++;if(count>=5)return m_turn;}elsebreak;
}
//向45度判断
for(i=1;i<5;i++)
{if(nx-i<0)continue;if(ny+i>14)break;if(m_board[nx-i][ny+i]==m_turn){count++;if(count>=5)return m_turn;}elsebreak;
}
4.6 悔棋
在之前的数据中已经保存了各黑白棋子的坐标struct pos ,pos posinfo[225];只要在重画一次即可。实现代码如下:
//悔棋函数
void CFivezq::BackGo(HWND hwnd,int gamemode)
若游戏模式为机先人后时的代码:
m_board[posinfo[posflag-1].x][posinfo[posflag-1].y]=0;
m_board[posinfo[posflag-2].x][posinfo[posflag-2].y]=0;
posflag=posflag-2;
while(posflag==1)posflag--;
游戏模式为人先机后时的代码:
{m_board[posinfo[posflag-1].x][posinfo[posflag-1].y]=0;m_board[posinfo[posflag-2].x][posinfo[posflag-2].y]=0;posflag=posflag-2;
}
消息提示:
elseMessageBox(hwnd,"您已经没有棋可悔!",NULL,MB_OK);
5、系统运行结果
5.1 系统运行环境
- 硬件环境
- 处理器:Intel® Core™ i5 CPU M 460@2.53GHz 2.53GHz
- 内存:2.00GB
- 软件环境
- 操作系统:Windows7
- 编码工具:Microsoft Visual C++ 6.0或 Microsoft Visual Studio 2010
5.2 系统服务模式
本系统是基于C++的MFC中的对话框Dialog进行开发的,所以系统的服务模式是windows窗体程序。
5.3 系统运行结果
5.3.1 系统主界面
本系统是五子棋游戏系统,在系统主界面的棋盘中即可落子下棋,在右侧可以看到玩家信息以及游戏的功能按钮。系统主界面如下图5.1所示:
5.3.2 登录界面
程序运行开始弹出登陆对话框,输入玩家姓名、年龄和性别,然后登录即可进入主界面。玩家登录界面如下图5.2所示:
5.3.3 玩家信息显示界面
玩家在登录界面输入信息登录后,其信息便显示在主界面。玩家信息显示界面如下图5.3所示:
5.3.4 游戏设置界面
玩家在游戏时可以设置游戏的模式:人先机后或者机先人后,也可以选择玩家的棋子颜色:黑棋或者白棋。游戏设置按钮如下图5.4所示:
游戏设置界面如下图5.5所示:
5.3.5 判断输赢界面
玩家下棋后,系统会根据算法判断棋局输赢并弹出对话框提示。胜利界面如下图5.6所示:
失败界面如下图5.7所示:
5.3.6 错误提示界面
当玩家下棋时,如果点击使棋子落在已有棋子的位置上,则会弹出错误提示“此处已经有棋子”;若点击使棋子落在棋盘外时,则会弹出错误提示“请到棋盘内下子”;当玩家悔棋至没有棋子可以悔时,则会弹出错误提示“您已经没有棋可以悔”。
“此处已经有棋子”错误提示界面如下图5.8所示:
“请到棋盘内下子”错误提示界面如下图5.9所示:
“您已经没有棋可以悔”错误提示界面如下图5.10所示:
5.3.7 帮助界面
如果玩家对五子棋不是很了解,可以通过点击“帮助”按钮进入帮助界面查看五子棋简介及游戏规则。帮助界面如下图5.11所示:
6、调试和改进
在游戏设计之初有许多BUG,其中我觉得影响最大的就是编写评分算法时分值的设置。开始我设置的分值差距较小,计算机在判断棋型得分时因为分数的累加得到相同的分数,而电脑在判断双方的分值的时候,就是在落子时对自己的落子点分值和对方的分值进行对比来进行之后落子的判断,分数相同就会使电脑判断错误,导致程序不够“聪明”,即使编写再好的算法也是杯水车薪。所以,后来便将评分算法的分值差距拉大,是电脑能够正确判断,程序能够正确运行。
7、心得和结论
7.1 结论
这是我第一次做课程设计,所以感触颇深。在设计时我遇到了许多问题,但是在解决问题的过程中也收获了很多知识和经验。在诸多困难中,我体会最深的一点就是设计系统架构的重要性。这个五子棋游戏程序不是很大,但是代码的组织是很重要的,因为关系到日后的维护和扩展。在设计之初,我主要针对五子棋的核心算法进行了研究,并得出一段合适的代码,但后来我便认识到这不仅仅是一个算法的问题,因为在完成核心算法之后,还有其他的功能需要编码实现。由于我的系统架构设计在编程之前没有做好,导致很多功能在编码实现的时候非常困难,所以在程序设计之初,必须设计一个好的系统架构才能将如此多个功能、如此多条代码合理的组织在一起,完成一个高性能的完整程序。
本次课程设计也令我获益匪浅。首先,我通过自己的努力完成了一个小型游戏程序设计与实现,也是对自己之前所学专业知识的复习以及能力的肯定,并在此基础上强化自己的实践意识,提高了我的实际动手能力和创新能力。其次,在解决设计过程中遇到的问题时,同学们一起交流经验,不仅获取了知识、开拓了自己的思路,而且还提升了同学之间的凝聚力和解决问题的积极性。再次,因为自己是第一次做课程设计,所以在经验及能力上还是有许多不足之处,需要查阅许多资料才能完成,在找资料的同时我找到了许多好的网站、论坛,比如CSDN IT技术社区,在这个社区中我可以同许多有经验和能力的人交流专业知识,也可以下载许多有用的资料,是自己将来工作或学习中解决问题的良好平台。
虽然这次做的程序有一定的缺陷,但是我相信在进一步的学习以及有了如此宝贵的经验之后,我一定会作出更好的作品。
7.2 进一步改进方向
随着互联网的迅速发展,人们对游戏的要求也越来越高,人机对弈的实现是不够的。本系统的改进方向是能够增加人人对弈功能并连接网络,使得玩家可以通过网络进行对弈。希望有一天可以实现。
主要参考文献
[1] 五子棋百度百科http://baike.baidu.com/view/2697.htm
[2] 刘锐宁、宋坤,visual C++开发典型模块大全,人民邮电出版社,2009年2月。
[3] 郑阿奇、丁有和,C++实用教程,电子工业出版社, 2008年1月。
[4] 明日科技,Visual C++程序开发范例宝典,人民邮电出版社,2007年7月。
[5] C++课程设计五子棋游戏http://wenku.baidu.com/view/979c7ccada38376bae1fae06.html
[6] MFC教程http://wenku.baidu.com/view/9d97c1acdd3383c4bb4cd2f2.html
相关文章:

基于MFC实现的人机对战五子棋游戏
基于MFC实现的人机对战五子棋游戏 1、引言 此报告将详细介绍本次课程设计的动机、设计思路及编写技术的详细过程,展现我所学过的C知识以及我通过本次课程设计所学到例如MFC等知识。在文档最后我也会记录我所编写过程遇到的问题以及解决方案。 1.1 背景 五子棋是…...

AIGC 时代的文学:变革与坚守
目录 一.AIGC 带来的文学变革 1.创作方式的改变 2.阅读体验的升级 3.文学市场的重塑 二.文学在 AIGC 时代的坚守 1.人类情感的表达 2.文学的艺术性 3.文学的社会责任 三.AIGC 与人类作家的共生之路 1.相互学习 2.合作创作 3.共同发展 另: 总结 随着人…...

InfluxDB 集成 Grafana
将InfluxDB集成到Grafana进行详细配置通常包括以下几个步骤:安装与配置InfluxDB、安装与配置Grafana、在Grafana中添加InfluxDB数据源以及创建和配置仪表板。以下是一个详细的配置指南: 一、安装与配置InfluxDB 下载与安装: 从InfluxDB的官…...

笔记本电脑usb接口没反应怎么办?原因及解决方法
笔记本电脑的USB接口是我们日常使用中非常频繁的一个功能,无论是数据传输、充电还是外接设备,都离不开它。然而,当USB接口突然没有反应时,这无疑会给我们的工作和学习带来不小的困扰。下面,我们就来探讨一下笔记本USB接…...

【开源】A060-基于Spring Boot的游戏交易系统的设计与实现
🙊作者简介:在校研究生,拥有计算机专业的研究生开发团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看项目链接获取⬇️,记得注明来意哦~🌹 赠送计算机毕业设计600个选题ex…...

static关键字在嵌入式C编程中的应用
目录 一、控制变量的存储周期和可见性 1.1. 局部静态变量 1.2. 全局静态变量 二、控制函数的可见性 2.1. 静态函数 2.2. 代码示例(假设有两个文件:file1.c和file2.c) 三、应用场景 3.1. 存储常用数据 3.2. 实现内部辅助函数 四、注…...
集合框架(1)
集合框架(1) 1、数组的特点与弊端 (1)特点: 数组初始化以后,长度就确定了。数组中的添加的元素是依次紧密排列的,有序的,可以重复的。数组声明的类型,就决定了进行元素初…...
Java 基础之泛型:类型安全的保障与灵活运用
在 Java 编程的世界里,泛型是一个至关重要且非常实用的特性。它在 Java 5 中被引入,从根本上改变了我们处理数据类型的方式,提供了更强的类型安全保障,同时也增加了代码的复用性和可读性。 一、什么是泛型 泛型(Gener…...

开发者如何使用GCC提升开发效率Opencv操作
看此篇前请先阅读 https://blog.csdn.net/qq_20330595/article/details/144134160?spm=1001.2014.3001.5502 https://blog.csdn.net/qq_20330595/article/details/144134160?spm=1001.2014.3001.5502 https://blog.csdn.net/qq_20330595/article/details/144216351?spm=1001…...

矩阵加法
矩阵加法 C语言代码C 语言代码Java语言代码Python语言代码 💐The Begin💐点点关注,收藏不迷路💐 输入两个n行m列的矩阵A和B,输出它们的和AB。 输入 第一行包含两个整数n和m,表示矩阵的行数和列数。1 <…...

yarn : 无法加载文件 E:\node\node_global\yarn.ps1,因为在此系统上禁止运行脚本
先确保安装了yarn —— npm install -g yarn 终端输入set-ExecutionPolicy RemoteSigned 若要在本地计算机上运行您编写的未签名脚本和来自其他用户的签名脚本,请使用以下命令将计算机上的执行策略更改为RemoteSigned 再去使用yarn okk~...

详解C++类与对象(四)
文章目录 1.类型转换1.1 前言1.2 类型转换的性质 2.static成员2.1 前言2.2 static的基本概念 3.友元4.内部类5.匿名对象 1.类型转换 1.1 前言 在C中,由于程序员可以自己显示定义一个新的类。这样就会出现一个问题:程序员自己显示定义的类类型与编译器中…...
Pandas处理和分析嵌套JSON数据:从字符串到结构化DataFrame
在数据分析领域,我们经常遇到需要从非结构化数据中提取有用信息的场景。特别是当数据以JSON字符串的形式出现时,如何有效地将其转换为结构化的表格形式,以便进行进一步的分析和处理,成为了一个常见的挑战。本文将通过一个具体的例…...

【强化学习入门笔记】1.5 贝尔曼最优公式
本系列为学习赵世钰老师的《强化学习的数学原理》所作的学习笔记. 课程视频网址:https://space.bilibili.com/2044042934 1.5.1 定义 1.5.1.1 Contraction mapping theorem (收缩映射定理) fixed point(不动点) 如果 x ∗ x^* x∗满足下式, x ∗ x^* x∗称之为…...
编码问题技术探讨:IDE全局GBK与项目UTF-8引发的中文乱码
在软件开发过程中,编码问题一直是开发者们需要面对和解决的难题之一。尤其是在使用IDE(集成开发环境)时,如果全局编码设置与项目编码设置不一致,往往会导致中文乱码的问题。本文将深入探讨这一问题的背景、示例以及解决…...

SpringBoot两天
SpringBoot讲义 什么是SpringBoot? Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式…...

自动化立体仓库项目任务调度系统中任务流程可视化实现
在运维自动化平台中,任务系统无疑是最核心的组成部分之一。它承担着所有打包编译、项目上线、日常维护等运维任务的执行。通过任务系统,我们能够灵活地构建满足不同需求的自定义任务流。早期的任务流后端采用了类似列表的存储结构,根据任务流内子任务的排序依次执行,尽管通…...

计算机毕业设计hadoop+spark民宿推荐系统 民宿数据分析可视化大屏 民宿爬虫 民宿大数据 知识图谱 机器学习 大数据毕业设计
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
Java中OGNL表达式语言的使用
文章目录 OGNL 介绍OGNL 使用场景- ognl- 主要功能- 注意事项- Ognl类的主要方法- 设置值- 获取值- 使用示例 - MybatisJava原生表达式的使用 - Fastjson- JSONPath类的主要方法- 主要功能- JSONPath的优势- 使用示例 Spring不选择OGNL的原因 OGNL 介绍 OGNL(Objec…...

[HCTF 2018]WarmUp-滑稽
启动场景打开链接,出现一下图片 F12查看代码出现一个注释,应该在这个文件中, 进入到该页面,出现一段代码 <?phphighlight_file(__FILE__);class emmm{public static function checkFile(&$page){$whitelist ["sourc…...

Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...