<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>1000copy</title>
    <description></description>
    <link>http://1000copy.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>[翻译]Program Development by stepwise refinement</title>
        <author>1000copy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://1000copy.javaeye.com">1000copy</a>&nbsp;
          链接：<a href="http://1000copy.javaeye.com/blog/206900" style="color:red;">http://1000copy.javaeye.com/blog/206900</a>&nbsp;
          发表时间: 2008年06月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;</p>
<h1 id="vvk-">&nbsp;</h1>
<h1 id="tp:s">翻译记录&nbsp;</h1>
<div id="nxmr">结构化编程的三大巨头，每个人都有论文，为什么在网上简直连中文版本都找不到？ </div>
<div id="y1vz">学编程的人都知道Edsger Dijkstra关于结构化编程、Nicholas Wirth关于逐步求精、David Parnas关于模块化设计</div>
<div id="aizs">那么这些巨头的原文是怎样的？既然没有中文版，我要自己翻译。</div>
<div id="afyi">&nbsp;</div>
<div id="bf9s">先找到Nicholas Wirth的论文，在acm的论文原件看到号称为209篇论文引用，其中引用它的还有Donald K的论文，可见它的价值。 </div>
<div id="w_:f"><a href="http://portal.acm.org/citation.cfm?id=362575.362577" id="u-lf">http://portal.acm.org/citation.cfm?id=362575.362577</a>
 </div>
<div id="ikis">&nbsp;</div>
<div id="ah2v">2008年3月17日&nbsp; 决定翻译</div>
<div id="wbop">2008年3月21日 初译完毕 逐字逐句的翻译</div>
<div id="pc6s">2008年3月21日 第二轮开始，表达意思，连贯性，确认表意正确的，就删除原文。</div>
<div id="thnl">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 原来&ldquo;[<em id="a7wt">x</em>
<span>1</span>
], [<em id="g:v6">x</em>
<span>1</span>
, <em id="cysp">x</em>
<span>2</span>
], [<em id="fz13">x</em>
<span>1</span>
, <em id="on:t">x</em>
<span>2</span>
, &middot;&middot;&middot; , <em id="qso5">x</em>
<span>n</span>
] &rdquo;半懂不懂的，现在懂了。第3节最后一个方法也明白了，书读百遍其义自见。</div>
<div id="nuw4">2008年3月21日23:45:45 这个老<em id="wh4i">Niklaus Wirth</em>
 ，废话挺多，等我翻译完后，写了程序，用口语说说，看看能砍掉多少废话？</div>
<div id="u6g7">2008年3月22日0:42:32&nbsp; 译注6我也是推测了很久的，其中反正我做了注的都是花费了些时间才琢磨出来的。相应的，后面的3个过程也就明白了。</div>
<div id="okc0">2008年3月22日0:55:41&nbsp; x[j]替换为i也明白了。该继续第5节了，过瘾。</div>
<div id="utnx"><br id="divg" />
<a href="http://www.cs.unca.edu/turing/cgi-bin/htimage/classics/banner.map" id="c95t">&nbsp;</a>
</div>
<div id="xjap"><strong id="ii:o"><span style="font-size: medium;">通过逐步求精编程</span>
</strong>
 </div>
<div id="cavu">&nbsp;</div>
<div id="mtfe"><em id="nz.l">Niklaus Wirth</em>
 </div>
<div id="a3ob">翻译：1000copy</div>
<p id="yphy">&nbsp;</p>
<p id="n1t2">创造性的编程活动-区别于编码-通常通过例子来展示某些技术。本文认为编程是一系列的关于分解任务到子任务，分解数据到数据结构的设计决定构成。对功能规格的细化过程将会通过简短但是不平凡的例子证明出来。 
</p>
<p id="wu:t">关键字：编程教育 编程技术 逐步编程构建。 
</p>
<hr id="j4oe" />
<h3 id="aics">1. 介绍 </h3>
<p id="hkra">&nbsp;编程这门技术通常通过例子来教授。编程课程是否成功往往取决于选择例子是否恰当。不幸的是，大部分人选择例子去说明计算机可
以做什么。与此相反，选择例子的主要标准应该是通过这些例子可以表达技术的应用方法。事实上，现在很多例子是首先被完成，成为一个成品，然后去解释它的目
的，以及语言的细节。但是活跃的编程应该包括设计新程序，而不是对这老程序去思考。这样的教学方法的结果会给学生获得一个印象：编程主要就是掌握一门语言
（所有的特殊性和复杂性,然后依赖自己的直觉，把自己的想法变成一个程序。非常清晰的是，编程的课程，应该去教授设计和构造的方法，例子的选择也可以演示
这个循序渐进的过程。 </p>
<p id="p29b">这个论文通过一个例子去表达我的两个目的。一些著名的技术将会被演示和传达，包括<em id="b3wy">策略的预选，逐步求精的试探方案，引入辅助数据，递归，</em>
而程序通过一系列的细化步骤被阶段的开发出来。 
</p>
<p id="mmyf">&nbsp;</p>
<p id="vga7">在每一步中，程序的一个或几个指令被分解成更详细的指令。这接二连三的分解或细化规格一直进行，直到所有的指令都被表达到计算
机语言或编程语言；执行此一程序的结果通过数据体现出来，这些数据，可能有必要引入进一步的分解，以便在子任务和指令之间实施数据沟通；这样，由于任务逐
步的细化，因此数据可能要加以细化，分解，结构化去实现设计决策。这样我们就可以得出非常自然的结论：<em id="knm5">程序的细化和数据的细化是同步进行的</em>
 。 
</p>
<p id="eo46">&nbsp;</p>
<p id="x4hp">每一次细化求精都意味着一些设计的决策。至关重要的是：这些决策需要明确制定，并且程序员知道做出这个决策下面的选择
标准和可选的其他解决方法。给定问题的可能解决方法就是一个树的叶子，每一个叶子都表达了审议和决定的一个结果。一个子树可以被认为是一组共同特征和结构
的解决方案集合。引入解决方案树的概念，是为了在一个程序的目标和环境发生改变的时候，程序需要调整时是有意义的。 </p>
<p id="p.uu">&nbsp;</p>
<p id="vl60">&nbsp;</p>
<p id="lbys">逐步求精的一个指导原则是，尽可能的分解决策，分开表面上看起来有相关性的，对于涉及细节比较多的表达，应该尽可能的
推迟决策。不同的环境（计算机或者语言），需要不同的表达。（译注1：比如11,在16进制为0xB,在二进制是..,,这些都太具体了，和解决问题本身
关系不大，就尽可能的把设计决策向后推）。 </p>
<p id="g:nn">选择的例子将会在第三节开始确定，在正式的阅读论文前，我强烈建议读者自己先去寻求问题的解决，论文的方案仅仅是众多的解法之一。 
</p>
<hr id="numf" />
<p id="k274">&nbsp;</p>
<p id="fit6">2. 符号 
</p>
<p id="a0p.">&nbsp;为了描述程序，这篇论文使用一个略微增强的Algol 60 符号体系。为了更好的表达语句的重复执行，而不必通过标签和跳转那么麻烦，采用这样的格式的记号：</p>
<pre><strong id="zg87">  repeat</strong>
 (statement sequence)  <br id="ej91" />
<strong id="qhr3">  until</strong>
 (boolean expression)</pre>
<p id="uvyy">含义是一直执行&nbsp;statement sequence，直到boolean expression为true。 
</p>
<p id="d1k9">&nbsp;</p>
<hr id="wso2" />
<h3 id="mf37"><a name="3" id="bb73">3.</a>
 八王后问题和解法</h3>
<p id="het.">&nbsp;</p>
<p id="rmo_">&nbsp;给定一个8X8的棋盘和8个彼此敌对的王后。为每个王后找到一个位置，以便任何一个王后都不会被另一个王后干掉（这意味着，
在棋盘上的每一行，每一列，每个对角线都只能有一个王后）。这个问题比较典型，典型在于这类问题预先并不知道解决方法&nbsp;，而必须通过试错去寻求方法。</p>
<p id="p5b7">通常，存在一个可能解的集合A，它满足条件P而被选择出来。解可以表达为X，这样就有一个方程为&nbsp;&quot;从集合Ａ中找到Ｘ，Ｘ满足 p(x)&quot;（译注2：这不是前文提及的Ａｌｇｏｌ６０的记号体系的内容，而是集合里面的符号）找出解的程序是：</p>
<pre><strong id="qdtl">repeat</strong>
 Generate the next element of <em id="nm_i">A</em>
 and call it <em id="tb8w">x</em>

<br id="d40y" />
<strong id="iek:">until</strong>
 <em id="iud-">p</em>
(<em id="mo6t">x</em>
) V (no more elements in <em id="v131">A</em>
);<br id="lni4" />
<br id="lgfs" />
<strong id="sa:a">if</strong>
 <em id="l.vj">p</em>
(<em id="e0rh">x</em>
) <strong id="zo6y">then</strong>
 <em id="ic43">x</em>
 = solution</pre>
<p id="jw0c">&nbsp;</p>
<p id="bfpe">这一类问题的困难程度往往和集合Ａ的大小有关，因为问题需要对可能符合条件的解进行穷举，因此必须考虑效率。本例内，
棋盘布局共有&nbsp;64!/(56! X 8!) = 2^32
个，假设每个解的产生和验证需要１００ｍｓ，那么粗略估计找到解的时间需要７个小时。因此找到一个捷径是必要的，通过这个捷径清除明显不符合的解。<em id="b.40">策略的预选可以表达为　把条件Ｐ分解为条件Ｑ　和条件Ｒ，让Ｂ是Ｘ的集合，并且Ｘ属于Ａ，且满足条件Ｒ（ｘ）。（译注3：都是集合代数内的符号，好不容易看懂了）。</em>
<span style="color: #0000ff;">.&nbsp;显然Ｂ是Ａ的子集</span>
 。</p>
