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

简介: 一、前言     WPF(Windows Presentation Foundation)是微软最近推出的一套界面实现技术。该技术实现了界面设计和逻辑代码的分离。
一、前言
    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小时开机的,而且性能可靠。
目录
相关文章
|
6月前
|
C# Windows
2000条你应知的WPF小姿势 基础篇<74-77 WPF 多窗口Tips>
2000条你应知的WPF小姿势 基础篇<74-77 WPF 多窗口Tips>
54 0
|
4月前
|
人工智能 机器人 C#
Windows编程课设(C#)——基于WPF和.net的即时通讯系统(仿微信)
一款参考QQ、微信的即时通讯软件。采用CS结构,客户端基于.Net与WPF开发,服务端使用Java开发。
|
5月前
|
C# 开发者
一款WPF开发的网易云音乐客户端 - DMSkin-CloudMusic
一款WPF开发的网易云音乐客户端 - DMSkin-CloudMusic
125 36
|
6月前
|
C# C++ Windows
2000条你应知的WPF小姿势 基础篇<28-33 WPF启动故事>
2000条你应知的WPF小姿势 基础篇<28-33 WPF启动故事>
34 0
一起谈.NET技术,Silverlight 游戏开发小技巧:透明背景的Silverlight程序
  一些朋友在玩窝窝世界的时候,发现官方网站上的进入入口程序是Silverlight,但是有趣的是一个透明背景的Silverlight程序,这个效果最早我也未找资料,在未来Silverlight程序会在各个方面应用,透明背景的效果就会涉及,这种效果预览如下:   下面一步一步的告诉大家这个小技巧,首...
949 0
|
算法
一起谈.NET技术,Silverlight 游戏开发小技巧:动感小菜单2
  动感小菜单其实是想模仿Apple的菜单按钮设计制作,但是画虎不成反类犬,看起来有点别扭,昨天各位园友提了这方面的建议,感觉太硬如果加入动画可能更好,非常感谢各位,而今天这篇的动感小菜单2,让按钮更加动感“柔”顺:)期望能做的更好吧。
922 0
|
C#
艾伟:闲话WPF之一(WPF的结构)
WPF进入我们的生活已经很多年。(写这句话让我想起来了“我不做大哥好多年”。) 个人认为在UI的实践中,用户需要的是易于操作的,更加绚丽的界面。这两个应该是最基本、也是最重要的宗旨。而对于开发人员就是要用最简单的方法开发出尽可能漂亮的界面,并且效率也不能太差。
829 0
|
前端开发 C# iOS开发
WPF触控程序开发(二)——整理的一些问题
原文:WPF触控程序开发(二)——整理的一些问题   上一篇(WPF触控程序开发)介绍了几个比较不错的资源,比较基础。等到自己真正使用它们时,问题就来了,现把我遇到的几个问题罗列下,大家如有遇到其他问题或者有什么好的方法还望赐教。
1020 0
|
C# C++
WPF编游戏系列 之四 用户控件
原文:WPF编游戏系列 之四 用户控件        在上一篇《WPF编游戏系列 之三 物品清单》中,对物品清单进行了演示,其中反复用到了同一组控件(如下图),而且 颜昌钢也指出在3.2.2中使用的C#代码过多,其实我在写这些代码时也有同感,的确很繁琐也不好维护。
592 0
|
C# 前端开发
WPF编游戏系列 之二 图标效果
原文:WPF编游戏系列 之二 图标效果        本篇将要实现图标的两个效果:1. 显示图标标签,2. 图标模糊效果。在上一篇中提到Image没有HTML 的Title属性(在MSDN中也没找到类似的属性),所以本篇将自行制作一个标签,它的功能是当鼠标移动到图标上方时会显示该图标的Tag说明,并且该图标模糊显示,如下图对比所示。
727 0