使用WPF技术实现基于MSN协议的五子棋程序

一、前言

    WPF(Windows Presentation Foundation)是微软最近推出的一套界面实现技术。该技术实现了界面设计和逻辑代码的分离。在WPF技术中,界面设计由xaml文件来完成。 xaml文件是XML格式的,用于设置用户界面中的各种控件(如文本框、列表框、按钮等)的属性和事件。WPF中的逻辑代码目前可以使用C#或 VB.Net来编写。编写的方式和传统的.net程序类似。在本文采用了WPF作为界面实现技术来完成五子棋程序。

    本文实现的五子棋程序从表面上看只是个普通的联机对战的棋牌类游戏,但实际上,该联机对战游戏并不需要自己编写服务端程序,更不需要为玩游戏而准备24小 时开机的服务器。本游戏的内部通讯协议采用了MSN协议,因此,可以直接使用MSN帐号(一个E-mail地址)进行登录,并在好友之间展开对弈。

    本文提供的五子棋游戏使用了一个开源的MSN协议实现(dotmsn2.0)来进行MSN用户之间的通讯。dotmsn2.0可从如下的网址下载:

    http://www.xihsolutions.net/dotmsn/download.html

    如果读者想了解更多关于MSN协议的内容,可以访问如下的网址:

    http://www.hypothetic.org/docs/msn/index.php

    在本游戏程序中使用了Linq技术来读取XML文件中保存的MSN帐号,并将用户最后一次成功登录的MSN帐号写入XML文件。为了安全起见,本程序并未在XML文件中保存密码,因此,在每次登录游戏时,都必须输入MSN帐号的密码。

 

二、实现原理

 

    使用dotmsn2.0可以非常容易使用MSN帐号进行登录,并和好友进行聊天。然而,在本文提供的程序中使用了一些特殊的信息(信息前面带有特殊前缀) 来传送下棋的命令(玩家棋子走的位置)和控制命令。如果双方使用的都是五子棋程序,下棋命令和控制命令并不会在聊天记录中出现。系统会将这些命令解释成相 应的动作。如当一个玩家走一步棋后,系统就会将该玩家所走的棋子的位置发送给另外一个玩家,而另外一个玩家的五子棋程序会将该命令解释成棋子的位置,并在 棋盘的相应位置放上对方所下的棋子。当这个玩家走棋后,也会采用同样的方式处理。

 

三、使用MSN帐号登录五子棋程序

 

    登录功能是实现五子棋程序的第一个要实现的部分。由于本游戏必须在两个拥有MSN帐号的玩家之间进行对弈,因此,就需要登录功能为本程序提供MSN帐号,并连接到MSN服务器上,以便为开始游戏做准备。

    登录界面的主要部分由两个文本框(MSN帐号输入框和密码输入框)和一个登录按钮组成。首先来设置一下登录界面中控件的位置、大小等信息。这些信息都保存在Login.xaml文件中,代码如下:

<Window x:Class="WpfMSNGame.Login"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="MSN 用户登录" Height="199" ResizeMode="NoResize"  Width="403"

           WindowStartupLocation="CenterScreen"  Icon="images/logo.ico"  

           WindowStyle="SingleBorderWindow"  Loaded="Window_Loaded">

    <Grid>

        <!--  登录按钮的配置代码  -->

        <Button Height="25" HorizontalAlignment="Right" Margin="0,0,21,16"

        Name="btnLogin"  VerticalAlignment="Bottom" Width="61"

        Click="btnLogin_Click">登录</Button>

        <!--  MSN帐号输入框的配置代码  -->

        <TextBox Height="30" Margin="112,21,21,0"  Name="txtAccount" FontSize="15"

        VerticalAlignment="Top" KeyDown="txtAccount_KeyDown"></TextBox>

        <!--  密码输入框的配置代码  -->

        <PasswordBox Margin="112,68,21,67" Name="txtPassword" ClipToBounds="False" 

        FontSize="15"  KeyDown="txtPassword_KeyDown" />

        <!--  其他控件的配置代码  -->

        <Label Height="30" HorizontalAlignment="Left" Margin="20,21,0,0" Name="label1"

        VerticalAlignment="Top" Width="88">电子邮件地址:</Label>

        <Label HorizontalAlignment="Left" Margin="20,70,0,32" Name="label2" Width="88"

        HorizontalContentAlignment="Right">密码:</Label>

        <Image HorizontalAlignment="Left" Margin="20,47,0,8" Name="image1"

        Source="images/key.jpg" Stretch="Fill" Width="46" />

        <Label FontSize="12" FontWeight="Normal" Foreground="Red" Height="35"

        Margin="99,0,97,16" Name="lblStatus" SnapsToDevicePixels="True"

        VerticalAlignment="Bottom" />

    </Grid>

