加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

C#建立一个网络客户服务器端的五子棋游戏(1)

(2008-11-01 15:38:39)
标签:

c

杂谈

分类: C#study

首先建立一个服务器端口。

打开vs2005.net。新建一个工程GobangServer

选择添加一个类 User  该类代表一个基本的用户

添加命名空间

using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.IO;

class User
    {
        public readonly TcpClient client;   //用户的ip地址

        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);
        }
    }

TcpClient:为TCP网络服务提供客户端连接.其GetStream()方法用于返回发送和接收数据的NetworkStream

NetworkStream: 提供用于网络访问的基础数据流。

StreamReader:实现一个 TextReader,使其以一种特定的编码从字节流中读取字符。

StreamReader (Stream, Encoding):用指定的字符编码为指定的流初始化StreamReader 类的一个新实例

StreamWriter:实现一个 TextWriter,使其以一种特定的编码向流中写入字符。

StreamWriter (Stream, Encoding):用指定的编码及默认缓冲区大小,为指定的流初始化StreamWriter 类的新实例

System.Text.Encoding.Default:获取系统的当前 ANSI 代码页的编码。

 

System.Net.Sockets 命名空间为需要严密控制网络访问的开发人员提供了 Windows Sockets (Winsock) 接口的托管实现。

TcpClient、TcpListener 和 UdpClient类封装有关创建到 Internet 的 TCP 和 UDP 连接的详细信息。

 

System.Collections.Generic 命名空间包含定义泛型集合的接口和类,泛型集合允许用户创建强类型集合,它能提供比非泛型强类型集合更好的类型安全性和性能

 

System.Text 命名空间包含表示 ASCII、Unicode、UTF-7 和 UTF-8 字符编码的类;用于将字符块转换为字节块和将字节块转换为字符块的抽象基类;以及操作和格式化 String 对象而不创建 String 的中间实例的 Helper 类。

System.IO 命名空间包含允许读写文件和数据流的类型以及提供基本文件和目录支持的类型。  

 

继续添加一个类 Player 游戏玩家类

 class Player
    {
        private User user;   //声明一个用户为玩家的成员变量
        public User GameUser //属性
        {
            get
            {
                return user;
            }
            set
            {
                user = value;
            }
        }
        //游戏是否已经开始
        private bool start;

        public bool Start
        {
            get
            {
                return start;
            }
            set
            {
                start = value;
            }
        }
        public Player() //初始化,游戏没有玩家和没有开始。
        {
            start = false;
            user = null;
        }
    }

继续添加一个类 GobangBoard 绘制棋盘,棋盘类。

using System;
using System.Collections.Generic;
using System.Text;

 