<p id="p.v0">现在不必考虑从集合Ａ中选择，而只要考虑集合Ｂ内的元素被生成和测试，测试的条件是Ｑ，而不是Ｐ，这样就满足如下的需求：</p>
<p id="hqrz">　　１．集合Ｂ比集合Ａ小 
</p>
<p id="f4z4">　　２。集合Ｂ的元素容易生成</p>
<p id="f5.s">　　３．条件Ｑ比条件Ｐ更容易验证</p>
<p id="le1-">相应的问题变成：</p>
<p id="qelr"><strong id="vjmc">repeat</strong>
 Generate the next element of B and call it <em id="cary">x</em>
<br id="mqdi" />
<strong id="paxf">until</strong>
 <em id="g0h9">q</em>
(<em id="ivdp">x</em>
) V&nbsp; (no more elements in <em id="ecl3">B</em>
);<br id="dtrw" />
<strong id="erz-">if</strong>
 <em id="w_un">q</em>
(<em id="p4so">x</em>
) <strong id="dbdn">then</strong>
 <em id="iffv">x</em>
 = solution<br id="dj25" />
&nbsp;</p>
<p id="s6pw">&nbsp;</p>
<p id="or8k">在八皇后问题中，一个比较恰当的条件R是&ldquo;棋盘上每一列必然只能有一个王后&rdquo;。条件Q仅仅限定每一行每一个对角线最多
只有一个王后。和条件P相比，条件Q更加容易验证。集合B（要求每列一个王后）仅仅有8^8 = 2^24
个元素。集合B可以通过王后在限定列上的移动来产生。这样以上所有条件都可以达到满足。 </p>
<p id="p:87">&nbsp;</p>
<p id="rq6e">&nbsp;</p>
<p id="ibid">在此假定验证一个潜在的解需要100ms，那么找到一个解将会花费100ms。如果有专用的强大的计算机，那么做完这
次优化就足够去提交程序运行了。如果运气不好，需要排队和他人共享计算机（按每秒一个解验证来计算，需要280小时），就需要继续花费时间去寻找更进一步
的捷径。</p>
<p id="a3mj">另外一个解决方法如下：把试验解x表达为 {<em id="ra75">x</em>
<span>1</span>
, <em id="iz0l">x</em>
<span>2</span>
, &middot;&middot;&middot; , <em id="oun5">x</em>
<span>n</span>
}的形式，这样每一个试验解都可以通过 [<em id="xhsr">x</em>
<span>1</span>
], [<em id="xwhu">x</em>
<span>1</span>
, <em id="uq_n">x</em>
<span>2</span>
], [<em id="ltok">x</em>
<span>1</span>
, <em id="rb9v">x</em>
<span>2</span>
, &middot;&middot;&middot; , <em id="j63j">x</em>
<span>n</span>
] 的相应步骤而得到。分解是这样的：</p>
<p id="gqak">1. 每一个步骤[<em id="peaj">x</em>
<span>1</span>
], [<em id="uabh">x</em>
<span>1</span>
, <em id="cb-p">x</em>
<span>2</span>
], [<em id="a8xd">x</em>
<span>1</span>
, <em id="leso">x</em>
<span>2</span>
, &middot;&middot;&middot; , <em id="h0vk">x</em>
<span>n</span>
] 都要比得到整个X([<em id="wb72">x</em>
<span>1</span>
, <em id="d16h">x</em>
<span>2</span>
, &middot;&middot;&middot; , <em id="rwf0">x</em>
<span>n</span>
] )更加简单</p>
<p id="pts6">2. 在j&lt;n的情况下 ,那么条件Q（Xj）是Q(<em id="so_.">X</em>
) 的子集</p>
<p id="r_1o">&nbsp;</p>
<p id="rpz2">如果前面的步骤就不再满足条件，那么这个步骤的后续步骤就不必再继续了。（译注4：比如验证到第三个王后的时候，就已经不能满
足条件Q的化，那么继续试探第四个王后的位置就不在必要了），反过来说，一个部分符合条件Q的试验解也不一定可以推演出完整的解来。（译注4：比如验证到
第三个王后的时候，还是满足条件Q的，这不意味着继续推演到第8个王后也一定可以放到棋盘上）。&nbsp;试验解的逐步构造方法因此需求当试验解在第j步失败时，
就停止继续试探，然后重新尝试其他可能。这个技术被称为<em id="wz1.">回溯，</em>
程序代码如下：</p>
<p id="b210">&nbsp; <em id="saxo">j</em>
 := 1;<br id="lyt_" />
<strong id="rvm7">&nbsp; repeat</strong>
 trystep <em id="axty">j</em>
;<br id="vjfg" />
&nbsp;&nbsp; <strong id="fpp:">if</strong>
 successful <strong id="r4.l">then</strong>
 advance <strong id="eers">else</strong>
 regress<br id="k_:s" />
<strong id="wtkx">&nbsp; until</strong>
 (<em id="vn0e">j</em>
 &lt; 1) V (<em id="oc2c">j</em>
 &gt; <em id="h539">n</em>
)</p>
<p id="fef2">&nbsp;</p>
<p id="pebg">&nbsp;在8王后的例子中，
通过从第一列开始，逐列的放置王后的方法可以找到一个解。显然，如果部分配置都不能满足王后间互不侵犯的条件，那么由这个部分配置继续向下搜索就不可能找
到一个解。因此，在第j步，只要考虑验证第j个王后是否满足互不侵犯的条件。仅仅判断第j步是否安全，和判断整个棋盘上的王后是否安全相比更加容易进行，
因此整个条件可以分解为第j步，在第j列为王后找到一个安全的位置。 </p>
<p id="q8ou">&nbsp;</p>
<p id="p-dw">程序将随后根据这个方法开发出来。通过验证876次棋盘布局找到一个完整的解。再次假设每次验证需要1秒，这个解法将会需要15分钟，如果每一步需要100ms，那么将会耗时0.9s。 
</p>
<hr id="q_xe" />
<h3 id="jfi1"><a name="4" id="eu_l">4</a>
. 程序开发</h3>
<p id="foh7">通过逐步求精的方法，我们产生问题的第一个版本的解法：</p>
<pre><strong id="szir">variable</strong>
 <em id="i3_0">board, pointer,  safe</em>
;<br id="lni40" />
<br id="jmkf" />
<em id="ql6c">considerfirstcolumn</em>
;<br id="lni41" />
<br id="k.el" />
<strong id="mq.s">repeat</strong>
 <em id="mnpw">trycolunm</em>
;<br id="lni42" />
<br id="ihpr" />
   <strong id="j1yj">if</strong>
 <em id="wlmh">safe</em>
 <strong id="u57d">then</strong>

<br id="mb3r" />
   <strong id="xk.:">begin</strong>
 <em id="ygly">setqueen; considernextcolumn</em>

<br id="crj1" />
   <strong id="uwuf">end else</strong>
 <em id="jpdh">regress</em>

<br id="npb5" />
<strong id="u6vf">until</strong>
 <em id="xxw_">lastcoldone</em>
 V <em id="rten">regressouttofirstcol</em>
</pre>
<p id="f831">&nbsp;</p>
<p id="u20m">这个程序由一系列更基本的指令集合（或者说procedures）构成，描述如下： 
</p>
<p id="o7.d">considerthiscolumn。问题就是去检查安全方格。变量pointer用来指示当前被检查的方格。这个方格所在的列被称为<em id="x11_">当前检查列</em>
。这个过程初始化变量pointer 到第一个列。 
</p>
<p id="qn4z">&nbsp;</p>
<p id="t6ns"><em id="rdl:">trycolumun。</em>
开始在当前列的当前方格内检查，在列里面向下移动直到找到<em id="r5sp">安全的方格，</em>
此时布尔变量<em id="tu94">safe</em>
设置为true，或者直到最后一个方格完成并且还不安全，这个情况下，布尔变量<em id="lxyy">safe</em>
被设置为false。 
</p>
<p id="vhmd"><em id="hm7y">setqueen</em>
.王后被放置到最后一个被检查的方格。 
</p>
<p id="gufa"><em id="nf.g">considernextcolumn。</em>
继续下一个列，并且初始化变量pointer </p>
<p><em id="pvtm">
<p id="mhj6"><em id="gbd0">regress</em>
.回溯到可以进一步放置王后的列，移开在回溯列之后的列上放置的王后。（注意，我们可能不得不至少回溯两列【todo】，为什么？）。</p>
<p id="sx6z">&nbsp;</p>
</em>
</p>
<p id="sx6z">&nbsp;</p>
<p id="jbsu">接着我们继续细化指令<em id="hz6s">trycolumn</em>
 ，<em id="qci1">regress </em>
</p>
<pre><strong id="br6-">procedure</strong>
 <em id="yep6">trycolumn</em>
;<br id="lni43" />
<strong id="fty1">repeat</strong>
 <em id="l-1_">advancepointer</em>
;  <em id="ca-y">testsquare</em>

<strong id="j2or">until</strong>
 <em id="oihx">safe</em>
 V <em id="c:wr">lastsquare</em>

</pre>
<p id="fo4n">&nbsp;</p>
<pre><strong id="ok.:">procedure</strong>
 <em id="ykm1">regress</em>
;<br id="lni44" />
  <strong id="rx9g">begin</strong>
 <em id="b2v9">reconsiderpriorcolumn</em>

     <strong id="ubgl">if</strong>
 - <em id="jm1m">regressouttofirstcol</em>
 <strong id="n31y">then</strong>

     <strong id="wvpz">begin</strong>
 <em id="nphu">removequeen</em>
