基于UDP协议的中国象棋游戏

  • 1、效果图
  • 2、项目阐述
  • 3、项目知识点
  • 4、部分界面实现
    • 4.1、背景界面面板
    • 4.2、输入客户端信息界面面板
    • 4.3、主界面
  • 5、功能实现
    • 5.1、界面切换
    • 5.2、音效实现
    • 5.3、联网功能实现(UDP协议)
    • 5.4、期盘功能实现
      • 5.4.1、棋盘以及棋子的绘画
      • 5.4.2、下棋
      • 5.4.3、悔棋
      • 5.4.4、认输
  • 6、总结

1、效果图

2、项目阐述

ps:由于代码量较多,就不放上完整代码及素材等资源啦~若有需要可到主页下载哦!
以下代码均为主要实现代码o( ̄▽ ̄)ブ

  • 本项目基于UDP协议,实现一个GUI界面的象棋游戏。要求实现玩家对战玩家、悔棋、认输、退出等功能,以及实现多个界面,如初始界面、游戏规则界面、开发团队界面、输入信息界面、游戏界面等界面之间的切换,并且实现点击时触发音效。
  • 开发软件:IDEA

3、项目知识点

  • UDP协议:用于实现玩家与玩家之间的联网操作协议。
  • 多线程:实现玩家与玩家之间的 " 即时通讯 "。
  • I/O流:实现点击音效
  • GUI:实现界面

4、部分界面实现

4.1、背景界面面板

项目中的大部分界面面板都是继承于“背景界面”类,实现背景渲染的功能。

package ChineseChess;import javax.swing.*;
import java.awt.*;
import java.net.URL;/*** 背景图片面板* @author TT* @create 2020-06-10-1:17*/
public class JPanel_Background extends JPanel{//标识符private static final long serialVersionUID = 1L;//图片对象Image image;//构造器public JPanel_Background() {setOpaque(false);//设置透明色!必须设置,否则显示不出背景!URL url = JFrame_Start.class.getResource("../static/StartBackground.jpg");image=new ImageIcon(url).getImage();}//重写paint函数,将背景图片绘画上去@Overridepublic void paint(Graphics g) {//具体参数信息//drawImage(图片对象,起始点X坐标,起始点Y坐标,宽度,高度,绘画在哪个面板上)g.drawImage(image,0,0,image.getWidth(this),image.getHeight(this),this);super.paint(g);}
}

4.2、输入客户端信息界面面板

获取IP地址及端口号,组件包括JLabel、JTextField、JButton

package ChineseChess;import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;/*** 客户端信息输入界面* @author TT* @create 2020-06-10-8:09*/
public class JPanel_input extends JPanel_Background{//标识符private static final long serialVersionUID = 1L;JLabel label_title;//输入客户端信息JLabel label_ip;//IPJLabel label_port;//端口号JTextField field_IP;//输入IPJTextField field_port;//输入IPpublic JPanel_input(){System.out.println("输入界面已运行");//绝对布局setLayout(null);//组件添加label_title = new JLabel("输入客户端信息");label_title.setBounds(290,0,692,200);label_title.setFont(new Font("",1,40));add(label_title);label_ip = new JLabel("请输入IP:");label_ip.setBounds(175,300,200,100);label_ip.setFont(new Font("",1,20));add(label_ip);field_IP = new JTextField();field_IP.setBounds(280,340,300,30);add(field_IP);label_port = new JLabel("请输入对方端口号:");label_port.setBounds(85,400,200,100);label_port.setFont(new Font("",1,20));add(label_port);field_port = new JTextField();field_port.setBounds(280,440,300,30);add(field_port);}}

4.3、主界面

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;/*** 开始界面* @author TT* @create 2020-06-10-1:11*/
public class JFrame_Start extends JFrame implements ActionListener {//标识符private static final long serialVersionUID = 1244L;JPanel_Background panel;//背景面板JButton button_back_help;//"帮助"面板的返回按钮JButton button_start;//开始按钮JButton button_help;//帮助按钮JButton button_exit;//退出按钮JButton button_concern;//确认按钮JButton button_back_team;//"开发团队"面板的返回按钮JButton button_team;//开发团队按钮JLabel label1;//中国象棋//构造器public JFrame_Start(){//调用自定义类(如"JPanel_Background")创建面板对象panel = new JPanel_Background();Data.panel_input = new JPanel_input();Data.panel_help = new JPanel_Help();Data.panel_teamMender = new JPanel_TeamMender();//将面板布局设置为"绝对布局"panel.setLayout(null);//创建组件对象button_start = new JButton("开始");button_help = new JButton("帮助");button_exit = new JButton("退出");button_team = new JButton("开发团队");label1 = new JLabel("中国象棋");//将组件添加到面板上label1.setBounds(320,0,692,200);label1.setFont(new Font("",1,60));panel.add(label1);button_start.setBounds(380,250,100,50);panel.add(button_start);button_help.setBounds(380,350,100,50);panel.add(button_help);button_team.setBounds(380,450,100,50);panel.add(button_team);button_exit.setBounds(380,550,100,50);panel.add(button_exit);//将面板添加到容器上Container container = getContentPane();container.add(panel);//窗口相关属性设置setTitle("中国象棋");setResizable(false);setVisible(true);setSize(880,820);this.addWindowListener(new WindowAdapter() {//绑定关闭窗口事件@Overridepublic void windowClosing(WindowEvent e) {if (!Data.isStart){System.exit(0);}else {Data.panel_game.send("quit|");//若一方退出游戏窗口,则游戏结束System.exit(0);}}});//为主面板的button组件添加监听事件button_start.addActionListener(this);button_help.addActionListener(this);button_exit.addActionListener(this);button_team.addActionListener(this);//为“帮助”面板添加按钮button_back_help = new JButton("返回");button_back_help.setBounds(700,650,100,50);Data.panel_help.add(button_back_help);button_back_help.addActionListener(this);//为“客户端信息输入”面板添加按钮button_concern = new JButton("确定");button_concern.setBounds(700,650,100,50);Data.panel_input.add(button_concern);button_concern.addActionListener(this);//为“开发团队”面板添加按钮button_back_team = new JButton("返回");button_back_team.setBounds(700,650,100,50);Data.panel_teamMender.add(button_back_team);button_back_team.addActionListener(this);}//监听事件请看“功能实现”部分......

5、功能实现

5.1、界面切换

  • 思想:“一个窗口,多个面板”
  • 实现方法:将各个面板类对象创建为全局常量,在窗口类绑定“切换面板”事件
 ......
//按钮监听事件@Overridepublic void actionPerformed(ActionEvent e) {Object source = e.getSource();if (button_start.equals(source)){//开始按钮,进入客户端信息输入界面Sound.click();//添加音效changeContentPanel(Data.panel_input);//切换界面}//其他面板切换......}//界面切换public void changeContentPanel(Container contentPanel){this.setContentPane(contentPanel);//就所需的面板放置进去this.revalidate();//重新计算组件的大小,并自动布局}

5.2、音效实现

  • 利用I/O流将音效文件导入
  • 以启动线程的方式实现音效效果

MusicPlayer类:

package ChineseChess;import javax.sound.sampled.*;
import java.io.File;
import java.io.FileNotFoundException;/*** @author D、* @create 2020-06-02-17:01*/
public class MusicPlayer implements Runnable{File soundFile;//音乐文件Thread thread;//父线程boolean circulate;//是否循环播放public MusicPlayer(String filepath, boolean circulate) throws FileNotFoundException {this.circulate = circulate;soundFile = new File(filepath);if(!soundFile.exists()){throw new FileNotFoundException(filepath + "未找到");}}/*** 播放*/public void play(){thread = new Thread(this);//创建线程对象thread.start();}/*** 停止播放*/public void stop(){thread.stop();//强制关闭线程}@Overridepublic void run() {byte[] auBuffer = new byte[1024 * 128];//创建128k的缓冲区do{AudioInputStream audioInputStream = null;SourceDataLine auline = null;try {//从音乐文件中获取音频输入流audioInputStream = AudioSystem.getAudioInputStream(soundFile);AudioFormat format = audioInputStream.getFormat();//获取音频格式//按照源数据行类型和指定音频格式创建数据行对象DataLine.Info info = new DataLine.Info(SourceDataLine.class,format);//利用音频系统类获得与指定Line.Info 对象中的描述匹配的行,并转换为源数据行对象auline = (SourceDataLine) AudioSystem.getLine(info);auline.open(format);//按照指定格式打开源数据行auline.start();//源数据开启读写活动int byteCount = 0;//记录音频输入流读出的字节数while (byteCount != -1){byteCount = audioInputStream.read(auBuffer,0,auBuffer.length);if (byteCount >= 0){auline.write(auBuffer,0,byteCount);//这里涉及到了IO流的知识}}} catch (Exception e) {e.printStackTrace();}finally {auline.drain();//清空数据行auline.close();//关闭数据行}}while (circulate);//判断是否循环播放}
}

Sound类:

package ChineseChess;import java.io.FileNotFoundException;/*** 音效工具类* @author D、* @create 2020-06-02-17:32*/
public class Sound {//播放声音private static void play(String file,boolean circulate){MusicPlayer player = null;//创建播放器try {player = new MusicPlayer(file, circulate);player.play();} catch (FileNotFoundException e) {e.printStackTrace();}}public static void hit(){play("src/music/hit.wav",false);//获取音乐文件}public static void click(){play("src/music/click.wav",false);}public static void refuse(){play("src/music/refuse.wav",false);}}

5.3、联网功能实现(UDP协议)

ps:由于涉及代码较多,就说一下一些关键点(完整代码可到主页下载资源哦)

  • 利用“多线程”的知识,每次执行一个操作便给另一个端口(即对方)发送消息,如请求悔棋,则可发送“ask”的消息到另一个端口
  • 对方端口则对接收到的消息进行判断,并通过具体的功能方法响应接收到的消息
  • 若对于线程的知识不太了解,推荐参考主页“聊天室”文章哦~

5.4、期盘功能实现

5.4.1、棋盘以及棋子的绘画

  • 绘制棋盘,其实就是采用“添加背景”的方式,找到棋盘图,导入并利用绘画函数,进行绘画,即可实现棋盘效果。同理,棋子也是利用该方法进行绘画,确定好每一个棋子的大小,绘画即可。
    (下面附上paint方法代码)
//重写paint函数,将背景图片绘画上去@Overridepublic void paint(Graphics g) {//判断是否轮到本方下棋,以便判定是否切换背景if (!Data.isStart){URL url = JFrame_Start.class.getResource("../static/chessBoard_Test3.jpg");//灰色背景,即未联网状态image=new ImageIcon(url).getImage();}else if (Data.isPlayer){URL url = JFrame_Start.class.getResource("../static/chessBoard_Test1.jpg");//绿色背景image=new ImageIcon(url).getImage();}else{URL url = JFrame_Start.class.getResource("../static/chessBoard_Test2.jpg");//红色背景image=new ImageIcon(url).getImage();}//drawImage(图片对象,起始点X坐标,起始点Y坐标,宽度,高度,绘画在哪个面板上)g.drawImage(image,0,0,image.getWidth(this),image.getHeight(this),this);super.paint(g);for (int i = 0; i < 32; i++) {if (Data.chess[i] != null){Data.chess[i].paint(g,this);}}//绘画选中框if (firstChess != null && firstChess.player == Data.localPlayer){//白色边框g.setColor(Color.WHITE);firstChess.drawSelectedChess(g);g.setColor(Color.BLACK);//只要改变了画笔的颜色,必须改变回来,方便后面使用}if (secondChess != null){g.setColor(Color.WHITE);secondChess.drawSelectedChess(g);g.setColor(Color.BLACK);}}

ps:主要实现如上所示,由于代码稍微复杂,可能一些地方看起来不容易理解,不过只需掌握主要实现思想即可~

5.4.2、下棋