</Window>

    <Windows>标签用于定义登录界面的窗口。x:Class属性表示和界面对应的类名(namespace.classname),其中WpfMSNGame是本程序的命名空间。

    在login.xaml中引用了一些图像资源,如<Image>标签的Source属性指定的”images/key.jpg“,这些资源都是加到当前工程的资源。如图1所示。

图1  当前工程中的图像资源

    引用这些资源后,在编译生成的exe时会自动包含这些资源,发布程序时只需要要提供exe及程序中引用的外部库(在本程序中是XihSolutions.DotMSN.dll文件)即可。

    在dotmsn2.0中提供了一个XihSolutions.DotMSN.Messenger类,通过该类的Connect方法可以联机MSN服务器。IM类负责连接MSN服务器,代码如下:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using XihSolutions.DotMSN;

using XihSolutions.DotMSN.Core;

using XihSolutions.DotMSN.DataTransfer;

namespace WpfMSNGame

{

    public class IM

    {

        public XihSolutions.DotMSN.Messenger messenger = new Messenger();

        public IM()

        {

            //  设置客户端ID,用来标识客户端软件(非常重要)

            messenger.Credentials.ClientID = "msmsgs@msnmsgr.com";

            //  设置客户端代码,用来标识客户端软件(非常重要)

            messenger.Credentials.ClientCode = "Q1P7W2E4J9R8U3S5";

        }

        //  使用MSN帐号连接MSN服务器

        public void Login(string account, string password)

        {                     

            //  如果已经连接MSN服务器,并断开连接

            if (messenger.Connected)

            {

                messenger.Disconnect();

            }

            messenger.Credentials.Account = account;

            messenger.Credentials.Password = password;

            //  开始连接MSN服务器

            messenger.Connect();           

        }

    }

}

当用户登录系统时会发生如下两个事件:

1.  登录成功(SignedIn事件)。该事件在使有和MSN帐号成功登录MSN服务器时发生。

2.  登录失败(AuthenticationError事件)。该事件在使用MSN帐号登录失败时发生。

这两个事件需要在装载登录界面时被添加,代码如下:

//  添加登录成功事件

im.messenger.Nameserver.SignedIn += new EventHandler(SignedIn);

//  添加登录失败事件

im.messenger.Nameserver.AuthenticationError +=

    new HandlerExceptionEventHandler(HandlerExceptionEvent);

登录成功后的处理代码如下:

private void SignedIn(object sender, EventArgs e)

{

    //  设置当前成功登录的用户状态为在线

    im.messenger.Owner.Status = PresenceStatus.Online;           

    this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, (ThreadStart)delegate

    {

        MessageBox.Show("登录成功!", "信息", MessageBoxButton.OK, MessageBoxImage.Information);

        if (main == null)

        {

            this.Hide();

            main = new Main(im);

            //  保存成功登录的MSN帐号

            XElement element = new XElement("config", new XElement("account",

                                           txtAccount.Text));

            element.Save("config.xml");

            //  显示程序的主界面

            main.ShowDialog();

        }

    });

}

    由于dotmsn2.0使用了异步的方式来调用这些事件方法,因此,在事件方法中必须使用BeginInvoke方法来执行访问界面控件的代码,如上面的代码所示。

    处理登录失败的代码如下:

public void HandlerExceptionEvent(object sender, ExceptionEventArgs e)