;<br id="lni45" />
        <strong id="f8iu">if</strong>
 lastsquare <strong id="sq9j">then</strong>

        <strong id="d.bd">begin</strong>
 <em id="mxyr">reconsiderpriorcolumn</em>
;<br id="lni46" />
           <strong id="g1op">if</strong>
 not <em id="db5s">regressouttofirstcol</em>
 <strong id="t1zy">then</strong>

              <em id="tq61">removequeen</em>

        <strong id="wr49">end</strong>

     <strong id="lizc">end</strong>

  <strong id="c87d">end</strong>

</pre>
<p id="kjzb">程序现在由指令和谓词构成，指令包括：</p>
<p id="d8t0"><em id="woj-">considerfirstcolumn</em>
 ，<em id="s7-y">considernextcolumn</em>
 ，<em id="l1ja">reconsiderpriorcolumn</em>
 ，<em id="xwkz">advancepointer</em>
 <br id="hwz_" />
<em id="po7j">testsquare</em>
 (sets the variable ) ，<em id="u709">setqueen</em>
 ，<em id="b:sd">removequeen</em>
 </p>
<p id="puq4">谓词包括：&nbsp;&nbsp;<em id="i44t">lastsquare</em>
 <em id="y-l4">lastcoldone</em>
 <em id="qey4">regressouttofirstcol</em>
 </p>
<p id="qva0">&nbsp;</p>
<p id="x3qs">为了让这些指令和谓词可以在通用编程语言中可以被表达出来，有必要用这些编程语言来表达它们。如何通过数据来表达这些相关的事实的决策不能再被推迟了。首先要表达的是皇后的位置，以及当前正在检测的方格。 
</p>
<p id="gy.6">&nbsp;</p>
<p id="gd0z">&nbsp;</p>
<p id="rxik">&nbsp;</p>
<p id="rynn">最直接的方法（&nbsp;为了便于理解，可以想象在木棋盘上放置大理石块）是引入一个方格矩阵b[i,j]，当b[i,j]=true表明方格的i，j位置已经被占用。 
</p>
<p id="upyy">&nbsp;</p>
<p id="ot4k">一个算法的成功，极度的依赖是否选择了一个良好的的数据结构表达，好的数据结构可以让在其上的操作更容易被表达出来。
除了这个，关于存储需求，可放在首要地位（尽管难以在这种情况下）
。程序设计上的一个公共的难题是--在对数据结构的决定必须做出的时候，经常很难预见到这个数据结构上将会发生的操作的细节，也无法估计一个数据结构相对
于另外一个的优点。通常，因此建议对数据结构的决策尽可能的推迟。 </p>
<p id="zc9n">&nbsp;(but not until it becomes obvious that no realizable solution will suit the chosen algorithm). 
</p>
<p id="s0f2">（但是不能推迟到对于选定的算法显然没有人任何可实现的解的时候[译注5：不明白]） 
</p>
<p id="b4ew">&nbsp;</p>
<p id="pufd">&nbsp;</p>
<p id="mq_x">对于当前问题，技术在这个阶段，下面的选择比起布尔矩阵来说，也更加简单，存储也更加经济。 
</p>
<p id="v2eb">&nbsp;</p>
<p id="vj-e">&nbsp;j是当前被检查列的索引，（xj，j）是前一个被检查方格的坐标；王后在k&lt;j的位置表达为(xk,k)。现在pointer&nbsp;和 board的定义为：</p>
<pre><strong id="gcvi">integer</strong>
 <em id="ipue">j</em>
  (0 &lt;= <em id="udkz">j</em>
 &lt;= 9)<br id="lni47" />
<strong id="z5:.">integer array</strong>
 <em id="x3wt">x</em>
[1:8] (0 &lt;= <em id="a:7g">xj</em>
 &lt;= 8)<br id="lni48" />
<br id="lni49" />
<p id="pw8s">条件和谓词表达为：<br id="lni410" />
<strong id="gzwz">procedure</strong>
 <em id="el88">considerfirstcolumn</em>
;<br id="lni411" />
   <strong id="tmo5">begin</strong>
  <em id="el_t">j</em>
 := 1; <em id="w0og">x</em>
[1] := 0 <strong id="nltw">end</strong>

</p>
<p id="qc2r"><strong id="i:1o">procedure</strong>
 <em id="u60t">considernextcolumn</em>
;<br id="lni412" />
   <strong id="ec-.">begin</strong>
 <em id="v51u">j</em>
 := <em id="lh4k">j</em>
 + 1; <em id="uz.5">x</em>
[<em id="nh9l">j</em>
] = 0 <strong id="rgmd">end</strong>

</p>
<p id="wijy"><strong id="ihky">procedure</strong>
 <em id="qgtb">reconsiderpriorcolumn</em>
; <br id="lni413" />
   <em id="z8xw">j</em>
 := <em id="w:el">j</em>
 - 1<br id="lni414" />
<br id="lni415" />
</p>
<p id="u6-8"><strong id="e8ba">procedure</strong>
 <em id="xm-s">advancepointer</em>
;<br id="lni416" />
   <em id="c3or">x</em>
[<em id="ik_n">j</em>
]  := <em id="rcai">x</em>
[<em id="p81-">j</em>
]   + 1<br id="lni417" />
<br id="lni418" />
</p>
<p id="v93o"><strong id="rg13">Boolean procedure</strong>
 lastsquare;<br id="lni419" />
   <em id="vsd4">lastsquare</em>
 := <em id="kgs4">x</em>
[<em id="rou-">j</em>
] = 8;<br id="lni420" />
 <br id="lni421" />
</p>
<p id="h1z8"><strong id="en_.">Boolean procedure</strong>
 <em id="p3-m">lastcoldone</em>
;<br id="lni422" />
   <em id="g1b7">lastcoldone</em>
 := <em id="csa8">j</em>
 &gt; 8<br id="lni423" />
 <br id="lni424" />
</p>
<p id="y46x"><strong id="fqfa">Boolean procedure</strong>
 <em id="n2tw">regressouttofirstcol</em>
 <br id="lni425" />
   <em id="h_in">regressouttofirstcol</em>
 := <em id="m:4.">j</em>
 &lt; 1<br id="lni426" />
</p>
</pre>
<p id="kcu1">于是，程序为如下的指令表达： 
</p>
<p id="qmd."><em id="hzl0">testsquare</em>
 <br id="qum0" />
<em id="i8qp">setqueen</em>
 <br id="zyw0" />
<em id="cnts">removequeen</em>
 
</p>
<p id="o_mi">&nbsp;</p>
<p id="i2jc">&nbsp;</p>
<p><span style="color: #ff0000;">
</span>
</p>
<p id="sh:."><span style="color: #ff0000;">&nbsp;<span style="color: #000000;">事实上，指令setqueen，removequeen可以当成空洞，如果我们决定testsquare来确定x1 ...xj-1(todo)</span>
 
