zoukankan      html  css  js  c++  java
  • 【笔记】Stanford OpenCourse—CS106A:Programming Methodology—002

    Problem solving in Karel

    Decomposition

    The Idea of an algorithm

    1. 翻山越岭的Karl

        Karl爬山,不管是百步梯还是千步梯,类似图1

    image

    图 1

    这个范例主要学习将问题分解成一个个简单的模块,化繁为简,逐步求精。

    思路:

    1> Karel来到山脚下(爬山当然要先到山边,没有自驾车,没有景区bus,没有。。。,只有2条腿;)。

    2> 开始爬山,就是上楼梯,下楼梯;

    3> 离开(爬山结束,该干嘛干嘛去,反正不能堵了山门干收费的勾当)。

    1>和3>好说,Karel够单一,认准一个方向(east)直走,碰到墙就停下。

    2>应该可以再分为3步:上山、登顶、下山。

    上山:只要前面有楼梯(墙)就上,也就是左转 –> 移动 –> 右转 –> 移动;如此循环,就登顶了。

    登顶:好不容易爬上来,会当临决定,总要做些啥,不管是插旗还是撒尿都可以表达到此一游,Karel只能放个方块表示。

    下山:应该类似上山,只要前面为空(悬崖,别抬杠),就前进 –> 右转 –> 前进 –> 左转,如此循环,直到下到山脚。

    分析到这里,似乎一切都ok,敲代码验证就完事儿了。但是,假设山是名山,修得特标准,上下都是一级级的台阶,但人就不同了,形形色色,四面八方,借问Karel一句:施主从何而来,又向何而去? Karel当然说:俺从西边来,向东边去。至于来有多近,去有多远。Karel就不操心了,按照指令走就是。这时,在看看上面的算法,似乎都ok,对应图1,下山也没问题,但要是环境变为11格,希望Karel走的更远,Karel就会撞地上了。悲催!

    所以,下山的步骤就需要修改下:前面的问题就在于Karel不晓得自己是否已下到山脚,所以下山的条件是脚下是空的才能下,

    下山:前进 –> 脚下是否为空(是 –> 右转 –> 前进 –> 左转 –> 看前面还有路否?(是 –> 前进)) 如此循环。

    代码:

    1 /*
    2 * File: MountainKarel7.java
    3 * -------------------------
    4 * The MountainKarel7 subclass gets Karel to climb a simple
    5 * mountain, plant a flag, and descend to the ground. This
    6 * version generalizes the program so that it can climb a
    7 * stair-step mountain of any size.
    8 */
    9
    10  import stanford.karel.*;
    11
    12  /* Main program */
    13
    14  public class MountainKarel7 extends SuperKarel {
    15
    16  /**
    17 * Runs the program.
    18 */
    19 public void run() {
    20 moveToWall();
    21 climbMountain();
    22 moveToWall();
    23 }
    24
    25  /**
    26 * Purports to climb up and down a stair-step mountain of
    27 * any size. This code is considerably better than the
    28 * last attempt, but still has a small bug.
    29 */
    30 private void climbMountain() {
    31 while (frontIsBlocked()) {
    32 stepUp();
    33 }
    34 putBeeper();
    35 move();
    36 while (rightIsClear()) {
    37 dropDown();
    38 }
    39 }
    40
    41  /**
    42 * Send Karel up the step ahead of it.
    43 */
    44 private void stepUp() {
    45 turnLeft();
    46 move();
    47 turnRight();
    48 move();
    49 }
    50
    51  /**
    52 * Drops down from the midair position just past a
    53 * descending step.
    54 */
    55 private void dropDown() {
    56 turnRight();
    57 move();
    58 turnLeft();
    59 if (frontIsClear()) {
    60 move();
    61 }
    62 }
    63
    64  /**
    65 * Moves Karel forward until it is blocked by a wall.
    66 */
    67 private void moveToWall() {
    68 while (frontIsClear()) {
    69 move();
    70 }
    71 }
    72 }

    2. “种树”的Karel

        春寒料峭,Stanford校园里的树都光秃秃的(啥,怎没有冬青树),Karel从西向东闲逛。路见秃树,就想把其装饰下,装饰前后的效果如图2、3.

    image

    图 2

    image

    图 3

    Karel不知道树有多高,多远。只确定有足够的方块装饰每棵树。

    算法分析:

    Karel要做的就是找到树,装饰它。

    找树简单,就好比碰到墙就停下。

    装饰树:爬树 –> 放树叶 –> 下树。

    爬树:左转 –> 只要右边有树(墙)就前进 –> 右转。

    放树叶:按图3所示放4个方块 –> 前进 –> 右转。

    放4个方块:放1个方块 –> 前进 –> 左转 (循环4次)。

    下树:类似上树,只要没碰到地就一直前进。

    代码:

    1 /*
    2 * File: BanishWinter.java
    3 * -----------------------
    4 * The BanishWinter subclass gets Karel adorn a series
    5 * of trees with a cluster of beeper leaves.
    6 */
    7
    8  import stanford.karel.*;
    9
    10  public class BanishWinter extends SuperKarel {
    11
    12  /* Main program */
    13
    14 public void run() {
    15 while (beepersInBag()) {
    16 findTree();
    17 addLeavesToTree();
    18 }
    19 moveToWall();
    20
    21 }
    22
    23  /*
    24 * Moves Karel up to the next tree.
    25 *
    26 * Programming style note: Since a tree is simply a wall,
    27 * this method can simply call moveToWall. You could
    28 * therefore replace the findTree call in the main program
    29 * with moveToWall, but the program might then be harder to
    30 * read because it violates the "tree" metaphor used at the
    31 * level of the main program.
    32 */
    33 private void findTree() {
    34 moveToWall();
    35 }
    36
    37  /*
    38 * Adorns a single tree with a cluster of leaves. The
    39 * precondition is that Karel must be immediately
    40 * west of the tree, facing east; the postcondition is
    41 * that Karel is at the bottom of the other side of the
    42 * tree, facing east.
    43 */
    44 private void addLeavesToTree() {
    45 turnLeft();
    46 climbTree();
    47 addLeaves();
    48 descendToGround();
    49 turnLeft();
    50 }
    51
    52  /*
    53 * Climbs to the top of the tree.
    54 */
    55 private void climbTree() {
    56 while (rightIsBlocked()) {
    57 move();
    58 }
    59 }
    60
    61  /*
    62 * Moves Karel back to the ground. Both the pre- and
    63 * postconditions have Karel facing south.
    64 */
    65 private void descendToGround() {
    66 moveToWall();
    67 }
    68
    69  /*
    70 * Creates the cluster of leaves at the top of a tree.
    71 * The precondition is that Karel must be facing north at
    72 * the top of the tree; the postcondition is that Karel
    73 * is still at the top, but on the other side of the
    74 * trunk, facing south.
    75 */
    76 private void addLeaves() {
    77 turnRight();
    78 createBeeperSquare();
    79 move();
    80 turnRight();
    81 }
    82
    83 /*
    84 * Moves Karel forward until it is blocked by a wall.
    85 */
    86 private void moveToWall() {
    87 while (frontIsClear()) {
    88 move();
    89 }
    90 }
    91
    92 /*
    93 * Creates a square of four beepers, leaving Karel in its
    94 * original orientation. The resulting square is positioned
    95 * ahead and to the left of Karel's starting position.
    96 */
    97 private void createBeeperSquare() {
    98 for (int i = 0; i < 4; i++) {
    99 putBeeper();
    100 move();
    101 turnLeft();
    102 }
    103 }
    104
    105 }
    106
    107

    PS:这个代码里假定只有4棵树,所以Karel的包里有20个方块,如果编辑方块的数量多于20,就会出错,因为Karel不能区别墙和树。

    3. 闯迷宫的Karel

      无它,右手法则,盲人摸象般,贴着右手的墙走,不通就左转。

    代码:

    1 public class karelMazeSolver extens SuperKarel {
    2 public void run() {
    3 while (noBeepersPresent()) {
    4 if (rightIsClear()) {
    5 turnRight();
    6 } else {
    7 while (frontIsBlocked()) {
    8 turnLeft();
    9 }
    10 }
    11 move();
    12 }
    13 }
    14 }

  • 相关阅读:
    【C】C99与C89区别以及转换方法
    【bug】warning #13200: No emms instruction before return from function
    【linux/makefile】-D_REENTRANT编译选项的作用
    【arm】arm交叉编译工具链使用说明
    【Linux】linux中的strip命令
    【Linux】nm命令中符号类型详解
    【link】illegal text-relocation in IOS platform
    【link】IOS平台下汇编函数符号链接问题
    【ffmpeg】ffserver搭建流媒体服务
    【economic】程序员外包平台
  • 原文地址:https://www.cnblogs.com/halflife/p/2065289.html
Copyright © 2011-2022 走看看