{

    this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, (ThreadStart)delegate

    {

        lblStatus.Content = "";

        MessageBox.Show(e.Exception.Message, "错误", MessageBoxButton.OK,

                  MessageBoxImage.Error);

    });

}

    在登录界面启动时,会使用Linq技术来读取保存在config.xml文件中的MSN帐号信息,代码如下:

XElement element = XElement.Load(@"config.xml");

IEnumerable<string> myAccount = from account in element.Descendants("account") select account.Value;

txtAccount.Text = myAccount.First();

    在编写完登录界面的代码后,启动程序,登录界面如图2所示。

图2  登录界面

 

四、列出当前MSN帐号的所有好友

   

    在成功登录系统后,首先需要列出当前MSN帐号的联系人(好友)。在本程序中使用TreeView控件来列出联系人及其分组。在每一个联系人节点的 TreeViewItem对象的Tag属性中保存了一个ItemObject对象。该对象封装了和某个好友相关的信息,如联系人信息(Contact对 象)、游戏窗口的对象、用于通信的SBMessageHandler对象等。可以通过Contact对象来获得当前好友的名称、E-mail、所有组等信 息。

    主界面中的核心控件有如下两个:

    1.  TreeView:用于显示联系人及联系人组信息。

    2.  CheckBox:用于控制是否只显示在线联系人。

    Main.xaml文件是设置主界面控件的xaml文件,代码如下:

<Window x:Class="WpfMSNGame.Main"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Main" Height="489" Width="308" Icon="images/logo.ico" ResizeMode="NoResize"  Loaded="Window_Loaded" Unloaded="Window_Unloaded">

    <Grid>

        <!--  TreeView控件的配置代码  -->

        <TreeView Margin="8,51,10,15" Name="tvContactList"

             MouseDoubleClick="tvContactList_MouseDoubleClick">

        </TreeView>

        <!--  CheckBox控件的配置代码  -->

        <CheckBox Height="16" Margin="0,23,0,0" Name="chkOnlineUser"

         VerticalAlignment="Top" HorizontalAlignment="Right" Width="119"

             Click="chkOnlineUser_Click" >只显示在线用户</CheckBox>

        <!--  Image控件的配置代码  -->

        <Image Height="34" HorizontalAlignment="Left" Margin="8,13,0,0" Name="image1" Source="images/logo.gif" Stretch="Fill" VerticalAlignment="Top" Width="37" />

    </Grid>

</Window>

    获得当前MSN帐号的所有联系人及联系人组,并将这些信息加载到TreeView控件的功能由UpdateContactlist方法完成。该方法在Windows_Unloaded事件被调用。UpdateContactlist方法的代码如下:

private void UpdateContactlist()

{

    //  使用Messenger类ContactList属性获得当前MSN帐号中所有的联系人,

    //  并依次处理这些联系人

    foreach (Contact contact in im.messenger.ContactList.All)

    {

        //  处理每一个联系人

        addContactAndGroup(contact);

    }

}

    在UpdateContactList方法中涉及到一个addContactAndGroup方法。该方法负责处理每一个联系人,代码如下:

private void addContactAndGroup(Contact contact)

 {

     ItemObject itemObject = null;

     //  根据当前联系人是否在线,选择相应的图标文件

     String iconUri = (contact.Status ==  PresenceStatus.Offline) ?

                "images/logo_gray.ico" : "images/logo.ico";

     //  如果当前联系人所属性组中已经有其他的好友,

     //  则当前联系人会找到相应的联系人组

     foreach (TreeViewItem tvGroupItem in tvContactList.Items)

     {

         String groupName = ((ItemObject)tvGroupItem.Tag).contactGroup.Name;

         if (groupName.Equals(contact.ContactGroup.Name))

         {                                      

             //  创建一个TreeViewIconsItem对象

             TreeViewIconsItem tvItem = new TreeViewIconsItem();

             // 为当前联系人添加一个图标

             tvItem.Icon = CreateImage(iconUri);                   

             itemObject = new ItemObject();

             itemObject.contact = contact;

             //  设置联系人节点名

             tvItem.HeaderText = contact.Name;

             tvItem.Tag = itemObject;

             //  添加联系人

             tvGroupItem.Items.Add(tvItem);

             return;

         }

     }

     //  当前联系人所有的组中暂时没有其他的好友,

     //  则创建一个新的联系人组节点和一个联系人节点

     TreeViewIconsItem tvNewGroupItem = new TreeViewIconsItem();   

     if (contact.ContactGroup.Name.Equals("Personen"))

         tvNewGroupItem.HeaderText = "其他联系人";

     else

         tvNewGroupItem.HeaderText = contact.ContactGroup.Name;

     itemObject = new ItemObject();

     itemObject.contactGroup = contact.ContactGroup;

     tvNewGroupItem.Tag = itemObject;

     //  添加联系人组节点

     tvContactList.Items.Add(tvNewGroupItem);

     TreeViewIconsItem tvNewItem = new TreeViewIconsItem();

     //  为联系人节点添加图标

     tvNewItem.Icon = CreateImage(iconUri);                   

     tvNewItem.HeaderText = contact.Name;

     itemObject = new ItemObject();

     itemObject.contact = contact;

     tvNewItem.Tag = itemObject;

     //  添加好联系人点

     tvNewGroupItem.Items.Add(tvNewItem);

 }

    为了方便向树节点中添加图标,在addContactAndGroup方法中使用了一个TreeViewIconsItem类,该类是TreeViewItem类的子类,负责向树节点添加图标。该类的实现代码如下:

//  负责向树节点中添加图标

public class TreeViewIconsItem : TreeViewItem

{

    ImageSource iconSource;

    TextBlock textBlock;

    Image icon;

    public TreeViewIconsItem()

    {

        StackPanel stack = new StackPanel();

        //  设置StackPanel中的内容水平排列

        stack.Orientation = Orientation.Horizontal;

        Header = stack;

        icon = new Image();

        icon.VerticalAlignment = VerticalAlignment.Center;

        icon.Margin = new Thickness(0, 0, 4, 0);

        icon.Source = iconSource;

        //  向StackPanel对象中添加一个图标对象

        stack.Children.Add(icon);

        //  创建用于添加文本信息的TextBlock对象

        textBlock = new TextBlock();

        textBlock.VerticalAlignment = VerticalAlignment.Center;

        //  向StackPanel对象中添加文本信息

        stack.Children.Add(textBlock);

    }

    //  用于设置或获得节点中的图标对象

    public ImageSource Icon

    {

        set

        {

            iconSource = value;

            icon.Source = iconSource;

            icon.Width = 16;

            icon.Height = 16;

        }

        get

        {

            return iconSource;

        }

    }

    //  用于设置或获得节点中的文本信息

    public string HeaderText

    {

        set

        {

            textBlock.Text = value;

        }

        get

        {

            return textBlock.Text;

        }

    }

}       

    在成功登录后,就会进入主界面,如图3所示。

图3  五子棋程序的主界面

 

五、实现基于MSN协议的聊天功能

    在图3所示的主界面中双击某个联系人,就会弹出与该联系人聊天和玩游戏的界面。图4为游戏界面(未开始对羿和聊天):

图4  下棋和聊天的界面(未开始对羿和聊天)

    从图4所示的界面可以看出,该界面的左侧是棋盘,右侧可以进行聊天。Game.xaml文件设置了该界面中的控件,代码如下:

<Window x:Class="WpfMSNGame.Game"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Game" Height="684" Width="1076" ResizeMode="NoResize" Icon="images/logo.ico" Loaded="Window_Loaded"  MouseDown="imgChessboard_MouseUp" Unloaded="Window_Unloaded" >

    <Grid>

        <!--  显示棋盘的Image控件的配置代码  -->

        <Image Margin="17,30,437,16" Name="imgChessboard" Stretch="Fill"

            IsHitTestVisible="False" ClipToBounds="False" />

        <!--  用于输入聊天信息的文本框的配置代码  -->

        <TextBox Height="23" HorizontalAlignment="Right" Margin="0,0,27,16" Name="txtMsg" VerticalAlignment="Bottom" Width="354" KeyUp="txtMsg_KeyUp" TextChanged="txtMsg_TextChanged" IsEnabled="True" />

        <!--  用于显示聊天记录的RichTextBox控件的配置代码  -->

        <RichTextBox HorizontalAlignment="Right" Margin="0,279,27,59" Name="rtxtMsgList" Width="354"  VerticalScrollBarVisibility="Auto" IsReadOnly="True" />

        <!--  用于控制棋子位置的Canvas控件的配置代码  -->

        <Canvas  Name="myCanvas" Margin="0,0,437,16"></Canvas>

        <!--  其他控件的配置代码  -->

        <Image Margin="899,156,0,0" Name="imgBlack" Stretch="Fill" Height="31" Visibility="Hidden" Width="31" HorizontalAlignment="Left" VerticalAlignment="Top" />

        <Image Height="31" HorizontalAlignment="Right" Margin="0,156,84,0" Name="imgWhite" Stretch="Fill" VerticalAlignment="Top" Visibility="Hidden" Width="31" ClipToBounds="True" />

        <Label Height="35" HorizontalAlignment="Right" Foreground="Blue"

        Margin="0,172,196,0" Name="lblStatus" VerticalAlignment="Top" Width="185"

        FontWeight="Normal" SnapsToDevicePixels="True" FontSize="20"></Label>

        <Image Height="120" HorizontalAlignment="Right" Margin="0,30,115,0"

Name="image1" Source="images/wpf_logo.jpg" Stretch="Fill" VerticalAlignment="Top" Width="152" />

        <Label FontSize="20" FontWeight="Normal" Foreground="Blue" Height="35"

        HorizontalAlignment="Right" Margin="0,172,38,0" Name="lblChessColor"

        SnapsToDevicePixels="True" VerticalAlignment="Top" Width="117" />

        <Label FontSize="20" FontWeight="Normal" Foreground="Red" Height="35"

         HorizontalAlignment="Right" Margin="0,225,38,0" Name="lblPlayer"

         SnapsToDevicePixels="True" VerticalAlignment="Top" Width="343" />

    </Grid>

</Window>

    可以通过SBMessageHandler的SendTextMessage方法向联系人发送文本信息。但该方法需要一个TextMessage对象来封装要发送的文本信息。发送文本信息的功能由SendInput方法来完成,代码如下:

private void SendInput(String msg)

{

    //  不能发送空字符串

    if (msg.Length == 0) return;

    //  封装要发送的文本信息

    TextMessage message = new TextMessage(msg);

    //  向联系人发送文本信息

    itemObject.switchboard.SendTextMessage(message);

}

    如果游戏的一方先打开游戏窗口,当第一次向对方发送聊天信息或走一步棋后,对方的五子棋程序也会打开一个类似图4所示的游戏窗口。打开该游戏窗口的代码需要放在接收聊天信息的事件中,代码如下:

private void TextMessageReceived(object sender, TextMessageEventArgs e)