</span>
</p>
<p id="rthy"><span style="color: #ff0000;"><span style="color: #000000;">不过，不幸的是testsquare是最经常执行的指令，一个指令不能仅仅考虑合理还要考虑效率，即使如此，这不失为是一个好的解法 。显然<em id="vqjc">testsquare</em>
以x1...xj-1方式表示是低效的。<em id="j9lq">testsquare明显比setqueen,removequeen执行的次数更多。后两个给偶出只有在列变化的时候才会执行（共有n次）</em>
前一个指令只要方格变化就会被执行(EM&gt;xm ),当然，setqueen,removequeen是唯一影响棋盘布局的过程。通过引入辅助变量V(x1...xj）来获取效率的提升。</span>
 
</span>
</p>
<p id="crys"><span style="color: #ff0000;">&nbsp;</span>
</p>
<p id="g2gb">&nbsp;</p>
<ol id="lgad">
<li id="i-gk">Whether a square is safe can be compllted more easily from <em id="w4zd">V</em>
(<em id="xxc6">x</em>
) than from <em id="iq.9">x</em>
 directly (say in <em id="k:0c">v</em>
 units of computation instead of <em id="e6xt">ku</em>
 units of computation). 
</li>
<li id="u5y1">The computation of <em id="sq6e">V</em>
(<em id="a4y7">x</em>
) from <em id="bzex">x</em>
 (whenever <em id="gknh">x</em>
 changes) is not too complicated (say of <em id="z8iz">v</em>
 units of computation). </li>
</ol>
<p id="ltm5">&nbsp;&nbsp; 1. 方格是否安全的验证，从V（x）来获得比起直接从x获得更加容易（通过v单元计算，而不是Ku单元计算todo）</p>
<p id="zjmh">&nbsp;&nbsp; 2.&nbsp; 从x计算V（x）并不复杂。</p>
<p id="hvxw">The introduction of <em id="tuhi">V</em>
 is advantageous (apart from considerations of storage economy), if 
</p>
<p id="s-b7"><em id="k15y">n(k - 1)u &gt; mu</em>
 or <em id="qebl">(n/m)(k - 1) &gt; (v/u)</em>
, 
</p>
<p id="w_nh">i.e. if the gain is greater than the loss in computation units. 
</p>
<p id="pwfm">&nbsp;如果<em id="k7jf">n(k - 1)u &gt; mu</em>
&nbsp;或者 <em id="a5r6">(n/m)(k - 1) &gt; (v/u)</em>
, 引入V是有利的（不考虑存储经济性），这样获得的效率提升比起计算单元的损失要大些。 
</p>
<p id="lo_2">&nbsp;</p>
<p id="ozcf">A most straightforward solution to obtain a simple version of <em id="hou-">testsquare</em>
 is to introduce a Boolean matrix <em id="tm3v">B</em>
 such that <em id="ubg.">B</em>
[<em id="ocgh">i</em>
,<em id="fi69">j</em>
] = <strong id="vyos">true</strong>
 signifies that square (<em id="e_x:">i</em>
,<em id="g.0h">j</em>
) recomputation whenever a new queen is removed is prohibitive (why?) and will more than outweigh the gain. 
</p>
<p id="t3_a">&nbsp;(todo) 
</p>
<p id="f88y">&nbsp;</p>
<p id="rlvo">方格安全条件的实现必须要求不能占用已经被另一个王后占用的行列和对角线，这导致更加经济的对V的选择。我们引入布尔数组a，b,c&nbsp;&nbsp; 
</p>
<p id="qjhf"><em id="hops">a</em>
k = <strong id="kiue">true</strong>
 : 行k没有王后</p>
<p id="ni8s">bk = <strong id="x58t">true</strong>
 : 45度对角线k没有王后</p>
<p id="l9yy"><em id="w2pb">c</em>
k = <strong id="zm5h">true</strong>
 : －45度对角线k没有王后</p>
<p id="i65l">&nbsp;</p>
<p id="hvau">&nbsp;</p>
<p id="o2pi">&nbsp;基于同在一个45度对角线的方格的坐标等和，同在一个-45度的对角线的方格的坐标等差的事实，并且行列的索引从1到8，我们得到三个数组的下标范围： <em id="z6w9">a</em>
[1:8],<em id="z8gb">b</em>
[2:16],<em id="wb.-">c</em>
[-7:7]&nbsp;（译注6：数组b用坐标的和做下标就可以确定唯一的棋盘上的方格的位置，相应的c用两个坐标的差做索引，也是同样的道理，紧接着的第四行中的<em id="qmu0">testsquare的定义可以看到：b下标就是j+x[j]坐标和,c的下标是j-x[j]也就是坐标差,从而验证了我的猜想是正确的</em>
）&nbsp; 
</p>
<p id="nz06">以上引入的辅助数据必须注意要正确的初始化。我们的算法从空的棋盘开始，因此必须通过对a，b，c的所有元素赋给true来表现这个事实。我们现在可以：</p>
<pre><em id="n:tz"><strong id="qd-r">procedure</strong>
 testsquare;<br id="lni427" />
safe := a[x[j]] and b[j + x[j]] and c[j - x[j]]<br id="lni428" />
<br id="lni429" />
<strong id="qmaz">procedure</strong>
 setqueen;<br id="lni430" />
   a[x[j]] := b[j + x[j]] := x[j - x[j]] := <strong id="e.mr">false</strong>


<strong id="jlz1">procedure</strong>
 removequeen;<br id="lni431" />
   a[x[j]] := b[j + x[j]] := c[j - x[j]]</em>
</pre>
<p id="w3gr">&nbsp;</p>
<p id="c55y">&nbsp;后面的过程的正确性依赖于这样的一个事实：当前每个王后都必然放置到安全的方格上，在一个被移除的王后后面放置的王后也必然已经移除完毕。因此被腾出来的方格再度变得安全。 
</p>
<p id="sb2j">对当前程序的严格检查发现变量x[j]（译注7：表示第j列的当前方格）是经常要使用的，这些地方的程序也执行的最频
繁。检查x[j]也比给j赋值更加频繁，因此，引入新的辅助数据可以进一步的提高效率。以整数i代表x[j],在j被增加前，x[j] =
i要被执行，在j被减少之后 ，i := x[j] 也要被执行&nbsp;,然后对以上过程的重新清理，改为如下代码： </p>
<p id="wk8o">&nbsp;</p>
<pre><strong id="gx76">procedure</strong>
 <em id="vt9s">testsquare</em>
;<br id="lni432" />
   <em id="z:70">safe</em>
 := <em id="i_ex">a</em>
[<em id="cphx">i</em>
] and <em id="xkd_">b</em>
[<em id="lzw_">i</em>
 + <em id="jhp-">j</em>
] and <em id="ekme">c</em>
[<em id="y729">i - j</em>
]<br id="lni433" />
<br id="lni434" />
<strong id="b-k9">procedure</strong>
 <em id="lqz4">setqueen</em>
;<br id="lni435" />
   <em id="s.ox">a</em>
[<em id="zzct">i</em>
] := <em id="ugkc">b</em>
[<em id="ew3c">i</em>
 + <em id="hd:-">j</em>
] := <em id="xo9x">c</em>
[<em id="tyc8">i - j</em>
] := <strong id="ag5x">false</strong>


<strong id="rm1y">procedure</strong>
 <em id="u9b.">removequeen</em>
;<br id="lni436" />
   <em id="ur6o">a</em>
[<em id="mz.x">i</em>
] := <em id="v1m4">b</em>
[<em id="reks">i</em>
 + <em id="x1qw">j</em>
] := <em id="wtqy">c</em>
[<em id="fkw6">i - j</em>
] := <strong id="hfmm">true</strong>


<strong id="weq1">procedure</strong>
 <em id="bac0">considerfirstcolumn</em>
;<br id="lni437" />
   <strong id="d2.o">begin</strong>
 <em id="y6bb">j</em>
 := 1; <em id="j98y">i</em>
 := 0 <strong id="l7xd">end</strong>


<strong id="irth">procedure</strong>
 <em id="e7ew">advancepointer</em>
;<br id="lni438" />
   <em id="ptoi">i</em>
 := <em id="xvil">i</em>
 + 1;<br id="lni439" />
<br id="lni440" />
<strong id="gs1j">procedure</strong>
 <em id="x626">considernextcolumn</em>
;<br id="lni441" />
   <strong id="v261">begin</strong>
 <em id="d5u2">x</em>
[<em id="qi7y">j</em>
] := i; <em id="syq1">j</em>
 := <em id="jquf">j</em>
 + 1; <em id="l5lc">i</em>
 := 0 <strong id="b280">end</strong>


<strong id="uk7f">Boolean procedure</strong>
 <em id="r_.k">lastsquare</em>

   <em id="zv2:">lastsquare</em>
 := <em id="vzqv">i</em>
 - 8<br id="lni442" />
</pre>
<p id="fu43">&nbsp;</p>
<p id="br7i">最终的程序使用了如下的过程：<em id="rqti">testsquare</em>
 <em id="i9.t">setqueen</em>
 <em id="lat:">regress</em>
 <em id="gabm">removequeen</em>
 ，其他的过程被直接替换，现在的程序是这样的：</p>
<pre><em id="o:b4">j</em>
 := 1; <em id="wd3w">i</em>
 := 0;<br id="lni443" />
<strong id="qngb">repeat</strong>

   <strong id="po6k">repeat</strong>
 <em id="o8.0">i</em>
 :=  <em id="c9eg">i</em>
 + 1; <em id="r8wc">testsquare</em>

   <strong id="y9.t">until</strong>
 <em id="ao0h">safe</em>
 or (<em id="oc8w">i</em>
 = 8);<br id="lni444" />
   <strong id="gfaz">if</strong>
 <em id="cv8b">safe</em>
 <strong id="ef1r">then</strong>

   <strong id="q8qy">begin</strong>
 <em id="z:i2">setqueen</em>
; <em id="z3bx">x</em>
[<em id="z.tm">j</em>
]  := <em id="s3ro">i</em>
; <em id="nkca">j</em>
 := <em id="sd20">j</em>
 + 1; <em id="j56v">i</em>
 := O<br id="lni445" />
   <strong id="uhqd">end else</strong>
 <em id="o0_o">regress</em>

<strong id="w3ld">until</strong>
 (<em id="mtw8">j</em>
 &gt; 8) or (<em id="qv0q">i</em>
 &lt; 1);<br id="lni446" />
<strong id="ivox">if</strong>
 <em id="n6i1">j</em>
 &gt; 8 <strong id="hl4d">then</strong>
 PRlNT(<em id="c:8u">x</em>
) <strong id="vt9q">else</strong>
 FAILURE</pre>
<p id="m_rs">&nbsp;</p>
<p id="fj7u">&nbsp;</p>
<p id="iswa">值得注意的是，程序的结构依然和第一步设计的版本相同。自然的，等效的有效解法可以通过逐步求精的方法得出和开发出
来。这个事实应该给学生明确的表达出来。一个可更换的方法是EWD提出的。解法基于这样的想法：棋盘上每一个列包含一个安全的位置，从空的棋盘开始到8列
填满结束。填写棋盘列的方法是一个过程，自然的办法是通过对这个过程进行递归获得完整的棋盘布局。它可轻易组成的同一套更为原始的指示，这些全部用于第一
个解决办法。</p>
<pre><strong id="t605">procedure</strong>
 <em id="hdsk">trycolumn</em>

  <strong id="v5qc">begin</strong>
 <strong id="tj-2">integer</strong>
 <em id="ol:-">i</em>
; <em id="yjwh">i</em>
 := 0;<br id="lni447" />
    <strong id="yx7h">repeat</strong>
 <em id="zjo8">i</em>
 := <em id="zkdp">i</em>
 + 1;  <em id="arm6">testsquare</em>
;<br id="lni448" />
      <strong id="hdi1">if</strong>
 <em id="p-5a">safe</em>
 <strong id="j7sh">then</strong>

      <strong id="n1fm">begin</strong>
 <em id="kw.6">setqueen</em>
;  <em id="ewd3">x</em>
[<em id="vecq">j</em>
] := <em id="puea">i</em>
;<br id="lni449" />
         <strong id="a_d5">if</strong>
 <em id="uuqu">j</em>
 &lt; 8 <strong id="ezra">then</strong>
 <em id="leq2">trycolumn</em>
(<em id="dgl:">j</em>
+1);<br id="lni450" />
         <strong id="drzx">if</strong>
 not <em id="vryh">safe</em>
 <strong id="ocv9">then</strong>
 <em id="juy.">removequeen</em>

      <strong id="a4cz">end</strong>

    <strong id="k79s">until</strong>
 <em id="s5_-">safe</em>
 or (<em id="v9nk">i</em>
 = 8)<br id="lni451" />
   <strong id="pv07">end</strong>

</pre>
<p id="sa2:">使用这个过程的程序是： 
</p>
<p id="ju_e">&nbsp;</p>
<p id="cs37"><em id="rr.6">Trycolumn</em>
(1); <br id="jn65" />
<strong id="qa7n">if</strong>
 <em id="jnab">safe</em>
 <strong id="e4:a">then</strong>
 PRINT(<em id="jpfg">x</em>
) <strong id="x.:y">else</strong>
 FAILURE </p>
<p id="q8dy">&nbsp;</p>
<p id="k.sm">（注意，因为递归过程中引入了一个变量I，每个列有自己的i，因此，每个过程也有自己的I，<em id="eq80">testsquare</em>
 <em id="mpfv">setqueen</em>
 <em id="i59j">removequeen</em>
 必须在Trycolumn 内本地声明，因为他们引用了I去扫描当前列的方格。）<br id="xvqu" />
&nbsp; 
</p>
<p id="jaz0">&nbsp;</p>
<hr id="zr0w" />
<p id="hm4:">5. 一般化的8王后问题。</p>
<p id="vyb9">&nbsp;</p>
<p id="y5_y">这个程序一旦执行正确和令人满意，就保持不再改变，这样的情况在现实计算世界内也比较罕见的。现实情况是，用户迟早会发现程序
不再能够给出希望的结果，或者更差的是，给出不是用户真正期望的结果。&nbsp;或者需求或者扩展就是必要的了，此时，逐步细化的程序设计和系统结构就更加有价值
和好处。如果程序组件和结构都是比较自洽的，哪么很多指令都不必修改即可通过。对再设计和再验证就不必花费太多的努力。可维护性对程序的结构化程度提出了
挑战。 </p>
<p id="oj4l">&nbsp;</p>
<p id="br3_">以下的章节的目的是：演示以一般化的看待8王后问题的好处。通过扩展前面提及的程序组件，来扩展原始的8王后问题和解法。 
</p>
<blockquote id="u_te">&nbsp;找出8个敌对的王后再8X8的棋盘上的全部位置，以便没有王后会被其他的王后干掉。 </blockquote>
<p id="n:7v">&nbsp;</p>
<p id="gak7">&nbsp;新的程序基本上有两个部分构成：</p>
<p id="kiki">1. 找到生成进一步解法的方法</p>
<p id="s619">2. 决定是否全部解都已经被生成</p>
<p id="hb8j">&nbsp;</p>
<p id="lqk2">显然,通过一些系统的方法去生成和验证候选的解是必要的。
一个办法是确定候选解的次序，并且找到最后一个解的验证条件。如果一个次序被找到了的话，那么解就可以映射到整数上面去。如果算法严格的按照递增的次序去
生成解，那么和解相关的这个数字限定条件实际上就是算法终止的标准。（译者：这一段我看了很多次，才慢慢的明白他的意思,最初的看法可以说是根本翻译不下
去了） </p>
<p id="ag2o">&nbsp;</p>
<p id="v1.s">可能解的上界是<em id="u-oy">M</em>
(<em id="k0k5">x</em>
<span>max</span>
) = 88888888 
</p>
<p id="vn_.">&nbsp;</p>
<p id="bq6n">上面的生成了一个解的程序，生成了一个最小数量的解，但是可以作为找到更多解的一个开始。新的测试方格的方法现在要严
格的按照M(x)递增的次序来进行，并且从00000000开始。生成进一步解的方法必须可以&ldquo;从一个当前解给出的棋盘布局开始，按照M（x）的递增次序
继续扫描更多的解，直到下一个解被找到，或者超出解的上界&rdquo;。 </p>
<p id="a.08">&nbsp;</p>
<hr id="xmkc" />
<p id="wuev">6. 扩展程序</p>
<p id="j94m">&nbsp;</p>
<p id="xpzf">&nbsp;通过修改全局的数据结构，并且共同相同的代码块的想法，可以将简单的8王后问题的程序扩展到可以解决一般化的8王后问题。全局的数据结构必须修改，这样同样的算法可以在找到第一个解后，能够继续找下一个解，直到解全部被找出来。</p>
<p id="l9g3">&nbsp;</p>
<p id="t6:7">当第一个王后已经移动到第8行之外，并且在这个回归程序已经回归出了第一列，此时就可以说明，全部可能解都已经遍历完毕，不必再继续找了；这样就得到了一个非递归版本的程序：</p>
<pre><em id="kiak">considerfirstcolumn</em>
;<br id="lni452" />
   <strong id="p8ex">repeat</strong>
 <em id="rf22">trycolumn</em>
;<br id="lni453" />
   <strong id="pdru">if</strong>
 <em id="b.n:">safe</em>
 <strong id="d3ty">then</strong>

   <strong id="fmji">begin</strong>
 <em id="c3:s">setqueen</em>
; <em id="x8xm">considernextcolumn</em>
;<br id="lni454" />
      <strong id="v7yz">if</strong>
 <em id="of4j">lastcoldone</em>
 <strong id="r4f5">then</strong>

      <strong id="lt6e">begin</strong>
 PRlNT(<em id="hzaa">x</em>
); <em id="gbte">regress</em>

      <strong id="rpzd">end</strong>

   <strong id="w3g3">end else</strong>
 <em id="b:7j">regress</em>

 <em id="ze-r">regressouttofirstcol</em>

</pre>
<p id="jw.g">&nbsp;</p>
<p id="aojh">&nbsp;指示解被找到的打印语句现在就在检查层执行，也即是说，在离开循环语句之前执行。算法继续寻找下一个解，并且使用一个捷径--直接回归到前一个列，毕竟每个成功的解在每个行都有一个王后，在8列内的移动最后一个王后也就不再必要。 
</p>
<p id="sqx.">&nbsp;</p>
<p id="j-2c">&nbsp;</p>
<p id="ev8s">遵循相同的考虑，以递归程序编写，就可以更加简单的做出扩展：</p>
<pre><strong id="vzeg">procedure</strong>
 <em id="me2y">Trycolumn(j)</em>
;<br id="lni455" />
<strong id="tp8x">begin integer</strong>
 <em id="px9i">i</em>
;<br id="lni456" />
   (declaralions of procedures <em id="ncad">testsquare, advancequeen,<br id="lni457" />
    setqueen, removequeen, lastsquare</em>
)<br id="lni458" />
   <em id="v:ym">i</em>
 := 0;<br id="lni459" />
   <strong id="hkp_">repeat</strong>
 <em id="k5.i">advancequeen; testsquare</em>
;<br id="lni460" />
      <strong id="xjms">if</strong>
 <em id="oyom">safe</em>
 <strong id="gr85">then</strong>

      <strong id="skca">begin</strong>
 <em id="v7.i">setqueen</em>
; <em id="f9s-">x</em>
[<em id="ozni">j</em>
] := <em id="th5j">i</em>
;<br id="lni461" />
         <strong id="vv37">if</strong>
 not <em id="mrp_">lastcoldone</em>
 <strong id="kds2">then</strong>
 <em id="fo94">Trycolumn</em>
(<em id="sb2jr">i</em>
 + l) <strong id="ijje">else</strong>
 PRlNl'(<em id="qfn1">x</em>
);<br id="lni462" />
         <em id="e0gv">removequeen</em>

      <strong id="oddc">end</strong>

   <strong id="toxf">until</strong>
 <em id="rsox">lastsquare</em>

