很多人研究汉诺塔,都是作为递归算法的案例,都是从最左侧,移动到最右侧。
对于任意状态,如何自动求解,很少有人研究。
看到一篇文章,照着做了一下。
汉诺塔杂谈(二)——汉诺塔图 - 知乎 (zhihu.com)
之前写过一个3阶,自动求解的。也是照着上面这篇文章,只不过是提前手动写好了路径,然后搜索路径。
汉诺塔
这里,参考上面的文章,用代码自动生成任意阶的汉诺塔的自动求解路径。
效果如下。
代码如下:
package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.MovieClip; import flash.display.SimpleButton; import flash.display.Sprite; import flash.events.Event; import flash.events.KeyboardEvent; import flash.events.MouseEvent; import flash.events.TextEvent; import flash.geom.Matrix; import flash.geom.Rectangle; import flash.net.FileReference; import flash.system.System; import flash.ui.Keyboard; import flash.text.TextField; import flash.utils.ByteArray; import com.adobe.images.PNGEncoder; public class HanoiGraph extends MovieClip { public var tf: TextField; public var btn1: SimpleButton; public var btn2: SimpleButton; public var btn3: SimpleButton; public var btn4: SimpleButton; private var con: Sprite; private var graph: Graph; private var path: Array; public function HanoiGraph() { // constructor code con = new Sprite(); addChildAt(con, 0); con.x = 400; con.y = 400; /* graph = new Graph(3); con.addChild(graph.print()); // trace(graph.getPath().join('\n')); */ /* var xi: Number = 0; var wi: Number = 0; var t: Number = new Date().getTime(); for (var i: int = 1; i <= 4; i++) { var g: Graph = new Graph(i); var sp: Sprite = g.print(); sp.x = xi + wi / 2 + sp.width * 0.7 / 2; wi = sp.width * 0.7; xi += sp.x; con.addChild(sp); var pt: Array = g.getPath(); var tf0: TextField = new TextField(); tf0.text = pt.join('\n'); con.addChild(tf0); tf0.x = sp.x - tf0.textWidth / 2; tf0.y = sp.y + sp.height / 3; tf0.width = tf0.textWidth; tf0.height = tf0.textHeight; } trace("用时:" + (new Date().getTime() - t) + 'ms'); */ // var node:Node = new Node("A"); // con.addChild(node.print()); //var tri: Triangle = new Triangle(); //con.addChild(tri.print()); stage.addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler); stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler); stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler); btn1.addEventListener(MouseEvent.CLICK, onClickHandler); onClickHandler(null); btn2.addEventListener(MouseEvent.CLICK, onExport1Handler); btn3.addEventListener(MouseEvent.CLICK, onExport2Handler); btn4.addEventListener(MouseEvent.CLICK, onClipBoardHandler); } private function onClipBoardHandler(e:MouseEvent):void { System.setClipboard(path.join('\n')); } private function onExport2Handler(e:MouseEvent):void { var bmp: Bitmap = drawSp(con.getChildAt(0) as Sprite); saveToLocal(bmp.bitmapData); } private function onExport1Handler(e:MouseEvent):void { var bmp: Bitmap = drawSp(con); saveToLocal(bmp.bitmapData); } private function saveToLocal(bmd: BitmapData): void { try{ var bytes: ByteArray = PNGEncoder.encode(bmd); var fs: FileReference = new FileReference(); if(fs['save'])fs['save'](bytes, 'hanoi-' + tf.text + '.png'); } catch (e: Error){ } } private function drawSp(sp: Sprite): Bitmap { var bmd: BitmapData = new BitmapData(sp.width, sp.height); var rect: Rectangle = sp.getBounds(sp); bmd.draw(sp, new Matrix(1, 0, 0, 1, -rect.x, -rect.y), null, null, null, true); var bmp: Bitmap = new Bitmap(bmd); return bmp; } private function onClickHandler(e:MouseEvent):void { var n: int = parseInt(tf.text); if (isFinite(n) && n > 0) { createN(n); } } private function createN(n: int): void { while (con.numChildren){ con.removeChildAt(0); } var t: Number = new Date().getTime(); var g: Graph = new Graph(n); var sp: Sprite = g.print(); con.addChild(sp); var pt: Array = g.getPath(); var tf: TextField = new TextField(); tf.text = pt.join('\n'); con.addChild(tf); tf.x = -tf.textWidth / 2; tf.y = sp.height / 3; tf.width = tf.textWidth; tf.height = tf.textHeight; trace("用时:" + (new Date().getTime() - t) + 'ms'); path = pt; } private function mouseUpHandler(e:MouseEvent):void { con.stopDrag(); } private function mouseDownHandler(e:MouseEvent):void { if (e.target == tf || e.target == btn1 || e.target == btn2 || e.target == btn3 || e.target == btn4){ return; } con.startDrag(); } private function mouseWheelHandler(e:MouseEvent):void { con.scaleX = con.scaleY = con.scaleX * (1 + e.delta * 0.05); } } } import flash.display.DisplayObjectContainer; import flash.display.Graphics; import flash.display.Sprite; import flash.geom.Point; import flash.text.TextField; class Graph { public var root: Triangle; public function Graph(n: int){ root = new Triangle(); for (var i: int = 1; i < n; i++){ var tri:Triangle = new Triangle(); var hrad: Triangle = root.clone().flip(); tri.head.triangle = hrad; tri.left.triangle = hrad.clone().turnRight(); tri.right.triangle = hrad.clone().turnLeft(); root = tri; } } public function print(): Sprite { return root.print(''); } public function getPath(): Array { var arr: Array = []; root.prepare(); var node: Node = root.head.leafHead(); node.walk(function(no: Node){ // trace(no.fullVale); var a:Array = []; do{ a.push(no.fullVale); }while (no = no.parent) arr.push(a.join('->')); }); return arr; } } class Triangle { public var head: Node; public var left: Node; public var right:Node; public var r: Number = 100; public var view: Sprite; public function Triangle(){ head = new Node("B"); left = new Node("A"); right = new Node("C"); turnLeft(); // 和之前手写的一致 view = new Sprite(); } public function clone(): Triangle { var tri:Triangle = new Triangle(); tri.head = head.clone(); tri.left = left.clone(); tri.right = right.clone(); return tri; } public function flip(): Triangle { var t: Node = right; right = left; left = t; head.flip(); right.flip(); left.flip(); return this; } public function turnRight(): Triangle { var t: Node = head; head = left; left = right; right = t; head.turnRight(); left.turnRight(); right.turnRight(); return this; } public function turnLeft(): Triangle { var t: Node = head; head = right; right = left; left = t; head.turnLeft(); left.turnLeft(); right.turnLeft(); return this; } public function prepare(pre: String = ''): void { head.prepare(pre); left.prepare(pre); right.prepare(pre); head.leafLeft().left = left.leafHead(); head.leafRight().right = right.leafHead(); // } public function print(pre: String = ''):Sprite { var sp: Sprite = view; var spHead: Sprite = head.print(pre); var spLeft: Sprite = left.print(pre); var spRight: Sprite = right.print(pre); sp.addChild(spHead); sp.addChild(spLeft); sp.addChild(spRight); var r0: Number = left.r; r = r0 * 2; var a0: Number = r0 * Math.sqrt(3); spHead.x = 0; spHead.y = -r; spLeft.x = -a0; spLeft.y = r0; spRight.x = a0; spRight.y = r0; if (!head.triangle){ sp.graphics.lineStyle(1, 0.000000, 1.0); sp.graphics.moveTo(head.view.x, head.view.y); sp.graphics.lineTo(left.view.x, left.view.y); sp.graphics.lineTo(right.view.x, right.view.y); sp.graphics.lineTo(head.view.x, head.view.y); } else { var pArr: Array = [ head.leafLeft().view, left.leafHead().view, head.leafRight().view, right.leafHead().view, left.leafRight().view, right.leafLeft().view ]; sp.graphics.lineStyle(1, 0.000000, 1.0); for (var i: int = 0; i < pArr.length; i += 2){ var p0: Point = toLocal(pArr[i]); var p1: Point = toLocal(pArr[i + 1]); sp.graphics.moveTo(p0.x, p0.y); sp.graphics.lineTo(p1.x, p1.y); } } return sp; } private function toLocal(sp: Sprite): Point{ var p:Point = new Point(); while (sp != view){ p.x += sp.x; p.y += sp.y; sp = sp.parent as Sprite; } return p; } } class Node { public var value: String; public var triangle: Triangle; public var r: Number = 50; public var view: Sprite; public var fullVale: String = ''; public var parent: Node; private var _left:Node; private var _right: Node; public function Node(v: String){ value = v; view = new Sprite(); } public function get left(): Node { return this._left; } public function set left(no: Node): void { this._left = no; no.parent = this; } public function get right(): Node { return this._right; } public function set right(no: Node): void { this._right = no; no.parent = this; } public function clone(): Node { var no: Node = new Node(value); if (triangle) { no.triangle = triangle.clone(); } return no; } public function flip():void { if (triangle){ triangle.flip(); } } public function turnRight():void { if (triangle){ triangle.turnRight(); } } public function turnLeft():void { if (triangle){ triangle.turnLeft(); } } public function prepare(pre: String): void { fullVale = pre + value; if (triangle) { triangle.prepare(fullVale); } } public function walk(callback: Function): void { if (!left && !right){ callback(this); } else { if (left){ left.walk(callback); } if (right) { right.walk(callback); } } } public function print(pre: String = ''): Sprite { var sp: Sprite = view; if (triangle) { var spTri: Sprite = triangle.print(pre + value); sp.addChild(spTri); r = triangle.r; } else { var tf:TextField = new TextField(); sp.addChild(tf); tf.text = pre + value; tf.x = -tf.textWidth / 2; tf.y = -tf.textHeight / 2; r = tf.textWidth * 0.8; sp.graphics.lineStyle(1, 0x000000, 1.0); sp.graphics.beginFill(0xfffffff, 1.0); sp.graphics.drawCircle(0, 0, r); sp.graphics.endFill(); } return sp; } public function leafHead(): Node { if (!triangle) { return this; } return triangle.head.leafHead(); } public function leafLeft(): Node { if (!triangle) { return this; } return triangle.left.leafLeft(); } public function leafRight(): Node { if (!triangle) { return this; } return triangle.right.leafRight(); } }
算法写的不太好,功能实现了,比较慢,多了太卡。
欢迎大神分享好的算法。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。