引
前段时间做了一道题,要求实现汉诺塔游戏的自动解题动画:
汉诺塔游戏应该都了解规则:
1、将盘子全部移动到塔C
2、每次只能移动一个圆盘;
3、大盘不能叠在小盘上面。
要求由用户输入盘子的数量,绘制盘子和塔,点击开始后自动解题,并以动画移动盘子的形式演示。
觉得还挺有意思的,而且在做的过程中也踩了一些坑,用了一些技巧和优化,因此记录下来。
效果:
汉诺塔解法
这道题中汉诺塔的解法本身并不是难点。
1、如果只有一个盘子,那就直接从A移动到C;
2、如果有两个盘子,那就要先把小盘子移动到B,然后大盘子移动到C,再把小盘子移动到C;
3、如果有三个盘子,那就要先把上面两个盘子移动到B(借助C的辅助),然后把底下的大盘子移动到C,然后把B上的两个盘子借助A移动到C;
……
4、如果有n个盘子,那就要先把上面n-1个盘子移动到B(借助C的辅助),然后把底下的大盘子移动到C,然后把B上的n-1盘子借助A移动到C。
综上所述,除了一个盘子的情况直接移动,其余都需要借助其他盘子的帮助,复杂情况虽然不一样,但是过程是递归不断重复的。
递归代码如下:
// 确定提交
- (void)submit {
if ([self.numberField.text isEqualToString:@""]) {
NSLog(@"未输入内容");
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"您还未输入层数!" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
}];
[alertController addAction:okAction];
[self presentViewController:alertController animated:YES completion:nil];
} else {
self.diskNumber = [self.numberField.text integerValue];
self.moveCount = 0;
[self hanoiWithDisk:self.diskNumber towers:@"A" :@"B" :@"C"];
NSLog(@">>移动了%ld次", self.moveCount);
}
}
// 移动算法
- (void)hanoiWithDisk:(NSInteger)diskNumber towers:(NSString *)towerA :(NSString *)towerB :(NSString *)towerC {
if (diskNumber == 1) {
// 只有一个盘子则直接从A塔移动到C塔
[self move:1 from:towerA to:towerC];
} else {
[self hanoiWithDisk:diskNumber-1 towers:towerA :towerC :towerB];// 递归把A塔上编号1~diskNumber-1的盘子移动到B塔,C塔辅助
[self move:diskNumber from:towerA to:towerC];// 把A塔上编号为diskNumber的盘子移动到C塔
[self hanoiWithDisk:diskNumber-1 towers:towerB :towerA :towerC];// 递归把B塔上编号1~diskNumber-1的盘子移动到C塔,A塔辅助
}
}
// 移动过程
- (void)move:(NSInteger)diskIndex from:(NSString *)fromTower to:(NSString *)toTower {
NSLog(@"第%ld次移动:把%ld号盘从%@移动到%@", ++self.moveCount, diskIndex, fromTower, toTower);
}
三层盘子时:
四层盘子时: