
         Q L   H A C K E R ' S   J O U R N A L
      ===========================================
           Supporting  All  QL  Programmers
      ===========================================
         #22                        October 1995
      
    The QL Hacker's Journal (QHJ) is published by Tim
Swenson as a service to the QL Community.  The QHJ is
freely distributable.  Past issues are available on disk,
via e-mail, or via the Anon-FTP server, garbo.uwasa.fi. 
The QHJ is always on the look out for article submissions.

        QL Hacker's Journal
     c/o Tim Swenson
     5615 Botkins Rd 
     Huber Heights, OH 45424 USA
     (513) 233-2178
     swensontc@mail.serve.com
     http://www.serve.com/swensont/

          
EDITOR'S FORUMN

   The biggest news this issue is I'VE GOT A HOME PAGE.  I
got a wild hair a while back and decided to get myself a
home page.  Since I could not use a server at work to host
my home page (the government sort of frowns on that), I had
to find a commerical service to do it.  I had full Internet
access from work, so I just needed a server to host the
home page.

   Luckily, just days after getting this wild hair I saw two
advertisements for just such a service.  I found one place
in Philidelphia, PA that would host my home page (with a 1
Meg limit) and provide mail forwarding, all for $24 a year. 
My new e-mail address and home page is:

       swensont@mail.serve.com
       http://www.serve.com/swensont/
   
   My old e-mail addresses still work, but having the mail
forwarding, I can move my main e-mail account but still have
a single permanent e-mail address.

   The home page is aimed at both friends and family, so it
does not say "QL Hacker's Journal" at the entry page, but
you will find the QHJ on the home page.  I've also put other
Sinclair related informantion on the page, such as:
   Sinclair Internet Resources List
   Master Sinclair E-Mail list
   Z88 Source Book
   
   For those with Web access, give it a try.  

   Having had the Pointer Environment (PE) for over a year,
I have been wondering what tools were available for doing
development in the PE.  I have found and bought two tools
for doing PE programming; QMENU and EASYPTR.  In this issue
I will discuss PE programming with QMENU.  Since EASYPTR is
a far more complex toolkit than QMENU, it may take me a
while to really get the grasp of it, but I hope to have some
article on it in a future issue.

   Big thanks to Jerome Grimbert for writing an article on
how he wrote the QL Pente program.  It does a good job of
documenting how a Pointer Environment program is done. 
Jerome is fairly quick.  He wrote the Pente program in only
2 days and wrote the article in only a few days after I
asked if he would write such an article.  


STRUCTURED SUPERBASIC VERSION 2.5

   Structured SuperBasic (SSB) has been sitting on my shelf
for a number of years without having any upgrades.  I
really only upgrade SSB when there is a new feature that I
need SSB to support.  Since I've had the Pointer
Environment (PE) for just over a year, I've always wanted
to do some programming supporting it.  Only recently have I
picked up two utilites that will help me do this; QMENU and
EasyPointer II.

   My intention is to create a version of SSB that will
work under the PE.  But, before I could get there, I needed
to upgrade SSB to give me some new features.  Version 2.5
provides some of these features and is designed to have a
limited life until version 3.0 comes out.  There will be a
version 2.6.  I've finally decided to use a few ToolKit II
extensions in SSB, hoping to make it better.  Version 2.6
will incorporate these extensions.

   The biggest upgrade in version 2.5 is the support of
conditional "compilation."  Anyone familiar with the C
Preprocessor is familiar with conditional compilation. 
Through the use of #DEFINE, #IFDEF, and #ENDIF statements,
various parts of source code can be left out of the final
code.  With the setting of one variable, a program can be
compiled to support MS-DOS while changing the variable can
allow it to support UNIX.

   Note that I put quotes around the word "compilation." 
Since SSB is really just a filter that converts SSB source
code to a SuperBasic ready form, there really is no
compilation.

Version 2.5 also supports imbedded print filter directives. 
I use a couple of "home-grown" print filters for printing
out various texts.  I have adopted the NROFF and WordStar
conventions of using dot (.) commands for imbedding
formating commands into the text.  A dot command is
something like this:

   .boldon
   
   This command tells the print filter to set the bold
