• 【Silverlight】汉诺塔游戏,带AI


    先看效果

    完整代码在此下载/Aimeast/SLAnyHanoi.zip

    简单的把设计说明一下

    ViewModel 和 Model 的设计如下:

    用到了其中的动画效果用的是自己实现的行为(Behavior)。

    using System;
    using System.Windows;
    using System.Windows.Interactivity;
    using System.Windows.Media.Animation;
    
    namespace AnyHanoi
    {
        public class DiscFluidMoveBehavior : Behavior<FrameworkElement>
        {
            public Point Translate
            {
                get { return (Point)GetValue(TranslateProperty); }
                set { SetValue(TranslateProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for Translate.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty TranslateProperty =
                DependencyProperty.Register("Translate", typeof(Point), typeof(DiscFluidMoveBehavior), new PropertyMetadata(Translate_PropertyChangedCallback));
    
    
            private static void Translate_PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                Point p = (Point)e.NewValue;
                DiscFluidMoveBehavior b = (DiscFluidMoveBehavior)d;
                try
                {
                    b.Update(p);
                }
                catch { }
            }
    
            private void Update(Point p)
            {
                Storyboard storyboard = new Storyboard();
                DoubleAnimation x = new DoubleAnimation();
                DoubleAnimation y = new DoubleAnimation();
                x.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath("(UIElement.RenderTransform).(CompositeTransform.TranslateX)"));
                y.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath("(UIElement.RenderTransform).(CompositeTransform.TranslateY)"));
                x.Duration = this.Duration;
                y.Duration = this.Duration;
                x.To = p.X;
                y.To = p.Y;
                Storyboard.SetTarget(x, base.AssociatedObject);
                Storyboard.SetTarget(y, base.AssociatedObject);
                storyboard.Children.Add(x);
                storyboard.Children.Add(y);
                storyboard.Begin();
            }
    
            public Duration Duration
            {
                get { return (Duration)GetValue(DurationProperty); }
                set { SetValue(DurationProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for Duration.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty DurationProperty =
                DependencyProperty.Register("Duration", typeof(Duration), typeof(DiscFluidMoveBehavior), new PropertyMetadata(new Duration(TimeSpan.FromSeconds(0.1))));
        }
    }
    

    需要事先引用 Expression 的 System.Windows.Interactivity 程序集。

    把这个行为应用到每个Items。

    AI的设计如下:

    方法是递归求解。

    基本思想和标准状态的思想是一样的。把最大的盘子移动到某个目标柱子,需要找到一个暂存柱子。然后按照这一思想进行递归求解。直到剩下最后一个盘子,就可以直接移动。

    递归求解的核心代码如下

            private void RecSolve(Puzzle puzzle)
            {
                int max = 0;
                Peg maxPeg = null;
    
                //找出当前状态下最大盘子所在的柱子
                foreach (Peg peg in puzzle.PegCollection)
                {
                    if (peg.Count > 0 && max < peg.Buttom)
                    {
                        max = peg.Buttom;
                        maxPeg = peg;
                    }
                }
    
                //当前状态只有一个盘子,直接移动
                if (puzzle.PegA.Count + puzzle.PegB.Count + puzzle.PegC.Count == 1)
                {
                    if (maxPeg.PegID != puzzle.DestPeg)
                        Move(maxPeg, puzzle.GetPeg(puzzle.DestPeg));
                    return;
                }
    
                //当前状态有多个盘子
                if (maxPeg.PegID == puzzle.DestPeg) //最大的盘子就在目标柱子上,不需要移动
                {
                    RecSolve(puzzle.NewLevelPuzzle(maxPeg.PegID, puzzle.DestPeg));
                }
                else //最大的盘子不在目标柱子上,需要移动
                {
                    //找出临时柱子,即 不是 目标柱子 也不是 最大盘子所在的柱子
                    Pegs tempPagID = Pegs.A;
                    if (tempPagID == maxPeg.PegID || tempPagID == puzzle.DestPeg) tempPagID = Pegs.B;
                    if (tempPagID == maxPeg.PegID || tempPagID == puzzle.DestPeg) tempPagID = Pegs.C;
    
                    //把当前状态 去掉最大盘子以后的新状态 继续递归处理
                    //这一步把所有盘子都移动到临时柱子上
                    RecSolve(puzzle.NewLevelPuzzle(maxPeg.PegID, tempPagID));
    
                    //把当前最大盘子移动到目标柱子上
                    Move(maxPeg, puzzle.GetPeg(puzzle.DestPeg));
    
                    //把上一步处理好的状态 去掉最大的盘子以后的状态
                    //即 所有盘子都在临时柱子 的 状态移动到目标状态
                    RecSolve(puzzle.NewLevelPuzzle(puzzle.DestPeg, puzzle.DestPeg));
                }
            }

    欢迎大家的评论!

  • 相关阅读:
    <<卸甲笔记>>-基础语法对比
    <<卸甲笔记>>-Oracle线下迁移到PPAS
    How to use PEM of PPAS
    PPAS Migration Toolkit document
    PostgreSQL中数据库,表,等对象的oid与对象名的对应关系
    使用pgstatspack分析PostgreSQL数据库性能
    Postgres Plus Advanced Server installation
    Ways to access Oracle Database in PostgreSQL
    Some settings of PostgreSQL
    nginx内置变量
  • 原文地址:https://www.cnblogs.com/Aimeast/p/2003917.html
Copyright © 2020-2023  润新知