A common practice among foot ball fans is to "bet" on the outcome of a big game by arranging a 10 x 10 matrix of squares to record a "pool." Each participant puts his or her name in one or more squares and pays the price per square amount to the pool manager. When all the squares are full numbers are drawn at random to place the digits zero thru nine across the top and down the left side. One team is identified with the left digits (rows) the other with the top digits (columns).
An example of a 1994 Superbowl pool is shown on page eight. In this example five winners are selected. One dollar per square is collected by the pool manager. The left team (first digit) is Dallas, the top team is Buffalo (second digit). The first winner is determined by the first quarter score. The units digit of the Dallas score is used to determine the row and the units digit of the Buffalo score determines the column. The four quarter score names receive $15. The final score of the game determines the fifth winner for $40. Each participant receives a copy of the completed pool sheet and then everyone waits for the game on Sunday.
When I saw the pool sheet I thought it would make a good example for several HP 48 data base programming concepts to discuss in our programming class. The first thing I did was to key the 100 entries left to right, top to bottom as named objects in a list in the form 'NAMENN'. I called the list POOL1. Once this was done I started thinking about what to do next. Then I realized I had made a serious mistake! I should have thought out the problem first, but this is what often happens in real life so let's use our programming skills to correct the error rather than re-enter the data. If you want to work on this problem ask for the POOL1 list to be beamed to your machine.
At this point it is useful to make a list of tasks that might assist the manager of the pool.
A. EXAMINE INPUT DATA |
Let's examine a few data base programming concepts involved with these tasks. Human beings make mistakes. Once the data is entered it is often more productive to have a program examine the data to find errors. In our example, the only predictable information is the fact that there are N data with a number ranging from zero to N. The machine could examine each entry and verify that there are N values and that there is only one of each, numbered zero thru 99. The numbers are the score numbers. The program is called CSCOR for Check SCORes.
'CSCOR' << POOL1 "" ADD 1 << DUP SIZE DUP 1 - SWAP SUB >> DOLIST STR-> SORT 0 OVER SIZE 1 - FOR j IF DUP j 1 + GET j # DOERR END NEXT "OK" SWAP DROP >>
Note: # in program listing is the not-equal symbol (slashed =).
I should have entered the data as a text string instead of a named object. The opening sequence; POOL1 "" ADD corrects this using the LIST processing feature of the HP 48 G series machines. The POOL1 list is converted by adding an empty text string to each element with the ADD command e.g. { 'DAVE89' 'LAURAT88' . . .} becomes { "DAVE89" "LAURAT88" . . .}. This is a very handy technique. It will not work on HP 48 S series machines.
List processing is applied again to this "converted list" to create another list of the same data but without the NAME. The command DOLIST requires three inputs. Level three is a list (the one previously converted). Level two is the number of inputs (objects) required by the program on level one. In this case it is 1. The fifth object of CSCOR is a sub program that takes "NAMENN" and extracts the score number NN. The result is a list of score numbers which are then sorted, once again using a list processing command - SORT.
The sequence 0 OVER SIZE 1 - sets up the two inputs for the FOR-NEXT loop. This loop GETs each element of the list and tests it with an IF-THEN-END structure to determine if the data NN is the same as the position N. If it is, the loop continues until all score numbers have been tested. The display will show "OK" if all expected numbers are present and in sequence. If a number is out of sequence the program will stop and display "ERROR N". At this point you must examine the score number and make he correction to POOL1 and run CSCOR again until POOL1 checks "OK".
Every data base should have error checking programs that are run frequently to insure that the data base is as accurate as possible. Our small POOL1 data base and CSCOR is a simple example of this concept.
B. PRINT PARTICIPANT LIST |
The next task the HP 48 may perform for the pool manager is to print a list of participants. This is handy to be sure that each participant gets a copy of the pool sheet. The program below processes POOL1 to remove the score numbers and duplicate names. The core of this program is a program written by Joseph Horn that examines a list and removes duplicate elements. It is elegant, fast and short. See separate handout that describes this program. The program below is called 'RDPN' for Remove DuPlicate Names.
'RDPN' << POOL1 "" ADD 1 << 1 OVER SIZE 2 - SUB >> DOLIST LIST-> { } 1 ROT START SWAP IF DUP2 POS THEN DROP ELSE SWAP + END NEXT SORT 'POOL2' STO >>
The program starts with POOL1 and converts the name list to a string list the same as 'CSCOR' above. The DOLIST program SUBs the name into a new list which is processed with Joseph's routine starting with LIST-> and ending with NEXT. The resulting list is placed into alphabetical order with SORT and stored in 'POOL2'.
The program below is to be used with the 82240A/B IR printer. It is called 'LISTP' for LIST Participants.
'LISTP' << 1 DELAY CR CR "EduCALC Superbowl Pool" PR1 DROP CR POOL2 1 << " " SWAP + PR1 DROP >> DOLIST CR POOL2 SIZE STD " Participants" + CR PR1 DROP CR CR CR CR CR >>
The list is not very long and may be printed faster than the default DELAY of 1.8 seconds per line. The printer is strongly influenced by supply voltage. It may slow to nearly half speed at the end of battery life (4V). The 1 DELAY assumes an AC operated printer or one with fresh batteries and that the printed list is not too long. If your (Paste Print out here printer prints a vertical broken using 'LISTP' program) rectangle you know that your delay is set too short. It may be set shorter. The example printed to the right has the DELAY set to 0.5 which is a little too short. The name after MS didn't get printed as the broken rectangle shows.
A table of delay settings and print times is shown below. Checking for the optimum DELAY for printing tables is an important consideration for maximum speed. Allow for all possible conditions, TEST, TEST, TEST.
|
|
'LISTP' uses the list created by 'RDPN' called 'POOL2'. The DELAY is set for optimum printing. The fifth object text string is the list title. PR1 prints the title and DROP removes it from the stack.
List processing is again done with the DOLIST program that adds four spaces to the front of the name, prints it, and drops it. CR is carrage return to provide one or more blank lines. The last line is the number of participants. 'POOL2' is brought to the stack, and its SIZE determined. This number is insured to be an integer with STD and added to the text string and printed. Five CR's are perfomed to make sure the paper is out far enough to tear off. HP doesn't recommend pulling the paper through the printer.
This list is a basic list of names. The ideas expressed in these programs may be applied to write a program to print a list that includes the name, score numbers, and number of entries multiplied by the cost per entry. This is left as an exercise for the student.
C. DETERMINE THE WINNER |
Three programs are described to determine the winner. The first is Joseph's and is called WIN1. Another program is a modified version called WIN2. The third is the most straight forward program called WIN3. WIN3 requires that the data be entered in score order. This is easy if you think of it before you enter the data.
'WIN1' << "DALLAS, BUFFALO:" "" INPUT OBJ-> 10 MOD { 9 8 3 4 2 0 6 1 5 7 } SWAP POS SWAP 10 MOD { 8 3 7 0 9 1 5 4 6 2 } SWAP POS 1 - 10 * + 'POOL1' SWAP GET >>
Run WIN1 and the INPUT command will prompt you with DALLAS, BUFFALO: at the top of the stack area. The blinking cursor shows that the command line is active. Type two numbers seperated by a space and press ENTER. The program uses the original data base 'POOL1'. Here is how it works. The program starts with two numbers on the stack following OBJ->. The Buffalo score is on level one, Dallas on level two.
The last digit is removed with 10 MOD. Next a list of the random buffalo comumn digits is placed on the stack. POS will return the position in the list of the score. Nine, for example, will return 1 since it is the first postion in the list. SWAP brings the Dallas score to level one and the process is repeated to get a second digit based on the position of that score number of the Dallas list. At this point a little arithmethic is performed. The Dallas digit has 1 subtracted and then it is multiplied by 10. The final + in the program adds the two numbers together to get a two digit number which represents the location of the name in 'POOL1'. 'POOL1' is brought to the stack and a single GET displays the winner.
This program has several features. (1) It is prompting. (2) The input scores may be the actual score or just the units digit. (3) The data base it uses is the original one as entered without modification. It is the latter feature that makes it nice. Suppose, however, that we thought about this before we entered the data. If we made our list of names only in square order 00, 01, 02, . . . we could have a very simple winner program. If we make a custom menu of 'POOL4' and GET we would not need a program at all! Press 'POOL4' menu, key the two units score digits Dallas first, no space, and then GET. A program that does this is 'WIN3'.
'WIN3' << 1 + POOL4 SWAP GET >>
This assumes the names in 'POOL4' are in score order. This is easily done with programs REDO1 and REDO2.
'REDO1' << POOL1 "" ADD 1 << DUP DUP SIZE DUP 1 - SWAP SUB SWAP 1 OVER SIZE 2 - SUB + >> DOLIST SORT 'POOL3' STO >>
Once again we use list processing to get the job done. If you have studied the programs above you will have no difficulty following these. It is important to note that the form of POOL3 is "NNNAME". Having the data in this form is useful for testing 'WIN1' and 'WIN2'. The correct winner is easily checked when it is brought to the display. One final process must be applied to 'POOL3' to remove the two digit score numbers. We created 'POOL3' with the numbers so we could sort them into score number order. Once we know that they are in this order we may remove the numbers with 'REDO2'.
'REDO2' << POOL3 1 << DUP SIZE 3 SWAP SUB >> DOLIST 'POOL4' STO >>
If the pool manager has to input many scores prompting is slow. WIN1 may be modified to retain the features of using POOL1 without prior or program ordering. Input is Dallas units score digit, space, Buffalo units score digit, WIN2 menu.
'WIN2' << { 9 8 3 4 2 0 6 1 5 7 } SWAP POS SWAP { 8 3 7 0 9 1 5 4 6 2 } SWAP POS 1 - 10 * + POOL1 SWAP GET >>
CONCLUSION |
Data bases MUST be thought out before data is entered. In our superbowl example I entered the data without thinking ahead - for execise purposes, of course. Because of this, several programs had to be written - REDO1 and REDO2 to put the data into a format that could be more easily used to search for the winning name given the score. These programs illustrate HP 48 G series list processing. They are summarized below.
Obviously this is an artifical exercise that may appeal to a sports fan. In reality the HP 48 could run one simple random number program that would emulate playing the game - pay your money, press a button to see if you won. The fact that the random winner selection is related to a real event is meaningless, but appeals to the players emotions'. Many slot machines in Las Vegas are 100% computer controlled, no moving parts to relate them to the real world. The visual screen is adaquate for the player to feed the machine money. If the pool manager received a percentage of the pool these programs would take on a whole new value.
Program Summary Program Bytes Purpose Creates ------- ------ --------------------------------------------- ------- CSCOR 162.5 Checks scores in POOL1 for sequence errors. - RDPN 132.5 Removes duplicate names from POOL1. POOL2 LISTP 159.0 List Participants in POOL2. - REDO1 110.0 Processes POOL1 to put in score order. POOL3 REDO2 67.5 Removes score numbers from POOL3. POOL4 WIN1 177.5 Displays winner. Prompting input, uses POOL1. - WIN2 121.5 Displays winner. Non-prompting WIN1. - WIN3 28.5 Displays winner. Simple program if names are - in score order.
Data SummaryName Bytes Format Created By Remarks ----- ----- ------- ---------------------- ----------------------- POOL1 996 'NAMENN' Keyed from pool sheet. Wrong format POOL2 233 "NAME" RDPN Name order, no dups. POOL3 1146 "NNNAME" REDO1 Score order w/ name. POOL4 946 "NAME" REDO2 Score order, name only.
--------------
REMOVING DUPLICATES FROM A LIST By Joseph K. Horn |
There are many possible ways to remove duplicat objects from a list on the HP 48.
You can sort the list into order using the G/GX's SORT command, and then loop through and keep only those objects which differ from the previous object. The drawback to this method is that it doesn't work on the S/SX, and only works on SORTable lists, namely, all the objects in the list must be of the same object type, and they can only be real numbers, strings, lists, names, binary integers, or unit objects. This much restriction is unacceptable.
Another method: Loop through the list, GET each element, and use POS on the original list to determine if this is the element's first occurance in the list. If so, dump it to the stack and increment a counter. When finished looping ->LIST. The drawback of this method is that you have to POS on the whole original list, which is time consuming.
Method used here: LIST-> the list onto the stack and put an empty list on level 1. Use POS on this new list to determine if the next item on the stack is in the list yet. If so, DROP it; if not, add it to the list. This method appears to be faster than the other methods, and is only 57.5 bytes long. If the order of the final list doesn't matter, the final SWAP can be removed, which speeds it up slightly and reduces the byte count to 50.
<< LIST-> { } 1 ROT START SWAP IF DUP2 POS THEN DROP Bytes #2FB4h 57.5. ELSE SWAP + END NEXT >>
SIZE OF ORIGINAL LIST | ||||||
No. Random | 8 | 16 | 32 | 64 | 128 | 256 |
1 - 8 | .2 | .4 | .7 | 1.2 | 2.4 | 5.0 |
1 - 16 | .2 | .4 | .9 | 1.8 | 3.5 | 7.1 |
1 - 32 | .2 | .5 | 1.2 | 2.6 | 5.8 | 11.0 |
1 - 64 | .2 | .6 | 1.5 | 4.1 | 9.6 | 20.8 |
1 - 128 | .2 | .6 | 1.8 | 4.8 | 14.4 | 41.0 |
1 - 256 | .2 | .6 | 1.8 | 5.8 | 19.3 | 74.1 |
S U P E R B O W L P O O L Winner at end 1st QTR $15 2nd QTR $15 3rd QTR $15 4th QTR $15 of game $40
D A L L A S |
BUFFALO
|