feature on.  SSB version 2.5 allows you to imbedd these
commands in your SSB code so that you can send the source
code through one of these filters and allow you to produce
a nice listing.  This concept is similar to Web programming.
Web, designed by Donald Knuth, believes that the code should
be self documenting, and to this end believes that the
documentation and source code should be one and the same.

   Dot commands must start in the first character of a line.
   
   Version 2.5 supports the / directive of line
continuation.  In the old days of line editors, if you went
past the 80th character in your code, you put in a / to
tell the compiler that the rest of the code for that line
is on the next line.  Since SSB is written using editors
based on 80 character screens, it is handy to not have real
long code lines, especially when indenting to show nesting
and program structure.

   To use /, the / character must be the last character of
the line.  The next line will be read in and appended to the
current line.  The one caveot is that you may not have two
line continuation marks in a row.  This means the following:

     This will not work:
     
     IF var = something THEN /
       LET some_variable  = /
       some_other_variable
       
     But this will work:
     
     IF var = something THEN /
       LET some_variable = some_other_variable
     IF var = something_else THEN /
       LET some_variable = nothing

   The big difference is that the continuation line does not
have a continuation itself.

** Test file for showing Conditonal "Compilation"

#define TEST
##define NOTEST

#ifdef TEST
  print "This is test"
  print "TEST is defined"
#endif

#ifdef NOTEST
  print "This is not a test"
  print "NOTEST is defined"
#endif

#ifdef TEST
  print "This is a second test"
  print "TEST is defined"
#endif

  print "This code should appear"
  print "This code should also appear

   This version of SSB has not been rigorously tested. 
I've tested the conditional "compilation" using the test
file above.  There might be a case in which this program
fails.  Since this is a limited life program (before the
next upgrade), I'm not too worried about it's bugs. 
Consider this to be a beta version of 3.0.  If you
encounter any problems, bugs, or have comments on SSB or my
lack of good programming, please let me know.

   One note of thanks to Herb Schaaf who helped me over a
stumbling block in my code.  He fixed the problem I could
not figure out.  Sometimes it can hinder you when you are
too close to the code.  It makes you read what is not there.

## Structured SuperBasic Filter
## Author:       Timothy Swenson
## Date Created: 16 Oct 1990
## Date Revised: 5 Sept 1995
## Version:      2.5

##   This program takes in SSB code and outputs a file
##     that is runnable in SuperBasic

## Init Variables
 DIM label$(30,16)
 DIM label(30)
 DIM defn$(30,16)
 label_var = 1
 define_var = 1
 num_count = 0
 file_num = 5

 OPEN #3,con_300x200a75x0_32
 BORDER #3,2,4
 PAPER #3,0 : INK #3,4 :  CLS #3

 PRINT #3,"     STRUCTURED SUPERBASIC FILTER"
 PRINT #3,"            Version 2.5"
 PRINT #3,"         by Timothy Swenson"
 PRINT #3

 PRINT #3,"Enter input file: ( _ssb) "
 INPUT #3,in_file$
 PRINT #3,"Enter output file: (default ";in_file$;"_bas) "
 INPUT #3,out_file$
 PRINT #3,"Enter Starting Line Number: (default 100) "
 INPUT #3,line_num$
 PRINT #3,"Enter Increment for Line Numbers: (default 10)  "
 INPUT #3,line_delta$

## Default for the output file is the input file with
##   a _bas extension.
 IF out_file$ = "" THEN out_file$=in_file$&"_bas"

 in_file$ = in_file$&"_ssb"

## Default for the starting line number is 100.
 IF line_num$ = "" THEN
   line_num_d = 100
 ELSE
   line_num_d = line_num$
 END IF

## Default for line number increment is 10.
 IF line_delta$ = "" THEN
   line_delta = 10
 ELSE
   line_delta = line_delta$
 END IF

 line_num = line_num_d
 PRINT #3,"    PASS 1"

 pass_one in_file$, file_num

 line_num = line_num_d
 PRINT #3
 PRINT #3,"    PASS 2"

 num_count = 0
 file_num = 5

 DELETE out_file$
 OPEN_NEW #4,out_file$

 pass_two in_file$, file_num

 CLOSE #4
 PRINT #3
 PRINT #3,"Program Done"
 CLOSE #3
 STOP