<span style="font-family: Verdana;"><strong id="jv0g">end</strong>
</span>
</pre>
<p id="aeze">主程序只有一个语句，就是<em id="o.5c">Trycolumn</em>
(1) . </p>
<p id="w1kp">&nbsp;</p>
<p id="e2eg">&nbsp;总结下，两个程序代表了一个相同的算法。通过对方格测试了15720次后获得了92个解。每个解平均花费了171次验证；找到下一个解验证的次数最多的是876次（就是第一个解），最小8个。（两个程序都是在cdc 6400上的pascel语言通过） 
</p>
<hr id="d6g2" />
<h3 id="ns95"><a name="7" id="behw">7. 总结</a>
</h3>
<p id="wv2c">&nbsp;这个带着一个例子的课程可以总结为以下要点：</p>
<p id="akdl">&nbsp;&nbsp;&nbsp;1.&nbsp;&nbsp; 程序构造可以有一系列的逐步求精的过程构成。给定任务的每一个步骤可以分解为许多的子任务。对任务描述的细化可以通过对子任务之间通讯的数据的细化获得。对程序的细化和对数据结构的细化应该并行进行。</p>
<p id="xa3s">&nbsp;&nbsp;&nbsp;2.&nbsp; 未来对程序进行功能上的修改或者扩充，或者需要相应调整以便适应新的执行环境（语言，计算机），这些工作的困难程度，就是由这种方式得到的模块化程度来决定的。</p>
<p id="x1yg">&nbsp;&nbsp; 3.
在逐步求精的过程中，应该尽可能的使用可以自然贴切的表达问题的符号体系。在逐步求精的过程中，符号发展的方向将会由最终采用的计算机语言决定，并且最终
和计算机语言一致。这些符号语言应该尽可能自然和清晰的表达在设计过程中逐步出现的程序结构和数据；同时也能够在逐步求精的过程中，通过表达基本的特征和
结构规律,从而对程序将要执行的计算机上也是自然的这一点给出指导。值得注意的是，很难找出一门很好的符合这些需求的语言，现在广泛使用的教学语言
Fortran只能说在很低程度上可以满足。</p>
<p id="unii">&nbsp;&nbsp;&nbsp; 4.
每一次细化都隐含着给予一组设计条件的设计决策。这些标准是效率，存储的经济，清晰，结构化。教学中学生应该自觉参与到设计决策中来，批判的检查解法，甚
至是拒绝解法，即使这个解法的结果是正确的；他们应该学会如何参照以上标准去权衡可选的方案。尤其是，如果有必要，他们应该被教到回到较早的设计决策，即
使已经回到了决策树的顶端。一个短程序样本就可以说明这个重要道理，仅仅考虑这个目的而去建立一个操作系统是根本没有必要的</p>
<p id="qxz6">&nbsp;&nbsp;&nbsp; 5.
甚至一个短程序的开发，要详细交代也需要有一个长的故事；这就说明谨慎的编程并不是一项无足轻重的议题。如果通过这个论文，有利于消除人们的普遍的错误认
识--认为编程是容易的，只要编程语言是足够强大的和现有的电脑速度够快的话，那么它已经取得了它的一个目的</p>
<p id="wa12"><em id="j_g0">致谢：</em>
作者感谢C.A.R. Hoare&nbsp;和 E. W. Dijkstra的帮助，以及和他们在讨论中得到的启发。</p>
<p id="k6mc">&nbsp;</p>
<hr id="fybo" />
<p id="yn9-">&nbsp;</p>
<h3 id="acvv"><a name="ref" id="ae0a">参考</a>
</h3>
<p>列出以下文章作为参考和进一步阅读 
</p>
<p id="pmm2">1. Dijkstra, E. W. A constructive approach lo the problem of program correctness. <em id="kp9q">BIT</em>
 8 (1968), 174-186. 
