做了个汉诺塔小游戏。
加上了自动求解。
大多数讲汉诺塔,都是作为递归算法的经典案例来讲。
自动求解,也都是从最初状态到目标状态。
对于任意初始状态的汉诺塔,如何求解,很少有人讲。
知乎上发现一个大神,写的很详细。有兴趣可以拜读一下。
汉诺塔杂谈(二)——汉诺塔图 - 知乎 (zhihu.com)
为了防止上面的链接不能用,下载了一个pdf版的:pdf版 。
效果如下:
代码:
package {
import flash.display.MovieClip;
import flash.display.SimpleButton;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
public class Hanoi extends MovieClip {
public var mc1: MovieClip;
public var mc2: MovieClip;
public var mc3: MovieClip;
public var mc4: MovieClip;
public var mc5: MovieClip;
public var mc6: MovieClip;
public var overMc: MovieClip;
public var btn1: SimpleButton;
public var btn2: SimpleButton;
private var stack1: Array = [];
private var stack2: Array = [];
private var stack3: Array = [];
private var poles: Array = [];
private var tweenMc: Object = null;
private var stacks: Array = [];
private var mcs: Array = [];
public function Hanoi() {
// constructor code
stage?initStage(null): addEventListener(Event.ADDED_TO_STAGE, initStage);
overMc.visible = false;
overMc.btn.addEventListener(MouseEvent.CLICK, onRestart);
btn1.addEventListener(MouseEvent.CLICK, onRestart);
btn2.addEventListener(MouseEvent.CLICK, onAutoPlay);
}
private function initStage(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, initStage);
drag(mc1);
drag(mc2);
drag(mc3);
mc1.id = 1;
mc2.id = 2;
mc3.id = 3;
onRestart(null);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e:Event):void
{
if (tweenMc) {
tweenMc.t += 1 / stage.frameRate;
var per: Number = Math.min(1.0, tweenMc.t / tweenMc.duration);
tweenMc.x = tweenMc.ox + Math.min(per * 5, 1.0) * (tweenMc.tx - tweenMc.ox);
tweenMc.y = tweenMc.oy + per * (tweenMc.ty - tweenMc.oy);
if (per == 1) {
var cb: Function = tweenMc.complete;
tweenMc = null;
cb();
}
}
}
private function onRestart(e:MouseEvent):void
{
if (tweenMc || curSp) {
return;
}
overMc.visible = false;
stack1 = [mc1, mc2, mc3];
stack2 = [];
stack3 = [];
poles = [mc4, mc5, mc6];
mc1.stack = stack1;
mc2.stack = stack1;
mc3.stack = stack1;
mc1.pole = mc4;
mc2.pole = mc4;
mc3.pole = mc4;
mc4.stack = stack1;
mc5.stack = stack2;
mc6.stack = stack3;
stacks = [stack1, stack2, stack3];
mcs = [mc1, mc2, mc3];
for (var i: int = 0; i < stack1.length; i++) {
stack1[i].x = mc4.x;
stack1[i].y = getPosY(i);
}
}
private function onAutoPlay(e:MouseEvent): void {
if (!tweenMc && !curSp && !overMc.visible) {
autoPlay();
}
}
private function getPosY(i: int): Number {
return 290 - i * 20;
}
private function canDrag(mc: MovieClip): Boolean {
return !tweenMc && !curSp && (onTop(stack1, mc) || onTop(stack2, mc) || onTop(stack3, mc));
}
private function onTop(stack: Array, mc: MovieClip): Boolean {
return mc == getTop(stack);
}
private function getTop(stack: Array): MovieClip {
return stack[stack.length - 1];
}
private function dragEnd(mc: MovieClip): void {
for (var i: int = 0; i < poles.length; i++ ) {
var pole: MovieClip = poles[i];
if (canPut(mc, pole)) {
put(mc, pole);
return;
}
}
put(mc, mc.pole);
}
private function canPut(mc: MovieClip, pole: MovieClip): Boolean {
if (checkHit(mc, pole)) {
var tp: MovieClip = getTop(pole.stack);
return !tp || tp == mc || tp.id < mc.id;
}
return false;
}
private function checkHit(mc: MovieClip, pole: MovieClip): Boolean {
return mc.hitTestObject(pole);
}
private function put(mc: MovieClip, pole: MovieClip): void {
mc.stack.pop();
mc.stack = pole.stack;
mc.stack.push(mc);
mc.pole = pole;
tweenTo(mc, pole.x, getPosY(mc.stack.length - 1), 0.3, checkWin);
}
private function tweenTo(mc: MovieClip, x: Number, y: Number, duration: Number, cb: Function): void {
// mc.x = x;
tweenMc = mc;
tweenMc.ox = mc.x;
tweenMc.oy = mc.y;
tweenMc.tx = x;
tweenMc.ty = y;
tweenMc.t = 0;
tweenMc.duration = duration;
tweenMc.complete = cb;
}
private function checkWin(): void {
if (isWin()) {
overMc.visible = true;
}
}
private function isWin(): Boolean {
return stack3.length == 3;
}
//-----------------------------
private var curSp:MovieClip;
private var draged:Boolean = false;
private function drag(sp:Sprite):void
{
sp.buttonMode = true;
sp.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
}
private function mouseDownHandler(e:MouseEvent):void
{
if (!canDrag(e.currentTarget as MovieClip)) {
return;
}
curSp = e.currentTarget as MovieClip;
curSp.startDrag();
addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
stage.addEventListener(Event.MOUSE_LEAVE, mouseUpHandler);
}
private function mouseUpHandler(e:MouseEvent):void
{
dragEnd(curSp);
curSp.stopDrag();
curSp = null;
removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
stage.removeEventListener(Event.MOUSE_LEAVE, mouseUpHandler);
}
private function mouseMoveHandler(e:MouseEvent):void
{
//
draged = true;
}
//----------------------------------
private function autoPlay(): void {
var s: String = getCurState();
var p: Array = findPath(s);
trace('-------------auto play-----------------');
trace('current state:', s);
trace('path:', p.join('->'));
step(p, 0);
}
private function step(p: Array, n: int): void {
if (n == p.length - 1) {
overMc.visible = true;
return;
}
var st: Array = getStep(p[n], p[n + 1]);
doStep(st[0], st[1], function() {
step(p, n + 1);
});
}
private function getStep(s1: String, s2: String): Array {
trace(s1, s2);
for (var i: int = 0; i < s1.length; i++) {
var c1: String = s1.charAt(i);
var c2: String = s2.charAt(i);
if (c1 != c2) {
return ['ABC'.indexOf(c1), 'ABC'.indexOf(c2)];
}
}
return null;
}
private function doStep(a: int, b: int, cb: Function): void {
var mc: MovieClip = stacks[a].pop();
stacks[b].push(mc);
var pole: MovieClip = poles[b];
tweenTo2(mc, pole.x, getPosY(stacks[b].length - 1), 3, cb);
}
private function tweenTo2(mc: MovieClip, x: Number, y: Number, duration: Number, cb: Function): void {
tweenTo(mc, mc.x, 30, duration / 3, function(){
tweenTo(mc, x, 30, duration / 3, function(){
tweenTo(mc, x, y, duration / 3, cb);
});
});
}
private function findPath(s: String): Array {
for (var i: int = 0; i < paths.length; i++) {
var p: Array = paths[i];
for (var j: int = 0; j < p.length; j++) {
if (s == p[j]) {
return p.slice(j);
}
}
}
return null;
}
private var paths: Array = [
['BBB', 'BBC', 'BAC', 'BAA', 'CAA', 'CAB', 'CCB', 'CCC'],
['AAA', 'AAC', 'ABC', 'ABB', 'CBB', 'CBA', 'CCA', 'CCC'],
['BCC', 'BCB', 'BAB', 'BAA', 'CAA', 'CAB', 'CCB', 'CCC'],
['ACC', 'ACA', 'ABA', 'ABB', 'CBB', 'CBA', 'CCA', 'CCC'],
['CAC', 'CAB', 'CCB', 'CCC'],
['CBC', 'CBA', 'CCA', 'CCC'],
['BBA', 'BBC', 'BAC', 'BAA', 'CAA', 'CAB', 'CCB', 'CCC'],
['BCA', 'BCB', 'BAB', 'BAA', 'CAA', 'CAB', 'CCB', 'CCC'],
['ACB', 'ACA', 'ABA', 'ABB', 'CBB', 'CBA', 'CCA', 'CCC'],
['AAB', 'AAC', 'ABC', 'ABB', 'CBB', 'CBA', 'CCA', 'CCC']
];
private var tree: Array = [
'CCC', [
'CCB', [
'CAB', [
'CAC', null,
'CAA', [
'BAA', [
'BAB', [
'BCB', [
'BCA', null,
'BCC', null
]
],
'BAC', [
'BBC', [
'BBB', null,
'BBA', null
]
]
]
]
]
],
'CCA', [
'CBA', [
'CBC', null,
'CBB', [
'ABB', [
'ABA', [
'ACA', [
'ACC', null,
'ACB', null
]
],
'ABC', [
'AAC', [
'AAB', null,
'AAA', null
]
]
]
]
]
]
]
];
private function getCurState(): String {
var a: Array = [];
for (var i: int = 0; i < mcs.length; i++) {
for (var j: int = 0; j < stacks.length; j++){
if (stacks[j].indexOf(mcs[i]) != -1){
a[i] = 'ABC'.charAt(j);
break;
}
}
}
return a.join('');
}
}
}
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。