07
2023
03

汉诺塔

做了个汉诺塔小游戏。

加上了自动求解。

大多数讲汉诺塔,都是作为递归算法的经典案例来讲。

自动求解,也都是从最初状态到目标状态。

对于任意初始状态的汉诺塔,如何求解,很少有人讲。

知乎上发现一个大神,写的很详细。有兴趣可以拜读一下。

汉诺塔杂谈(二)——汉诺塔图 - 知乎 (zhihu.com)

为了防止上面的链接不能用,下载了一个pdf版的:pdf版 。


效果如下:

获得 Adobe Flash Player


代码:

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('');
  }
  
 }
 
}

   


源码打包下载

« 上一篇下一篇 »

相关文章:

汉诺塔自动求解  (2023-3-15 9:1:50)

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。