网络五子棋
1. 课程设计内容
五子棋游戏以其优秀的传统知识跟智慧深受广大玩家的喜爱,编制五子棋程
序因其规则简单而大受编程者的欢迎,然而它却要求程序员对五子棋规则有相当
深入的了解。网络五子棋的主要内容是:根据五子棋的基本规则,要让对方客户
端知道该在哪一点下子,就要根据盘面的形势,并把棋盘棋子的重新绘制,也就
是更新该点的位置,然后再通过监听网络传递的消息,直到新的位置放在棋盘的
什么位置上,在进行修改,并通过计算,判定游戏的获胜方和游戏的结束与否.,因此
玩家就能反复的通过网络进行联机游戏。
2. 课程设计目的
为了更深入地理解 TCP 协议的具体应用编程技巧,本设计使用功能强大的
VS2008 开发工具和 C#开发语言,开发出一个拥有自己特色的五子棋程序,其中
VS2008 是一个能开放代码的开发工具,基本 C#的扩展平台。就该五子棋程序来
讲,它只是一个框架和一组服务,用于通过插件,组件,控件构建开发环境。
对于游戏,要求能够达到以下功能:
(1).服务器可以同时服务多桌,每桌允许两个玩家通过 internet 对弈。
(2)允许玩家自由选择坐在哪里一桌的哪一方。如果两个玩家坐在同一桌,双
方老师应能看到对方的状态。两个玩家均单击开始按钮后,游戏才开始。
(3)游戏开始后,由黑色棋子的玩家先下棋。
(4)每当玩家走完一步棋子后,都检测相当颜色的棋子是否已经相邻的出现达
到五个,即游戏结束。
(5)同一桌的玩家可以聊天。
3. 背景知识
同步工作方式,利用 TCP 编写程序执行到发送,接收或监听语句时,在未完
成工作前是不会往下执行,即处于阻塞状态,这样的 TCP 协议有利于编写五子
棋这样的回合制游戏。采用 Socket 类编程,运用了系统提供相应的方法。逻辑
关系上,都会涉及服务器,客户端这两个概念。
课程设计报告
4. 工具/准备工作
资源方法有棋盘,黑白棋子,还有游戏室的位置头像如下图:
5. 设计步骤与方法
5.1. 服务器端编程
服务器启动后,需要创建一个线程专门用于监听玩家连接请求。在监听线程
中,服务器一旦接受一个连接,就创建一个线程与该玩家对应的线程,用于接收
该玩家发送的信息,并根据玩家发送的信息来提供相应的服务。有多少个玩家就
得创建多少个对应的线程。直到玩家退出游戏室,其对应的线程才终止。
服务器必须限制进入游戏室的玩家数量,具体多少,可以由服务器的启动来
设置。
5.1.1. 服务器具体实现步骤如下:
创建一个命名为 GameServer 的 Windows 应用程序,将 Form1.cs 改名为
FormServer.cs,界面设计如下:
第 2 页 共 42 页
课程设计报告
5.1.1.1. 玩家信息
在资源管理器中,添加 User.cs,用于保存与该玩家的通信所需要的信息。代
码如下:
class User
{
public readonly TcpClient client;
public readonly StreamReader sr;
public readonly StreamWriter sw;
public string userName;
public User(TcpClient client)
{
}
this.client = client;
this.userName = "";
NetworkStream netStream = client.GetStream();
sr = new StreamReader(netStream, System.Text.Encoding.Default);
sw = new StreamWriter(netStream, System.Text.Encoding.Default);
5.1.1.2. 游戏桌位信息
在资源管理器中,添加 Player.cs,用于保存已经坐到游戏桌位上玩家的情况。
代码如下:
class Player
{
private User user;
public User GameUser
{
}
get
{return user; }
set
{user = value; }
public bool Start
{get{return start; }
set{start = value; }
}
第 3 页 共 42 页
课程设计报告
public Player()
start = false;
user = null;
{
}
}
5.1.1.3. 公用的方法
在资源管理器中添加类文件 Service.cs,用于提供公用的方法。代码如下:
class Service
{
private ListBox listbox;
private delegate void AddListBoxItemCallback(string str);
private AddListBoxItemCallback addListBoxItemCallback;
public Service(ListBox listbox)
{
}
this.listbox = listbox;
addListBoxItemCallback = new AddListBoxItemCallback(AddListBoxItem);
public void AddListBoxItem(string str)
{
if (listbox.InvokeRequired == true)
{
}
listbox.Invoke(addListBoxItemCallback, str);
else
{
if (listbox.IsDisposed == false)
listbox.Items.Add(str);
listbox.SelectedIndex = listbox.Items.Count - 1;
listbox.ClearSelected();
{
}
}
}
第 4 页 共 42 页
课程设计报告
5.1.1.4. 玩家房间状态信息
在资源管理器中添加一个类文件 GameRoom.cs,用来保存玩家游戏的顺序分
配及判定输赢。代码如下:
class GameRoom
{
private GobangBoard gameBoard = new GobangBoard();
public GobangBoard GameBoard
{
}
get
{
}
return gameBoard;
///
/// 向listbox中添加显示信息以及向客户发送信息
///
private ListBox listbox;
private Service service;
//构造函数
public GameRoom(ListBox listbox)
{
}
this.listbox = listbox;
gamePlayer[0] = new Player();
gamePlayer[1] = new Player();
service = new Service(listbox);
//将棋盘上的棋子全部清除
gameBoard.InitializeBoard();
public void SetChess(int i, int j, int chessColor)
{
//发送格式:SetChess,行,列,颜色
gameBoard.Grid[i, j] = chessColor;
gameBoard.NextIndex = gameBoard.NextIndex == 0 ? 1 : 0;
service.SendToRoom(this, string.Format("SetChess,{0},{1},{2}", i, j,
chessColor));
if (gameBoard.IsWin(i, j))
{
}
ShowWin(chessColor);
else
{
第 5 页 共 42 页
课程设计报告
service.SendToRoom(this, "NextChess," + gameBoard.NextIndex);
}
}
private void ShowWin(int chessColor)
gamePlayer[0].Start = false;
gamePlayer[1].Start = false;
gameBoard.InitializeBoard();
//发送格式:Win,胜方棋子颜色
service.SendToRoom(this, string.Format("Win,{0}", chessColor));
{
}
}
5.1.1.5. 登录窗体事件
在 FormServer 的代码编辑下,添加对应的控件代码,源程序如下:
public partial class FormServer : Form
{
private int port = 51888;
private TcpListener myListener;
private Service service;
public FormServer()
{
}
InitializeComponent();
listBoxStatus.HorizontalScrollbar = true;
service = new Service(listBoxStatus);
private void FormServer_Load(object sender, EventArgs e)
{
}
listBoxStatus.HorizontalScrollbar = true;
IPAddress[] addrIP = Dns.GetHostAddresses(Dns.GetHostName());
localAddress = addrIP[0];
buttonStop.Enabled = false;
private void buttonStart_Click(object sender, EventArgs e)
{
if (int.TryParse(textBoxMaxTables.Text, out maxRoomNumbers) == false ||
int.TryParse(textBoxMaxUsers.Text, out maxUsers) == false)
{
}
MessageBox.Show("请输入在规定范围内的正整数");
return;
第 6 页 共 42 页
课程设计报告
if (maxUsers < 1 || maxUsers > 500)
{
}
MessageBox.Show("允许进入的人数只能在1-300之间");
return;
if (maxRoomNumbers < 1 || maxRoomNumbers > 100)
{
}
MessageBox.Show("允许开出的房间数只能在1-100之间");
return;
textBoxMaxUsers.Enabled = false;
textBoxMaxTables.Enabled = false;
//初始化数组
gameRoom = new GameRoom[maxRoomNumbers];
for (int i = 0; i < maxRoomNumbers; i++)
{
}
gameRoom[i] = new GameRoom(listBoxStatus);
myListener = new TcpListener(localAddress, port);
myListener.Start();
service.AddListBoxItem(string.Format(
"{0:yyyy年M月d日(dddd)h点m分} 开始在{1}:{2}监听客户连接",
DateTime.Now, localAddress, port));
//创建一个线程监听客户端连接请求
ThreadStart ts = new ThreadStart(ListenClientConnect);
Thread myThread = new Thread(ts);
myThread.Start();
buttonStart.Enabled = false;
buttonStop.Enabled = true;
}
private void buttonStop_Click(object sender, EventArgs e)
{
service.AddListBoxItem(string.Format("目前连接用户数:{0}",
userList.Count));
service.AddListBoxItem(string.Format(
"{0:yyyy年M月d日(dddd)h点m分} 开始停止服务,并依次使用户退出。",
DateTime.Now));
StopCLientAndListener();
buttonStart.Enabled = true;
buttonStop.Enabled = false;
textBoxMaxUsers.Enabled = true;
textBoxMaxTables.Enabled = true;
}
private void StopCLientAndListener()
第 7 页 共 42 页
课程设计报告
{
}
for (int i = 0; i < userList.Count; i++)
{
}
userList[i].client.Close();
myListener.Stop();
private void ListenClientConnect()
{
while (true)
{
TcpClient newClient = null;
try
{
}
newClient = myListener.AcceptTcpClient();
catch
{
}
break;
ParameterizedThreadStart pts = new
ParameterizedThreadStart(ReceiveData);
Thread threadReceive = new Thread(pts);
User user = new User(newClient);
threadReceive.Start(user);
userList.Add(user);
service.AddListBoxItem(string.Format("[{0}]连接服务器成功。",
newClient.Client.RemoteEndPoint));
service.AddListBoxItem(string.Format("当前连接用户数:{0}",
userList.Count));
}
}
private void ReceiveData(object obj)
{
User user = (User)obj;
TcpClient client = user.client;
bool normalExit = false;
bool exitWhile = false;
while (exitWhile == false)
{
string receiveString = null;
try
{
receiveString = user.sr.ReadLine();
第 8 页 共 42 页