</p>
<p id="z182">2. Dijkstra, E. W. Notes on structured programming. EWD 249 Technical U. Eindhoven, The Netherlands, 1969. 
</p>
<p id="xgzv">3. Naur, P. Programming by action clusters. <em id="mp7d">BIT</em>
 9 (1969) 250 - 258. 
</p>
<p id="w5eq">4. Wirth, N. Programming and programming languages. Proc. Internat. Comput. Symp., Bonn, Germany, May 1970. 
</p>
<p id="n5jm">&nbsp;</p>
<hr id="mnst" />
<p>
<br id="r0c2" />
</p>
&nbsp;
          <br/>
          <span style="color:red;">
            <a href="http://1000copy.javaeye.com/blog/206900#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 22 Jun 2008 20:37:35 +0800</pubDate>
        <link>http://1000copy.javaeye.com/blog/206900</link>
        <guid>http://1000copy.javaeye.com/blog/206900</guid>
      </item>
      <item>
        <title>-------------2008年6月20日  ruby 做着玩(6)  使用scafold   </title>
        <author>1000copy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://1000copy.javaeye.com">1000copy</a>&nbsp;
          链接：<a href="http://1000copy.javaeye.com/blog/206617" style="color:red;">http://1000copy.javaeye.com/blog/206617</a>&nbsp;
          发表时间: 2008年06月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><br />
&nbsp; 技术障碍已经差不多扫除了，现在来一个真的:使用scafold，做一个serial 的crud程序。<br />
&nbsp; rails -dmysql serialcrud <br />
&nbsp; cd serialcrud <br />
&nbsp; ruby script/generate scaffold Serial serialformat:string <br />
&nbsp; rake db:migrate<br />
&nbsp;<br />
&nbsp; Ready to test <br />
&nbsp; 这样就有了一个serial的crud的程序了。<br />
&nbsp; 参考1：<br />
&nbsp; &nbsp;&nbsp;&nbsp; #&nbsp; rake db:migrate&nbsp; <br />
&nbsp;&nbsp;&nbsp; #&nbsp; # 迁移数据库通过在db/migrate目录下的脚本.可以指定版本号通过VERSION=x&nbsp; <br />
&nbsp;&nbsp;&nbsp; #&nbsp; rake db:schema:dump&nbsp; <br />
&nbsp;&nbsp;&nbsp; #&nbsp; # 创建一个db/schema.rb文件，通过AR能过够支持任何数据库去使用&nbsp; <br />
&nbsp;&nbsp;&nbsp; #&nbsp; rake db:schema:load&nbsp; <br />
&nbsp; 参考2：<br />
&nbsp;&nbsp;&nbsp; http://www.tutorialspoint.com/ruby-on-rails-2.1/rails-scaffolding.htm</p>
          <br/>
          <span style="color:red;">
            <a href="http://1000copy.javaeye.com/blog/206617#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 21 Jun 2008 11:25:44 +0800</pubDate>
        <link>http://1000copy.javaeye.com/blog/206617</link>
        <guid>http://1000copy.javaeye.com/blog/206617</guid>
      </item>
      <item>
        <title>2008年6月20日  ruby 做着玩(5)  trouble shooting</title>
        <author>1000copy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://1000copy.javaeye.com">1000copy</a>&nbsp;
          链接：<a href="http://1000copy.javaeye.com/blog/206616" style="color:red;">http://1000copy.javaeye.com/blog/206616</a>&nbsp;
          发表时间: 2008年06月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><br />
想要尝试下rails db:migrate ,看看这样管理数据库的创建脚本和升级脚本如何，于是在rails的网站找到一个例子:<br />
&nbsp; class CreateSystemSettings &lt; ActiveRecord::Migration<br />
&nbsp; def self.up<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; create_table :system_settings,&nbsp;&nbsp;&nbsp; &nbsp;:force =&gt; true do |t|<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t.string&nbsp; :name<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t.string&nbsp; :label<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t.text&nbsp; :value<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t.string&nbsp; :type<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t.integer&nbsp; :position<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SystemSetting.create :name =&gt; &quot;notice&quot;, :label =&gt; &quot;Use notice?&quot;, :value =&gt; 1<br />
&nbsp; end<br />
<br />
&nbsp; def self.down<br />
&nbsp;&nbsp;&nbsp; drop_table :system_settings<br />
&nbsp; end<br />
end<br />
&nbsp; 我的执行步骤是这样的：<br />
&nbsp; 1. 运行instantrails，<br />
&nbsp; 2. 打开 instantrails提供的ruby console内执行 <br />
&nbsp; 3. 执行 ruby script/generate migration CreateSystemSetting ,修改001__CreateSystemSetting.rb<br />
&nbsp; 4. rake&nbsp; db:migrate ,但是它总是报错，&quot;SystemSetting constant undefined &quot;<br />
<br />
&nbsp;原因是还没有生成model，只要 ruby script/generate model SystemSetting ,就ok了。<br />
&nbsp;学会了，下一步做serial的model和migration测试。<br />
&nbsp; 同时也了解到rails development environment。我从instantrails 的相应按钮点开的。<br />
&nbsp; ruby有irb，可以让代码交互运行，更快的查看代码执行的效果<br />
&nbsp; rails 有 rails development environment ,道理相同。<br />
&nbsp; 在 rails development environment 内可以直接执行比如&nbsp; SystemSetting.create :name =&gt; &quot;notice&quot;, :label =&gt; &quot;Use notice?&quot;, :value =&gt; 1，不需要完整的require之类的，它都已经建立完毕了。当然 drop_table不能直接执行，因为它来自 ActiveRecord::Migration ，但是可以通过ActiveRecord::Migration.drop_table 来跑。<br />
&nbsp; <br />
&nbsp;参考：<br />
&nbsp; 1. 不错的turorials ：http://www.tutorialspoint.com/ruby-on-rails-2.1/rails-migrations.htm<br />
&nbsp; 2. 这里还有一个视频：http://www.rubyonrails.org/screencasts，也很不错。<br /></p>
          <br/>
          <span style="color:red;">
            <a href="http://1000copy.javaeye.com/blog/206616#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 21 Jun 2008 11:25:03 +0800</pubDate>
        <link>http://1000copy.javaeye.com/blog/206616</link>
        <guid>http://1000copy.javaeye.com/blog/206616</guid>
      </item>
      <item>
        <title>-------------2008年6月18日 ruby 做着玩(4) 关于取得form内参数的 t</title>
        <author>1000copy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://1000copy.javaeye.com">1000copy</a>&nbsp;
          链接：<a href="http://1000copy.javaeye.com/blog/206615" style="color:red;">http://1000copy.javaeye.com/blog/206615</a>&nbsp;
          发表时间: 2008年06月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><br />
print params[:serialformat]<br />
<br />
要想 params[:serialformat] 取得 form内的 serialformat 字段，必须<br />
&nbsp;&nbsp;&nbsp; &lt;form action=&quot;index&quot;&gt;<br />
&nbsp;&nbsp;&nbsp; serial format&lt;input&nbsp; name=&quot;serialformat&quot; value=&quot;2008-6-14-string-1&quot;&gt;&lt;p&gt;<br />
&nbsp;&nbsp;&nbsp; last serial&lt;input id=&quot;serialformat1&quot; value=&quot;&quot;&gt;&lt;p&gt;<br />
&nbsp;&nbsp;&nbsp; lastnum:&lt;input id=&quot;serialformat2&quot; value=&quot;0&quot;&gt;&lt;p&gt;<br />
&nbsp;&nbsp;&nbsp; new serial:&lt;input id=&quot;serialformat&quot; &gt;&lt;p&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;input type=&quot;submit&quot; value=&quot;submit&quot;&gt;&lt;p&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/form&gt;<br />
中的：<br />
&nbsp; &lt;input id=&quot;serialformat&quot;&nbsp; name=&quot;serialformat&quot; value=&quot;2008-6-14-string-1&quot;&gt;<br />
而不能是：<br />
&nbsp; &lt;input id=&quot;serialformat&quot;&nbsp; value=&quot;2008-6-14-string-1&quot;&gt;</p>
          <br/>
          <span style="color:red;">
            <a href="http://1000copy.javaeye.com/blog/206615#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 21 Jun 2008 11:23:36 +0800</pubDate>
        <link>http://1000copy.javaeye.com/blog/206615</link>
        <guid>http://1000copy.javaeye.com/blog/206615</guid>
      </item>
      <item>
        <title>-------------2008年6月14日 ruby 做着玩(3) </title>
        <author>1000copy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://1000copy.javaeye.com">1000copy</a>&nbsp;
          链接：<a href="http://1000copy.javaeye.com/blog/206614" style="color:red;">http://1000copy.javaeye.com/blog/206614</a>&nbsp;
          发表时间: 2008年06月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>-------------2008年6月14日 ruby 做着玩(3)<br />
&nbsp; ROR的环境必须要有，否则什么也玩不了。我不会从头开始，有InstantRails呢，什么mysql，apache都在，还有一个编辑器scite呢.我不会用它的，还是emeditor好。<br />
&nbsp; 总之先下一个，解压后执行instantrails.exe就可以用了。<br />
&nbsp; 然后去ror网站看turorial。<br />
&nbsp;&nbsp;&nbsp; http://www.rubyonrails.org/down<br />
&nbsp; 内提到了创建一个应用的方法：<br />
&nbsp;&nbsp;&nbsp; rails path/to/your/new/application<br />
&nbsp;&nbsp;&nbsp; cd path/to/your/new/application<br />
&nbsp;&nbsp;&nbsp; ruby script/server<br />
&nbsp; rails，ruby在那里呢?<br />
&nbsp; 在D:\setup\InstantRails-2.0-win\ruby\bin\ 内，把他设置为path吧。不然太麻烦。<br />
&nbsp; 不过设置path也麻烦，不如自己用 instantrails 提供的Create New Rails App。他会把path设置好，并且到那个黑乎乎的dos prompt 。<br />
&nbsp; 在黑屏内，输入ruby，rails试试看，它们都可以直接运行了。 来吧。<br />
&nbsp; rail serial <br />
&nbsp; cd serial<br />
&nbsp; ruby script\server<br />
&nbsp; 列出的信息表明，服务器已经启动了，在3000端口上等着你呢。试试http://localhost:3000<br />
&nbsp; 看到Ruby on rails :Welcome aboard 了吗？<br />
&nbsp; 还提示你如何Getting Started :创建数据库，修改yml的，不过数据库的东西先不去惹，咱们初来乍到，先搞点简单的。<br />
&nbsp; 创建controller....<br />
&nbsp; ruby script/generator controller serial <br />
&nbsp; 访问 http://localhost:3000/serial ,不行。rhtml也创建了，serial内的index方法也写了。<br />
&nbsp; TroubleShooting：<br />
&nbsp; 创建了controller，但是总报这个错。<br />
&nbsp;&nbsp;&nbsp; Routing Error<br />
<br />
&nbsp;&nbsp;&nbsp; No route matches &quot;/generateserial/index&quot; with {:method=&gt;:get}<br />
&nbsp; 只要重启ruby script/server 就可以了。<br />
&nbsp; 被这个问题挡了有一会儿，LP让我休息，我肚子也饿了，睡觉吧，明天继续。</p>
          <br/>
          <span style="color:red;">
            <a href="http://1000copy.javaeye.com/blog/206614#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 21 Jun 2008 11:21:49 +0800</pubDate>
        <link>http://1000copy.javaeye.com/blog/206614</link>
        <guid>http://1000copy.javaeye.com/blog/206614</guid>
      </item>
      <item>
        <title>-------------2008年6月14日 ruby 做着玩(2) </title>
        <author>1000copy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://1000copy.javaeye.com">1000copy</a>&nbsp;
          链接：<a href="http://1000copy.javaeye.com/blog/206613" style="color:red;">http://1000copy.javaeye.com/blog/206613</a>&nbsp;
          发表时间: 2008年06月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp; 前面一篇提到了不用数据库，也没有界面的一个函数，但是没有ui，没有persistant，只有函数，那只是在玩。对用户有用就必须有ui，而要有记忆必须有数据库（或者其他类似数据库的东西），因此这篇要看ui和db。<br />
&nbsp; 但是前一篇提到的思路还是很重要，先逻辑，在db，ui。ui只不过是逻辑的输入输出，db也一样。逻辑理清了，db，ui就简单了，并且逻辑更加容易重用。<br />
&nbsp; 思路归思路，这里不多谈。看ui，db。<br />
&nbsp; ruby的c/s ui基本上就是玩的，什么wx，tk，fox之类的，毫无实用价值，而数据库没有问题，毕竟db 接口简单。<br />
&nbsp; 把ui，db结合到一起，现在还是ROR做的好，b/s的东西，也有标准，基于标准做事情，比起和专用的接口更加放心，专用接口是什么？想想死掉的bde，还有被微软逐渐废掉的odbc，dao，oledb，ado的，难过啊。凡是用dotnet的，现在是ado.net的天下了。<br />
&nbsp; Feature：<br />
&nbsp; 1. 能够配置 ${yyyy}-${mm}-${dd}-string-${autonum}样式<br />
&nbsp; 2. 用户按一个&ldquo;生成系列号&rdquo;的按钮，就显示一个新的系列号<br />
&nbsp; 隐含着一个需求， 能够记忆 last_num,last_serial_no <br />
&nbsp; Feature都是 ui的事情，但是隐含的需求是db的，或者是persistant的事情。为了方便期间，以后都说就是db的事情。<br />
&nbsp; 需求我很清楚，做出什么样子我也清楚，但是ROR我也不熟悉，因此做的过程，依然和第一篇一样，自顶向下，涉及到技术的时候，自底向上。<br />
<br />
&nbsp; 第2个feature比起第一个要简单的多，既然要自底向上，那么就先做简单的，把第二个先拿来欺负下。先把技术的东西搞明白。<br />
&nbsp; 把2在分解下:<br />
&nbsp; 2.1 提供三个edit，一个edit输入，先手输入serial_format，不去配置；一个用来输入上一个last_serial；一个用来输入last_num<br />
&nbsp; 2.2 一个按钮，点击后显示新的系列号<br />
&nbsp; 看，这个ui不就是GenenateSerialNo的输入输出吗?如果把逻辑当成一个机器，那么ui就不过是给逻辑喂草料的，所以说，逻辑才是系统的关键。<br />
&nbsp; 需求搞明白了，稳住一头了，现在我们来面对技术这一头。不要两面受敌，这是开发软件的分而治之。一次搞定一块就行了。<br />
&nbsp; ROR的东西还是一大坨，需要先学习下。</p>
          <br/>
          <span style="color:red;">
            <a href="http://1000copy.javaeye.com/blog/206613#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 21 Jun 2008 11:21:09 +0800</pubDate>
        <link>http://1000copy.javaeye.com/blog/206613</link>
        <guid>http://1000copy.javaeye.com/blog/206613</guid>
      </item>
      <item>
        <title>-------------2008年6月14日 ruby 做着玩(1)</title>
        <author>1000copy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://1000copy.javaeye.com">1000copy</a>&nbsp;
          链接：<a href="http://1000copy.javaeye.com/blog/206612" style="color:red;">http://1000copy.javaeye.com/blog/206612</a>&nbsp;
          发表时间: 2008年06月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><br />