{

    //  如果发送的是命令字符串,不弹出聊天窗口

    //  COMMAND_PREFIX为命令信息的前缀

    if (e.Message.Text.StartsWith(Game.COMMAND_PREFIX))

        return;

    this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, (ThreadStart)delegate

    {

        ItemObject itemObject = null;

        //  从联系人列表中查找相应的联系人节点。

        foreach (TreeViewItem tvGroupItem in tvContactList.Items)

        {

            foreach (TreeViewItem tvContractItem in tvGroupItem.Items)

            {

                ItemObject item = (ItemObject)tvContractItem.Tag;

                //  使用E-mail来判断联系人是否相同

                if (item.contact.Mail.Equals(e.Sender.Mail))

                {

                    itemObject = item;

                    if (item.game != null)

                    {

                        //  如果该联系人的游戏窗口已经打开,将该窗口设为焦点状态

                        itemObject.game.Show();

                        return;

                    }

                    break;

                }

            }

            if (itemObject != null) break;

        }

        //  如果联系人不在列表中,拒绝游戏请求

        if(itemObject == null) return ;

        //  将sender参数转换成SBMessageHandler对象

        SBMessageHandler switchboard = (SBMessageHandler)sender;

        itemObject.contact = e.Sender;

        itemObject.switchboard = switchboard;

        //  将主窗口的聊天信息接收事件删除

        switchboard.TextMessageReceived -=

            new TextMessageReceivedEventHandler(TextMessageReceived);

        //  创建游戏窗口对象

        Game game = new Game(im, itemObject);

        game.lblStatus.Content = "该对方走棋了!";

        game.lblStatus.Tag = 0;   

        //  人工调用游戏窗口的聊天信息接收事件

        game.TextMessageReceived(sender, e);

        itemObject.game = game;

        //  添加游戏窗口的聊天信息接收事件

        itemObject.switchboard.TextMessageReceived +=

            new TextMessageReceivedEventHandler(game.TextMessageReceived);

        //  添加联系人离线事件

        itemObject.contact.ContactOffline +=

            new Contact.StatusChangedEventHandler(game.StatusChangedEvent);

        game.setChessColorInfo(ChessColor.WhiteChess);

        //  显示游戏窗口

        game.Show();            

    });

}

    当游戏的双方都启动如图4所示的游戏界面后,两个玩家就可以进行聊天和玩游戏了。

 

六、利用MSN聊天信息发送命令和下棋指令

    在上一节介绍了如何实现两个联系人之间的聊天功能。在本程序中通过在聊天信息中加前缀的方式来发送命令文本。命令文本有如下两种:

    1.  普通命令文本:该命令文本的前缀由Game.COMMAND_PREFIX指定。

    2.  下棋命令文本:该命令文本的前缀由Game.CHESSMESSAGE_PREFIX指定。

    如在下棋时,可以使用如下的代码来发送聊天信息:

    SendInput(CHESSMESSAGE_PREFIX + x.ToString() + ":" + y.ToString());

    其中x和y为鼠标点击Canvas的当前坐标。发送到对方的聊天信息为如下的形式:

    ^%@^210:200

    其中“^%@^”为下棋命令的前缀,读者也可以使用其他的字符串,但要比较特殊。

    对方在接收到该聊天信息后,会按着下棋命令来解释它,也就是说,会根据这个信息在棋盘上放一个棋子,而不会在聊天记录中显示这条信息。

    玩家之前下棋和聊天的界面如图5所示。

图5  下棋和聊天界面

七、判断五子棋的输赢

 

    本文提供的五子棋程序可以判断输赢。对于五子棋程序来说,判断输赢非常简单,只需要判断最后一个走的棋子在如下四个方向是否存在连续五个同色棋子,如果存在,则走该棋子的玩家赢。

    1.  水平方向

    2.  垂直方向

    3.  西北到东南的方向

    4.  东北到西南的方向

    程序在判断每一个方向时,需要以当前棋子为中心,向两个方向对判断。如判断水平方向是否满足五子连续,需要以当前棋子为中心,先向左侧去判断是否满足条 件,如果不满足,以左侧连续同色棋子的数目为基础,向右侧继续统计同色棋子的数目。如果满足条件,在水平方向上就满足连续五个同色棋子的条件。该玩家赢得 游戏。这个算法的实现代码如下:

//  如果当前玩家赢得游戏,返回true,否则返回false

private bool verifyWinner()

