本次项目按照文档中的要求设计了相应的GUI,主菜单的菜单栏中包括两个选项,分别是connect和play,connect下面包括三个选项,分别是create the connection, connect to server以及disconnect from server,而点击第一个选项会弹出一个包含本机IP地址的确认窗口,点击窗口的确认按钮即可创建服务器并开启监听,同时开始显示军棋棋盘,点击第二个选项会弹出IP输入窗口,可点击相应按键输入要连接的IP地址,点击确认键后系统会依据正则表达式确定输入的IP地址是否符合IPV4的基本格式,如果符合,系统会自动创建socket并连接对应IP的服务器,如果不符合,系统会弹出wrong input提示窗口,并将已经输入的IP地址字符串进行清零。另外,play菜单下面包含两个选项,分别是start和admit defeat,当创建好连接之后,第一个点击start按钮的程序端会弹出“The other player has not started"的提示信息框,同时另一侧会弹出“The other player has started"的信息框,提醒该侧的玩家开始游戏,当该侧的玩家点击start按钮之后,另一侧的玩家处会弹出”The game has started"的提示信息框,同时游戏正式开始,并在棋盘上侧的qlabel上面显示相应的游戏信息,包括remaining time, out times for current player, your side 和 current side四项,其中your side在游戏未确定两边玩家信息的时候显示not decided,确定之后分别显示红蓝,current side则显示you和other。在进行游戏的时候,棋盘是在一个大的label上面绘制,而相对应的可以放置棋子的地方都贴上了不可见的label,每次完成一次走子后,这些label会通过绘制相对应的正确图案保证军旗的正确进行,同时,经过逻辑运算,如果点击不合法,会弹出“Please select the lawful place”和“Unlawful selection”的相应提示信息。为方便玩家进行游戏,第一次点击如果选中了一个可动的棋子,在两侧都会用绿色的框将这枚棋子圈出,而在走子侧还会用绿色的框显示出在拓扑关系上可以走到的位置,超时或第二次点击都会使两侧的绿色框消失。当点击admit defeat按钮时,如果总步数没有超过20步,会弹出"The turns have not reached 20"作为警告,如果总步数超过20但没有轮到己方走棋,会弹出”It‘s not your turn now",如果符合正常的认输条件,会在胜者侧弹出“You have won the game"弹窗,负者侧弹出"You have lost the game"弹窗,并且两端停止计时,相应的,如果其他胜负条件触发,也会有同样的反应。在主窗口的右侧有一个浮窗,上面显示了一些基本的军旗规则,一方面可以达到美观的效果,另一方面也是对于不熟悉规则的玩家的提示。
#####网络编程架构
本项目采用服务器和套接字连接的通信方式组织网络架构,并将读取和发送操作都放入单独的线程之中,这样一来可以避免阻塞导致程序运行不畅,二来可以通过高效的收发机制防止粘包现象的发生,方便编码和解码的流程(如果担心在网络时断时续的极端情况下无法运行,也可以加入标准前缀和标准后缀进行编码和解码,但是实际测量在正常网络环境下不存在这个问题,所以就没有加入相应的机制)
每当一端想要发送相应的信息时,其自带的socket会进行相应报文的写入,经过网络通信,另一端负责监听的socket收到并读取相应的报文之后通过信号返回主程序并进行解码工作。当点击”Disconnect from server"的按钮之后,相应的窗口会断开与另一端的连接,同时另一端的窗口会显示“The other side disconnect'的信息框,如果在未建立连接的时候点击Disconnect from server之后再点击IP设置窗口的确认按钮,不会建立连接
本项目采用TCP网络通信协议传输报文,具体的报文字符串(具体实现为char[])的编码和解码规则如下(如果传递的信息为整数数字,则统一在编码的时候将他们的数值加33对应的ascii码为报文)
这里需要明确本项目对于棋盘不同的形态的编码方式,-3表示未翻开,-2表示空兵站,-1表示空行营,0表示蓝军旗,1表示红军旗,2、4、6表示蓝地雷,3、5、7表示红地雷,8、10表示蓝炸弹,9、11表示红炸弹,12、14、16表示蓝工兵,13、15、17表示红工兵,18、20、22表示蓝排长,19、21、23表示红排长,24、26、28表示蓝连长,25、27、29表示红连长,30、32表示蓝营长,31、33表示红营长,34、36表示蓝团长,35、、37表示红团长,38、40表示蓝旅长,39、41表示红旅长,42、44表示蓝师长,43、45表示红师长,46表示蓝军长,47表示红军长,48表示蓝司令,49表示红司令
- 若报文以a开头,则传送本机的IP地址,第二个字符为IP地址的长度,之后各字符为IP地址的各个字符
- 若报文以b开头,代表在两者皆为开始的情况下发送端已经开始
- 若报文以c开头,代表在一段已经开始而另一端未开始的情况下未开的一端开始
- 若报文以d开头,代表这是一则初始化信息,之后的60个数字是60个位置的初始形态,在后面一个数字是服务器随机产生的0或1,决定了哪一方先下棋
- 若报文以1开头且继之以0,则表示在尚未决定两方红蓝的时候翻棋的行为,之后两个数字代表被翻棋子的横竖坐标
- 若报文以1开头且继之以1,则表示这一步决定了两方红蓝,下一个数字代表发报方的颜色(0为蓝而1为红),之后的两个数字代表被翻棋子的横竖坐标
- 若报文以2开头,则表示走棋时的翻棋之后两个数字为被翻开棋子的横竖坐标
- 若报文以3开头,则表示走棋时的选中棋子,之后两个数字为被选中棋子的横竖坐标
- 若报文以4开头,则表示取消选中棋子,之后的两个数字为取消选中的棋子的横竖坐标
- 若报文以5开头,则表示走棋至空地,之后的两个数字为走子的横竖坐标,再之后的两个数字为空地的横竖坐标
- 若报文以6开头,则表示吃子,之后的两个数字为吃子的横竖坐标,再之后的两个数字为被吃子的横竖坐标
- 若报文以l开头,则表示对方输棋
- 若报文以w开头,则表示对方赢棋
- 若报文以z开头,则表示对方断线
本项目的信号与槽设计主要集中在线程之间的通信中,如果主窗口想要发送一个报文,则会发出writesignal,由socket负责发送;如果socket收到报文,则会返回finishreading,由主窗口负责解码;如果主窗口判定负,则发出losesignal,若主窗口判定为胜,则发出winsignal,若主窗口检测到断开,则发出disconnectsignal,这些信号由主窗口中对应的槽函数接收后统一整理成相应的writesignal发送,另外的信号和槽则集中在ui的设计上。