文章目录:
由于文章较长,↑↑↑点击目录快速移动到想看的部分↑↑↑(好像只有电脑版csdn才能快速定位)
1 前言
- 1 前言
- 2 棋类合集
- 2.1 围棋
- 2.2 四子棋
- 2.3 走四棋
- 2.4 五子棋(含禁手)
- 2.5 围五子棋
- 2.6 六子棋
- 2.7 九子棋
- 2.8黑白棋
- 3 后记
用一个框架写了不少棋类小游戏(其中包含一个我自创的四子棋小游戏),初学者可以学习体会一下各个程序之间相似的结构和其中的不同,写了新的棋类游戏的话我也会在这里收录。
2 棋类合集 2.1 围棋简介: 游戏支持键盘下棋和鼠标下棋两种下棋方式
键盘下棋:
- ↑↓←→键移动棋子
- 空格键(space)下棋
- Backspace键悔棋
- 'r’键重新开始
鼠标下棋:
- 左键下棋
- 右键悔棋
- 左右键同时按下重新开始
围棋吃子的判定较为复杂,故需要三个m文件组成完整函数,目前还没写判定胜负和禁手模块,有待更新。
游戏效果:
完整代码: m文件1: go.m | (围棋程序的主体)
function go
axis equal
axis([-10,10,-10,10])
set(gca,'xtick',[],'ytick',[],'xcolor','w','ycolor','w')
set(gca,'color',[0.8392,0.7216,0.3804])
hold on
%按键函数初始化设置:
set(gcf,'KeyPressFcn',@key,'tag','keyset')
set(gcf,'WindowButtonDownFcn',@buttondown)
%全局变量:
global winner;
global turn;
global checher_board
global black;
global white;
global postion;
global plotblack;
global plotwhite;
global plotpostion;
global bout;
global warehouse;
init()
function init(~,~)
%初始化前清除原有图像:
delete(findobj('tag','piece'));
delete(findobj('tag','redcross'));
delete(findobj('type','line'));
delete(findobj('type','patch'));
%棋盘绘制:
x1=[-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3,-3,-2,-2,-1,-1,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9];
y1=[-9,9,9,-9,-9,9,9,-9,-9,9,9,-9,-9,9,9,-9,-9,9,9,-9,-9,9,9,-9,-9,9,9,-9,-9,9,9,-9,-9,9,9,-9,-9,9];
x2=[-9,9,9,-9,-9];y2=[9,9,-9,-9,9];x3=[-9.2,9.2,9.2,-9.2,-9.2];y3=[9.2,9.2,-9.2,-9.2,9.2];
x4=[-6,-6,-6,0,0,0,6,6,6];y4=[6,0,-6,6,0,-6,6,0,-6];
plot(x1,y1,'k'),plot(y1,x1,'k')
plot(x2,y2,'k','LineWidth',2)
plot(x3,y3,'k'),scatter(gca,x4,y4,30,'k','filled')
%棋子棋盘数值初始化:
winner=0;postion=[0 0];turn=1;
black=[20,20 0];white=[-20,-20 0];
black(1,:)=[];white(1,:)=[];
checher_board=zeros(19,19);
bout=1;
warehouse{bout,1}=checher_board;
warehouse{bout,2}=turn;
warehouse{bout,3}=black;
warehouse{bout,4}=white;
%绘制函数初始化:
plotblack=scatter(gca,black(:,1),black(:,2),150,'k','filled','tag','piece');
plotwhite=scatter(gca,white(:,1),white(:,2),150,'w','filled','tag','piece');
plotpostion=scatter(gca,postion(1,1),postion(1,2),150,'rx','tag','redcross');
end
function key(~,event)
%按键函数
switch event.Key
case 'uparrow',postion=postion+[0,1];
case 'downarrow',postion=postion+[0,-1];
case 'leftarrow',postion=postion+[-1,0];
case 'rightarrow',postion=postion+[1,0];
case 'space',set_piece();
case 'backspace',undo();
case 'r',init();
end
postion(postion>9)=-9;
postion(postion9)
endpoint=pos+dir.*i;break;
end
if map(temp_pos(1)+10,temp_pos(2)+10)==-1
endpoint=pos+dir.*i;break;
end
endpoint=pos+dir.*i;
end
end
end
m文件4: double_four.m |(判断是否四四)
function boolean=double_four(mat,map,pos)
boolean=0;
temp_list_1=get_connection_area2(mat,pos,1);
temp_list_2=get_connection_area2(mat,pos,2);
temp_list_3=get_connection_area2(mat,pos,3);
temp_list_4=get_connection_area2(mat,pos,4);
temp_list_1_endpoint=[temp_list_1;temp_list_1+ones(size(temp_list_1,1),1)*[0 1];...
temp_list_1+ones(size(temp_list_1,1),1)*[0 -1]];
temp_list_2_endpoint=[temp_list_2;temp_list_2+ones(size(temp_list_2,1),1)*[1 0];...
temp_list_2+ones(size(temp_list_2,1),1)*[-1 0]];
temp_list_3_endpoint=[temp_list_3;temp_list_3+ones(size(temp_list_3,1),1)*[1 1];...
temp_list_3+ones(size(temp_list_3,1),1)*[-1 -1]];
temp_list_4_endpoint=[temp_list_4;temp_list_4+ones(size(temp_list_4,1),1)*[1 -1];...
temp_list_4+ones(size(temp_list_4,1),1)*[-1 1]];
temp_list_1_endpoint=unique(temp_list_1_endpoint,'rows');
temp_list_2_endpoint=unique(temp_list_2_endpoint,'rows');
temp_list_3_endpoint=unique(temp_list_3_endpoint,'rows');
temp_list_4_endpoint=unique(temp_list_4_endpoint,'rows');
[~,d1,~]=intersect(temp_list_1_endpoint,temp_list_1,'rows');
[~,d2,~]=intersect(temp_list_2_endpoint,temp_list_2,'rows');
[~,d3,~]=intersect(temp_list_3_endpoint,temp_list_3,'rows');
[~,d4,~]=intersect(temp_list_4_endpoint,temp_list_4,'rows');
temp_list_1_endpoint(d1,:)=[];
temp_list_2_endpoint(d2,:)=[];
temp_list_3_endpoint(d3,:)=[];
temp_list_4_endpoint(d4,:)=[];
temp_list_1_endpoint(abs(temp_list_1_endpoint(:,1))>9,:)=[];
temp_list_1_endpoint(abs(temp_list_1_endpoint(:,2))>9,:)=[];
temp_list_2_endpoint(abs(temp_list_2_endpoint(:,1))>9,:)=[];
temp_list_2_endpoint(abs(temp_list_2_endpoint(:,2))>9,:)=[];
temp_list_3_endpoint(abs(temp_list_3_endpoint(:,1))>9,:)=[];
temp_list_3_endpoint(abs(temp_list_3_endpoint(:,2))>9,:)=[];
temp_list_4_endpoint(abs(temp_list_4_endpoint(:,1))>9,:)=[];
temp_list_4_endpoint(abs(temp_list_4_endpoint(:,2))>9,:)=[];
boolean1=0;boolean2=0;boolean3=0;boolean4=0;
if sum(map(temp_list_1_endpoint(:,1)+10+(temp_list_1_endpoint(:,2)+9).*19)==0)==2&&size(temp_list_1,1)==4
boolean1=1;
end
if sum(map(temp_list_2_endpoint(:,1)+10+(temp_list_2_endpoint(:,2)+9).*19)==0)==2&&size(temp_list_2,1)==4
boolean2=1;
end
if sum(map(temp_list_3_endpoint(:,1)+10+(temp_list_3_endpoint(:,2)+9).*19)==0)==2&&size(temp_list_3,1)==4
boolean3=1;
end
if sum(map(temp_list_4_endpoint(:,1)+10+(temp_list_4_endpoint(:,2)+9).*19)==0)==2&&size(temp_list_4,1)==4
boolean4=1;
end
if boolean1+boolean2+boolean3+boolean4>=2
boolean=1;
end
end
m文件5: long_connect.m |(判断是否长联)
function boolean=long_connect(mat,pos)
boolean=0;
if size(get_connection_area2(mat,pos,1),1)>=6||...
size(get_connection_area2(mat,pos,2),1)>=6||...
size(get_connection_area2(mat,pos,3),1)>=6||...
size(get_connection_area2(mat,pos,3),1)>=6
boolean=1;
end
end
2.5 围五子棋
简介: 围棋和五子棋的结合,被围住的棋子会改变颜色,连成五子胜利。
游戏支持键盘下棋和鼠标下棋两种下棋方式
键盘下棋:
- ↑↓←→键移动棋子
- 空格键(space)下棋
- Backspace键悔棋
- 'r’键重新开始
鼠标下棋:
- 左键下棋
- 右键悔棋
- 左右键同时按下重新开始
函数分为三个m文件
游戏效果: 完整代码: m文件1: wei_fiveinrows.m | (围五子棋程序的主体)
function wei_fiveinrows
%图形界面初始化:
axis equal
axis([-10,10,-10,10])
set(gca,'xtick',[],'ytick',[],'xcolor','w','ycolor','w')
set(gca,'color',[0.8392,0.7216,0.3804])
hold on
%按键函数初始化设置:
set(gcf,'KeyPressFcn',@key,'tag','keyset')
set(gcf,'WindowButtonDownFcn',@buttondown)
%全局变量:
global winner;
global turn;
global checher_board
global black;
global white;
global postion;
global plotblack;
global plotwhite;
global plotpostion;
global bout;
global warehouse;
init()
function init(~,~)
%初始化前清除原有图像:
delete(findobj('tag','piece'));
delete(findobj('tag','redcross'));
delete(findobj('type','line'));
delete(findobj('type','patch'));
%棋盘绘制:
x1=[-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3,-3,-2,-2,-1,-1,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9];
y1=[-9,9,9,-9,-9,9,9,-9,-9,9,9,-9,-9,9,9,-9,-9,9,9,-9,-9,9,9,-9,-9,9,9,-9,-9,9,9,-9,-9,9,9,-9,-9,9];
x2=[-9,9,9,-9,-9];y2=[9,9,-9,-9,9];x3=[-9.2,9.2,9.2,-9.2,-9.2];y3=[9.2,9.2,-9.2,-9.2,9.2];
x4=[-6,-6,-6,0,0,0,6,6,6];y4=[6,0,-6,6,0,-6,6,0,-6];
plot(x1,y1,'k'),plot(y1,x1,'k')
plot(x2,y2,'k','LineWidth',2)
plot(x3,y3,'k'),scatter(gca,x4,y4,30,'k','filled')
%棋子棋盘数值初始化:
winner=0;postion=[0 0];turn=1;
black=[20,20 0];white=[-20,-20 0];
black(1,:)=[];white(1,:)=[];
checher_board=zeros(19,19);
bout=1;
warehouse{bout,1}=checher_board;
warehouse{bout,2}=turn;
warehouse{bout,3}=black;
warehouse{bout,4}=white;
%绘制函数初始化:
plotblack=scatter(gca,black(:,1),black(:,2),150,'k','filled','tag','piece');
plotwhite=scatter(gca,white(:,1),white(:,2),150,'w','filled','tag','piece');
plotpostion=scatter(gca,postion(1,1),postion(1,2),150,'rx','tag','redcross');
end
function key(~,event)
%按键函数
switch event.Key
case 'uparrow',postion=postion+[0,1];
case 'downarrow',postion=postion+[0,-1];
case 'leftarrow',postion=postion+[-1,0];
case 'rightarrow',postion=postion+[1,0];
case 'space',set_piece();
case 'backspace',undo();
case 'r',init();
end
postion(postion>9)=-9;
postion(postion0)*(5:7)+(postion(2)0)*(5:7)+(postion(1)0)*(5:7)+(red(i,2)0)*(5:7)+(red(i,1)3
rows_search1=pos_appropriated(pos_appropriated(:,2)==postion(2),1);
rows_search1=rows_search1(abs(rows_search1-postion(1))==min(abs(rows_search1-postion(1))));
cols_search1=pos_appropriated(pos_appropriated(:,1)==postion(1),2);
cols_search1=cols_search1(abs(cols_search1-postion(2))==min(abs(cols_search1-postion(2))));
rows_search2=pos_avilable(pos_avilable(:,2)==postion(2),1);
rows_search2(rows_search2==postion(1))=[];
rows_search2=rows_search2(abs(rows_search2-postion(1))==min(abs(rows_search2-postion(1))));
cols_search2=pos_avilable(pos_avilable(:,1)==postion(1),2);
cols_search2(cols_search2==postion(2))=[];
cols_search2=cols_search2(abs(cols_search2-postion(2))==min(abs(cols_search2-postion(2))));
pos_arrivable1=[[rows_search1,postion(2).*ones(length(rows_search1),1)];...
[postion(1).*ones(length(cols_search1),1),cols_search1]];
pos_arrivable2=[[rows_search2,postion(2).*ones(length(rows_search2),1)];...
[postion(1).*ones(length(cols_search2),1),cols_search2]];
pos_arrivable=intersect(pos_arrivable1,pos_arrivable2,'rows');
elseif size(blue,1)==3
pos_arrivable=pos_appropriated;
end
nowaplace=postion;
case checher_board(postion(1)+4,postion(2)+4)==1
pos_arrivable(:,:)=[];
nowaplace(:,:)=[];
case ~isempty(intersect(postion,pos_arrivable,'rows'))
checher_board(nowaplace(1)+4,nowaplace(2)+4)=0;
blue(sum(abs(blue-nowaplace),2)==0,:)=[];
blue=[blue;postion];
checher_board(postion(1)+4,postion(2)+4)=-1;
all_piece=[red;blue];
pos_appropriated(sum(abs(pos_appropriated-postion),2)==0,:)=[];
pos_appropriated=[pos_appropriated;nowaplace];
pos_arrivable(:,:)=[];
if (sum(checher_board(postion(1)+4,:))*(postion(1)~=0)...
+sum(checher_board(postion(1)+4,(postion(1)~=0)*[1 1 1]+(postion(1)==0)*((postion(2)>0)*(5:7)+(postion(2)0)*(5:7)+(postion(1)0)*(5:7)+(red(i,2)0)*(5:7)+(red(i,1)白棋]一直找,
% 直到找到紧挨着白棋的空白,该空白是一个黑棋可下子处,所有可下子处的集合
% 就是我们要找的outcome
% ---------------------------------------------------------------
% 但是为了方便代码编写,我们对流程稍加改进(以黑子为例):
% [1] 找到每一个黑子的位置
% [2] j=1:8分八个方向找到该棋子该方向上所有位置的情况
% 例如某黑色棋子(星号)左右情况为:○*○○囗●○○
% 则其右侧方向棋子情况为:○○囗●○○
% [3] 判断某方向棋子第一个是白子,上面例子第一个就是白子
% [4] 如果某防线棋子第一个是白子,删除该方向所有白子
% 上面的例子删除后长这样:囗●
% [5] 如果删除后,第一个位置为空,则该位置为可行位置,上例第一个就是囗,
% 所以是可行位置
% [6] 找到所有可行位置,并删除重复项
% 输出集合初始化
outcome=[0 0];
outcome(1,:)=[];
switch t
case 1,t=1;
case 0,t=-1;
end
% 首先找到棋盘中(黑/白)子位置
[x,y]=find(board==t);
collection=[x,y];
% 上下左右八个方向
dir=[1 0;-1 0;0 1;0 -1;1 1;-1 -1;1 -1;-1 1];
if ~isempty(collection) % 如果棋盘上有棋子(这句话其实有没有都一样)
for i=1:size(collection,1)% 遍历某颜色全部棋子
for j=1:8% 分别搜索八个方向
% 找到某方向全部棋子,由于棋盘每个方向都最多有八个棋子,所以,以
% 要检测棋子为中心,向某方向取七个位置就能取到全部位置,超出棋盘
% 的删掉即可
temp_set=collection(i,:)+((1:7)')*dir(j,:);
temp_set(temp_set(:,1)>8|temp_set(:,1)8|temp_set(:,2)size(black,2))||isempty(black)
winner=-1;
case (all(all(abs(checher_board)))&&size(white,1)==size(black,2))
winner=3;
end
%弹出窗口
if winner~=0
redraw()
switch winner
case 1
buttonName1=questdlg('黑棋胜利','black win','关闭','重新开始','关闭');
if isempty(buttonName1),buttonName1='end';end
if strcmp(buttonName1,'重新开始'),init();
elseif strcmp(buttonName1,'关闭'),close;
end
case -1
buttonName1=questdlg('白棋胜利','white win','关闭','重新开始','关闭');
if isempty(buttonName1),buttonName1='end';end
if strcmp(buttonName1,'重新开始'),init();
elseif strcmp(buttonName1,'关闭'),close;
end
case 3
buttonName1=questdlg('平局','tie','关闭','重新开始','关闭');
if isempty(buttonName1),buttonName1='end';end
if strcmp(buttonName1,'重新开始'),init();
elseif strcmp(buttonName1,'关闭'),close;
end
end
end
end
end
3 后记
能看到这里也是辛苦了,毕竟这么长一个文章,大家可以将文中的代码复制下来运行一下,看看其中相似的结构部分,和为了迎合不同功能做出的改变。
欢迎大家指出程序中的问题,之后可能会尝试写一些国际象棋,跳棋之类的棋类游戏,敬请期待。