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

简介:
[源码下载]


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


作者: webabcd


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


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


在线DEMO



思路
1、卡片初始排列算法:已知容器容量为 x, 不重复的卡片数量为 y, x >= y && 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 

         /// <summary> 
         /// 连连看核心模块 
         /// </summary> 
         public  class Core : INotifyPropertyChanged 
        { 
                ObservableCollection<CardModel> _cards =  null
                 int _rows = 0; 
                 int _columns = 0; 
                SynchronizationContext _syncContext =  null
 
                 public Core() 
                { 
                         // 在容器上布满空的卡片 
                        _cards =  new ObservableCollection<CardModel>(); 
                         for ( int i = 0; i < 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<CardModel> 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 < Global.ContainerColumns; x++) 
                        { 
                                 for ( int y = 0; y < Global.ContainerRows; y++) 
                                { 
                                         // 18 张图随机排列 
                                         string imageName = r.Next(1, Global.ImageCount + 1).ToString().PadLeft(2, '0'); 
                                        var cardPoint =  new CardPoint(x, y); 
 
                                         if (x >= minX && x <= maxX && y >= minY && y <= maxY) 
                                        { 
                                                _cards[cardPoint.Position] =  new CardModel(imageName, cardPoint.Position); 
                                        } 
                                } 
                        } 
 
                         // 相同的卡片个数为奇数的集合 
                        var oddImages = _cards.Where(p => p.ImageName != Global.EmptyImageName) 
                                .GroupBy(p => p.ImageName) 
                                .Select(p =>  new { ImageName = p.Key, Count = p.Count() }) 
                                .Where(p => p.Count % 2 > 0) 
                                .ToList(); 
 
                         // 如果 oddImages 集合的成员为奇数个(保证容器容量为偶数个则不可能出现这种情况) 
                         if (oddImages.Count() % 2 > 0) 
                        { 
                                 throw  new Exception( "无法初始化程序"); 
                        } 
                         else 
                        { 
                                 // 在集合中将所有的个数为奇数的卡片各自取出一个放到 temp 中 
                                 // 将 temp 一刀切,使其右半部分的卡片的 ImageName 依次赋值为左半部分的卡片的 ImageName 
                                 // 由此保证相同的卡片均为偶数个 
                                List<CardModel> tempCards =  new List<CardModel>(); 
                                 for ( int i = 0; i < oddImages.Count(); i++) 
                                { 
                                         if (i < oddImages.Count() / 2) 
                                        { 
                                                var tempCard = _cards.Last(p => p.ImageName == oddImages.ElementAt(i).ImageName); 
                                                tempCards.Add(tempCard); 
                                        } 
                                         else 
                                        { 
                                                var tempCard = _cards.Last(p => p.ImageName == oddImages.ElementAt(i).ImageName); 
                                                _cards[tempCard.Position].ImageName = tempCards[i - oddImages.Count() / 2].ImageName; 
                                        } 
                                } 
                        } 
 
                         if (!IsActive()) 
                                Replace(); 
 
                         return _cards; 
                } 
 
                 /// <summary> 
                 /// 判断两卡片是否可消 
                 /// </summary> 
                 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) && MatchLine(px.p1x, px.p2x) && 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 < 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) && MatchLine(py.p1y, py.p2y) && 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); 
 
                                         // 查找最短连接路径 
                                         if (length < minLength) 
                                        { 
                                                minLength = length; 
                                                point1 = p1; 
                                                point2 = py.p1y; 
                                                point3 = py.p2y; 
                                                point4 = p2; 
                                        } 
                                        result =  true
                                } 
                        } 
 
                         if (removeCard && result) 
                        { 
                                RemoveCard(c1, c2, point1, point2, point3, point4); 
                        } 
 
                         return result; 
                } 
 
                 /// <summary> 
                 /// 直线上的两个 CardPoint 是否可以消去 
                 /// </summary> 
                 private  bool MatchLine(CardPoint p1, CardPoint p2) 
                { 
                         if (p1.X != p2.X && p2.Y != p2.Y) 
                                 return  false
 
                        var range = _cards.Where(p => 
                                p.Position > Math.Min(p1.Position, p2.Position) 
                                && p.Position < Math.Max(p1.Position, p2.Position)); 
 
                         if (p1.X == p2.X) 
                        { 
                                range = range.Where(p => (p.Position - p1.Position) % Global.ContainerColumns == 0); 
                        }; 
 
                         if (range.Count() == 0 || range.All(p => p.ImageName == Global.EmptyImageName)) 
                                 return  true
 
                         return  false
                } 
 
                 /// <summary> 
                 /// 获取指定的 CardPoint 的 X 轴方向上的所有 ImageName 为 Global.EmptyImageName 的 CardPoint 集合 
                 /// </summary> 
                 private List<CardPoint> GetXPositions(CardPoint p) 
                { 
                        var result =  new List<CardPoint>() { p }; 
                         for ( int i = 0; i < Global.ContainerColumns; i++) 
                        { 
                                var point =  new CardPoint(p.Y * Global.ContainerColumns + i); 
                                 if (_cards[point.Position].ImageName == Global.EmptyImageName) 
                                        result.Add(point); 
                        } 
 
                         return result; 
                }
 





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

相关文章
|
C# 图形学
C#之四十九 游戏编程周每日总结
C#之四十九 游戏编程周每日总结
53 0
|
2月前
|
SQL API 定位技术
基于C#使用winform技术的游戏平台的实现【C#课程设计】
本文介绍了基于C#使用WinForms技术开发的游戏平台项目,包括项目结构、运行截图、实现功能、部分代码说明、数据库设计和完整代码资源。项目涵盖了登录注册、个人信息修改、游戏商城列表查看、游戏管理、用户信息管理、数据分析等功能。代码示例包括ListView和ImageList的使用、图片上传、图表插件使用和SQL工具类封装,以及高德地图天气API的调用。
基于C#使用winform技术的游戏平台的实现【C#课程设计】
|
4月前
|
存储 缓存 C#
C#语言编写的仅有8KB大小的简易贪吃蛇开源游戏
C#语言编写的仅有8KB大小的简易贪吃蛇开源游戏
C#语言编写的仅有8KB大小的简易贪吃蛇开源游戏
|
6月前
|
程序员 C# Python
100行python代码,轻松完成贪吃蛇小游戏_c#游戏100行代码(2)
100行python代码,轻松完成贪吃蛇小游戏_c#游戏100行代码(2)
|
6月前
|
存储 程序员 C#
100行python代码,轻松完成贪吃蛇小游戏_c#游戏100行代码
100行python代码,轻松完成贪吃蛇小游戏_c#游戏100行代码
|
6月前
|
存储 C# 开发工具
22.C# 中使用变量记录玩家创建的角色名:实现与游戏角色的互动
22.C# 中使用变量记录玩家创建的角色名:实现与游戏角色的互动
58 0
|
6月前
|
定位技术 C# 图形学
Unity和C#游戏编程入门:创建迷宫小球游戏示例
Unity和C#游戏编程入门:创建迷宫小球游戏示例
152 2
C#实现的打飞机游戏(课程设计)
C#实现的打飞机游戏(课程设计)
144 1
|
存储 C# UED
C# 拼图游戏(超详细)
C# 拼图游戏(超详细)
461 0
C# 拼图游戏(超详细)
下一篇
无影云桌面