Hardware World Issue 6 Contents Software Scene

helpline




Andrew Hewson

Data handling can be achieved on ZX-81

I CANNOT claim that the column has a theme this month, as the letters in my postbag have been too varied; it must be something to do with the weather. John Perry writes: "I have been trying to convert a program written for the TRS-80 but the program uses DATA and READ statements which are not available on the ZX-81. I am considering jumping on the machine because if it cannot handle data it is useless."

There is a solution to the problem but first let me explain that DATA and READ statements provide a method for declaring the value of variables at the time the program is written, to save the user from entering the items at run-time. For example, the lines:

10 DATA 1,2,3
20 READ A,B,C

will assign the values 1, 2 and 3 to A, B and C respectively every time the program is RUN. The same effect could, of course, be achieved by using

10 LET A=1
15 LET B=2
20 LET C=3

The real power of DATA and READ statements is that they allow the programmer to change the values of variables during execution. For example:

10 DATA 1,2,3,4,5,6
20 READ A,B,C
.
.
.
.
1000 READ A,B,C

will cause A, B, C to take the values 1, 2, 3 initially and then 4,5,6 at line 1000. Once again, the same effect could be achieved using LET statements and so the ZX-81 Basic programming manual is correct in pointing out on pages 145 and 146 that READ and DATA are more or less superfluous instructions.

To prevent Perry jumping on his ZX-81, here is a method of simulating READ and DATA:

  10 PRINT "INITIALISE, CALCULATE OR SAVE*(I,C,S)?"
  20 INPUT Z$
  30 GO TO 10+40*(Z$="I")+190*(Z$="C")+1990*(Z$="S")
  50 PRINT "INITIALISE",,"ENTER TEN SETS OF THREE CONSTANTS"
  60 DIM B(3,10)
  70 FOR I=1 TO 10
  80 FOR J=1 TO 3
  90 INPUT B(J,I)
 100 NEXT J
 110 NEXT I
 120 PRINT "INITIALISATION COMPLETE"
 130 GO TO 10
.
.
.
.
2000 PRINT "SAVE ROUTINE",,"ENTER PROGRAM NAME"
2010 INPUT Z$
2020 SAVE Z$
2030 GO TO 10

For the purposes of the demonstration I have assumed that the important part of the program lies between lines 200 and 1999. The initialising routine at lines 50 to 130 asks the user to enter the values which simulate the DATA statement. Those values need only be entered once, because the save routine at line 2000 saves both the program and the variables on cassette and then jumps back to the beginning of the program.

Next time the program is loaded from cassette it will "come in running" and jump back to line 10 with the values of all the variables, in particular the values in array B, still intact. He is then free to transfer the values out of the array later in his program.

In fact, once the values of B are established, lines 50 to 130 are redundant and could be deleted by entering each line number in turn in the usual way - see my answer to Mike Chandler later for a more interesting method. It is important, however, not to start a program by using RUN if you want to retain the variables. You should use GO TO 1 or some other appropriate line number instead.

John Randall should note the use of GO TO instead of RUN. He writes: "Can you suggest a programming technique so that initials and a score are keyed in and retained during saves to enable a best-score system to operate for games?"

I have been asked that kind of question a surprising number of times. The answer is that so long as you do not use RUN, NEW or CLEAR, all your variables are retained. They are also copied on to cassette during SAVE and copied back into memory during LOAD.

"Deleting lines by entering their line numbers in turn is a nuisance. Is there a method for deleting blocks of lines?" asks Mike Chandler of Glasgow.

There is, because the length in bytes of each line is held in two locations immediately following the line number and we can manipulate them to our advantage. To see the line length, clear your ZX-81 by entering NEW and then enter the following line:

10 REM

Then PEEK at the first few bytes in the program area which starts at 16509 and you will see:

AddressContentsMeaning
165090line number=
1651010256*0+10=10
165112line length=
1651202+256*0=2
16513234code for REM
16514118code for newline

Notice that the line length excludes the four bytes required for the line number and the line length. The following routine finds the address of the first byte of two lines entered by the user:

9000 DIM B(2)
9101 LET START=16509
9020 PRINT "ENTER FIRST AND LAST LINE NOS"
9030 INPUT B(1)
9040 INPUT B(2)
9050 IF B(1)<0 OR B(2)< OR B(1)>9999 OR B(2)9999 THEN GO TO 9020
9100 FOR I=1 TO 2
9110 LET L=PEEK (START+2)+256*PEEK(START+3)
9120 LET LINEND=256*PEEK START+PEEK (START+1)
9130 LET START=START+L+4
9140 IF LINEND<B(I)THEN GO TO 9110
9150 LET B(1)=START(L+4)*(I=1)
9160 NEXT I

The routine finishes with the two addresses held in B(1)and B(2).The next trick is to fool the ZX-81 into thinking that all the lines between and including the two line numbers are just one monster line by POKEing the difference between B(2)and B (1) less 4 into the slot for the line length of the first line. That is achieved by adding the lines:

9200 LET B(2)=B(2)-B(1)-4
9210 POKE B(1)+2,B(2)-256*INT(B(2)/256)
9220 POKE B(1)+3,INT (B(2)/256)

The monster line can then be deleted in the usual way, by entering the line number alone.

Sinclair printout

Derek Chadwick has an interesting question. He asks: "Is there any way of lining up figures by the right? I am calculating interest amounts to two decimal places."

The following routine will round to two decimal places the data entered at line 20 and right-justify the figure printed at line 80. Notice that 0.5 is added in the calculation to round the number in line 30 because the INT function always rounds down. If the 0.5 were not present, then 9.877, for example, would be rounded down to 9.87 when it should be rounded up to 9.88.

The print position is determined by converting the value of I to a string and then calculating where the decimal point occurs; it functions correctly even if I is an integer and hence has no decimal point.

 10 LET D$="."
 20 INPUT I
 30 LET I=INT(100*I+5)/100
 40 LET ZS=STR$I
 60 IF ZS(J)=D$ THEN GO TO 80
 70 NEXT J
 80 PRINT AT 21,16-J;Z$
 90 SCROLL
100 GO TO 20

Janet Peterson asks: "Is it possible for a cassette tape to wear out? I am a teacher and my class has used a commercial cassette of games many times but I am finding it increasingly difficult to load."

Yes, magnetic tape will fail eventually. There are several problems. First, simply reading a cassette degrades the signal stored on it by a small amount so if you LOAD from it many times the signal will become weak. Second, if you leave a cassette untouched the signal from each layer of tape will print through on to the next, causing an eventual degradation of the tape. Finally, if you always stop the cassette at the same place and then re-wind it, the tape will stretch.

My advice is always to make a second copy of important cassettes. If you have a commercial cassette which you cannot copy because you cannot break the program while it is running, then "exercise" the cassette regularly by re-winding it completely. That will help to avoid print-through and stretch.

© Copyright Hewson Consultants 1982



Hardware World Issue 6 Contents Software Scene

Sinclair User
September 1982