{

    //  当count变量的值为5时,表示在某个方向上已经有五个同色棋子,

    //  当前玩家赢得游戏

    int count = 0;           

    //  验证垂直方向,向上验证

    for (int i = currentRow; i >= 0; i--)

    {

        //  判断当前棋子是否和最后一个走的棋子为同色

        if (isSameChess(i, currentCol))

        {

            count++;

            if (count == 5)

                return true;

        }

        else

            break;

    }

    //  验证垂直方向,向下验证

    for (int i = currentRow + 1; i < Chessboard.GetLength(0); i++)

    {

        if (isSameChess(i, currentCol))

        {

            count++;

            if (count == 5)

                return true;

        }

        else

            break;

    }

    //  计数器清零

    count = 0;

    //  验证水平方向,向左验证

    for (int i = currentCol; i >= 0; i--)

    {

        if (isSameChess(currentRow, i))

        {

            count++;

            if (count == 5)

                return true;

        }

        else

            break;

    }

    //  验证水平方向,向右验证

    for (int i = currentCol + 1; i < Chessboard.GetLength(0); i++)

    {

        if (isSameChess(currentRow, i))

        {

            count++;

            if (count == 5)

                return true;

        }

        else

            break;

    }

    //  计数器清零

    count = 0;

    //  验证西北至东南方向,向西北验证

    for (int i = currentRow, j = currentCol; i >= 0 && j >= 0; i--, j--)

    {

        if (isSameChess(i, j))

        {

            count++;

            if (count == 5)

                return true;

        }

        else

            break;

    }

    //  验证西北至东南方向,向东南验证

    for (int i = currentRow + 1, j = currentCol + 1; i < Chessboard.GetLength(0) && j < Chessboard.GetLength(0); i++, j++)

    {

        if (isSameChess(i, j))

        {

            count++;

            if (count == 5)

                return true;

        }

        else

            break;

    }

    //  计数器清零

    count = 0;

    //  验证东北至西南方向,向东北方向验证

    for (int i = currentRow, j = currentCol; i >= 0 && j < Chessboard.GetLength(0); i--, j++)

    {

        if (isSameChess(i, j))

        {

            count++;

            if (count == 5)

                return true;

        }

        else

            break;

    }

    //  验证东北至西南方向,向西南方向验证

    for (int i = currentRow + 1, j = currentCol - 1; i < Chessboard.GetLength(0) && j >=0; i++, j--)

    {

        if (isSameChess(i, j))

        {

            count++;

            if (count == 5)

                return true;

        }

        else

            break;

    }

    return false;

}

 

八、总结

 

    dotmsn2.0的功能非常强大。在本文提供的程序只使用了dotmsn2.0的功能的很少的一部分。如果读者对基于MSN协议的程序感兴趣,可以使用 dotmsn2.0实现更复杂的系统。本文的游戏程序通过在聊天信息中加前缀的方法将聊天信息进行分类,从而可以使系统根据不同类别的聊天信息进行各种控 制。读者也可以利用这种方法来实现更有趣的程序,如各类棋牌类游戏。虽然使用这种方法从表面上看不如自已通过socket实现客户端和服务端直接,但至少 不需要为游戏程序准备服务器了。MSN服务器可以24小时开机的,而且性能可靠。

时间: 2024-10-26 07:53:59

使用WPF技术实现基于MSN协议的五子棋程序的相关文章

利用ASP技术开发基于WWW的数据库检索程序

程序|数据|数据库  ASP是微软公司推出的用以取代CGI的新技术,是目前公认的建立Windows NT动态站点最好的工具.它与ADO(Active Data Object,一种新的数据访问模型)的充分结合,提供了强大的数据库访问功能,使之成为进行网上数据库管理的重要手段.     一.ASP简介   ASP内含于Internet Information Server(简称IIS3.0)中,扩展名以.asp表示.ASP文件可以用常规的文本编辑器编辑,也可以利用专门的辅助开发工具InterDev进

linux网络编程之socket(十四) 基于UDP协议的网络程序

一.下图是典型的UDP客户端/服务器通讯过程 下面依照通信流程,我们来实现一个UDP回射客户/服务器 #include <sys/types.h> #include <sys/socket.h>  ssize_t send(int sockfd, const void *buf, size_t len, int flags); ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struc

用C#实现基于TCP协议的网络通讯

网络 TCP协议是一个基本的网络协议,基本上所有的网络服务都是基于TCP协议的,如HTTP,FTP等等,所以要了解网络编程就必须了解基于TCP协议的编程.然而TCP协议是一个庞杂的体系,要彻底的弄清楚它的实现不是一天两天的功夫,所幸的是在.net framework环境下,我们不必要去追究TCP协议底层的实现,一样可以很方便的编写出基于TCP协议进行网络通讯的程序. 要进行基于TCP协议的网络通讯,首先必须建立同远程主机的连接,连接地址通常包括两部分--主机名和端口,如www.yesky.c

