【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));
}
}
欢迎大家的评论!



浙公网安备 33010602011771号