关于Karel迷宫问题的讨论

《关于Karel迷宫问题的讨论》

在如上图所示的迷宫中,Karel需要从(1,1)出发前往右上方捡拾beeper,用stanford的Karel插件在eclipse中解决这一问题

编程思路: 能向右转时向右转,在每一次移动时总是优先考虑向右行动的可能性

代码1:在大循环里只要Karel没有找到beeper,它将一直移动,如果右边是clear的,则右转前进,否则左转零次,一次到两次直至前方clear后再前进。 在这个if判断里,如果右侧是clear没有问题,如果右侧有遮挡,此时优先考虑继续沿原方向前进,再次考虑左转再前进,再次考虑退回去,优先顺序不可颠倒,否则会陷入来回走动的死循环。若颠倒则优先顺序为优先原方向,再次右转,再次退回去。而此时已知右侧有遮挡,则其实只有两个选择,继续前进和退回去,若另外一侧也是相同情况则进入死循环。 综上,我们可以知道,在else分支里应该使用turnLeft而不是turnRight

  1. import stanford.karel.*;
  2. public class mazeSolverKarel extends SuperKarel {
  3. public void run() {
  4. while (noBeepersPresent()) {
  5. if (rightIsClear()) {
  6. turnRight();
  7. move();
  8. }else {
  9. while (frontIsBlocked()) {
  10. turnLeft();
  11. }
  12.                move();
  13. }
  14. }
  15. }
  16. }

代码2:观察代码1,我们可以发现在if和else分支里均共享了move(); 为精简语句我们可以将move()语句提取出来,从而获得代码2

  1. import stanford.karel.*;
  2. public class mazeSolverKarel extends SuperKarel {
  3. public void run() {
  4. while (noBeepersPresent()) {
  5. if (rightIsClear()) {
  6. turnRight();
  7. }else {
  8. while (frontIsBlocked()) {
  9. turnLeft();
  10. }
  11. }
  12. move();
  13. }
  14. }
  15. }

代码3:观察代码2,我们可以发现if和while(frontIsBlocked)均含有类似的判断,换句话说在代码2中,if分支里我们先判断了右侧是clear然后执行了右转,在else分支中,我们已知右侧不可通行试图寻找非右侧的通路,也就是说这里的if和
while功能上有重复性,因此我们可以进一步简化代码为代码3. 在代码3中,直接让Karel右转,如果可以通行那么不进入while循环找其他路,如果不可以那么右侧一定被block了,frontIsClear可以给出反馈,则进入while循环,先左转返回原方向以试探原方向,原路不可行再左转试探左侧,依然不可行则沿原方向的反方向退出此处。如此一来,while循环就实现了if分支的作用。 从代码功能上看,代码2可以让Karel在直通路(如图中迷宫的最左侧道路)上少做转向操作但是程序内多了分支判断,代码3更为精炼但是在直通路上Karel会有多余的转向操作,从而影响到达时间。

  1. import stanford.karel.*;
  2. public class mazeSolverKarel extends SuperKarel {
  3. public void run() {
  4. while (noBeepersPresent()) {
  5. turnRight();
  6. while (frontIsBlocked()) {
  7. turnLeft();
  8. }
  9. move();
  10. }
  11. }
  12. }

总结:代码1,2,3之间的逻辑关系很明确,从实用性和可读性上推荐代码1,但是就思想性代码3远胜代码1.

    原文作者:迷宫问题
    原文地址: https://blog.csdn.net/young2203/article/details/56490661
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