&nbsp; 这些天总是想要用ruby做点什么，因为喜欢ruby，也因为最近技术上缺少变化，想要主动的搞点不同的东西。想了不少的东西，但是很显然现在很忙，白天也不会有时间，只有晚上做，因此不能太大了，完整的系统就不要想了，但是找些耦合性不大的，有点意思的模块还是没有问题的，不如就做一个编号生成模块吧。<br />
&nbsp; 今天周六，在床上睡得七荤八素的，想到左右没有事情，或者想到些事情也不想动，不如写写这个模块，动手。<br />
&nbsp; 先看看需求<br />
&nbsp; A. Feat：做一个编号生成模块<br />
&nbsp; 1. 通过类似${yyyy}-${mm}-${dd}-string-${autonum}样式来生成编码，这样生成的编号在今天就是2008-06-14-string-1,依次递增。<br />
&nbsp; 2. 可以配置上面的格式化字符串<br />
&nbsp; 3. 可以生成一个新的编号，并且不会重复，前面字符串变化后，后面的autonum可以归零再来。 <br />
<br />
&nbsp; B. 技术限定：用函数，不要动不动就是数据库，想都不能想；总在做数据库，早就烦了，这次至少要改变些什么，要不然太没有意思了。<br />
<br />
&nbsp; C. 我要做的就是这个函数<br />
&nbsp;&nbsp; function GenenateSerialNo(serial_format,last_serial_no,last_num)<br />
&nbsp;&nbsp;&nbsp;&nbsp; 当然需要通过下面的测试。实际上有了测试，这个函数才完整。<br />
&nbsp; D. testcase :<br />
&nbsp;&nbsp;&nbsp; assert_equal(&quot;2008-6-14-string-1&quot;,GenenateSerialNo(&quot;${yyyy}-${mm}-${dd}-string-${autonum}&quot;,&quot;&quot;,0))<br />
&nbsp;&nbsp;&nbsp; assert_equal(&quot;2008-6-14-string-4&quot;,GenenateSerialNo(&quot;${yyyy}-${mm}-${dd}-string-${autonum}&quot;,&quot;2008-6-14-string-3&quot;,3))<br />
&nbsp;&nbsp;&nbsp; assert_equal(&quot;2008-6-14-string-9&quot;,GenenateSerialNo(&quot;${yyyy}-${mm}-${dd}-string-${autonum}&quot;,&quot;2008-6-14-string-8&quot;,8))<br />
&nbsp; &nbsp;&nbsp;&nbsp; assert_equal(&quot;2008-6-14-string-1&quot;,GenenateSerialNo(&quot;${yyyy}-${mm}-${dd}-string-${autonum}&quot;,&quot;2008-6-13-string-8&quot;,8))<br />
<br />
&nbsp; 如果用数据库的思路，现要考虑数据库表如何规划，上一个num和上一个格式化字符串的位置，还有这3张表的关系，耦合大了去了，又如何去重用呢？<br />
<br />
&nbsp; E. Testcase换成Ruby的表达，更详细的设计<br />
<br />
&nbsp; 可是我不知道在ruby中如何表达单元测试？<br />
&nbsp; google &quot;ruby unit test&quot;<br />
&nbsp; 找到一个例子：<br />
&nbsp; 少许调整，改成自己想要的东西。然后....ruby serail_test<br />
&nbsp; 架子成了，休息下，听音乐，音乐好啊。<br />
<br />
&nbsp; F. 开始写代码 - 表意代码，但是必须替换为ruby的样子，ruby估计不会有什么now.month,也不会有replace的方法。<br />
&nbsp;&nbsp;&nbsp; def GenenateSerialNo(serial_format,last_serial_no,last_num)<br />
&nbsp;&nbsp;&nbsp; &nbsp;serial_format.replace(&quot;${yyyy}&quot;,now.year);<br />
&nbsp;&nbsp;&nbsp; &nbsp;serial_format.replace(&quot;${mm}&quot;,now.month);<br />
&nbsp;&nbsp;&nbsp; &nbsp;serial_format.replace(&quot;${dd}&quot;,now.day);<br />
&nbsp;&nbsp;&nbsp; &nbsp;temp = serail.replace(&quot;${autonum},last_num&quot;)<br />
&nbsp;&nbsp;&nbsp; &nbsp;if (temp == last_serial_no)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;serial_format.replace(&quot;${autonum}&quot;,last_num+1);<br />
&nbsp;&nbsp;&nbsp; &nbsp;else<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; serial_format.replace(&quot;${autonum}&quot;,1);<br />
&nbsp;&nbsp;&nbsp; &nbsp;serial_format<br />
&nbsp;&nbsp;&nbsp; end<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这些代码只能算是伪代码，表达意思没有问题，但是ruby显然不是这样表达的，其中的日期函数肯定不是这样的，replace函数恐怕也没有，就算有，恐怕也不能用一个数字来替换，比如last_num,必须转成string才可以。<br />
&nbsp; G. 如何表达string.replace ? 继续google &quot;ruby string replace &quot;,知道gsub可以干这个事情<br />
&nbsp;&nbsp;&nbsp;&nbsp; 用irb验证<br />
&nbsp;&nbsp;&nbsp;&nbsp; &quot;abc&quot;.gsub(&quot;ab&quot;,&quot;c)<br />
&nbsp;&nbsp;&nbsp;&nbsp; ==&gt; cc<br />
&nbsp;&nbsp;&nbsp;&nbsp; 就是它。<br />
&nbsp; H. 那么now.year 呢？ google :&quot;ruby date year&quot;,每个语言对日期的处理都不一样，不过也没有必要说那么多，都是知识性的，总之找到，然后用irb来测试。<br />
&nbsp; &nbsp;&nbsp;&nbsp; irb(main):011:0&gt; Time.now.day<br />
&nbsp;&nbsp;&nbsp; =&gt; 14<br />
&nbsp;&nbsp;&nbsp; irb(main):012:0&gt; Time.now.year<br />
&nbsp;&nbsp;&nbsp; =&gt; 2008<br />
&nbsp;&nbsp;&nbsp; irb(main):013:0&gt; Time.now.month<br />
&nbsp;&nbsp;&nbsp; =&gt; 6<br />
&nbsp;&nbsp;&nbsp; irb(main):015:0&gt; Time.now.month.to_s()<br />
&nbsp;&nbsp;&nbsp; =&gt; &quot;6&quot;<br />
&nbsp;&nbsp;&nbsp; irb(main):016:0&gt; Time.now.month.to_s<br />
&nbsp;&nbsp;&nbsp; =&gt; &quot;6&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这样基本库函数的就比较明确了，正式编码了。<br />
&nbsp;&nbsp; J. 废话少说,看代码，然后通过第一个测试,随后以及也就通过了，懒得在看了。<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; def GenenateSerialNo(serial_format,last_serial_no,last_num)<br />
&nbsp;&nbsp;&nbsp; &nbsp;serial = serial_format<br />
&nbsp;&nbsp;&nbsp; &nbsp;serial = serial.gsub(&quot;${yyyy}&quot;,Time.now.year.to_s)<br />
&nbsp;&nbsp;&nbsp; &nbsp;serial = serial.gsub(&quot;${mm}&quot;,Time.now.month.to_s)<br />
&nbsp;&nbsp;&nbsp; &nbsp;serial = serial.gsub(&quot;${dd}&quot;,Time.now.day.to_s)<br />
&nbsp;&nbsp;&nbsp; &nbsp;temp = serial.gsub(&quot;${autonum}&quot;,last_num.to_s)<br />
&nbsp;&nbsp;&nbsp; &nbsp;if (temp == last_serial_no)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;serial = serial.gsub(&quot;${autonum}&quot;,(last_num+1).to_s);<br />
&nbsp;&nbsp;&nbsp; &nbsp;else<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; serial = serial.gsub(&quot;${autonum}&quot;,1.to_s);<br />
&nbsp;&nbsp;&nbsp; &nbsp;serial<br />
&nbsp;&nbsp;&nbsp; &nbsp;end<br />
&nbsp;&nbsp;&nbsp; end<br />
&nbsp;&nbsp; K. 总结<br />
&nbsp;&nbsp; 一开始通过测试驱动的方式来，更加容易集中于代码，而不是考虑数据库如何，表如何.<br />
&nbsp;&nbsp; 因为和数据库，表没有关系，更加容易重用。<br />
&nbsp;&nbsp; 因为和数据库没有关系，也就有了新意，好玩，并且代码也就不多。<br />
&nbsp;&nbsp; 不要着急进入代码细节，先表意，然后用ruby翻译，当然如果ruby比较熟悉了，可以一步到位，而我现在不熟悉，就干脆从顶到下，思路更加清晰。人的头脑不适合在层次中切换，如果先考虑好上一层，然后在进入下一层，当然更加容易。<br />
&nbsp;&nbsp; irb可以交互执行，看库函数，或者快速看结果更合适，不像ruby.exe 那么死板。可以在刚刚提到的场合多用，这个工具更加容易看到脚本比编译的灵活快速的特点。</p>
          <br/>
          <span style="color:red;">
            <a href="http://1000copy.javaeye.com/blog/206612#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 21 Jun 2008 11:19:39 +0800</pubDate>
        <link>http://1000copy.javaeye.com/blog/206612</link>
        <guid>http://1000copy.javaeye.com/blog/206612</guid>
      </item>
      <item>
        <title>回复“每周一测” - Make change</title>
        <author>1000copy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://1000copy.javaeye.com">1000copy</a>&nbsp;
          链接：<a href="http://1000copy.javaeye.com/blog/190764" style="color:red;">http://1000copy.javaeye.com/blog/190764</a>&nbsp;
          发表时间: 2008年05月07日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">class Array; def sum; inject( nil ) { |sum,x| sum ? sum+x : x }; end; end
def clonearray(arr)
	b = []
	for a in arr
	  b &lt;&lt; a 
	end
	return b
end
def match(condidatesolution,avail,paymoney)
	@temp = 0
	for i in 0..avail.size-1
		@temp += condidatesolution[i] * avail[i]
	end
	return ( @temp ==paymoney)
end
def printarray(arr)
	print &quot;[&quot;
	for a in arr
		print a.to_s + &quot;,&quot;
	end
	print &quot;]&quot;
end
def makechange2(paymoney,avail)
	# 相当于解方程 aW+bX+cY+dZ = paymoney
	# 要求：
	# 这里W,X,Y,Z = 10,7,5,1
	# 要求找到所有的[a,b,c,d]的集合中
	#  a+b+c+d 是最小的作为解。
	#
	# 最大范围的数组 [3,5,7,39]
	
	# 获得最大数组 coinmax
	@coinmax = []
	@coincurr = []
	for coinavail in avail
	  @coinmax &lt;&lt; paymoney/coinavail
	  @coincurr &lt;&lt; 0
	end
	#printarray @coinmax
	#printarray @coincurr
	@size = @coincurr.size()
	# 循环遍历可能解空间，升位，直到 @coincurr[@size-1] &gt; @coinmax[@size-1] 
	@i =0 
	@mincoincount = 99999 

	while @coincurr[@size-1] &lt;= @coinmax[@size-1] 
	    if match(@coincurr,avail,paymoney)
		  print &quot;a solution:&quot;
		  printarray @coincurr
		  puts
		  @coincount = 	@coincurr.sum
		  if @coincount &lt; @mincoincount 
		    @mincoincount = @coincount
		    @finalsolution = clonearray(@coincurr)		    
		  end 
		end	
		@first = @coincurr.shift
		@coincurr.insert(0,@first+1)
		#print &quot;--&quot;
		#printarray @coincurr
		for i in 0..(@size -2)
		  if @coincurr[i] &gt; @coinmax[i] 
		    @coincurr[i+1] = @coincurr[i+1] + @coincurr[i] / (@coinmax[i]+1)
		    @coincurr[i] = @coincurr[i] % (@coinmax[i]+1)
		  end
		end  
	end
	print &quot;finalsolution:&quot;
	printarray @finalsolution
end
makechange2( 39,[10,7,5,1]) 


</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://1000copy.javaeye.com/blog/190764#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 07 May 2008 23:12:27 +0800</pubDate>
        <link>http://1000copy.javaeye.com/blog/190764</link>
        <guid>http://1000copy.javaeye.com/blog/190764</guid>
      </item>
  </channel>
</rss>