class GobangBoard
    {
        public const int None = -1; //无棋子
        public const int Black = 0; //黑色棋子
        public const int White = 1;//白色棋子        
        private int[,] grid = new int[15, 15]; //15*15的方格棋盘
        public int[,] Grid  //只读属性,返回一个15*15的方格棋盘
        {
            get
            {
                return grid;
            }
        }
        private int nextIndex;
        public int NextIndex    //属性,设置或返回一个值,指明下一步该到谁走了。
        {
            get
            {
                return nextIndex;
            }
            set
            {
                nextIndex = value;
            }
        }
        public GobangBoard()
        {
            InitializeBoard();  //构造函数初始化。
              
        public void InitializeBoard()   
        {
            for (int i = 0; i <= grid.GetUpperBound(0); i++)
            {
                for (int j = 0; j <= grid.GetUpperBound(1); j++)
                {
                    grid[i, j] = None; //初始化时:将15*15格的坐标都设置为无格子。
                }
            }
            nextIndex = Black;    //并指明下一步由黑方走棋
              
        public bool IsExist(int i, int j)  //判断下棋位置是否有棋子

        {
            if (grid[i, j] != None)
            {
                return true;
            }
            else
            {
                return false;
            }
             
        public bool IsWin(int i, int j) //棋子放下后,是否胜利
        {
            //与方格的第i,j交叉点向四个方向的连子数,依次是水平,垂直,左上右下,左下右上
            int[] numbers = new int[4];
            numbers[0] = GetRowNumber(i, j);  //水平方向
            numbers[1] = GetColumnNumber(i, j); //垂直方向
            numbers[2] = GetBacklashNumber(i, j);//左上右下
            numbers[3] = GetSlashNumber(i, j);   //左下右上
          //检查是否获胜
            for (int k = 0; k < numbers.Length; k++)
            {
                if (Math.Abs(numbers[k]) == 5)  //是否5连
          {
                    return true;
                }
            }
            return false;
              
        private int GetRowNumber(int i, int j)  //水平方向相同颜色棋子的个数
               
            int num = 1;
            int x = i + 1;   //向右检查
            while (x < 15)
            {
                if (grid[x, j] == grid[i, j])//前方棋子与i,j点不同时跳出循环
                {
                    num++;
                    x++;
                }
                else
                {
                    break;
                }
                      
            x = i - 1;//向左检查
            while (x >= 0)
            {
                if (grid[x, j] == grid[i, j])//前方棋子与i,j点不同时跳出循环
                {
                    num++;
                    x--;
                }
                else
                {
                    break;
                }
            }
            return num;
        }
        private int GetColumnNumber(int i, int j)// 判断垂直相同颜色的棋子个数
               
            int num = 1;

            int y = j + 1; //向下检查
            while (y < 15)
            {
                if (grid[i, y] == grid[i, j])//前方的棋子与i,j点不同时跳出循环
                {
                    num++;
                    y++;
                }
                else
                {
                    break;
                }
                      
            y = j - 1;//向上检查
            while (y >= 0)
            {
               if (grid[i, y] == grid[i, j])//前方的棋子与i,j点不同时跳出循环
                {
                    num++;
                    y--;
                }
                else
                {
                    break;
                }
            }
            return num;
        }
        private int GetBacklashNumber(int i, int j)// 判断左上到右下相同颜色的棋子个数
        {
            int num = 1;
            int x = i + 1;//右下方向
            int y = j + 1;
            while (x < 15 && y < 15)
            {
                if (grid[x, y] == grid[i, j])//前方的棋子与i,j点不同时跳出循环
                {
                    num++;
                    x++;
                    y++;
                }
                else
                {
                    break;
                }
                      
            x = i - 1;//左上方向(x-,y-)
            y = j - 1;
            while (x >= 0 && y >= 0)
            {
               if (grid[x, y] == grid[i, j])//前方的棋子与i,j点不同时跳出循环
                {
                    num++;
                    x--;
                    y--;
                }
                else
                {
                    break;
                }
            }
            return num;
              
        private int GetSlashNumber(int i, int j)// 判断左下到右上相同颜色的棋子个数
        {
            int num = 1;
            int x = i - 1;
            int y = j + 1;
            while (x >= 0 && y < 15)
            {
                if (grid[x, y] == grid[i, j])
                {
                    num++;
                    x--;
                    y++;
                }
                else
                {
                    break;
                }
            }
            x = i + 1;
            y = j - 1;
            while (x < 15 && y >= 0)
            {
                if (grid[x, y] == grid[i, j])
                {
                    num++;
                    x++;
                    y--;
                }
                else
                {
                    break;
                }
            }
            return num;
        }
    }

棋盘类:None代表无棋子,Black代表黑棋子,White代表白棋子。

  grid[i,j]代表棋盘是每一个格。如果=-1 代表无棋子,0代表黑棋子,1代表白棋子.我们可以通过这些数字很快就能判断那个格上是什么棋子了。

grid.GetUpperBound(0): 获取 Array 的指定维度的上限。

 

建立一个Service类   用于在房间发送消息或服务器端显示消息。

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.IO;

 

 class Service
    {
        private ListBox listbox;   //表示用于显示项列表的 Windows 控件。       
        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)
        {
      //比较调用AddListBoxItem方法的线程和创建listBox的线程是否同一个线程           

          if (listbox.InvokeRequired == true) //不同线程
            {
                //用委托执行AddListBoxItem方法,
                //listbox.Invoke会导致listbox.InvokeRequired返回false
                //所以委托调用该方法时执行的是else中的内容
                listbox.Invoke(addListBoxItemCallback, str);
            }
            else
            {
                //包含listbox的窗体关闭时会导致listbox.IsDisposed返回true
                if (listbox.IsDisposed == false)
                {
                    listbox.Items.Add(str);  
                    listbox.SelectedIndex = listbox.Items.Count - 1;
                    listbox.ClearSelected();
                }
            }
                          
        public void SendToOne(User user, string str) //将信息发送给指定的客户
        {
            try
            {
                user.sw.WriteLine(str);   //写入数据
                user.sw.Flush();
                //-------此语句仅用于观察发送给客户端的信息,希望观察时可以去掉注释-----//
                //AddListBoxItem(string.Format("向{0}发送{1}", user.userName, str));
                //----------------------------------------------------------------------//
            }
            catch
            {
                AddListBoxItem(string.Format("向{0}发送信息失败", user.userName));
            }
              
        public void SendToRoom(GameRoom gameRoom, string str) // 将信息发送给指定房间的所有人

        {
            //向玩家发送
            for (int i = 0; i < gameRoom.gamePlayer.Length; i++)
            {
                if (gameRoom.gamePlayer[i].GameUser != null)
                {
                    SendToOne(gameRoom.gamePlayer[i].GameUser, str);                 }
            }
            //向旁观者发送
            for (int i = 0; i < gameRoom.lookOnUser.Count; i++)
            {
                SendToOne(gameRoom.lookOnUser[i], str);
            }
        }

   //给所有人发送信息
        public void SendToAll(System.Collections.Generic.List<User> userList, string str)
        {
            for (int i = 0; i < userList.Count; i++)
            {
                SendToOne(userList[i], str);
            }
        }
    }

delegate: 表示委托,委托是一种数据结构.它引用静态方法或引用类实例及该类的实例方法 
bool InvokeRequired(): 获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程以外的线程中。
   返回结果: 如果控件的 System.Windows.Forms.Control.Handle 是在与调用线程不同的线程上创建的(说明您必须通过 Invoke方法对控件进行调用),则为 true;否则为 false。

Invoke:提供对某一对象公开的属性和方法的访问。

ListBox.Invoke: 在拥有此控件的基础窗口句柄的线程上执行委托。
ListBox.IsDisposed:获取一个值,该值指示控件是否已经被释放。

ClearSelected() :取消选择 ListBox 中的所有项。

StreamWriter.WriteLine: 写入重载参数指定的某些数据,后跟行结束符

StreamWriter.Flush: 清理当前编写器的所有缓冲区,并使所有缓冲数据写入基础流。

string.Format:将指定的String中的每个格式项替换为相应对象的值的文本等效项

 

 

继续新建一个新类 GobangServer 游戏房间类。

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.IO;

 class GameRoom
                       
        public List<User> lookOnUser = new List<User>(); // 进入房间的旁观者        
        public Player[] gamePlayer = new Player[2]; // 坐在桌上的黑白两个玩家
        public Player BlackPlayer    // 坐在桌上的黑方玩家
        {
            get
            {
                return gamePlayer[0];
            }
            set
            {
                gamePlayer[0] = value;
            }
        }
        public Player WhitePlayer   // 坐在桌上的白方玩家
        {
            get
            {
                return gamePlayer[1];
            }
            set
            {
                gamePlayer[1] = value;
            }
        }
        private GobangBoard gameBoard = new GobangBoard(); //实例化一个棋盘类。生成一个棋盘
        public GobangBoard GameBoard
        {
            get
            {
                return gameBoard;
            }
             
        private ListBox listbox;  //声明一个listbox

        private Service service;  //声明一个 显示发送信息类        
        public GameRoom(ListBox listbox)  //构造函数,初始化
        {
            this.listbox = listbox;
            gamePlayer[0] = new Player();
            gamePlayer[1] = new Player();
            service = new Service(listbox);  //初始化service类            
            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
            {
                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));
        }
    }

GameRoom 游戏房间

主要的成员变量为:玩家,旁观者。

主要的成员方法为:放置棋子。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有