  • 下棋,实际上是对每一次操作进行重新绘画,从而实现下棋效果。
  • 棋子类存储相应的属性以及方法,由于象棋有32个棋子,因此创建一个容量为32的Chess型数组。
  • 棋盘采用的是一个二维数组,即10行9列的一个10*9的数组,对应棋盘上的每一个交点。
  • 当交点处没有棋子时,则其值为-1。(即数组初始化操作)
  • 当交点处由棋子时,则其值为对应的棋子数组的下标。
  • 每一次操作,即更改棋盘上的点对应的值,并且进行重画,从而实现下棋。

Chess类:

import javax.swing.*;
import java.awt.*;/*** 类似于C语言的结构体* 棋子所属玩家,棋子类别,棋子所在行数、棋子所在列数、棋子图案* @author TT* @create 2020-06-10-20:06*/
public class Chess {public int player;//棋子所属玩家public  String type;//棋子类别public int x;//棋子所在列public int y;//棋子所在行public Image chessImage;//棋子图案//空参构造器public Chess(){}//带参构造器public Chess(int player,String type,int x,int y){this.player = player;this.type = type;this.x = x;this.y = y;if (player == Data.RedPlayer){switch (type){case "帅":chessImage = Toolkit.getDefaultToolkit().getImage(Data.chess7RedURL);break;case "仕":chessImage = Toolkit.getDefaultToolkit().getImage(Data.chess8RedURL);break;case "相":chessImage = Toolkit.getDefaultToolkit().getImage(Data.chess9RedURL);break;case "马":chessImage = Toolkit.getDefaultToolkit().getImage(Data.chess10RedURL);break;case "车":chessImage = Toolkit.getDefaultToolkit().getImage(Data.chess11RedURL);break;case "炮":chessImage = Toolkit.getDefaultToolkit().getImage(Data.chess12RedURL);break;case "兵":chessImage = Toolkit.getDefaultToolkit().getImage(Data.chess13RedURL);break;}}else{switch (type){case "将":chessImage = Toolkit.getDefaultToolkit().getImage(Data.chess0BlackURL);break;case "士":chessImage = Toolkit.getDefaultToolkit().getImage(Data.chess1BlackURL);break;case "象":chessImage = Toolkit.getDefaultToolkit().getImage(Data.chess2BlackURL);break;case "马":chessImage = Toolkit.getDefaultToolkit().getImage(Data.chess3BlackURL);break;case "车":chessImage = Toolkit.getDefaultToolkit().getImage(Data.chess4BlackURL);break;case "炮":chessImage = Toolkit.getDefaultToolkit().getImage(Data.chess5BlackURL);break;case "卒":chessImage = Toolkit.getDefaultToolkit().getImage(Data.chess6BlackURL);break;}}}//下棋public void setPos(int x,int y){this.x = x;this.y = y;}//翻转棋子,实现不同端口显示下棋效果public void ReversePos(){x = 9 - x;y = 8 - y;}//绘画棋子public void paint(Graphics g , JPanel i){g.drawImage(chessImage,Data.startX + y*72,Data.startY + x*74,68,68,i);}//绘画选中框public void drawSelectedChess(Graphics g){g.drawRect(Data.startX + y*72,Data.startY + x*74,68,68);}
}

游戏规则(Rule)类:

/*** 游戏规则* @author TT* @create 2020-06-11-22:12*/
public class Rule {Chess chess;//移动的棋子int oldX,oldY;//原先的坐标int newX,newY;//新的坐标String chessName;//棋子的种类public Rule(Chess chess, int newX, int newY){this.chess = chess;this.newX = newX;this.newY = newY;this.chessName = chess.type;}public boolean IsAbleToMove(){oldX = chess.x;oldY = chess.y;//"将" Or "帅"if ("将".equals(chessName) || "帅".equals(chessName)){//"将"吃"帅",判断二者是否同列,且保证二者之间不存在任何棋子if (oldY == newY && (Data.chessBoard[newX][newY]==0 || Data.chessBoard[newX][newY]==16)){for (int i = newX-1; i >oldX ; i--) {if (Data.chessBoard[i][newY] != -1){return false;}}return true;}//斜着走if ((newX-oldX) * (newY-oldY) != 0){return false;}//下棋距离超过一格if (Math.abs(newX-oldX)>1 ||Math.abs(newY-oldY)>1){return false;}//超出九宫格区域if ((newX>2 && newX<7) || newY>5 || newY<3){return false;}return true;}//"士" Or "仕"if ("士".equals(chessName) || "仕".equals(chessName)){//横着走或者竖着走if ((newX - oldX) * (newY - oldY) == 0){return false;}//如果斜走距离超过一格,即判断横向或者纵向的位移量是否大于一if (Math.abs(newX-oldX)>1 ||Math.abs(newY-oldY)>1){return false;}//超出九宫格区域if ((newX>2 && newX<7) || newY>5 || newY<3){return false;}return true;}//"象" Or "相"if ("相".equals(chessName) || "象".equals(chessName)){//横着走或者竖着走if ((newX - oldX) * (newY - oldY) == 0){return false;}//如果不是走"田"字形,即横向或者纵向距离不同时为2if (Math.abs(newX-oldX)!=2 ||Math.abs(newY-oldY)!=2){return false;}//如果象越"楚河-汉界"if (newX<5){return false;}int i=0,j=0;//记录象眼位置if (newX - oldX == 2){ //象向下跳i = oldX+1;}if (newX - oldX == -2){ //象向上跳i = oldX -1;}if (newY - oldY == 2){ //象向右跳j = oldY+1;}if (newY - oldY == -2){ //象向左跳j = oldY-1;}if (Data.chessBoard[i][j] != -1){ //象眼被堵return false;}return true;}//省略其他约束......}

5.4.3、悔棋

