home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / pas_nl / 06 / pnl006.txt < prev    next >
Text File  |  1991-03-17  |  64KB  |  1,692 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.                                
  16.                                                         
  17.                                                                     
  18.                                                                     
  19.                                    ////////    //    //    //   
  20.                                   //    //    ///   //    //    
  21.                                  //    //    ////  //    //     
  22.                                 ////////    // // //    //      
  23.                                //          //  ////    //       
  24.                               //          //   ///    //          
  25.                              //          //    //    ///////    
  26.                                                                     
  27.                                                                     
  28.                                                                 
  29.                                                                
  30.                                                                
  31.                                      Pascal NewsLetter         
  32.                                           Issue #6
  33.                                          March, 1991             
  34.                                                                
  35.                                                                
  36.                                      Editor: Pete Davis         
  37.                                                                
  38.                                                                
  39.                                                                
  40.                                                                
  41.                                                                
  42.                                                                
  43.                                                                
  44.                                                                
  45.                                                                
  46.                                                                
  47.                                                                
  48.                                                                
  49.                                                                    
  50.                        The Programmer's Forum BBS is the home of
  51.                        PNL. It can be reached in Washington, DC at
  52.                        (202)966-3647. Information is available 
  53.                        through the following locations:        
  54.                                                                
  55.                        FidoNet:  Pete Davis@1:109/138           
  56.                        GEnie:    P.DAVIS5                          
  57.                        BitNet:   HJ647C@GWUVM & UE356C@GWUVM
  58.                        InterNet: HJ647C@GWUVM.GWU.EDU 
  59.                               or UE356C@GWUVM.GWU.EDU
  60.                        Uucp:     Pete.Davis@f138.n109.z1.fidonet.org
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.                                   Table of Contents
  69.  
  70.  
  71.  
  72.  
  73.              Introduction ................................  3 (P.D.)
  74.  
  75.  
  76.              Returning Structured Data Using TP Functions.  5 (B.M.)
  77.  
  78.  
  79.              Displaying an Integer with Commas, Revisited. 10 (N.P.)
  80.  
  81.  
  82.              Chess-Ter ................................... 13 (P.D.)
  83.  
  84.  
  85.              Searching ................................... 19 (K.S.)
  86.  
  87.  
  88.              For Beginners ............................... 21 (B.G.)
  89.  
  90.  
  91.              Conclusion .................................. 26 (P.D.)
  92.  
  93.  
  94.  
  95.  
  96.  
  97.           Key:
  98.           ----
  99.             P.D. - Pete Davis        : Editor-in-Chief
  100.             R.M. - Richard Morris    : Editor-Over-The-Pond
  101.             B.G. - Bob Gowans        : Columnist
  102.             B.M. - Bill Madison      : Contributing Writer
  103.             N.P. - Nathan Phillips   : Contributing Writer
  104.             K.S. - Kelly Schwarzhoff : Contributing Writer
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.                                   Introduction
  114.  
  115.           Well, it's  been quite a while  since PNL005 and I  apologize for
  116.      the delay. Many of you know why it took so long, and for those  of you
  117.      who don't, I  will give you  my excuse.  First of all,  since this  is
  118.      going to remain a free newsletter in the foreseeable future, I have to
  119.      put my priorities in order. Since money isn't going to be my priority,
  120.      school is.  I have decided  to add  to my  course load so  that I  can
  121.      graduate a semester  earlier than  planned. This has  resulted in  the
  122.      addition of two credits bringing my  total to 17. Also, I decided (not
  123.      wisely) to take a graduate course. The additional two credits and  the
  124.      graduate course have taken up an enormous amount of extra time. On top
  125.      of  this I  also work  20-30  hours a  week. These,  combined with  an
  126.      attempt to  maintain my social life  (very hard with school  and work)
  127.      has left  little  time for  keeping  the newsletter  coming out  at  a
  128.      regular interval. Right  now I am in my spring  break which will allow
  129.      me  a little  time to get  this issue  out. I  hope to get  started on
  130.      PNL007 before summer, but I just  can't be sure. If the first half  of
  131.      this semester is  any indication, PNL007 won't come out  until about a
  132.      week after summer vacation  begins. Also, getting the issues  out over
  133.      summer won't be as easy as last summer as I am going to be taking some
  134.      classes over the summer and working almost full time.
  135.  
  136.           Well, that's  my excuse.  Don't get  me wrong,  I love doing  the
  137.      newsletter, and  if I  didn't have  to worry about  school and  work I
  138.      would certainly be working much harder on it. 
  139.  
  140.           I would like to  bring up some very good news, though.  One of my
  141.      professors,  Ray Thomas,  who was  my professor  for some of  my first
  142.      classes in programming, will be retiring soon. Professor Thomas taught
  143.      me a lot  of what I know and is directly or indirectly responsible for
  144.      several articles that I have written. He has also been very supportive
  145.      of  the newsletter. He has told me  that after his retirement (the end
  146.      of this  semester) he will  be writing articles  now and then  for the
  147.      newsletter. This is very good news to me and I think many of  you will
  148.      be pleased.
  149.  
  150.           The introduction and  conclusion areas  are sort of  my areas  to
  151.      ramble  on about things related to the newsletter as opposed to Pascal
  152.      specific things. So, to that end, here are some  things I want to talk
  153.      about. First of all: I love getting comments and suggestions about the
  154.      newsletter. (Not quite as  much as getting articles, but  the comments
  155.      help a  lot.) So, keep  them coming.  Also, I've  been thinking  about
  156.      dividing  the  newsletter into  sections.  Maybe  having a  beginners,
  157.      moderate and advanced level areas.  I'd like to hear comments  on this
  158.      idea. Would it help you find the stuff you want a little quicker? 
  159.  
  160.           I feel like I have a million things to talk about. It has been so
  161.      long since my last  issue, but I  would probably bore  many of you.  I
  162.      will just add a  little about what you can expect  from this issue and
  163.      then let you go on to the good stuff.
  164.  
  165.                                       - 3 -
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174.           This issue  I will  start my  series on Chess-Ter,  a chess  game
  175.      written by me and  5 others. It's not an artificial intelligence chess
  176.      program,  but one  that two  people can  play. I  present it  for it's
  177.      application to Pascal, not AI. The first two  or three installments of
  178.      this article  aren't going to go  very in-depth and will  only get the
  179.      surface of certain parts of the program. The idea being  that you, the
  180.      reader, will tell me what parts  interest you and confuse you, then in
  181.      later  issues  I will  go back  and cover  things  in a  more in-depth
  182.      fashion. Just because of the size of the program, it  is going to take
  183.      a long time cover the whole thing and I want to  get the whole program
  184.      out to  you, the  readers, as quickly  as possible.  Anyway, read  the
  185.      article for more information.
  186.  
  187.           Bill Madison presents a method of Returning Structured Data Using
  188.      Pascal Functions.  Also, we  have Displaying  an Integer with  Commas,
  189.      Revisited.  This piece,  by  Nathan  S.  Phillips is  a  return  to  a
  190.      procedure that appeared in issue #2 of the PNL. He goes  into new ways
  191.      of doing the same thing and  showing the good and bad aspects of  each
  192.      method.  This  is  a  great  lesson  in  program  optimization.  Kelly
  193.      Schwarzhoff, a high school sophmore, shows some  methods of searching.
  194.      a list. And Bob Gowans, my faithful companion comes through again with
  195.      another column in the For Beginners section. 
  196.  
  197.           Richard  Morris' article  has been dis-continued  temporarily. We
  198.      hope to have it continued as soon as possible. 
  199.  
  200.           Well, that's about it, hope you enjoy this issue.
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207.  
  208.  
  209.  
  210.  
  211.  
  212.  
  213.  
  214.  
  215.  
  216.  
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223.  
  224.  
  225.  
  226.                                       - 4 -
  227.  
  228.  
  229.  
  230.  
  231.  
  232.  
  233.  
  234.              Returning Structured Data Using Turbo Pascal Functions
  235.                                  by Bill Madison
  236.  
  237.                         W. G. Madison & Associates, Ltd.
  238.                             8425 Greenbelt Road, #101
  239.                                   P. O. Box 898
  240.                                Greenbelt, MD 20770
  241.                                   (301)552-7234
  242.                                   CIS 73240,342
  243.  
  244.  
  245.      ABSTRACT
  246.           Turbo Pascal  is, without  question, the development  language of
  247.      choice  for microcomputer applications in which  portability is not an
  248.      overriding issue (C addicts to the contrary notwithstanding).
  249.  
  250.           Turbo  Pascal,  or any  dialect of  Pascal  for that  matter, has
  251.      several serious shortcomings. One of the more important among these is
  252.      Pascal's inability  to establish structured data types  (with the sole
  253.      exception of strings) as a function return. This effectively precludes
  254.      the writing of many types of packages in a programmer-friendly manner.
  255.  
  256.           This article  explores a technique for  circumventing the problem
  257.      by using  the mechanism of functions having returns of type POINTER or
  258.      a variant thereof. Examples are shown, drawn from a COMPLEX unit which
  259.      has been designed, written, and used by myself.
  260.  
  261.      INTRODUCTION AND MOTIVATION
  262.           I was recently  given an  assignment by a  client which  involved
  263.      extensive manipulation of complex numbers. This was not the first time
  264.      this had occurred.
  265.  
  266.           Tired of  re-inventing  the wheel  every  time it  occurred,  and
  267.      equally tired  of making  interminable procedure  calls to evaluate  a
  268.      simple expression,  he decided that there  had to be a  better way. IF
  269.      ONLY  TURBO PASCAL WOULD  PERMIT FUNCTIONS  TO RETURN  STRUCTURED DATA
  270.      TYPES!!! The result  turned out  even better than  expected; a  design
  271.      methodology emerged  which, when implemented, would  work equally well
  272.      for ANY structured data  type. With minor modification, it  would even
  273.      work well  with data types  in which,ideally, the  size of the  actual
  274.      data to be manipulated  could not be determined until  execution time;
  275.      e.g., matrices, long  strings (i.e., strings whose length  exceeds 255
  276.      characters).
  277.  
  278.           To  refresh your memory, complex  numbers, which will  be used to
  279.      develop this discussion, are numbers of the form  R + (i*I), where i =
  280.      sqrt(-1)).  In  a Pascal  environment,  this  inherently represents  a
  281.      RECORD structure:
  282.  
  283.                type
  284.                  ComplexBaseType = record
  285.                    Re,
  286.  
  287.                                       - 5 -
  288.  
  289.  
  290.  
  291.  
  292.  
  293.  
  294.  
  295.                    Im   : real;
  296.                  end; {ComplexBaseType}
  297.  
  298.           Mathematical rules  exist which define the  four basic arithmetic
  299.      operations with  respect to the  complex numbers.  Given these  rules,
  300.      other rules have  been derived such  that, if an operation  exists for
  301.      conventional REAL  numbers an  analogous rule  exists for the  COMPLEX
  302.      numbers. Thus, one may speak of  powers and roots of complex  numbers,
  303.      their trigonometric functions, etc.
  304.  
  305.           In  order to define these operations to Pascal, they would either
  306.      need to be defined in  the native compiler or the compiler  would need
  307.      to be syntax extensible. Then one would be able to write, for example,
  308.  
  309.                  C := A + B;
  310.  
  311.      where A, B, C have been declared to be type ComplexBaseType.
  312.  
  313.           Yet it is  impossible to expect that the plethora of unusual data
  314.      types  which  one  might devise  could  be  compiled  in native  mode.
  315.      Further,  syntax  extensibility  is  a compiler  attribute  not  found
  316.      (unfortunately) in commercially available  compilers. (The most recent
  317.      commercially  available   compiler  having  any   form  of   syntactic
  318.      extensibility which  I have  seen was  the FORTRAN for  the CDC  1604,
  319.      built during the mid-1960's.)
  320.  
  321.           An alternative, therefore, would  be to permit the user  to write
  322.      functions   implementing  desired   operations,  which   would  return
  323.      arbitrary data types as  function results. Were this language  feature
  324.      available, and assuming that functions  to combine two complex numbers
  325.      were declared
  326.  
  327.       function CAdd(A, B : ComplexBaseType) : ComplexBaseType;
  328.       function CSub(A, B : ComplexBaseType) : ComplexBaseType;
  329.       function CMul(A, B : ComplexBaseType) : ComplexBaseType;
  330.       function CDiv(A, B : ComplexBaseType) : ComplexBaseType;
  331.  
  332.         one could write the equivalent of
  333.  
  334.                       E := (A + B * C) / D
  335.                as
  336.                       E := CDiv(CAdd(A, CMul(B, C)), D);
  337.  
  338.  
  339.  
  340.           Clumsy  as  this might  appear at  first,  it is  infinitely more
  341.      readable (in my opinion) than declarations of
  342.  
  343.        procedure CAdd(A, B : ComplexBaseType;
  344.                                 var C : ComplexBaseType);
  345.        procedure CSub(A, B : ComplexBaseType;
  346.                                 var C : ComplexBaseType);
  347.  
  348.                                       - 6 -
  349.  
  350.  
  351.  
  352.  
  353.  
  354.  
  355.  
  356.        procedure CMul(A, B : ComplexBaseType;
  357.                                 var C : ComplexBaseType);
  358.        procedure CDiv(A, B : ComplexBaseType;
  359.                                 var C : ComplexBaseType);
  360.  
  361.       and an evaluation of the expression as
  362.  
  363.                       CMul(B, C, Temp);
  364.                       CAdd(A, Temp, Temp);
  365.                       CDiv(Temp, D, E);
  366.  
  367.      especially as one attempts to evaluate more complex expressions.
  368.  
  369.           Of  course, we  are still  not out  of the  woods,  because Turbo
  370.      Pascal can't return structured values from functions!
  371.  
  372.  
  373.      ONE POSSIBLE SOLUTION
  374.           Suppose,  instead  of  working  with ComplexBaseType  as  defined
  375.      above, we work with
  376.  
  377.          type
  378.            Complex = ^ComplexBaseType;
  379.  
  380.      and then in addition to declaring our variables
  381.  
  382.          var
  383.            A, B, C, D, E : Complex;
  384.  
  385.      we declare the functions as
  386.  
  387.          function CAdd(A, B : Complex) : Complex;
  388.          function CSub(A, B : Complex) : Complex;
  389.          function CMul(A, B : Complex) : Complex;
  390.          function CDiv(A, B : Complex) : Complex;
  391.  
  392.      then we can write the above expression evaluation as
  393.  
  394.          E^ := CDiv(CAdd(A, CMul(B, C)), D)^;
  395.  
  396.      which,  as we  can see,  is  just as  readable and  convenient as  the
  397.      original  (with the minor inconvenience of requiring the "^" symbol on
  398.      each side of the replacement operator.
  399.  
  400.           Note, however, that since all  operations are being performed  by
  401.      nested function calls, the normal rules of operator precedence are not
  402.      applicable. All "operators" are  of equal precedence. It is  therefore
  403.      incumbent  on the  programmer  to assure  that  any required  operator
  404.      dependency is properly managed.
  405.  
  406.           If this  approach of  using pointer-type functions  is taken,  an
  407.      additional step must be included. Note that a variable of type Complex
  408.  
  409.                                       - 7 -
  410.  
  411.  
  412.  
  413.  
  414.  
  415.  
  416.  
  417.      is  actually a pointer. Unless a pointer is initialized with something
  418.      to point to, strange things  will occur very quickly when  the program
  419.      is executed. Therefore,  each variable, in addition  to being declared
  420.      must be initialized.
  421.  
  422.           Pointer  variables suggest (but  do not require)  that the things
  423.      pointed to must be on the heap. Assume that we  accept the suggestion,
  424.      and agree  to store all  Complex data on  the heap. Further,  assume a
  425.      function CInit, declared as
  426.  
  427.                 function CInit(A : Complex) : boolean;
  428.  
  429.      which  will  return  FALSE  if  and  only  if  there  is  insufficient
  430.      contiguous space left on  the heap. Then, prior to the first reference
  431.      to any of the variables, we would have a sequence of instructions like
  432.  
  433.                 if not CInit(A) then {Do error recovery};
  434.                 if not CInit(B) then {Do error recovery};
  435.                 if not CInit(C) then {Do error recovery};
  436.                 if not CInit(D) then {Do error recovery};
  437.                 if not CInit(E) then {Do error recovery};
  438.  
  439.           One  additional requirement  must  be met  to  use this  approach
  440.      effectively; specifically, the storage of intermediate results. When a
  441.      value  is returned  from a  function in  Turbo Pascal,  that  value is
  442.      stored on a stack and is popped off as required. The stack maintenance
  443.      code is generated by the compiler, as part of the compilation process.
  444.      However, when we take over a part of the compiler's  functionality, as
  445.      we  are doing  here, we  must also  assume responsibility  for keeping
  446.      track of the structured values being returned. This is necessitated by
  447.      the  fact that  the  function returns  are  pointers to  the  returned
  448.      values, and not the values themselves!
  449.  
  450.           This is most conveniently  done by establishing one or  more ring
  451.      buffers,  again probably (but not necessarily) on the heap. The actual
  452.      structured value is  then stored  in the ring  buffer, and the  return
  453.      from the Pascal function  becomes the pointer value pointing  into the
  454.      ring. The  size  (i.e., the  number of  elements) of  the ring  buffer
  455.      determines the maximum  complexity of the expression  to be evaluated.
  456.      Theoretically  it  would  be   possible  to  write  expressions  whose
  457.      evaluation would  require storage of  any desired number  of temporary
  458.      results. A more  serious threat,  however, lies in  the evaluation  of
  459.      recursive procedure or function  calls, in which a stack (or  ring) of
  460.      any size could be quickly exhausted.
  461.  
  462.  
  463.      CONCLUSION
  464.           While no  perfect solution  exists for  the easy  manipulation of
  465.      structured data types within the confines of any dialect of the PASCAL
  466.      programming  language, a  methodology has  been suggested  which, when
  467.      properly applied, can approach this ideal.
  468.  
  469.  
  470.                                       - 8 -
  471.  
  472.  
  473.  
  474.  
  475.  
  476.  
  477.  
  478.           The  use  of Pascal  functions  which accept  and  return pointer
  479.      values and  allocate data storage on the heap provides a mechanism for
  480.      effectively  and  relatively  easily and  readably  manipulating  data
  481.      structures of any degree of complexity.
  482.  
  483.  
  484.      A WORKING EXAMPLE
  485.           Following is  the code  for a unit  I wrote to  implement COMPLEX
  486.      arithmetic using Turbo Pascal, along with  the code for a program used
  487.      to test the unit.  The code for both the unit and  the test program is
  488.      available on many BBSs under the name SHCMPLX1.ZIP.
  489.  
  490.           I have also used this basic technique to implement a unit for the
  491.      manipulation of long strings (up to 65517 characters),  without having
  492.      to allocate the  full maximum  allowable length for  each long  string
  493.      declared. The code for both  the LongString unit and its test  program
  494.      is available on many BBSs under the name SHLNGST1.ZIP.
  495.  
  496.      {Editor's note: The file SHCMPLX1.ZIP is included with this PNL006.ZIP
  497.      file and the code mentioned in the article is found there.}
  498.  
  499.  
  500.  
  501.  
  502.  
  503.  
  504.  
  505.  
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512.  
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530.  
  531.                                       - 9 -
  532.  
  533.  
  534.  
  535.  
  536.  
  537.  
  538.  
  539.                   Displaying an Integer with Commas, Revisited
  540.                               by Nathan S. Phillips
  541.  
  542.           In the second issue of the PNL, I discussed a recursive method of
  543.      displaying  an integer with commas  (12345 -> 12,345).   The recursive
  544.      procedure provided as an example at that time has several problems.
  545.  
  546.           First,  being  recursive, stack  space  is  used for  storage  of
  547.      parameter values  and calls.   The program  has to keep  track of  all
  548.      local  variable  values used  in  the procedure  so that  they  can be
  549.      restored when the  next call returns.  It takes  time to perform these
  550.      housekeeping tasks.  Although in this particular example these are not
  551.      major concerns, you should  bear them in mind when  contemplating more
  552.      complex recursive routines.
  553.  
  554.           The  second problem  with  the procedure  is  that it  is  fairly
  555.      cryptic;  anyone attempting to revise or debug the code would probably
  556.      spend  several minutes figuring out how the blasted thing works in the
  557.      first  place.   More than  likely,  the person  would  then choose  to
  558.      rewrite the  entire procedure, resulting in  more lost time.   As with
  559.      the  first  point, this  is not  a major  problem with  the particular
  560.      routine  being considered, but with a  larger piece of code the amount
  561.      of wasted time could add up very quickly.
  562.  
  563.           Finally, since the procedure does the output internally, you must
  564.      position  the cursor  before calling  the procedure;  the number  with
  565.      commas is then simply 'spit out' at that location.  This makes it very
  566.      difficult to do  formatting such as  right justification, because  you
  567.      don't know in advance (without doing additional calculations) how long
  568.      the number  will be once  the commas are included.   Also, to  get the
  569.      output to  go somewhere besides  the display,  you have to  modify the
  570.      procedure!   Not good programming practice  at all.  If  it returned a
  571.      string, we could then put  the string wherever we want to,  and with a
  572.      simple Length() call, we would know how long it is.
  573.  
  574.           Wouldn't it be nice if this were a non-recursive, easily modified
  575.      function which  took the number as  a parameter and returned  a string
  576.      which was the number with commas included?  Well, let's make it so:
  577.  
  578.  
  579.      function NumWithCommas(theNum : longint) : string;
  580.  
  581.      var nwcStr,  { the working string } 
  582.          tempStr  { a temporary string }
  583.              : string;          
  584.  
  585.      begin  { function NumWithCommas }
  586.  
  587.        nwcStr := '';  { initialize working string } 
  588.  
  589.        while theNum >= 1000 do  { as long as we need more commas }
  590.          begin  { while theNum } 
  591.  
  592.                                      - 10 -
  593.  
  594.  
  595.  
  596.  
  597.  
  598.  
  599.  
  600.            Str(theNum mod 1000, tempStr);  { put the last 3 digits }
  601.                                            { of theNum in tempStr  }
  602.  
  603.            while Length(tempStr) < 3 do  { pad tempStr with }
  604.              tempStr := '0' + tempStr;   { '0's on the left } 
  605.  
  606.            nwcStr := ',' + tempStr + nwcStr;  { add comma & digits } 
  607.                                               { to working string  }
  608.            theNum := theNum div 1000;  { discard the 3 digits }
  609.                                        { we just took care of }    
  610.          end;  { while theNum }
  611.  
  612.        Str(theNum,tempStr);  { now theNum is less than 1,000 }
  613.  
  614.        NumWithCommas := tempStr + nwcStr;  { put first digits }
  615.                                            { at the beginning }
  616.      end;  { function NumWithCommas } 
  617.  
  618.  
  619.  
  620.           This function has very  little overhead, is easier to  revise and
  621.      debug, and is generally more useful.
  622.  
  623.           (Sidebar  to technically inclined:   I tested both  forms of this
  624.      routine  using  Turbo Profiler  and found,  to  my surprise,  that the
  625.      non-recursive function version shown here is faster by a small amount.
  626.      I  was  sure  that  the  string  operations  it  uses  would  make  it
  627.      considerably slower -  any ideas what  this isn't so?   I forced  this
  628.      function  to  write  the  result  before  returning,  so  the  'output
  629.      slowdown' should have been the same for both routines.)
  630.  
  631.           Now, how does one go about  using this new function?  Suppose you
  632.      wish  to  inform the  user of  the number  of  bytes that  the current
  633.      directory is taking up on the hard disk.  A typical method is:
  634.  
  635.           writeln(bytesUsed:1, ' bytes used for directory ',dirName);
  636.  
  637.      which produces:
  638.  
  639.           1348857 bytes used for directory FOO
  640.  
  641.  
  642.      With NumWithCommas, you can dress up the output very easily:
  643.  
  644.           writeln(NumWithCommas(bytesUsed),' bytes used for directory',
  645.                   dirName);
  646.  
  647.      which produces:
  648.  
  649.           1,348,857 bytes used for directory FOO
  650.  
  651.  
  652.  
  653.                                      - 11 -
  654.  
  655.  
  656.  
  657.  
  658.  
  659.  
  660.  
  661.           But the old recursive  procedure could do that!  Why did we go to
  662.      the  trouble of rewriting it?   Suppose there  are several directories
  663.      for which you want  to display size information in column format. With
  664.      the old DisplayWithCommas, you had to settle for:
  665.           
  666.           for i := 1 to numDirs do
  667.             begin
  668.               for j := 1 to 8-Length(dirName[i]) do
  669.                 write(' ');
  670.               write(dirName[i],' - ');
  671.               DisplayWithCommas(bytesUsed[i]);
  672.               writeln(' bytes');
  673.             end;
  674.  
  675.      which produces:
  676.  
  677.                FOO - 1,348,857 bytes
  678.             LABELS - 243,567 bytes
  679.               UTIL - 16,344,059 bytes
  680.            FAKEDIR - 1,024 bytes
  681.  
  682.  
  683.      Now with NumWithCommas as a function, you can do this:
  684.  
  685.           for i := 1 to numDirs do
  686.             begin
  687.               for j := 1 to 8-Length(dirName[i]) do
  688.                 write(' ');
  689.               write(dirName[i],' - ');
  690.               wcStr := NumWithCommas(bytesUsed[i]);
  691.               for j := 1 to 10-Length(wcStr) do
  692.                 write(' ');
  693.               writeln(wcStr,' bytes');
  694.             end;
  695.  
  696.      producing:
  697.        
  698.                FOO -  1,348,857 bytes
  699.             LABELS -    243,567 bytes
  700.               UTIL - 16,344,059 bytes
  701.            FAKEDIR -      1,024 bytes
  702.  
  703.  
  704.           The combination of commas  and formatting makes it very  easy for
  705.      the  user to  determine at  a  glance the  relative magnitude  of each
  706.      value.  And the easier  your program is for the user,  the more likely
  707.      it is to be used (and, hopefully, paid for).
  708.  
  709.  
  710.  
  711.  
  712.  
  713.  
  714.                                      - 12 -
  715.  
  716.  
  717.  
  718.  
  719.  
  720.  
  721.  
  722.                                     Chess-Ter
  723.                                   By Pete Davis
  724.  
  725.           Well,  I mentioned  in  a previous  issue that  I  would do  this
  726.      article  and,  after a  good deal  of  procrastination, I  finally got
  727.      started on it.  Part of  the delay is  just due to  the volume of  the
  728.      program itself. The code is broken into 8 units and comes to over 4800
  729.      lines of code. This sheer volume makes it a little difficult to handle
  730.      in the  newsletter. I have decided to break up the article into either
  731.      two or three parts, initially. The two or three parts would be sort of
  732.      a quick  overview and between  those two or  three, the  entire source
  733.      code would be released. 
  734.  
  735.           For  example,  in  this  issue,  I  plan  on  talking  about  the
  736.      CHESSTER.PAS,  GLOBALS.PAS,  KB1.PAS  and DRAW_PCS.PAS.  I  will  only
  737.      release the  source  code for  those parts  of the  program with  this
  738.      issue. Then, in the next issue, I  will release the source code to the
  739.      other parts of the program I discuss and, if necessary, I will release
  740.      anything remaining in the third part.
  741.  
  742.           I am doing a rather brief overview at first so that I can get out
  743.      the different parts of  the program quickly. After the  entire program
  744.      has been released,  I will back-track and talk about  some of the more
  745.      technical aspects of  the program  and discuss ways  of improving  the
  746.      code and so-forth.
  747.  
  748.           First,  I suppose  I should  provide some  sort of  background on
  749.      Chess-Ter. Last  semester I took a class  called Software Engineering.
  750.      The main thrust of the class was putting together large projects. I've
  751.      thought  about  concentrating  on  that  issue  in  a  series  in  the
  752.      newsletter,  but unless I get some requests,  I'm going to hold off on
  753.      that. Anyway, about two weeks into the semester we got our assignment,
  754.      which was due  at the  end of the  semester. The project  was a  Chess
  755.      program  that two people could play. This  is not an AI chess program,
  756.      it  only lets two  people play. The  AI part  is left for  you, if you
  757.      dare.
  758.  
  759.           Anyway, I got into a group  of 5 other programmers who turned out
  760.      to be very hard working.  Good thing, because I'm not and  without the
  761.      push from the rest  of the group, a  project like this would not  have
  762.      been  done by me. So,  I would first like to  name all the authors and
  763.      point out their contributions:
  764.  
  765.      Mark Friedman  - Did most of the  chess pieces and the  board. He also
  766.      did the Handle Moves Request and Handle Take-Back Request.
  767.  
  768.      Jessica Chestnut  - Did most  of the checks  for legal moves.  (A very
  769.      impressive feat for someone who had  never played chess until a couple
  770.      days before the project was completed.)
  771.  
  772.      Akiko Okamoto - Did the Load and Save games file handling.
  773.  
  774.  
  775.                                      - 13 -
  776.  
  777.  
  778.  
  779.  
  780.  
  781.  
  782.  
  783.      John  Loux -  Wrote  the  main  keyboard  interface  and  the  central
  784.      procedure of the program.
  785.  
  786.      Paul  Sternal  -  Wrote the  Replay  procedures  that  allow for  game
  787.      replays.
  788.  
  789.      and  Me  -  I  did  the  Check  for  Check  and  Check for  Check-Mate
  790.      procedures.  I also  did the  intro screen  and the  screen interface.
  791.      (With the exception of the board and pieces.)
  792.  
  793.           That  about covers  the  intro to  the project.  There are  a few
  794.      things I'd  like to bring  up, though.  First of all,  the program  is
  795.      copyrighted and the source code is released not just from me, but from
  796.      the entire group (collectively  known as The Pascal Team). Also, I had
  797.      considered  cleaning the program up  before writing this,  but then it
  798.      occurred to me that leaving in some of the problems might be useful in
  799.      discussion  of  improvements for  the program.  I  hope to  bring some
  800.      improvements into the program through future issues.
  801.  
  802.           Well, let's get  started. First of all, I guess  I should discuss
  803.      the main program  file, CHESSTER.PAS. Not a  whole lot to discuss.  It
  804.      includes all the necessary units: Globals  (discussed later), CRT, KB1
  805.      (discussed  later), DOS, and Draw_Pcs. The  screen is initialized, the
  806.      game  is initialized, the board  is drawn, text  displayed and finally
  807.      Get_Keyboard is  called, which  is an  iterative procedure that  keeps
  808.      going until the game is quit. Then the endprompt is shown. Not a whole
  809.      lot in the main program. 
  810.  
  811.           For  large projects  it's a  good idea to  keep the  main program
  812.      itself rather small.  This helps to enforce the idea of modularity, or
  813.      breaking your programs into smaller pieces. 
  814.  
  815.           The  first unit I want  to discuss is  GLOBALS. GLOBALS contained
  816.      all  the type definitions and  procedures which were common throughout
  817.      the program.  I want to  point out that  this wasn't always  the case.
  818.      This  was  the desired  result, but  sometimes  it turned  out  that a
  819.      procedure we  thought would be  used globally,  turned out only  to be
  820.      used one place, or vica-versa. The representation of our board was, of
  821.      course, a  key concern, but even more  important was the current state
  822.      of the game. We  felt the best way for all the different procedures to
  823.      share information was  to create  a variable type  of Game_State.  The
  824.      Game_State had everything from a 2 dimensional array of all the pieces
  825.      on the board  to the current move  number, whose move it  was and what
  826.      mode the game was playing in. (A short note about the  modes. The game
  827.      has a  novice and expert mode.  The novice mode allows  the ability to
  828.      take back moves  and find  out what all  the legal moves  for a  given
  829.      piece  are.)  The game  state also  kept  various flags  about current
  830.      moves.
  831.  
  832.           Along  with the  game_state there  is also  a move  history which
  833.      keeps track of all  the moves made. This is basically  an array of the
  834.      Move_Type. The Move_Type  contains the pieces  from and to  locations,
  835.  
  836.                                      - 14 -
  837.  
  838.  
  839.  
  840.  
  841.  
  842.  
  843.  
  844.      the piece color, the piece_type, what kind of piece was taken, if any,
  845.      and what  the move  type  was (i.e.  castle,  check, mate,  and  other
  846.      exceptional conditions).
  847.  
  848.           Although it  is usually considered  bad practice  to keep  global
  849.      variables, in  this case we found it necessary and sometimes it is. We
  850.      kept  several things global: The current game state, the current move,
  851.      the move_history and  the list of legal  moves for the  current moving
  852.      piece.
  853.  
  854.           Now I'd  like to get into  the graphics a bit.  Here is something
  855.      that  is mentioned in the Turbo manual and has turned out to be a very
  856.      useful feature.  Instead of having the  BGI files we  needed loaded at
  857.      run-time, we decided to  have them linked in at compile-time. This has
  858.      several advantages:  First of all,  it keeps  you from having  to keep
  859.      track of more than  one file in the run-time program. It  also saves a
  860.      bit of trouble, I feel. 
  861.  
  862.           In this program  we used EGA mode.  This was done  mainly because
  863.      that  was  the only  graphics  I had  and since  I  did a  lot  of the
  864.      graphics, I had to have  it compatible with my system. So,  here's how
  865.      we handle the compile-time linking of BGI files. (I also did this with
  866.      the Gothic character set included with TP.) Since we are working  with
  867.      EGA, used  the EGAVGA.BGI file. I changed this to an object file using
  868.      BINOBJ.EXE. I then  typed, from  the DOS prompt,  with EGAVGA.BGI  and
  869.      BINOBJ.EXE in the current directory:
  870.  
  871.      BINOBJ EGAVGA.BGI EGAVGA.OBJ EGAVGA
  872.  
  873.           This turns  the .BGI into  a .OBJ and gives  it a public  name of
  874.      EGAVGA (Don't worry about that last part, just stick to using the part
  875.      of the filename before the period  and you should be fine.) I followed
  876.      this by doing the same thing to the gothic character set:
  877.  
  878.      BINOBJ GOTH.CHR GOTH.OBJ GOTH
  879.  
  880.           This  turns the  .CHR file  into a  .OBJ file  also. Then  in the
  881.      GLOBALS procedure  I  link both  of  these .OBJ  files into  the  main
  882.      program as follows:
  883.  
  884.  
  885.      procedure EGAVGA; external;
  886.      { The procedure name must match the Public name given above. }
  887.  
  888.      {$L EGAVGA.OBJ}  
  889.  
  890.      { the $L, above actually links it in. }
  891.  
  892.  
  893.      procedure GOTH; external;
  894.      { Just like above: }
  895.      {$L GOTH.OBJ}
  896.  
  897.                                      - 15 -
  898.  
  899.  
  900.  
  901.  
  902.  
  903.  
  904.  
  905.  
  906.           That's all there is to it. You now have the .BGI files linked in.
  907.      Now, to actually  use those  .BGI routines you  need to register  them
  908.      with TP. This is all done in the InitScrn procedure in the GLOBALS.PAS
  909.      file.
  910.  
  911.           Some  of  the  other  important procedures  included  the  Prompt
  912.      procedure which  put a line  of text on  the 23rd line  of the screen.
  913.      This was  basically used to  send some  sort of message  to the  user.
  914.      There  was  also a  beep  procedure  that went  well  with  the prompt
  915.      procedure. 
  916.  
  917.           Then  a Query  procedure was  added, which  worked just  like the
  918.      prompt procedure,  but then read in  a line of  text from the  user so
  919.      that a response  could be  returned. Then there  is the  Error_Display
  920.      procedure which is like Prompt, but in a different color  to help grab
  921.      the user's attention. 
  922.  
  923.           The next thing on  our list is the InitGame  procedure. Basically
  924.      this is  called everytime you start  a new game. This  initializes all
  925.      the  conditions  in the  game and  finds out  whether the  user want's
  926.      expert  or novice mode. Also initial  positions for all the pieces are
  927.      set. This should all be very straight forward. 
  928.  
  929.           One thing you might  notice in the InitGame procedure is the very
  930.      beginning.  The  code  starting  with  SetFillStyle(8,  Blue)  through
  931.      OutTextXY(370,220,'(C)  ...  this is  the  opening  screen. Using  the
  932.      simple  Gothic font  and some  easy to  use graphic  procedures, Turbo
  933.      Pascal let's you do some very nice opening screens. 
  934.  
  935.           The Convert_Rank and Convert_File procedures were used to convert
  936.      the board  positions  (A1-H8)  to  screen pixel  positions.  This  was
  937.      necessary  since we were  using a board  that was 8x8  in concept, but
  938.      actually several hundred pixels in length and height.
  939.  
  940.           The Display_Move_History  updates the Move_History that  is shown
  941.      on the screen. Basically it's  a list of all move made since  the game
  942.      began. This, again, is  done in a fairly straight-forward  way, except
  943.      for  one thing.  I used  the assignment:  directvideo:= false;  before
  944.      doing any screen writes. This allows you to write text into a graphics
  945.      screen.
  946.  
  947.           The  show_text procedure,  like  the  Display_Move_History  turns
  948.      directvideo  off. All  it  really does  is  displays the  text on  the
  949.      screen, other than the move_history.  It is straight-forward and  easy
  950.      to follow.
  951.  
  952.           The next  unit I want to cover is  the Draw_Pcs unit. This one is
  953.      very  simple  to follow.  It  was more  of  a tedious  routine  to put
  954.      together than a complicated  routine. Basically you sit and  draw your
  955.      pieces one line at a time and keep looking at them on the screen until
  956.      they look good. In this case, the pieces were drawn  by Mark Friedman,
  957.  
  958.                                      - 16 -
  959.  
  960.  
  961.  
  962.  
  963.  
  964.  
  965.  
  966.      who spent a lot of time drawing the pieces out. 
  967.  
  968.           I would like  to point  out one improvement  we encountered  when
  969.      writing this. Originally Mark  wrote the procedure using  for-do loops
  970.      and the putpixel  procedure to draw the pieces. This  turned out to be
  971.      very slow, so we ended up replacing all the putpixels and for-do loops
  972.      with lineto procedures. This  resulted in a huge time  savings. You'll
  973.      notice that the squares are still drawn using the putpixel routine. We
  974.      left this that  way for the visual effects it  provides. That's really
  975.      all there is to the Draw_Pcs. 
  976.  
  977.           The last  unit we will  be discussing  in this issue  is the  KB1
  978.      unit. This  Get_Keyboard procedure  at  the end  of  the unit  is  the
  979.      center-piece  for the entire program. It is  where the user's input is
  980.      handled. It checks  to make sure certain keystrokes are  valid for the
  981.      current  mode.  (Expert or  Novice).  It  takes  care  of  check-mate.
  982.      Basically  the routine  is centered  around a  repeat-until loop  that
  983.      reads the  keyboard input and  then uses a  case statement to  process
  984.      different requests from the user.
  985.  
  986.           Going back to the  beginning of the unit we have  the Arrow_Moves
  987.      procedure. This  reads in the  keypad arrows and uses  them for cursor
  988.      movement  in the game. It also  checks to make sure  the user stays on
  989.      the board and doesn't try to roam off.
  990.  
  991.           Following  that are  two  Beep routines  (Beep2  & Beep4)  These,
  992.      looking  back, probably belong  in the Globals unit  with Beep, but we
  993.      will  discuss  that later  when  we talk  about  ways  to improve  the
  994.      program. 
  995.  
  996.           The  Select_A_Piece procedure changes the color of a piece on the
  997.      board after the  user has selected that  piece to be moved.  Following
  998.      that is  DeSelect which then  turns the  piece back  to it's  previous
  999.      color. 
  1000.  
  1001.           The  Check_Move_Piece  procedure takes  care  of  picking up  and
  1002.      moving pieces on the board. IT calls the logic  procedures(Legal_Move)
  1003.      to see if the moves are legal. We'll get involved in the logic part in
  1004.      a later issue.
  1005.  
  1006.           The Check_Legal_Piece checks  to see  if the piece  the user  has
  1007.      selected is a piece on his side.
  1008.  
  1009.           And  the final  procedure  is the  Handle_New_Game_Request  which
  1010.      basically re-initializes the game state and board.
  1011.  
  1012.           Now, I know  what you're  thinking. You think  I've shot  through
  1013.      this program  without a whole lot  of explanation and you're  right. I
  1014.      want  to give you a quick overview  of everything first and when we've
  1015.      covered  the entire  program I  will back-track  and go  in-depth into
  1016.      parts we've only touched on now.
  1017.  
  1018.  
  1019.                                      - 17 -
  1020.  
  1021.  
  1022.  
  1023.  
  1024.  
  1025.  
  1026.  
  1027.           The  entire program is  very large and  represents a lot  of work
  1028.      done by six people. There are errors and the  code is not perfect, but
  1029.      I believe that showing some  of the mistakes we made can  help prevent
  1030.      you from making the same ones. 
  1031.  
  1032.  
  1033.  
  1034.  
  1035.  
  1036.  
  1037.  
  1038.  
  1039.  
  1040.  
  1041.  
  1042.  
  1043.  
  1044.  
  1045.  
  1046.  
  1047.  
  1048.  
  1049.  
  1050.  
  1051.  
  1052.  
  1053.  
  1054.  
  1055.  
  1056.  
  1057.  
  1058.  
  1059.  
  1060.  
  1061.  
  1062.  
  1063.  
  1064.  
  1065.  
  1066.  
  1067.  
  1068.  
  1069.  
  1070.  
  1071.  
  1072.  
  1073.  
  1074.  
  1075.  
  1076.  
  1077.  
  1078.  
  1079.  
  1080.                                      - 18 -
  1081.  
  1082.  
  1083.  
  1084.  
  1085.  
  1086.  
  1087.  
  1088.                                     Searching
  1089.                               By Kelly Schwarzhoff
  1090.       
  1091.                  Internet schwarzhoff@f103.n914.z8.rbbs-net.org
  1092.                                Rbbs-Net 8:914/103
  1093.                                 Fidonet 1:125/41
  1094.       
  1095.           For anyone who is planning on taking a Pascal class there comes a
  1096.      time when he/she must make a search program.  For me that happened two
  1097.      weeks ago in my high school AP  Computer Science class.  I had to make
  1098.      a program that would search for a certain inventory part and print out
  1099.      the  inventory or  "not found"  if  there are  none. In  the following
  1100.      examples I assume you're using the following type definitions:
  1101.       
  1102.          list=record
  1103.               id:integer;
  1104.               inv:integer;
  1105.          end;
  1106.          parts=array[1..5000] of list;
  1107.       
  1108.           I  also assume you  have defined variable  a to be  a variable of
  1109.      type parts (this  is the raw data) and a variable  count to be of type
  1110.      integer  (this  is  how  many  different  parts  there actually  are).
  1111.      Finally, I expect the id #'s to be pre-sorted from smallest to biggest
  1112.      (see PNL #3 for an excellent article on sorting).
  1113.       
  1114.           There  are  two main  type of  searches.   The  easiest way  is a
  1115.      sequential sort that simply goes through the list and will  search for
  1116.      a particular number.
  1117.       
  1118.           Although  the sequential sort is  nice and easy,  it is extremely
  1119.      slow.  Luckily for  us there  is a  faster (and  harder) way  called a
  1120.      binary  search. Binary search requires the  data to be sorted in order
  1121.      of  the item-type you  are searching for.  The procedure will  set two
  1122.      variables  (called b and  z in the program)  to be at  each end of the
  1123.      parts array.  It will then create  a variable mid that  will equal the
  1124.      middle of b and z ( (b+z) div 2).  It  will then check to see what the
  1125.      value of the id number of mid  is (a[mid].id) and make an if then else
  1126.      if  check.  If  the number is  equal to the  number you're looking for
  1127.      (a[mid].id=look) then you found it and it will return that number.  If
  1128.      the mid is greater  than the number  then it is in  the lower side  of
  1129.      your  list in which case you set the right hand side variable to right
  1130.      below mid. If the  mid is less than the number  then the number you're
  1131.      looking for is  in the lower side of  your list in which case  you set
  1132.      the left-hand variable  to right above mid.   This continues until the
  1133.      two variables either collide  or you find the  variable.  If the  id #
  1134.      you're looking for is never found the function will return -1.
  1135.       
  1136.           For those of you who  want the technical speeds of the  searches,
  1137.      sequential is on  average an O(N/2) search and binary  is an O(log2 N)
  1138.      search.
  1139.       
  1140.  
  1141.                                      - 19 -
  1142.  
  1143.  
  1144.  
  1145.  
  1146.  
  1147.  
  1148.  
  1149.           If  you have any questions feel free  to contact me at the listed
  1150.      network addresses.
  1151.  
  1152.      {Editor's Note: Two files included with PNL006.ZIP are SEQUENT.PAS and
  1153.      BINARY.PAS. These are related to this article.
  1154.  
  1155.        A note  about the author.  Kelly Schwarzhoff is  a sophmore in  high
  1156.      school. I bring this up, mostly to point out that the articles in this
  1157.      newsletter are  not written by  PhDs in  Computer Science. One  of the
  1158.      most common compliments about  the newsletter is that it's  written by
  1159.      regular people like you and me, so go ahead and send in an article!}
  1160.  
  1161.  
  1162.  
  1163.  
  1164.  
  1165.  
  1166.  
  1167.  
  1168.  
  1169.  
  1170.  
  1171.  
  1172.  
  1173.  
  1174.  
  1175.  
  1176.  
  1177.  
  1178.  
  1179.  
  1180.  
  1181.  
  1182.  
  1183.  
  1184.  
  1185.  
  1186.  
  1187.  
  1188.  
  1189.  
  1190.  
  1191.  
  1192.  
  1193.  
  1194.  
  1195.  
  1196.  
  1197.  
  1198.  
  1199.  
  1200.  
  1201.  
  1202.                                      - 20 -
  1203.  
  1204.  
  1205.  
  1206.  
  1207.  
  1208.  
  1209.  
  1210.                                   For Beginners
  1211.                                   by Bob Gowans
  1212.       
  1213.           In this  issue of PNL  I thought  we could develop  a programming
  1214.      project based on the  knowledge we have obtained from  previous issues
  1215.      of  PNL. As wordprocessors  are familiar to  us all I  have decided to
  1216.      build our  project around  text manipulation.  First, it will  involve
  1217.      counting the number  of words in a  line of text.  Second, calculating
  1218.      the length of a line of text. Both procedures are obviously simplified
  1219.      versions  of those  a commercial  wordprocessor would  make use  of to
  1220.      invoke word wrap and set text between left and  right margins, however
  1221.      the principle of problem solving, program design and program coding is
  1222.      the same whether the project is large or small.
  1223.  
  1224.           Before running to  the nearest  PC and hastily  churning out  the
  1225.      code for our project lets stop and think a while  about program design
  1226.      and  any constraints  we may have  to impose  on the  program. Program
  1227.      constraints will be given, bearing in mind the knowledge that has been
  1228.      obtained  from  the  last  five  articles  in  the  beginners  column.
  1229.      Obviously there may  be better ways to implement the  program than the
  1230.      way suggested, but  we must write the  program within the confines  of
  1231.      what we  know. It is  not unusual for programmers  to have constraints
  1232.      placed  upon them - for example  financial constraints could influence
  1233.      the implementation of one design over another.
  1234.       
  1235.  
  1236.      Wordcount/Line length -
  1237.       
  1238.           A line of  text is to  be processed, each  word is followed  by a
  1239.      single  space  including  the  last  word in  the  line.  The  line is
  1240.      processed to determine  the total number of words. We  can assume that
  1241.      the line of text is entered by the user from the keyboard and at least
  1242.      one word will be entered.  The result, the total number of  words in a
  1243.      line is printed to the screen. In addition a count of the total number
  1244.      of characters in  the line,  including spaces, is  calculated. A  line
  1245.      length is then  calculated in  inches based on  an assumption that  10
  1246.      characters will be one inch in length.
  1247.       
  1248.           The design for  this process must  involve a loop that  scans the
  1249.      text, looking  for the single  space between the  words, it must  also
  1250.      involve a counter to keep track of the number  of spaces. How will the
  1251.      loop  be terminated? ie. as  the line of text is  scanned how will the
  1252.      program know  it has  reached the  end of  the line.  We can  make the
  1253.      decision that the end of the line will include a space  then a special
  1254.      character,  % (percent). Also,the  loop must make  a count of  all the
  1255.      characters in  the line, excluding the final space and the special end
  1256.      of line character (%).
  1257.       
  1258.      Pseudo-code
  1259.       
  1260.      1. read in first character
  1261.      2. initialize variables updated in loop
  1262.  
  1263.                                      - 21 -
  1264.  
  1265.  
  1266.  
  1267.  
  1268.  
  1269.  
  1270.  
  1271.      3. loop while there are characters in the line of text
  1272.      4.   process characters
  1273.      5.   read in next character
  1274.      6. loopend
  1275.      7. calculate total number of words
  1276.      8. calculate length of line of text
  1277.      9. write out total number of words
  1278.      10. write out length of text
  1279.       
  1280.           Assuming  that the  character  to be  processed  is held  in  the
  1281.      variable called character, step 3 can be refined as follows :
  1282.       
  1283.           3.1 loop while character <> percent sign
  1284.       
  1285.           The  end of each  word is marked  by a space so  if the character
  1286.      being  processed is a space we can  update a variable spacecount by 1,
  1287.      if  the character  being  processed is  anything  else we  update  the
  1288.      variable lettercount by one. 
  1289.       
  1290.           4.1 if character = space
  1291.           4.2 then
  1292.           4.3   update spacecount by one
  1293.           4.4 else
  1294.           4.5   update lettercount by one
  1295.           4.6 ifend
  1296.       
  1297.      The variables spacecount and lettercount are initialized in step 2 and
  1298.      are further refined below:
  1299.       
  1300.           2.1 set spacecount to zero
  1301.           2.2 set lettercount to zero
  1302.       
  1303.      Step 7 does not really need refining as  the total number of spaces is
  1304.      equivalent to the total number of words in the line of text. When  the
  1305.      loop is terminated  spacecount will  contain the value  for the  total
  1306.      number of words.
  1307.  
  1308.      For the sake of clarity we will write step 7 as follows:
  1309.       
  1310.           7.1 set totalwords to spacecount
  1311.       
  1312.      Step 8 however, requires  a bit more thought. The length of  a line of
  1313.      text  in inches is given by the  total number of characters divided by
  1314.      10.  The  total number  of characters  would  be calculated  by adding
  1315.      lettercount and spacecount minus  one (the last  space on the line  is
  1316.      not counted). This would give the total number of characters including
  1317.      spaces.  To complete the calculation the total number of characters is
  1318.      divided by  10 and the  result printed  out, in inches,  to 2  decimal
  1319.      places.
  1320.       
  1321.           8.1 set totalcharacters to lettercount + spacecount - 1
  1322.           8.2 set linelength to totalcharacters/10
  1323.  
  1324.                                      - 22 -
  1325.  
  1326.  
  1327.  
  1328.  
  1329.  
  1330.  
  1331.  
  1332.       
  1333.           The final design is as follows:
  1334.  
  1335.       
  1336.      1.   read in first character
  1337.      2.1  set spacecount to 0
  1338.      2.2  set lettercount to 0
  1339.      3.1  loop while character <> percent sign
  1340.      4.1        if character = space
  1341.      4.2        then
  1342.      4.3           update spacecount by one
  1343.      4.4        else
  1344.      4.5           update lettercount by one
  1345.      4.6        ifend
  1346.      5.         read in next character
  1347.      6.   loopend
  1348.      7.1  set wordcount to spacecount
  1349.      8.1  set totalcharacters to lettercount + spacecount - 1
  1350.      8.2  set linelength to totalcharacters/10
  1351.      9.1  writeout 'Total words in text line = ',totalwords
  1352.      10.  writeout 'Length of line of text = ',linelength,' inches'
  1353.       
  1354.                           Implementation of the design
  1355.       
  1356.           The Pascal coding of  the design should not present  any problems
  1357.      as we have covered most of the issues before. However I would  like to
  1358.      introduce constants into this particular  code. Constants are used  to
  1359.      give a fixed value to an identifier. The system uses constants such as
  1360.      Boolean  values or  the  set of  integer  values, these  are  internal
  1361.      constants set by the system.  Constants can also be named by  the user
  1362.      as illustrated:
  1363.       
  1364.      const
  1365.           interest_rate = 0.15;
  1366.       
  1367.           The Pascal  reserved  word CONST  must come  before the  constant
  1368.      definition.  Constant  definitions are  placed,  in  order of  program
  1369.      sequence,  before variable declarations as you will notice in the code
  1370.      below. Notice also that the assignment symbol for a constant is simply
  1371.      an  equals (=)  sign and  not the Pascal  assignment symbol  (:=). The
  1372.      advantages of using named constants are  that you can make your code a
  1373.      lot more readable if you  use them wisely. When using constants  it is
  1374.      useful to bear in mind the possibility  of your program being updated.
  1375.      In the example  above, the constant definition  of interest_rate could
  1376.      be used  in a program that calculates loan repayments. We all know too
  1377.      well how interest  rates fluctuate  so it is  advantageous to  declare
  1378.      interest rate as a constant. When it comes to updating the program, as
  1379.      a new  interest rate is given,  we simply have to  change the constant
  1380.      definition line. All  references to interest_rate  in the program  are
  1381.      then automatically updated, saving you a lot of work!
  1382.  
  1383.  
  1384.  
  1385.                                      - 23 -
  1386.  
  1387.  
  1388.  
  1389.  
  1390.  
  1391.  
  1392.  
  1393.      Constructing a data table for the design:
  1394.       
  1395.      IDENTIFIER                   DESCRIPTION                    TYPE
  1396.       
  1397.      space                        the space character ' '        constant
  1398.      line_end                     the percent character '%'      constant
  1399.      cpi                          characters per inch            constant
  1400.      character                    characters input by user       char
  1401.      spacecount                   counter of space characters    integer
  1402.      lettercount                  counter of letter characters   integer
  1403.      total_chrs                   holds total number of
  1404.                                   letters and spaces             integer
  1405.      total_words                  holds total number of words    integer
  1406.      line_length                  length in inches of 10
  1407.                                   characters                     real
  1408.       
  1409.       
  1410.      Here's the code to our design:
  1411.       
  1412.      program process_line;
  1413.       
  1414.      {By R.Gowans 7/2/91 - Manchester Polytechnic Didsbury}
  1415.       
  1416.      {Calculates number of words in a line of text as input by the user and
  1417.      outputs the result to  the screen. Calculates line length  given there
  1418.      are 10 characters per inch and outputs results to screen.}
  1419.       
  1420.      const
  1421.           space = ' ';
  1422.           line_end = '%';
  1423.           cpi = 10;
  1424.       
  1425.      var
  1426.           character : char;
  1427.           spacecount,lettercount,total_chrs,total_words : integer;
  1428.           line_length : real;
  1429.       
  1430.      begin
  1431.        writeln('Input a line of text, each word must be followed by a');
  1432.        writeln('space,the line must be terminated by a pct sign (%)');
  1433.        writeln;
  1434.        write('Enter line > ');
  1435.        read(character);
  1436.        spacecount := 0;
  1437.        lettercount := 0;
  1438.        while character <> line_end do
  1439.          begin
  1440.            if character = space
  1441.              then
  1442.                spacecount := spacecount + 1
  1443.              else
  1444.                lettercount := lettercount + 1;
  1445.  
  1446.                                      - 24 -
  1447.  
  1448.  
  1449.  
  1450.  
  1451.  
  1452.  
  1453.  
  1454.              read(character)
  1455.          end;
  1456.        total_words := spacecount;
  1457.        total_chrs := lettercount + spacecount - 1;
  1458.        line_length := total_chrs/cpi;
  1459.        writeln;
  1460.        writeln('Total words in text line = ',total_words);
  1461.        writeln;
  1462.        writeln('Length of line = ',line_length:4:2,' inches')
  1463.      end.
  1464.       
  1465.           You will  have probably  noticed that there  are a  lot of  'What
  1466.      if's???'  about this  program and if  it has raised  some questions in
  1467.      your mind,  well that is the  intention. Some of the  questions I hope
  1468.      you may be asking yourself are:
  1469.       
  1470.           1. What if the character read in is not a space, letter or a     
  1471.         percent sign?
  1472.           2. What if the first character is a percent symbol?
  1473.           3. What if there is more than one space between the words?
  1474.       
  1475.      You  can  probably  think of  more  questions  which  will reveal  the
  1476.      weaknesses of this  program and it is fitting to  be critical in order
  1477.      to  make the best possible,positive modifications to a program. I will
  1478.      leave  you to  think about  the question  of data  checking, it  is an
  1479.      essential part  of any  non-trivial program.  Try predicting  what the
  1480.      program will do when you enter unusual data then try it out! A word of
  1481.      warning - be sure  you know how to break  out of a program if  you are
  1482.      attempting  the unpredictable, the usual  sequence on a  PC is to hold
  1483.      down the CTRL key and press c or break.
  1484.  
  1485.  
  1486.  
  1487.  
  1488.  
  1489.  
  1490.  
  1491.  
  1492.  
  1493.  
  1494.  
  1495.  
  1496.  
  1497.  
  1498.  
  1499.  
  1500.  
  1501.  
  1502.  
  1503.  
  1504.  
  1505.  
  1506.  
  1507.                                      - 25 -
  1508.  
  1509.  
  1510.  
  1511.  
  1512.  
  1513.  
  1514.  
  1515.                                    Conclusion
  1516.  
  1517.           Well,  that about wraps up this rather hastily assembled issue of
  1518.      the newsletter. I'm sorry for taking so long and I hope  to be able to
  1519.      do another issue before  summer, but I can't promise  anything. Either
  1520.      way, I plan on trying to make up  for it this summer by putting out  4
  1521.      or 5 issues over the summer.
  1522.  
  1523.           I really need your  help. The readers who contribute  really make
  1524.      this happen and unless I receive articles from the user, it's going to
  1525.      take longer and longer between issues. Eventually, if I  have to carry
  1526.      the load  of writing the entire newsletter, it will fade away. I don't
  1527.      want to see that happen, so please try to help out. Try to set aside a
  1528.      few hours on a weekend and put something together for us here. 
  1529.  
  1530.           I'm still not too sure about what's in-store  for the next issue.
  1531.      I haven't really thought  about it too much. I will  do more on Chess-
  1532.      Ter and surely  Bob will be  back with For  Beginners. I hope to  have
  1533.      Richard  back  writing  his articles  on  Graphics  in  TP. I  haven't
  1534.      published anything about TP6.0 because frankly, I haven't had a chance
  1535.      to use it myself, yet, and I haven't received anything from my readers
  1536.      on it, so  if there are those  of you that  have gotten familiar  with
  1537.      TP6.0, I'd sure like to see some reviews.
  1538.  
  1539.           Oh well, enough begging on my part. I'll leave the rest up to you
  1540.      guys.  I'm off  to complete  what  is left  of my  vacation. Hope  you
  1541.      enjoyed the issue and I'll write to you in the next issue.
  1542.  
  1543.                                              _Pete Davis
  1544.  
  1545.  
  1546.  
  1547.  
  1548.  
  1549.  
  1550.  
  1551.  
  1552.  
  1553.  
  1554.  
  1555.  
  1556.  
  1557.  
  1558.  
  1559.  
  1560.  
  1561.  
  1562.  
  1563.  
  1564.  
  1565.  
  1566.  
  1567.  
  1568.                                      - 26 -
  1569.  
  1570.  
  1571.  
  1572.  
  1573.  
  1574.  
  1575.  
  1576.           The  Pascal NewsLetter  is  Copyrighted by  Pete Davis.  Articles
  1577.      submitted by others  are  the property of  the  authors and are   used
  1578.      with  permission. They   may  not be  treated   seperately   from this
  1579.      newsletter    without the  author's permission  and thus  maintain all
  1580.      distribution rules of the   newsletter as a  whole. It may  be  freely
  1581.      distributed  in   un-modified  form,   but  no   charge whatsoever may
  1582.      be  incurred on the  recipient.  All code is provided  'as-is' with no
  1583.      guarantees whatsoever.
  1584.  
  1585.           The  Pascal  NewsLetter    can  be  obtained   from the following
  1586.      locations:
  1587.  
  1588.                     GEnie : General Electric Network for Information       
  1589.                     Exchange. It is located in the IBMPC                   
  1590.                     filelist.
  1591.  
  1592.                    Simtel : Internet address: 26.2.0.74 or                 
  1593.                    Simtel20.ARPA It is located in the                      
  1594.                    <MSDOS.PASCAL> directory.
  1595.  
  1596.                    Programmer's Forum : This is the home of the PNL.       
  1597.                    Each issue can be found in                              
  1598.                    the PNL directory from the main area.
  1599.                    The number is on the title page.
  1600.  
  1601.           If  you  would like  to   receive  back  issues  of  PNL directly
  1602.      from  me,   send  a  diskette  and  $2.00   for shipping. Don't forget
  1603.      to include your address.
  1604.  
  1605.                     Send your order to:
  1606.                        Peter Davis
  1607.                        4851 Brandywine St. NW
  1608.                        Washington, DC   20016
  1609.  
  1610.           If  you are   a SysOp that   will regularly carry  PNL  and would
  1611.      like to   have your  bulletin board  listed as such,  here, send me  a
  1612.      message either  by postal mail or  at one of the  electronic addresses
  1613.      given   on the  title   page, with your  bulletin board's  name, phone
  1614.      number, and your name.
  1615.  
  1616.  
  1617.  
  1618.  
  1619.  
  1620.  
  1621.  
  1622.  
  1623.  
  1624.  
  1625.  
  1626.  
  1627.  
  1628.  
  1629.                                      - 27 -
  1630.  
  1631.  
  1632.  
  1633.  
  1634.  
  1635.  
  1636.  
  1637.  
  1638.                      The Pascal NewsLetter Distribution List
  1639.  
  1640.  
  1641.      BBS                       | Fidonet Address      |  Phone #
  1642.      --------------------------+----------------------+---------------
  1643.      The Bored                 | 1:397/3              | (512) 303-0471
  1644.      Classic City BBS          | 1:370/10             | (404) 548-0726
  1645.      Thieve's World BBS        | 1:106/805            | (713) 463-8053
  1646.      Hippocampus BBS           | 1:141/205            | (203) 484-4621
  1647.      Rogers State College      | 1:170/711            | (918) 341-8982
  1648.      The Foxtrot BBS           | 1:272/26             | (914) 567-1814
  1649.      Turbo City BBS            | 1:208/2              | (209) 599-7435
  1650.      Austin IEMUG/MIDI BBS     | 1:382/14             | (512) 258-0626
  1651.      Laser Publishers          | 1:170/403            | (918) 438-2749
  1652.      Fargo RBBS-PC             | 1:10/8               | (701) 293-5973
  1653.      Momentary Lapse of Reason |                      | (704) 327-6361
  1654.      The Demon's Den           |                      | (508) 433-2702
  1655.      The Cannibal Cafe         |                      | (508) 840-6589
  1656.      IBM Tech FIDO             |                      | (508) 433-6491
  1657.      The User Friendly BBS     |                      | (704) 323-8223
  1658.      KHIRON Software-Mail Only | 3:640/378            | 61-7-878-1194
  1659.      Beyound Frontiers BBS     | 2:230/101            | (+45)8694-1609
  1660.      Collision Theory          |                      | (703) 503-9441
  1661.      Merlin's Mailbox          | 2:245/39             |
  1662.      Ed-Net 9600               | 1:153/734            | (604) 732-8877
  1663.      EILC BBS                  | 1:3610/60            | (407) 676-2998
  1664.      Polysyncronism BBS        |                      | (708) 358-5104
  1665.      (Name Unknown)            |                      | (315) 592-7300
  1666.  
  1667.  
  1668.  
  1669.  
  1670.  
  1671.  
  1672.  
  1673.  
  1674.  
  1675.  
  1676.  
  1677.  
  1678.  
  1679.  
  1680.  
  1681.  
  1682.  
  1683.  
  1684.  
  1685.  
  1686.  
  1687.  
  1688.  
  1689.  
  1690.                                      - 28 -
  1691.  
  1692.