五子棋实习报告_实习报告五子棋
五子棋实习报告由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“实习报告五子棋”。
《JAVA程序设计》
实习报告
实习题目 学生姓名 学生学号 学生姓名 学生学号 学生姓名 学生学号 所在专业 所在班级 指导教师 实习时间
成绩: 老师评语:
五子棋
计算机网络技术
11/6/27—11/7/1
五子棋
下面是五子棋的部分截图:
这里实现了服务器:数据的保存及转发; 联网对战:桌位的选择、悔棋、认输、和棋; 聊天模块:文本聊天、语音聊天; 练习模式:难度的划分、悔棋。
这些功能是如何实现的呢?下面来一步步分解。服务器
1、服务器与客户端是用socket来连接的。连接成功后,客户端会把客户的登陆的信息(用户名、性别、头像)发往服务器。服务器是通过链表来记录每个用户的信息。
cla Node{
String username=null;//用户昵称
String tableNum=null;//桌 号及座位号,格式是:桌号:座位号 int score;//分数 Socket Socket=null;//套接字
ObjectOutputStream output=null;//输出流 ObjectInputStream input=null;//输入流
Node next=null;//保存链表中下一节点的指针 }
2、下面是服务器通过链表记录的客户对像流来转发数据给相应的客户端。代码还是简单明了的。如:
if(type2.equalsIgnoreCase(“重新开局”))
{
}
String isResart=(String)
tobody.output.writeObject(“下棋操作”);tobody.output.flush();
tobody.output.writeObject(“重新开局”);tobody.output.flush();
tobody.output.writeObject(isResart);tobody.output.flush();node.input.readObject();//System.out.println(“isResart:”+isResart);
3、由于这是一个可以有十六个玩家进来的游戏,那么怎样确定哪个玩家与哪个玩家在同一张桌子上下棋呢?我这里用到的链表记录的String tableNum=null;//桌 号及座位号,格式是:桌号:座位号。
如第一张桌第一个坐位与第二个坐位的记录是:0:0;0:1。以此类推。1:0,1:1;2:0,2:1……
服务器的根据桌号与坐位号来转发数据的。用IF语句判断。获得对手的对像流来发送数据。
//获取发送对象
String table=node.tableNum.substring(0, String
String tableNum=null;
if(Integer.parseInt(seat)==0)
tobody=userInfoList.findtable(tableNum);
tableNum=table+“:”+1;tableNum=table+“:”+0;else node.tableNum.indexOf(“:”));seat=node.tableNum.substring(node.tableNum.indexOf(“:”)+1);
客户端
1、棋盘里的棋子是用一个整型二维数组来记录的。GramP[x][y],x代表横的格数,并是具体坐标;y代表竖的格数,并是具体坐标;x*
28、y*28就是具体坐标。0代表没有棋子,1代表白棋,2代表黑棋。
2、判断输赢的方法很简单,每下一个棋子,都要判断一次。在当前棋子的0、45、90、135度方向上判断是否有五个同样的棋子相连。这里用到了y=kx+b函数来计算。要分开黑棋与白棋的判断,定义一个入口参数,增加代码的复用性,输与赢会用到重画方法,所以也定义了Graphics g入口参数。代码如下:
public void isWin(int cheID,Graphics g)
{
//横向判断
for(int k=0;k
} whiteScore=0;
//竖向判断
for(int h=0;h
if(GramP[x][h]==cheID){ {
}
whiteScore=0;++whiteScore;}else
if(GramP[k][y]==cheID){
}else {
}
//如果大于五子连珠,就为赢 if(whiteScore>=5){
} win_tip(cheID,g);break;whiteScore=0;++whiteScore;
}
if(whiteScore>=5){
} win_tip(cheID,g);break;whiteScore=0;//135向判断 int b1;b1=y-x;if(b1>=0){
{
for(int a=-b1,b=0;a
if(GramP[a][b]==cheID){
{ ++whiteScore;for(int a=0,b=b1;b
} whiteScore=0;
if(GramP[a][b]==cheID){
{
}
if(whiteScore>=5){
} win_tip(cheID,g);break;whiteScore=0;++whiteScore;
}else
}else
}else
}
}
}
if(whiteScore>=5){
} win_tip(cheID,g);break;whiteScore=0;whiteScore=0;//45向判断 int b2;b2=x+y;if(b2
{
for(int c=18,d=b2-18;d
if(GramP[c][d]==cheID){ ++whiteScore;for(int c=b2,d=0;c>=0;c--,d++){
} whiteScore=0;if(GramP[c][d]==cheID){
}else {
}
if(whiteScore>=5){
} win_tip(cheID,g);break;
whiteScore=0;++whiteScore;}else
}
}
} }else {
}
if(whiteScore>=5){
} win_tip(cheID,g);break;
whiteScore=0;whiteScore=0;//平局
int count=0;for(int i=0;i
} if(count==180){ } win_tip(3,g);for(int j=0;j
} if(GramP[i][j]==cheID){ } count++;
3、悔棋分为悔一步还是悔两步。由一个布尔变量来判断,如果下完棋再悔棋,只悔一个棋。如果没下棋,就悔两个棋。由一维的字符串数组ReGame[]来记录下棋的先后顺序。格式中: ReGame[R++]=x+“:”+y;下面是悔两个棋子的代码。
public void regretGrame2()
for(int i=0;i
}
} {
} //System.out.println(ReGame[i-1]);//System.out.println(ReGame[i-2]);String X1=ReGame[i-1].substring(0, String String X2=ReGame[i-2].substring(0, String GramP[Integer.parseInt(X1)][Integer.parseInt(Y1)]=0;GramP[Integer.parseInt(X2)][Integer.parseInt(Y2)]=0;ReGame[i-1]=null;ReGame[i-2]=null;R-=2;break;ReGame[i-1].indexOf(“:”));Y1=ReGame[i-1].substring(ReGame[i-1].indexOf(“:”)+1);ReGame[i-2].indexOf(“:”));Y2=ReGame[i-2].substring(ReGame[i-2].indexOf(“:”)+1);repaint();悔一个棋子的,类似。
这只是悔棋函数,只能应用于本用户进行悔棋操,与电脑下棋的悔棋,就直接调用这个函数即可。
但是在联网模式中,通过对像流向服务器发送悔棋标识,再由服务器转发给对手,如果对手同意的吧,对手就会调用悔棋函数,进行自身棋盘的悔棋,同时会向服务器返回一个yes1或yes2标识,发起方收到了,也会调用悔棋函数进行悔棋操作。如果对方不同意,则会返回一个no标识,发起方只会提示玩家,而不进行悔棋操作。
认输及和棋的步骤类似,不再累述。下面是悔棋操作的部分主要代码: 发起请求悔棋:
//请求悔棋
public void isRegretGrame(){
if(R>=2&&!isEnd)//只有两个棋子以上才可以悔棋,否则数组会越界.分胜负时也不能悔棋
{
{ if(flag)//下棋前,悔棋 {
try {
} oos.writeObject(“下棋操作”);oos.flush();oos.writeObject(“悔棋”);oos.flush();oos.writeObject(“isRegret2”);oos.flush();
e.printStackTrace();} catch(IOException e){ }else //下棋后,悔棋 {
} try {
} oos.writeObject(“下棋操作”);oos.flush();oos.writeObject(“悔棋”);oos.flush();oos.writeObject(“isRegret1”);oos.flush();e.printStackTrace();} catch(IOException e){ }else
JOptionPane.showMeageDialog(this, “不能执行悔棋操作”, “警告”, JOptionPane.WARNING_MESSAGE);} } 服务器转发悔棋请求: 这只是服务转发的悔棋部分的数据。
String type=(String)node.input.readObject();//读取信息类型
{
if(type2.equalsIgnoreCase(“悔棋”))
{
String isRegret=(String)if(type.equalsIgnoreCase(“下棋操作”))node.input.readObject();
}
}
tobody.output.writeObject(“下棋操作”);tobody.output.flush();
tobody.output.writeObject(“悔棋”);tobody.output.flush();
tobody.output.writeObject(isRegret);tobody.output.flush();收接悔棋请求:下面代码是在客户端收接数据的线程里的。
String type=(String)ois.readObject();if(type.equalsIgnoreCase(“下棋操作”)){
if(type2.equalsIgnoreCase(“悔棋”))
{){
JOptionPane.showMeageDialog(this, “对方不同意悔棋
String isRegret=(String)ois.readObject();if(”yes2“.equalsIgnoreCase(isRegret)){
} else if(”yes1“.equalsIgnoreCase(isRegret)){
regretGrame1();
regretGrame2();
}else
if(”no1“.equalsIgnoreCase(isRegret)||”no2“.equalsIgnoreCase(isRegret)”, “提示”,JOptionPane.WARNING_MESSAGE);
}
else if(“isRegret2”.equalsIgnoreCase(isRegret)){
int result = JOptionPane.showConfirmDialog(this, “对方请求悔棋,是否同意?”, “提示”, JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE);
if(result == JOptionPane.YES_OPTION){
oos.writeObject(“下棋操作”);oos.flush();
oos.writeObject(“悔棋”);
}
oos.flush();
oos.writeObject(“yes2”);oos.flush();regretGrame2();
}else if(result==JOptionPane.NO_OPTION){
//System.out.println(“对方不同意悔棋”);
oos.writeObject(“下棋操作”);oos.flush();
oos.writeObject(“悔棋”);oos.flush();
oos.writeObject(“no2”);oos.flush();} else if(“isRegret1”.equalsIgnoreCase(isRegret)){
int result = JOptionPane.showConfirmDialog(this, “对方请求悔棋,是否同意?”, “提示”, JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE);
}
if(result == JOptionPane.YES_OPTION){
oos.writeObject(“下棋操作”);oos.flush();
oos.writeObject(“悔棋”);oos.flush();
oos.writeObject(“yes1”);oos.flush();
regretGrame1();
} 聊天模块
1、文字聊天,也是通过服务器转发数据的,客户端就接收与显示。在这里不再详说了。
2、重点是语音聊天,这里的语音连接,首先通过服务器转发发起方的语音标识,对方收到后,如果选择“是”,那它就会通过服务器转发IP地址给发起方,并同时起动serversocket监听。发起方收到对方同意语音连接的标识与IP地址后,就可以与对方连接了,语音链路就建起了。断开的思路也是差不多的。练习模式
1、电脑下棋的算法:
通过遍历棋盘,计算权值,哪个位置的权值最高,就在哪个位置下棋。权值的大小预定为:
//黑白白空 50
//空白白空 100 //黑白白白空 500 //空白白白空 1000 //黑白白白白空 5000 //空白白白白空 10000
//白白白白白 100000 首先假定下棋点,再计算权值之和的大小。
权值之和=0度方向的带胜权值和堵敌的权值之和+45度方向的带胜权值和堵敌的权值之和+90度方向的带胜权值和堵敌的权值之和+135度方向的带胜权值和堵敌的权值之和.下面代码,假定落子点,再把四个方向上的的权值加起来。
//记录当前假定的落子点
private int getQuan(int i,int j)
{
} //水平权值
private int getQuan0(int i, int j){
int samecheNumS=0;//相同棋子的个数 int samecheNumF=0;int blankNumS=0;// 空子的个数 int blankNumF=0;int q=0;//求当前位置的权值
q+=getQuan0(i,j);//得到水平方向上的权值,下面类似 q+=getQuan90(i,j);q+=getQuan135(i,j);q+=getQuan45(i,j);
return q;
下面是只是求水平权值的代码,通过一个二维二元数组来左右求索棋子的个数。
} int q=0,qS=0,qF=0;int [][]ij0=new int[2][2];//计算权值用的 ij0[0][0]=ij0[0][1]=i;ij0[1][0]=ij0[1][1]=j;samecheNumS=getsamecheNum0(ij0,back);//得到黑子数目
if(ij0[0][0]>=0)
//得到速胜权值
ij0[0][0]=ij0[0][1]=i;ij0[1][0]=ij0[1][1]=j;samecheNumF=getsamecheNum0(ij0,white);//得到白子数目
if(ij0[0][0]>=0)
if(curche[ij0[0][0]][ij0[1][0]]==Che)blankNumF++;if(curche[ij0[0][0]][ij0[1][0]]==Che)blankNumS++;if(ij0[0][1]
private int getsamecheNum0(int[][] qij, int cheID){
int num=1;//存储相同棋子数目,当前点满足条件 qij[0][0]--;//向左探索我们只探索临近的4个点,注意不要出边界 while(qij[0][0]>=0&&num
} qij[0][1]++;//向右求索
while(qij[0][1]
} {
}
return num;if(curche[qij[0][1]][qij[1][1]]!=cheID)break;num++;qij[0][1]++;//求得某一方向上的一半权值
private int getQuanpart(int sameCheNum, int blankNum){
} if(sameCheNum==2&&blankNum==1)return q2o;else if(sameCheNum==2&&blankNum==2)return q2;else if(sameCheNum==3&&blankNum==1)return q3o;else if(sameCheNum==3&&blankNum==2)return q3;else if(sameCheNum==4&&blankNum==1)return q4o;else if(sameCheNum==4&&blankNum==2)return q4;else if(sameCheNum==5)return q5;else return 0;
2、划分难度等级
我这里,是通过改变它的预定权值的大小,而达到改变难度的。
3、悔棋,比对战模式(即联网对战)的悔棋还简单。只需用到悔两个棋子的悔棋函数即可。