## Pass_one is strictly designed to count line numbers
## and to find all labels.  This allows goto labels to
## refer to code that the filter has not yet seen
## (as compared to a single pass filter).

 DEFine PROCedure pass_one (in_file$, file_num)

   OPEN_IN #file_num,in_file$
   REPeat pass_1
     num_count = num_count + 1
     IF (num_count MOD 10) = 0 THEN PRINT #3,CHR$(1);
     IF EOF(#file_num) THEN EXIT pass_1
     INPUT #file_num,in$
     ## Get first non-space character
     temp=first_char(in$)
     ## Check for Blank Lines
     IF temp=0 THEN NEXT pass_1
     ## If the ** comment line then don't count as a line
     IF in$(temp TO temp+1)="**" THEN NEXT pass_1
     ## Ignore dot commands for print filters
     IF in$(temp)="." THEN NEXT pass_1
     ## A \ is at the end of a line meaning to add the next line
     IF in$(LEN(in$))="\" THEN
       IF EOF(#file_num) THEN abort_out(1)
       INPUT #file_num,in2$
       temp = first_char(in2$)
       in$ = in$( TO LEN(in$))&in2$(temp TO)
     END IF
     ## If the AT symbol is found, then it's a label
     IF in$(1)=CHR$(64) THEN
       label$(label_var) = in$
       label(label_var) = line_num
       label_var = label_var + 1
     ELSE
       ## If it's the include statement then call pass_one again
       IF upper$(in$(1 TO 8))="#INCLUDE" THEN
         pass_one in$(10 to ), file_num+1
       ELSE
         IF upper$(in$(1 TO 7))="#DEFINE" THEN
           defn$(define_var) = upper$(in$( 9 TO))
           define_var = define_var+1
         ELSE
           IF upper$(in$(1 TO 6))="#IFDEF" THEN
             temp1 = 0
             temp$ = upper$(in$(8 TO))
             FOR x = 1 TO define_var
               IF temp$ = defn$(x) THEN temp1 = 1
             NEXT X
             IF temp1 = 0 THEN
               REPEAT loop
                 IF EOF(#file_num) THEN abort_out(1)
                 INPUT #file_num,in2$
                 IF upper$(in2$(1 TO 6))="#ENDIF" THEN EXIT loop
               END REPeat loop
             END IF
           ELSE
             line_num = line_num + line_delta
           END IF
         END IF
       END IF
     END IF
   END REPeat pass_1

   CLOSE #file_num
 END DEFine pass_one

## Pass_two does the main work of the filter.
##  It adds the line numbers and the goto references.

 DEFine PROCedure pass_two (in_file$, file_num)

   OPEN_IN #file_num,in_file$
   REPeat pass_2
     num_count = num_count + 1
     IF (num_count MOD 10) = 0 THEN PRINT #3,CHR$(1);
     IF EOF(#file_num) THEN EXIT pass_2
     INPUT #file_num,in$
     temp=first_char(in$)
     ## Ignore blank Lines
     IF temp=0 THEN NEXT pass_2
     ## Ignore Labels
     IF in$(1)=CHR$(64) THEN NEXT pass_2
     ## Ignore ** comments
     IF in$(temp TO temp+1)="**" THEN NEXT pass_2
     ## Ignore dot commands
     IF in$(temp)="." THEN NEXT pass_2
     ## Ignore #DEFINE commands since DEFINE table is already established
     IF upper$(in$(1 TO 7))="#DEFINE" THEN NEXT pass_2
     ## A \ is at the end of a line meaning to add the next line
     IF in$(LEN(in$))="\" THEN
       IF EOF(#file_num) THEN abort_out(1)
       INPUT #file_num,in2$
       temp = first_char(in2$)
       in$ = in$( TO LEN(in$))&in2$(temp TO)
     END IF
     IF in$(temp TO temp+1)="##" THEN
       PRINT #4,line_num;" remark ";in$(1 TO temp-1);in$(temp+2 TO )
       line_num = line_num + line_delta
     ELSE
       temp = CHR$(64) INSTR in$
       IF temp<>0 THEN
         a$ = in$(temp TO )
         temp2 = 0
@label1
         temp2 = temp2 + 1
         IF temp2 > 30 THEN
           PRINT #3,"Warning - Label ";a$;" Not Found"
           END REPeat pass_2
         END IF
         IF label$(temp2) <> a$ THEN GO TO @label1
         PRINT #4,line_num;" ";in$(1 TO temp-1);label(temp2)
         line_num = line_num + line_delta
       ELSE
         IF upper$(in$(1 to 8))="#INCLUDE" THEN
           pass_two in$(10 to), file_num+1
         ELSE
           IF upper$(in$(1 TO 6))="#IFDEF" THEN
             temp1 = 0
             temp$ = upper$(in$(8 TO))
             FOR x = 1 TO define_var
               IF temp$ = defn$((x),1 TO LEN(temp$)) THEN temp1 = x
             NEXT X
             IF temp1 = 0 THEN
               REPEAT loop
                 IF EOF(#file_num) THEN abort_out(1)
                 INPUT #file_num,in2$
                 IF upper$(in2$(1 TO 6))="#ENDIF" THEN EXIT loop
               END REPeat loop
             END IF
           ELSE
             IF upper$(in$(1 TO6))<>"#ENDIF" THEN
               PRINT #4,line_num;" ";in$
               line_num = line_num + line_delta
             END IF
           END IF
         END IF
       END IF
     END IF
   END REPeat pass_2
   CLOSE #file_num
 END DEFine pass_two


## Function first_char
##   returns the location of the first non-white
##   space character.
 DEFine FuNction first_char (a$)
  LOCal count
  count=0
@label2
   count=count+1
   IF count > LEN(a$) THEN RETurn 0
   IF a$(count)=" " THEN GO TO @label2
   RETurn count
 END DEFine first_char

## Function upper$
##   Takes in input string and returns the
##   same string in all upper case letters.
 DEF FuNction upper$(up$)
    LOCal x, temp

    FOR x = 1 TO LEN(up$)
       temp = CODE(up$(x))
       IF temp > 96 AND temp < 123 THEN up$(x)=CHR$(temp-32)
    NEXT x
    RETURN up$
 END DEFine

## Procedure abort_out
##   A separate procedure to neatly close all
##   of the files and exit the program.
##   Usually reserved for fatal errors.
 DEF PROCedure abort_out(err_code)

## error = 1   End of File while doing an #IFDEF

   IF err_code = 1 THEN
      PRINT #3,"FATAL ERROR - #ENDIF not found before end of file"
      IF file_num = 5 THEN
         CLOSE #5
      ELSE
         FOR x = 5 TO file_num
            CLOSE #x
         NEXT X
      END IF
      CLOSE #4
      CLOSE #5
      CLOSE #3
      STOP
   END IF

 END DEFine


PHILOSOPHY OF STRUCTURED SUPERBASIC
   
   Philosophy is defined as a system of principles for
guidance in practical affairs.  The Philosophy of
Structured SuperBasic (SSB) is the principles behind the
creation of SSB.  This philosophy guides the development of
SSB.  Knowing the philosophy behind the design and
implementation of SSB helps to understand the what's and
why's of SSB.
   
   
1.  SSB Must "compile" itself.

   This principle comes directly from Small-C.  When
Small-C was written, one of it's principles was that
Small-C was to be written in Small-C.  When I first wrote
SSB, I initially wrote the source code in SSB.  I then hand
translated it to SuperBasic to produce the first working
program.  From then on, SSB has always compiled newer
versions of itself.
   
   
2.  Implement What is Not Implemented.
   
   SSB was always designed to support features not built
into SuperBasic, but not support those that were supported.
A good example of this is the use of the #DEFINE directive.
In C #DEFINE VAR is used to set conditional "compilation"
when ever the #IFDEF VAR is encounted.  #DEFINE can also be
used to define constants ( #DEFINE YES 1 ).  When I
implemented #DEFINE I supported only the conditional
"compilation" aspect of #DEFINE but not its support in
defining constants, since the defining of constants can be
done easily in SuperBasic ( LET YES = 1 ).


3.  Structured SuperBasic Must Support The Lowest QL.

   I have never liked writting distributable software that
relied on having any add-on's to the QL.  This includes
using ToolKit II, QLiberator, or Minerva extensions. 
Version 2.6 will be the first version to support TKII, but
it also has the conditional "compilation" option of
supporting the bare bones QL.  Version 3.0 which will
support the Pointer Environment will also support the
Non-Pointer Environment QLs.


PROGRAMMING WITH QMENU

   QMENU is a Pointer Environment (PE) programming tool put
out by Jochem Merz.  QMENU is a number of SuperBasic
extensions that provide PE compatability.  The extensions
are fairly simple to understand and to program with.  It
really does not take too much time to get programming in the
PE.

   As easy as QMENU is to use I don't know if it will
become my prefered PE programming tool.  My first real
program to write in the PE is going to be Structured
SuperBasic (SSB).  I have sat down and started thinking
about how I was going to convert SSB to the PE, what QMENU
extensions I will use, and how I want the windows to look. 
I did run into one fairly significant problem:  QMENU
extensions are designed for input only.

   The QMENU extensions are designed to get input from the
user, be it asking for a string, a file extension, a file
name, or something else.  With the call of an extension,
your program waits for user input.  You can't pop up a
window and then continue processing.  There are no
extensions that allow the creation of a window for output. 
You can't open up a window and display the output from your
program.

   I do like the look and feel of QMENU.  The extension for
getting a file name opens up a big window and allows the
user to browse through the directory of a disk, select a
new disk drive, etc.  It's a powerful extension.  The other
extensions are great and suit the need they were designed
for.  But without the inclusion of an extension to get our
output to the user, it can be kind of hard to write a
number of programs with QMENU.

   You could just leave the screen blank while your program
did it's processing or number crunching, but that leaves the
user wondering if the program has locked up or is just
taking a while to chug.  It's better to have a display on
the screen saying that the program is working ( a flashing
WORKING is what I like to use).

   The key thing going for QMENU is it's easy of use.  I am
worried about the time it will take for me to get up to
speed with EASYPTR and get using it (it's manual is fairly
thick for a QL manual).  I may use QMENU as my main PE
toolkit because of it's easy of use and despite it's major
fault.


DAY OF THE WEEK

   In the April 1995 issue of "Dr. Dobb's Journal", in the
"Algorithm Alley" column, Kim Larsen presents an algorithm
on determining the day of the week, given a day, month, and
year.  The algorithm is fairly straight forward and will
work from any date from September 14th, 1752 (the day we
switched to the current calendar system).  The article goes
into detail on how the algorithm was created.  If anyone is
interested in the full discussion, I can photocopy the
article and send it in the mail.

   Below is a SuperBasic version of the algorithm.  I've
also included another function that takes today's date and
tell you what day of the week it is.  If you need a numberic
answer on the day of the week, you can easily change the
return value to reflect the actual number generated and skip
the conversion to a text name.


DEFine FuNction day_of_week$(d, m, y)
    LOCal a
  IF m = 1 OR m = 2 THEN 
     m=m+12
     y = y - 1
  END IF 

  a = (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) MOD 7

  If a = 0 THEN RETurn "Sunday"
  IF a = 1 THEN RETurn "Monday"
  IF a = 2 THEN RETurn "Tuesday"
  IF a = 3 THEN RETurn "Wednesday"
  IF a = 4 THEN RETurn "Thursday"
  IF a = 5 THEN RETurn "Friday"
  IF a = 6 THEN RETurn "Saturday"

END DEFine 


DEFine FuNction today$
   LOCal a$, year, month, month$, day
   
  LET a$ = DATE$
  LET year = a$( 1 TO 4)
  LET month$ = a$(6 TO 8)
  LET day = a$(10 TO 11)

  IF month$ = "Jan" THEN month=1
  IF month$ = "Feb" THEN month=2
  IF month$ = "Mar" THEN month=3
  IF month$ = "Apr" THEN month=4
  IF month$ = "May" THEN month=5
  IF month$ = "Jun" THEN month=6
  IF month$ = "Jul" THEN month=7
  IF month$ = "Aug" THEN month=8
  IF month$ = "Sep" THEN month=9
  IF month$ = "Oct" THEN month=10
  IF month$ = "Nov" THEN month=11
  IF month$ = "Dec" THEN month=12

  LET to_day$ = day_of_week$(day,month,year)
  RETurn to_day$

END DEFine 


WRITING A PENTE PROGRAM FOR THE QL
   By Jerome Grimbert
   
   First, let me introduce myself.  I'm 25 years old, live
in France (as I'm French) and have had a QL since 1986/87. 
My main use of the QL is games and game programming, so I'm
very glad to have C68.  My prefered type of game is one of
reflexion and not dexterity (may be because I'm not very
quick with my finger.  I always loose).  Anyway, sometime
ago I was able to get back issues of the QLHJ (or QHJ). 
Reading issue #19 I saw a call for a Pente program.  I
decided to make one.

   Let me first explain the rules of Pente:
   
   On a standard goban (chinese board of 19x19
intersections), each player takes turns placing a stone
(like Go stones) of his/her color on the board.  The winner
is the player who gets five stones in a row, in any of the
eight directions, or who has taken 5 pairs of stones from
his/her opponent.

   Example of winning alignment:
   
   + + X + + O +    + O O O O O X +
   + X + + O + +    + + + + + + + +
   + + + O + + X    Horizontaly
   + + O + X + +
   + O + + X + +  <---  Diagonaly
   
   A pair of stones is taken (captured) when it is inside
two opposite stones.
      
      Start Position       + + + X O O + +
      X's Move             + + + X O O X +
      End of Move 2        + + + X + + X +

   But making a pair this way is does not result in a
capture.
   
      Start Position       + + + X O + X +
      O's Move             + + + X O O X +

   It's the capturing move (drop of the X stone) that takes
the pair of O's.  The forming of a pair of O's inside a pair
of X's is allowed and does not result in a capture.

   Taking more than one pair with one move (stone) is
possible.

   X + + X + + +
   + O + O + + +   ! is a winning play for each player.
   + + O O + + +   X will win by 5 captures.
   + + + ! O O X   O will win by alignment.
   + + O O + + +
   + O + O + + +


   Additionally, the first move is always on the center of
the board (this is a forced move) and the third move (first
player's second move) is always at least three intersections
away from the center.  The reduces the advantage of the
first player.

   + + + + + + +  X cannot play it's second move on .
   + . . . . . +  O can play it's first move anywhere.
   + . . . . . +
   + . . X . . +
   + . . . . . +
   + . . . . . +
   + + + + + + +

   So now you are ready to play Pente.
   
   The big problem when playing is choosing which way you
want to win, by alignment or capture.  You have to be
carefull about what your opponent does, stopping him/her
from doing alignment may expose you to capture. This will
allow your opponent to try again an alignment, because your
blocking stones have been taken, or will make you loose
because you lost too many pairs.  This game may seem easy,
but it can be very difficult and tense.
   
   So now you know the rules.  Now about programming the game.
   
   First, I designed the general screen layout.  Having a
QL, my screen resolution is 512x256, and I wanted to use
the entire screen, I base my board size and stone size on
this resolution.  256/19 is the limit of the stone size. 
The stones were created with an Icon Editor ( or Sprite
Editor to stick to QL terms) from QTPR.  The board will be
white with black lines and the stones will be red and green
(this is a little like the colors used in the original
board version of the game).

   I then designed the sprites for the stone and the board. 
I used a sprite for the board because drawing lines is kind
of slow.  Board sprites are mainly intersections, except on
the border (where there is only three lines connecting), on
the corner (where there is only two), and at the GoBan node
(the dotted intersections).  Board sprites will allow for
quick rewrites of the screen when captures take place, since
only those intersections affected need to be redrawn instead
of the whole board.

   The next step was the C programming.

   As I have existing game sources, I copy the Main file
which contains the window description.  This file does not
change very much.  In main(), I declare the Windows,
Status, Loose Items, and so on, with the definition of the
acting routines (which may call other bigger functions).  I
defined the window description, putting in the application
window in which the board is drawn and the standard loose
item menu (Sleep, Move, Help, Quit (ESC), and Wait).  To
these loose items I add Computer Play For Me, which has the
computer play your next move for you, and How Many Players,
which the user uses to select one or two players.  I don't
have Computer vs Computer now, but sometime in the future. 


   What is also standard is the Info Item with the name of
the application.  I also add other Info Items showing the
number of taken pairs by each side and an About selection. 
I liked the About from QD and FIFI, so I added it in.  The
Info Item for the Count of pairs taken is just two strings
of text that will be redrawn when the count changes.

    Now I have a nice looking empty board with mainly all of
the Loose Items working.  Resize, Move, Quit, Number of
Players, Wake are almost always the same, so I just copy
them.  In fact, as I started with the Windows Demo of C68, I
have a module to Pop-up a menu choice either vertically,
horizontaly or even in a 2x3 frame with up to six different
choices.  It allows a standard prompt and the possible
choice; i.e, the Quit prompt is "OK to Quit" and the choices
are "Yes", "No", or "Sleep" with a default of "No."  All is
taken care of by the routine, so the caller only needs to
see a very sympathetic line of C:

   choice = menu_choice_h("Ok to Quit",3,2,"Yes","No","Sleep");
   
   The function returns -1 to choice if the ESC key was
pressed, else it returns the C index in the list of choices.

   Next I need to write the 'About', a new thing for me,
which will be a pop-up window with some text.  I derived it
from the menu_choice() routine, removing all of the
paramaters (it's hard coded) and adding the text and sprite
item.  I kept the last line as a Loose Menu Item so a mouse
user could close the window without having to hit the ESC
key (which should be the instinctive way to close this
window).

   Now I had to put the stones on the board.  The first
player is Red, so at the start of Pente, the application
cursor (in the application window) is the red stone sprite.
The hit routine will then get the cursor coordinates,
transform them into Board coordinates, and call a specific
routine to  1) check for the validity of the move, 2) to
see if pairs have been taken, 3) put the stone on the
screen, 4) and either make the computer play (if there is
only one player, or change the color of the pointer to the
green stone sprite.

   If the move is not legal (especially for the first and
third stones) then a pop-up window is shown, just saying
that the move was illegal.  ESC or DO in this window will
close it.  Since you Hit to put your stone, the mouse user
will have to change his/her finger to close it.  It forces
them to read it and to think.  This window is made from the
menu_choice/About code.

   We now have the input/ouput of part of the program.  The
next step is to provide the brain.

   For Pente, I bought the brain from Mr. FrankEinstein,
a.k.a. an old french revue "Jeux & Strategie" (Game &
Strategy) who once printed a Basic Pente program.  I took
this program, removed the input/output sections, and
concentrated on the internals.

   The player side is easy:
      - Verify validity of move
      - Put the stone
      - Check for victory by alignment with the new stone
      - If the new stone has captured any pairs, update
counters and board, and check for capture victory.
      - Swap the player to go
      
   The computer side is not so easy.  The program was
written to have the computer always play the second player
and that is not what I wanted.

   For each move the computer looks for any known alignment
or partial figures, giving points for each free
intersection.  The higher the points the better the move. 
The whole intelligence of the program is the weighting
between figures and the intersection with the higher sores
in the move played. 

   To be accurate, there is also and end game behavior. 
When the computer has already captured 4 pairs, it will give
more points to a move that will allow it to take the last
pair, hence making a sensitive choice of one move to take
the pairs rather than many to win by alignment.

   The base of the evaluation is that each time a stone is
put on the board the intersections near it gain points.

   Once this behavior is translated in C, then comes the
hairy things: testing.  I did recognize that I had
forgotten to add multiple captures. 

   Once the testing was done, I just had to finish with the
details (the Help Loose Item is now easy now that there is
a brain).  And then you have a wonderful Pente Program.

   It only took me two days (Yes!) to write the program,
but I had a lot of things already written; menu, skeleton
of the program, resize routine, etc.  The sprite Editer was
a must. I would have wasted a lot of time computing hex
numbers to get my sprites.  My logo ( a rose ) is a big
sprite that came from a previous program, as did the Help
and Player sprites used as Loose Items.

   It appeared that the most difficult thing was the Hit
routine interface, as it evolved with time and the version
of C68 (it seems to be stable, but I don't use it a lot, so
I'm less familiar with it than with the Loose Item or even
the Menu Item action routines).  It's by smithing that you
become a smith.

   For once, I have not done a Mode 8 design.  Maybe I
shall, but the color is just fine for the moment and I don't
think I will double the size of the text items and recreate
the sprites in Mode 8, even if this is very simple.  Should
Masterpice come soon (the new graphics card), I may well use
the 512x512 in Mode 8 as well as the 1024x512 in Mode 4.

   For those of you that are interested you may get the
Pente Executable from me by email (just write to
jgrimbert@wtk.suresnes.marben.fr).  It's absolutely free.
You may also ask for the sources, but I reserve the right
to not give them out.  Just send email to the same address.

   Please expect a little delay before the answer, as the
first request will make me go home, get the files, go back
to work, and send them.  Also, due to personal/professional
travel, requests before 1 December 1995 may be delayed.

   Please Note:  Tim Swenson has the first public version of
the program, but there is an annoying flickering of the
counter when the board is redrawn. [ I'm happy just to have
a Pente program.  I can live with the flicker - ED]  Ask me
for the lastest version.

 