  • 悔棋功能有两个要求:请求悔棋、还原上一步操作
  • 请求悔棋:利用线程,发送悔棋请求到对方端口,再接收来自对方端口是否同意的信息
  • 还原:利用ArrayList集合,添加自定义Node泛型,记录棋谱信息。每一次悔棋,即还原集合末尾下标的存储的数据,并进行重画,即可实现悔棋。

Node类:

/*** 存储棋谱信息,实现"悔棋"功能* @author TT* @create 2020-06-11-8:17*/
public class Node {int index;//移动的棋子int x,y;//棋子移动后的坐标int oldX,oldY;//棋子移动前的坐标int eatChessIndex = -1;//被吃掉的棋子,若棋子没有被吃掉,则等于-1public Node(int index, int x, int y, int oldX, int oldY, int eatChessIndex) {this.index = index;this.x = x;this.y = y;this.oldX = oldX;this.oldY = oldY;this.eatChessIndex = eatChessIndex;}@Overridepublic String toString() {return "index:" + index +" x:" + x + " y" + y + " oldX:" + oldX + " oldY:"+oldY + " eatchessindex:" + eatChessIndex;}
}

部分“悔棋”线程代码:

     ......
else if (array[0].equals("agree")){//接收"agree"信息 -->同意悔棋JOptionPane.showMessageDialog(Data.panel_game,"对方同意了你的悔棋请求");Node temp = Data.list.get(Data.list.size()-1);//获取棋谱的最后一步棋Data.list.remove(Data.list.size()-1);//移除最后一步信息if (Data.localPlayer == Data.RedPlayer){//假如我是红方if (temp.index >= 16){//上一步是我下的,退后一步backChess(temp.index,temp.x,temp.y,temp.oldX,temp.oldY);if (temp.eatChessIndex!=-1){//上一步吃子resetChess(temp.eatChessIndex,temp.x,temp.y);//将被吃的棋子放回棋盘}}else{//上一步是对方下的,退后两步backChess(temp.index,temp.x,temp.y,temp.oldX,temp.oldY);if (temp.eatChessIndex!=-1){//上一步吃子resetChess(temp.eatChessIndex,temp.x,temp.y);//将被吃的棋子放回棋盘}temp = Data.list.get(Data.list.size()-1);Data.list.remove(Data.list.size()-1);backChess(temp.index,temp.x,temp.y,temp.oldX,temp.oldY);if (temp.eatChessIndex!=-1){//上一步吃子resetChess(temp.eatChessIndex,temp.x,temp.y);//将被吃的棋子放回棋盘}}}else {//假如我是黑方if (temp.index < 16){//上一步是我下的,退后一步backChess(temp.index,temp.x,temp.y,temp.oldX,temp.oldY);if (temp.eatChessIndex!=-1){//上一步吃子resetChess(temp.eatChessIndex,temp.x,temp.y);//将被吃的棋子放回棋盘}}else{//上一步是对方下的,退后两步backChess(temp.index,temp.x,temp.y,temp.oldX,temp.oldY);if (temp.eatChessIndex!=-1){//上一步吃子resetChess(temp.eatChessIndex,temp.x,temp.y);//将被吃的棋子放回棋盘}temp = Data.list.get(Data.list.size()-1);Data.list.remove(Data.list.size()-1);backChess(temp.index,temp.x,temp.y,temp.oldX,temp.oldY);if (temp.eatChessIndex!=-1){//上一步吃子resetChess(temp.eatChessIndex,temp.x,temp.y);//将被吃的棋子放回棋盘}}}Data.isPlayer = true;repaint();}else if (array[0].equals("refuse")){//接收"refuse"信息 -->不同意悔棋Sound.refuse();JOptionPane.showMessageDialog(Data.panel_game,"对方拒绝了你的悔棋请求");}......

ps:以上部分代码可能很多看不明白,但只需理解主要思想即可,包括一些约束条件等。(完整代码可到主页下载)

5.4.4、认输

  • 认输功能有两个要求:请求认输、退出游戏
  • 请求认输:通过线程,发送认输请求到对方端口,再接收来自对方端口是否同意的信息
  • 退出游戏:实现弹窗弹出并退出游戏

部分“认输”线程代码:

             ......
else if (array[0].equals("lose")){//接收"lose"信息 -->对方认输JOptionPane.showConfirmDialog(Data.panel_game,"对方认输,比赛胜利!","对方认输",JOptionPane.DEFAULT_OPTION);System.exit(0);}else if (array[0].equals("quit")){//接收"quit"信息 -->对方退出游戏JOptionPane.showConfirmDialog(Data.panel_game,"对方退出游戏,比赛结束!","对方退出",JOptionPane.DEFAULT_OPTION);System.exit(0);}......

6、总结

  • 个人觉得该项目的重点在于多线程部分的编写,很多小细节需要注意,耗时占比也是最大的。
  • 项目改进建议:①添加重新开始游戏功能 ②添加聊天室功能。
  • 由于代码量相对较多,就没有放上完整代码及素材等资源,若有需要,可到主页下载。
  • 象棋实现功能参考文章:

https://blog.csdn.net/A1344714150/article/details/85724241

程序小白一枚,发表文章只是为了整理知识~也希望可以和大家一起学习进步!看完的小伙伴可以点赞收藏哦o( ̄▽ ̄)ブ,有问题可在文章底部进行评论探讨哦!

基于UDP协议的中国象棋游戏实现!相关推荐

  1. 基于python的游戏设计与实现-基于Python的网络中国象棋游戏设计与实现

    基于Python的网络中国象棋游戏设计与实现 摘要中国象棋是一种家喻户晓的棋类游戏,随着互联网时代的到来,人们的娱乐方式也逐渐向PC端和移动端上发展.本文将传统的中国象棋游戏和当下的互联网技术结合作为 ...

  2. 基于Java+Swing实现中国象棋游戏

    基于Java+Swing实现中国象棋游戏 一.系统介绍 二.功能展示 三.其他系统 四.获取源码 前言 中国象棋是起源于中国的一种棋,属于二人对抗性游戏的一种,在中国有着悠久的历史.由于用具简单,趣味 ...

  3. java中白盒测试用例_基于JAVA开发的中国象棋游戏的开发与研究白盒测试用例.doc...

    中国象棋白盒测试用例 文件状态当前版本V1.0草稿 作 者梁世聪完成日期2012/6/17文档模板SSP-VER-T13-V1.0密 级变更历史 版本完成日期变更记录作者批准签字V1.02012/6/ ...

  4. HTML5中国象棋游戏(自定义象棋难度)源码下载

    棋类游戏在桌面游戏中已经非常成熟,中国象棋的版本也非常多.今天这款基于HTML5技术的中国象棋游戏非常有特色,我们不仅可以选择中国象棋的游戏难度,而且可以切换棋盘的样式.程序写累了,喝上一杯咖啡,和电 ...

  5. 基于Java的中国象棋游戏的设计与实现

    技术:Java等 摘要: 近些年,Java技术日趋成熟,它的跨平台性,健壮性以及使用人数的增多都表明了它的受欢迎程度不断攀升,因此选用了Java语言作为中国象棋游戏的开发语言.并且中国象棋文化源远流长 ...

  6. 【C++课程设计】期末大作业 - 基于Qt开发的中国象棋软件

    1 题目 基于Qt的中国象棋软件开发 本博客只是简略的描述论文的大致结构.框架,以及软件开发的大致过程.有兴趣的参考原文档资料. 2总体设计与主要功能 2.1概述 中国象棋是起源于中国的一种棋,属于二 ...

  7. Qt终极教程——用Qt编程实现中国象棋游戏(提供源代码和程序编译运行教程)

    Qt终极教程--用Qt编程实现中国象棋游戏 目录 Qt终极教程--用Qt编程实现中国象棋游戏 简介 运行可执行程序体验象棋游戏 Qt 安装 源代码的编译.运行与调试 生成预编译的可执行程序 简介 本文 ...

  8. 基于Java EE的中国象棋网上对战的设计与实现

    技术:Java.JSP等 摘要:中国象棋是一种起源于中国古代的双人对战棋类游戏,广泛的流行在全国各地,是中华文化的典型代表之一,体现着中华文化的智慧和蕴含.为了传承这一重要的传统,理解其中的精髓,以及 ...

  9. C#中国象棋+游戏大厅 服务器 + 客户端源码

    来源:www.ajerp.com/bbs C#中国象棋+游戏大厅 服务器 + 客户端源码 源码开源 C#版中国象棋(附游戏大厅) 基于前人大虾的修改版 主要用委托实现 服务器支持在线人数,大厅桌数的设 ...

最新文章

  1. regression
  2. MySQL软件的介绍
  3. [0] Tornado Todo 开篇
  4. 软件:推荐5款职场人必备的效率神器APP
  5. 使用 C# 和 Blazor 进行全栈开发
  6. 阿里发布《2015-2016中国云栖创新报告》,北上杭深广排名前5
  7. xcode7: Undefined symbols for architecture i386: _iconv_open, referenced from:
  8. Weka算法Classifier-meta-AdaBoostM1源代码分析(一)
  9. linux java bin 安装_linux下安装后缀为bin的Java JDK
  10. 一个支持CGI的极简WebServer
  11. 五款优秀重复文件查找工具
  12. es nested object区别
  13. ubuntu Anaconda安装gi模块 ValueError: Namespace Gtk not available
  14. 巧用快捷键轻松设置Eexel单元格格式(转)
  15. PATA1066题解
  16. 台式机+无线路由 配置 wifi热点
  17. 《模型轻量化-剪枝蒸馏量化系列》YOLOv5无损剪枝(附源码)
  18. HDFS、Ceph文件系统以及Hbase、Cassendra、TiDB比较
  19. 【tomcat】使用jks配置https
  20. LigoWave品牌的产品分类及项目选型

热门文章

  1. 如何写一个精益和敏捷合同
  2. CSS学习(3) - 轮廓文本和字体图标
  3. vscode可以配置开发环境c或java。
  4. RNA 13. SCI 文章中加权基因共表达网络分析之 WGCNA
  5. Java中使用注解校验参数
  6. luogu P4752
  7. 微信小程序获取文件图片的MD5
  8. 图形(graphic、图像image和视频video有什么区别
  9. 【圣诞树】用C语言给女友写一个圣诞树
  10. Ubuntu文件校验MD5