【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));
            }
        }

 

欢迎大家的评论!

posted @ 2011-04-02 22:27  Aimeast  阅读(2426)  评论(13编辑  收藏  举报