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


    [索引页]
    [源码下载]


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



    作者:webabcd


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


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


    在线DEMO
    Get Microsoft Silverlight


    思路
    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;
            }


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

            private List<CardPoint> GetYPositions(CardPoint p)
            
    {
                var result 
    = new List<CardPoint>() { p };
                
    for (int i = 0; i < Global.ContainerRows; i++)
                
    {
                    var point 
    = new CardPoint(i * Global.ContainerColumns + p.X);
                    
    if (_cards[point.Position].ImageName == Global.EmptyImageName)
                        result.Add(point);
                }


                
    return result;
            }


            
    /// <summary>
            
    /// 执行消去两个卡片的任务
            
    /// 参数为:两个卡片对象和消去路径的四个点(此四个点需按路径方向依次传入)
            
    /// </summary>

            private void RemoveCard(CardModel c1, CardModel c2, CardPoint p1, CardPoint p2, CardPoint p3, CardPoint p4)
            
    {
                _cards[c1.Position] 
    = new CardModel(Global.EmptyImageName, c1.Position);
                _cards[c2.Position] 
    = new CardModel(Global.EmptyImageName, c2.Position);

                Points.Clear();
                Points.Add(CardPoint2Point(p1));
                Points.Add(CardPoint2Point(p2));
                Points.Add(CardPoint2Point(p3));
                Points.Add(CardPoint2Point(p4));

                Thread thread 
    = new Thread
                (
                    x 
    =>
                    
    {
                        Thread.Sleep(
    100);

                        _syncContext.Post
                        (
                            y 
    =>
                            
    {
                                Points.Clear();
                            }
    ,
                            
    null
                        );
                    }

                );
                thread.Start();
            }


            
    /// <summary>
            
    /// CardPoint 转换成坐标位置 Point
            
    /// </summary>

            private Point CardPoint2Point(CardPoint cardPoint)
            
    {
                
    // 38 - 每个正方形卡片的边长
                
    // 19 - 边长 / 2
                
    // cardPoint.X * 2 - 卡片的 Padding 为 1 ,所以卡片间的间距为 2
                var x = cardPoint.X * 38 + 19 + cardPoint.X * 2;
                var y 
    = cardPoint.Y * 38 + 19 + cardPoint.Y * 2;

                
    return new Point(x, y);
            }


            
    /// <summary>
            
    /// 检查当前是否仍然有可消除的卡片
            
    /// </summary>

            public bool IsActive()
            
    {
                var currentCards 
    = _cards.Where(p => p.ImageName != Global.EmptyImageName).ToList();

                
    for (int i = 0; i < currentCards.Count() - 1; i++)
                
    {
                    
    for (int j = i + 1; j < currentCards.Count(); j++)
                    
    {
                        
    if (Match(currentCards[i], currentCards[j], false))
                            
    return true;
                    }

                }


                
    return false;
            }


            
    /// <summary>
            
    /// 重新排列当前卡片集合
            
    /// 并保证有可消卡片
            
    /// </summary>

            public void Replace()
            
    {
                Random r 
    = new Random();
                var currentCards 
    = _cards.Where(p => p.ImageName != Global.EmptyImageName).ToList();
                var count 
    = currentCards.Count;
                
    if (count == 0)
                    
    return;

                var targetImageNames 
    = currentCards.Select(p => p.ImageName).ToList();
                var targetPositions 
    = currentCards.Select(p => p.Position).ToList();

                
    for (int i = 0; i < count; i++)
                
    {
                    var index 
    = r.Next(0, count - i);

                    var targetImageName 
    = targetImageNames.Skip(index).First();
                    var targetPosition 
    = targetPositions.Skip(i).First();

                    _cards[targetPosition] 
    = new CardModel(targetImageName, targetPosition);
                    targetImageNames.RemoveAt(index);
                }


                
    while (!IsActive())
                
    {
                    Replace();
                }

            }


            
    /// <summary>
            
    /// 清除卡片集合
            
    /// </summary>

            public void Clear()
            
    {
                _cards.Clear();
                Points.Clear();
            }


            
    /// <summary>
            
    /// 当前卡片数量
            
    /// </summary>

            public int CardCount
            
    {
                
    get return _cards.Where(p => p.ImageName != Global.EmptyImageName).Count(); }
            }


            
    /// <summary>
            
    /// 连连看的卡片集合
            
    /// </summary>

            public ObservableCollection<CardModel> Cards
            
    {
                
    get return _cards; }
            }


            
    private PointCollection _points;
            
    /// <summary>
            
    /// 可消两卡片的连接路径上的 4 个点的集合
            
    /// </summary>

            public PointCollection Points
            
    {
                
    get
                
    {
                    
    if (_points == null)
                        _points 
    = new PointCollection();

                    
    return _points;
                }

                
    set
                
    {
                    _points 
    = value;
                    
    if (PropertyChanged != null)
                        PropertyChanged(
    thisnew PropertyChangedEventArgs("Points"));
                }

            }


            
    public event PropertyChangedEventHandler PropertyChanged;
        }

    }




    OK
    [源码下载]

  • 相关阅读:
    黄聪:让wordpress模板完全整合google AdSense搜索广告
    黄聪:如何用SQL Server内置的存储过程模板对数据库进行备份和恢复
    git使用安装实战
    Redis持久化之大数据服务暂停问题
    redis的那些事
    centos上安装git
    拿什么守护你PHP程序级守护进程的实现与优化
    redis学习资料链接地址汇总
    redis搭建实战记录
    zeromq_传说中最快的消息队列
  • 原文地址:https://www.cnblogs.com/webabcd/p/1436926.html
Copyright © 2020-2023  润新知