天天看点

游戏人生Silverlight(4) - 连连看[Silverlight 2.0(c#)]

<a href="http://down.51cto.com/data/101271" target="_blank">[源码下载]</a>

游戏人生Silverlight(4) - 连连看[Silverlight 2.0(c#)]

介绍

使用 Silverlight 2.0(c#) 开发一个连连看游戏

玩法

用鼠标左键选中卡片,如果选中的两卡片间的连线不多于 3 根直线,则选中的两卡片可消除

在线DEMO

思路

1、卡片初始排列算法:已知容器容量为 x, 不重复的卡片数量为 y, x &gt;= y &amp;&amp; x % 2 == 0, 首先在容器内随机排列卡片,然后取出容器内相同的卡片个数为奇数的集合(集合内成员数量必为偶数个),最后将该集合一刀切,将集合右半部分的卡片的依次复制到集合左半部分。以上算法保证了在一定随机率的基础上,不会出现相同的卡片个数为奇数的情况

2、无解算法和重排算法:在容器内存在的卡片中,两两计算是否存在可消路径,如果没有就是无解,需要重排。重排时,需要得到现存的卡片集合和卡片位置集合,在卡片集合中随机取卡片(取出一个,原集合就要移除这一个),然后依次放到卡片位置集合内,从而达到将现存卡片重新排列的目的

3、两点消去路径的算法以及取最优消去路径的算法:取玩家选的第一点的 x 轴方向和 y 轴方向上的所有无占位符的坐标集合(包括自己),名称分别为 x1s, y1s;取玩家选的第二点的 x 轴方向和 y 轴方向上的所有无占位符的坐标集合(包括自己),名称分别为 x2s, y2s。先在 x1s 和 x2s 中找 x 坐标相等的两点,然后找出该两点与玩家选的两点可组成一条连续的直线的集合,该集合就是可消路径的集合,之后同理再在 y1s 和 y2s 中找到可消路径的集合。两集合合并就是玩家选中的两点间的所有可消路径的集合,该集合为空则两点不可消,该集合内的最短路径则为最优消去路径,集合内的 4 点连接线则为消去路径的连接线

4、游戏使用MVVM(Model - View - ViewModel)模式开发

关键代码

Core.cs

using System; 

using System.Net; 

using System.Windows; 

using System.Windows.Controls; 

using System.Windows.Documents; 

using System.Windows.Ink; 

using System.Windows.Input; 

using System.Windows.Media; 

using System.Windows.Media.Animation; 

using System.Windows.Shapes; 

using YYMatch.Models; 

using System.Collections.ObjectModel; 

using System.Linq; 

using System.Collections.Generic; 

using System.ComponentModel; 

using System.Threading; 

namespace YYMatch.ViewModels 

        /// &lt;summary&gt; 

        /// 连连看核心模块 

        /// &lt;/summary&gt; 

        public class Core : INotifyPropertyChanged 

        { 

                ObservableCollection&lt;CardModel&gt; _cards = null; 

                int _rows = 0; 

                int _columns = 0; 

                SynchronizationContext _syncContext = null; 

                public Core() 

                { 

                        // 在容器上布满空的卡片 

                        _cards = new ObservableCollection&lt;CardModel&gt;(); 

                        for (int i = 0; i &lt; Global.ContainerColumns * Global.ContainerRows; i++) 

                        { 

                                _cards.Add(new CardModel("00", i)); 

                        } 

                        _syncContext = SynchronizationContext.Current; 

                } 

                public void Start(int rows, int columns) 

                        _rows = rows; 

                        _columns = columns; 

                        InitCard(); 

                private ObservableCollection&lt;CardModel&gt; InitCard() 

                        Random r = new Random(); 

                        // 卡片集合在容器内的范围 

                        int minX = (Global.ContainerColumns - _columns) / 2; 

                        int maxX = minX + _columns - 1; 

                        int minY = (Global.ContainerRows - _rows) / 2; 

                        int maxY = minY + _rows - 1; 

                        for (int x = 0; x &lt; Global.ContainerColumns; x++) 

                                for (int y = 0; y &lt; Global.ContainerRows; y++) 

                                { 

                                        // 18 张图随机排列 

                                        string imageName = r.Next(1, Global.ImageCount + 1).ToString().PadLeft(2, '0'); 

                                        var cardPoint = new CardPoint(x, y); 

                                        if (x &gt;= minX &amp;&amp; x &lt;= maxX &amp;&amp; y &gt;= minY &amp;&amp; y &lt;= maxY) 

                                        { 

                                                _cards[cardPoint.Position] = new CardModel(imageName, cardPoint.Position); 

                                        } 

                                } 

                        // 相同的卡片个数为奇数的集合 

                        var oddImages = _cards.Where(p =&gt; p.ImageName != Global.EmptyImageName) 

                                .GroupBy(p =&gt; p.ImageName) 

                                .Select(p =&gt; new { ImageName = p.Key, Count = p.Count() }) 

                                .Where(p =&gt; p.Count % 2 &gt; 0) 

                                .ToList(); 

                        // 如果 oddImages 集合的成员为奇数个(保证容器容量为偶数个则不可能出现这种情况) 

                        if (oddImages.Count() % 2 &gt; 0) 

                                throw new Exception("无法初始化程序"); 

                        else 

                                // 在集合中将所有的个数为奇数的卡片各自取出一个放到 temp 中 

                                // 将 temp 一刀切,使其右半部分的卡片的 ImageName 依次赋值为左半部分的卡片的 ImageName 

                                // 由此保证相同的卡片均为偶数个 

                                List&lt;CardModel&gt; tempCards = new List&lt;CardModel&gt;(); 

                                for (int i = 0; i &lt; oddImages.Count(); i++) 

                                        if (i &lt; oddImages.Count() / 2) 

                                                var tempCard = _cards.Last(p =&gt; p.ImageName == oddImages.ElementAt(i).ImageName); 

                                                tempCards.Add(tempCard); 

                                        else 

                                                _cards[tempCard.Position].ImageName = tempCards[i - oddImages.Count() / 2].ImageName; 

                        if (!IsActive()) 

                                Replace(); 

                        return _cards; 

                /// &lt;summary&gt; 

                /// 判断两卡片是否可消 

                /// &lt;/summary&gt; 

                public bool Match(CardModel c1, CardModel c2, bool removeCard) 

                        bool result = false; 

                        if (c1.ImageName != c2.ImageName 

                                || c1.ImageName == Global.EmptyImageName 

                                || c2.ImageName == Global.EmptyImageName 

                                || c1.Position == c2.Position) 

                                return false; 

                        // 如果可消的话,则 point1, point2, point3, point4 会组成消去两卡片的路径(共4个点) 

                        CardPoint point1 = new CardPoint(0); 

                        CardPoint point2 = new CardPoint(0); 

                        CardPoint point3 = new CardPoint(0); 

                        CardPoint point4 = new CardPoint(0); 

                        // 最小路径长度 

                        int minLength = int.MaxValue; 

                        CardPoint p1 = new CardPoint(c1.Position); 

                        CardPoint p2 = new CardPoint(c2.Position); 

                        var p1xs = GetXPositions(p1); 

                        var p1ys = GetYPositions(p1); 

                        var p2xs = GetXPositions(p2); 

                        var p2ys = GetYPositions(p2); 

                        // 在两点各自的 X 轴方向上找可消点(两个可消点的 X 坐标相等) 

                        var pxs = from p1x in p1xs 

                                            join p2x in p2xs 

                                            on p1x.X equals p2x.X 

                                            select new { p1x, p2x }; 

                        foreach (var px in pxs) 

                                if (MatchLine(p1, px.p1x) &amp;&amp; MatchLine(px.p1x, px.p2x) &amp;&amp; MatchLine(px.p2x, p2)) 

                                        int length = Math.Abs(p1.X - px.p1x.X) + Math.Abs(px.p1x.Y - px.p2x.Y) + Math.Abs(px.p2x.X - p2.X); 

                                        // 查找最短连接路径 

                                        if (length &lt; minLength) 

                                                minLength = length; 

                                                point1 = p1; 

                                                point2 = px.p1x; 

                                                point3 = px.p2x; 

                                                point4 = p2; 

                                        result = true; 

                        // 在两点各自的 Y 轴方向上找可消点(两个可消点的 Y 坐标相等) 

                        var pys = from p1y in p1ys 

                                            join p2y in p2ys 

                                            on p1y.Y equals p2y.Y 

                                            select new { p1y, p2y }; 

                        foreach (var py in pys) 

                                if (MatchLine(p1, py.p1y) &amp;&amp; MatchLine(py.p1y, py.p2y) &amp;&amp; MatchLine(py.p2y, p2)) 

                                        int length = Math.Abs(p1.Y - py.p1y.Y) + Math.Abs(py.p1y.X - py.p2y.X) + Math.Abs(py.p2y.Y - p2.Y); 

                                                point2 = py.p1y; 

                                                point3 = py.p2y; 

                        if (removeCard &amp;&amp; result) 

                                RemoveCard(c1, c2, point1, point2, point3, point4); 

                        return result; 

                /// 直线上的两个 CardPoint 是否可以消去 

                private bool MatchLine(CardPoint p1, CardPoint p2) 

                        if (p1.X != p2.X &amp;&amp; p2.Y != p2.Y) 

                        var range = _cards.Where(p =&gt; 

                                p.Position &gt; Math.Min(p1.Position, p2.Position) 

                                &amp;&amp; p.Position &lt; Math.Max(p1.Position, p2.Position)); 

                        if (p1.X == p2.X) 

                                range = range.Where(p =&gt; (p.Position - p1.Position) % Global.ContainerColumns == 0); 

                        }; 

                        if (range.Count() == 0 || range.All(p =&gt; p.ImageName == Global.EmptyImageName)) 

                                return true; 

                        return false; 

                /// 获取指定的 CardPoint 的 X 轴方向上的所有 ImageName 为 Global.EmptyImageName 的 CardPoint 集合 

                private List&lt;CardPoint&gt; GetXPositions(CardPoint p) 

                        var result = new List&lt;CardPoint&gt;() { p }; 

                        for (int i = 0; i &lt; Global.ContainerColumns; i++) 

                                var point = new CardPoint(p.Y * Global.ContainerColumns + i); 

                                if (_cards[point.Position].ImageName == Global.EmptyImageName) 

                                        result.Add(point); 

                }

<a href="http://webabcd.blog.51cto.com/1787395/345623" target="_blank">未完待续&gt;&gt;</a>

     本文转自webabcd 51CTO博客,原文链接:http://blog.51cto.com/webabcd/345624,如需转载请自行联系原作者

继续阅读