用C#实现基于用C#实现基于TCP协议的网络通讯

网络 TCP协议是一个基本的网络协议,基本上所有的网络服务都是基于TCP协议的,如HTTP,FTP等等,所以要了解网络编程就必须了解基于TCP协议的编程.然而TCP协议是一个庞杂的体系,要彻底的弄清楚它的实现不是一天两天的功夫,所幸的是在.net framework环境下,我们不必要去追究TCP协议底层的实现,一样可以很方便的编写出基于TCP协议进行网络通讯的程序. 要进行基于TCP协议的网络通讯,首先必须建立同远程主机的连接,连接地址通常包括两部分--主机名和端口,如www.yesky.c

java web基于snmp协议的局域网远程电源管理系统

问题描述 java web基于snmp协议的局域网远程电源管理系统 5C 准备通过java web做基于snmp协议的局域网远程电源管理系统,(学校机房有3层,1200台电脑以上)以下是我的想法,请各位指导提建议哈,在此感谢呀 通过mib borwer收集第三方电源有关的mib库,保存到枚举,集合或xml中 遍历mib库,遍历电脑ip,管理端通过snmp的get获取agent端电源有关信息,进行数据的处理然后保存到db(通过异步,队列,多线程或分批方式定时获取) 设置报警阈值,agent端定时t

《Web异步与实时交互——iframe AJAX WebSocket开发实战》—— 1.1 基于HTTP协议的Web交互

1.1 基于HTTP协议的Web交互 HTTP协议(Hyper Text Transport Potocol,超文本传输协议),是基于服务器/客户端模式的无连接.无状态的协议.基于HTTP协议的Web应用中,所有的请求是由客户端发起的,服务器处于被动响应的地位.然而,服务器却相当于是信息的发布者,当有新信息产生时,服务器并不能主动将新信息发送给客户端,必须等待客户端主动发起访问请求建立连接后才能发送给客户端. 当遇到实时监控.即时通信.在线互动等的Web交互开发需求(如设备监控.聊天室.股票行情

基于OPC协议的工控网络系统防护浅析

一.协议概述 提到OPC协议,大家想到最多的就是OPC Classic 3.0,实际上现在OPC协议有两个大类,一种是基于微软COM/DCOM技术的"Classic",另一种是基于Web service的OPC UA.前者在DCOM协议之上,诞生较早,已广泛应用在各种工业控制系统现场,成为工业自动化领域的事实标准.后者与前者比出生较晚,但在设计时考虑了安全因素,有了加密机制,不过目前应用范围较小.本文主要讨论的是前者在工控系统中的防护. 微软的DCOM协议是在网络安全问题被广泛认识之前

Java基于UDP协议实现简单的聊天室程序_java

最近比较闲,一直在抽空回顾一些Java方面的技术应用. 今天没什么事做,基于UDP协议,写了一个非常简单的聊天室程序. 现在的工作,很少用到socket,也算是对Java网络编程方面的一个简单回忆.  先看一下效果:   实现的效果可以说是非常非常简单,但还是可以简单的看到一个实现原理.  "聊天室001"的用户,小红和小绿相互聊了两句,"聊天室002"的小黑无人理会,在一旁寂寞着.  看一下代码实现:  1.首先是消息服务器的实现,功能很简单:•将客户端的信息(进

艾伟_转载:用C#实现基于TCP协议的网络通讯

TCP协议是一个基本的网络协议,基本上所有的网络服务都是基于TCP协议的,如HTTP,FTP等等,所以要了解网络编程就必须了解基于TCP协议的编程.然而TCP协议是一个庞杂的体系,要彻底的弄清楚它的实现不是一天两天的功夫,所幸的是在.net framework环境下,我们不必要去追究TCP协议底层的实现,一样可以很方便的编写出基于TCP协议进行网络通讯的程序.  要进行基于TCP协议的网络通讯,首先必须建立同远程主机的连接,连接地址通常包括两部分--主机名和端口,如www.yesky.com:8