|
Post by sarossell on Mar 1, 2020 19:43:01 GMT -5
Okay, so I suck at this. If there's a category of programming skill between beginner and intermediate, that would be me.
I ran across the following program in an old copy of Syntax ZX80 dating all the way back to...yep, 1980. The program was originally written for the Sinclair ZX80 with only 1K RAM.
I tried converting the code to Liberty BASIC, but as I mentioned earlier, I suck.
The program is called Cryptoquote. I've included an image of original listing just in case my typed in copy has any typos.
Some things to know about ZX80 BASIC:
1. The TL$ command simply removed the first letter of a string. So, TL$("OKAY") yielded "KAY". 2. The CODE command returned the ASCII code of the first character of a string. So CODE("ABC") yielded 38. 3. GOSUB and GOTO both had a space after GO. 4. You had to use the LET command.
5. You couldn't have multiple lines of code on the same line separated with a colon.
Trivia: The ZX80 allowed arrays to start with 0, but all subsequent Sinclair BASIC versions required you to start with 1 and didn't offer an option for 0. Weird.
And now that I write this, it occurs to me that I could have created functions to replace the missing commands, as zzz000abc so recently did for the (contest?) 10 Line Atari Basic Game - to LB thread. Dangit! Consider that a hint. Okay, so I'll give it another try. in the meantime, anyone else care to give it a shot?
P.S.: If you happen to have copies of the Syntax ZX80 Newsletter, I'm missing four issues. I've already sifted through the Internet pretty heavily.
:@)
6 DIM T(25) 7 LET K=1000 60 FOR X=0 TO 25 65 LET T(X)=220 70 NEXT X 100 CLS 110 GO SUB 990 120 PRINT T$ 123 LET X=C0DE(T$) 125 IF X<38 OR X>63 THEN GO TO 170 130 PRINT CHR$(T(X-38)) 140 LET T$=TL$(T$) 160 GO TO 123 170 IF X=1 THEN GO TO 200 175 PRINT CHR$(X); 180 GO TO 140 200 PRINT 205 PRINT "COMMAND:"; 210 INPUT F$ 220 IF CODE(TL$(F$))=227 THEN LET T(CODE(F$)-38)=CODE(TL$(TL$(F $))) 222 IF F$="F" THEN GO TO 400 240 GO TO 100 400 CLS 410 GO SUB 990 460 LET N=CODE(T$)-38 470 IF N=-37 THEN GO TO 500 480 IF N<0 OR N>25 THEN GO TO 485 483 LET T(N)=T(N)+K 485 LET T$=TL$(T$) 490 GO TO 460 500 FOR X=0 TO 12 505 LET S=T(X)-CT(X)/K)*K 506 LET S2=T(X+13)-(T(X+13)/K)*K 510 PRINT CHR$ (X+38);"(";CHR$(S);"):";T(X)/K;" ";CHR$(X+51);"(";CHR$(S2);"):";T(X+13)/K 520 LET T(X)=S 525 LET T(X+13)=S2 530 NEXT X 540 GO TO 200 990 LET T$="UVQ JVQQXZX KQ JQYGZKZ UBKV YWJVBPZX WJJZGKX KVZ JQ PMBKBQPX QC XFWDZLH" 999 RETURN
|
|
|
Post by Chris Iverson on Mar 1, 2020 21:47:18 GMT -5
Transcription errors on lines 220, 505, and 510.
220: final F$ can't have a space in it.
505: actual line is
505 LET S=T(X)-(T(X)/K)*K
(Parenthesis was replaced with a capital "C")
510: First CHR$() has a space after the $, that's not there in the original. This will break LB parsing.
Also, requesting clarification on how CODE() and TL$() behaved in ZX80 BASIC. In particular, how do they behave when faced with an empty string? What does TL$() return if you give it a string with only one character in it? With zero characters? What does CODE() return if you pass it an empty string?
The reason I ask is because a Sinclair BASIC manual I found online says that CODE() returns zero on an empty string(same as LB's ASC() would do), however, I believe that would break the code as written.
The code seems to check for 1 being returned from CODE() to indicate the end of the input string. (See lines 170 and 470) I don't see how that would happen if TL$() just returns an empty string at the end, and CODE() returns zero on an empty string.
|
|
|
Post by sarossell on Mar 2, 2020 2:09:12 GMT -5
Thanks for catching the typos. My eyesight isn't what it used to be. That's why I included the original image just in case. All valid questions about ZX80 BASIC. I broke out an emulator, but I ran into an unexpected problem. TL$("") and TL$("A") both yield nothing, but with no error. But unfortunately, as for CODE, I couldn't find it on the friggin' keyboard! I know the program was written for the ZX80 because the ZX81 didn't exist yet. And the CODE command is in the manual. So I'm kind of at a loss here.
UPDATE: I used a ZX81 emulator and found the CODE command under the I key. With that, I tested it and CODE ("") yields the number 0. I'm guessing the programmer assumed the ZX80 had a new 8K ROM upgrade which was essentially the same ROM in the ZX81.
|
|
|
Post by Rod on Mar 2, 2020 5:52:58 GMT -5
Ok, stumped at the moment. Code() is kinda like asc() only Spektrum letters run from 38 to 63 Thats 27 less than true ASC. Also that's what the -38 is about using the array T() to store frequency so starting at 0. TL$() just chops the first letter of a string and returns the rest or ""
So far so good. Chr$() prints a character but needs the +27 to print the correct character.
This is what I am stumped on 130 PRINT CHR$(T(X-38)) what is it doing? The code below runs but not correctly.
The -38 is about pointing the array to 0 - 25 instead of 38 - 63
6 DIM T(25) 7 LET K=1000 60 FOR X=0 TO 25 65 LET T(X)=220 70 NEXT X 100 CLS 110 GOSUB 990 120 PRINT T$ 123 LET X=CODE(T$) 125 IF X<38 OR X>63 THEN GOTO 170 130 PRINT CHR$(T(X-38)) 140 LET T$=TL$(T$) 160 GOTO 123 170 IF X=1 THEN GOTO 200 175 PRINT CHR$(X+27); 180 GOTO 140 200 PRINT 205 PRINT "COMMAND:"; 210 INPUT F$ 220 IF CODE(TL$(F$))=227 THEN LET T(CODE(F$)-38)=CODE(TL$(TL$(F$))) 222 IF F$="F" THEN GOTO 400 240 GOTO 100 400 CLS 410 GOSUB 990 460 LET N=CODE(T$)-38 470 IF N=-37 THEN GOTO 500 480 IF N<0 OR N>25 THEN GOTO 485 483 LET T(N)=T(N)+K 485 LET T$=TL$(T$) 490 GOTO 460 500 FOR X=0 TO 12 505 LET S=T(X)-(T(X)/K)*K 506 LET S2=T(X+13)-(T(X+13)/K)*K 510 PRINT CHR$(X+38+27);"(";CHR$(S+27);"):";T(X)/K;" ";CHR$(X+51+27);"(";CHR$(S2+27);"):";T(X+13)/K 520 LET T(X)=S 525 LET T(X+13)=S2 530 NEXT X 540 GOTO 200 990 LET T$="UVQ JVQQXZX KQ JQYGZKZ UBKV YWJVBPZX WJJZGKX KVZ JQ PMBKBQPX QC XFWDZLH" 999 RETURN
function TL$(x$) TL$=right$(x$,len(x$)-1) end function
function CODE(x$) CODE=asc(x$)-27 end function
|
|
|
Post by sarossell on Mar 2, 2020 6:41:53 GMT -5
I have no idea, Rod. But I sure appreciate you taking a stab at it!
I did the same thing you did by creating the functions for TL$ and CODE. I hadn't yet caught onto the fact that the character numbering wasn't ASCII. You've made far more progress than I could manage so far. I got caught up trying to get past the error "Array CODE() requires numeric parameters." until I realized that I had somehow managed to type a zero instead of an Oh in the word CODE! Grr.
:@(
|
|
|
Post by Rod on Mar 2, 2020 7:58:06 GMT -5
OK, a little better but not quite right yet. I had a missing ; now it lists the crypt plus the substituted letter below. When it gets to the command input you can either get a frequency report or key in a substitution like Q=E
The = was problematic because its code 227, a graphic character so I substitute 34 which is the code number of asc("=") ie 61-27
To break out the first loop you somehow had to get to x=1 I fudged that in the code() functuion. Now it gets to the command and will provide a frequency report. Sometimes it takes a substitution sometimes not and it seems to lose previous substitutions which I am sure it should not do so more debugging required.
6 DIM T(25) 7 LET K=1000 60 FOR X=0 TO 25 65 LET T(X)=220 70 NEXT X
'print the string as we know it, initially without substitution 100 CLS 110 GOSUB 990 120 PRINT T$ 123 LET X=CODE(T$) 125 IF X<38 OR X>63 THEN GOTO 170 130 PRINT CHR$(T(X-38)+27); 140 LET T$=TL$(T$) 160 GOTO 123
170 IF X=1 THEN GOTO 200 175 PRINT CHR$(X+27); 180 GOTO 140
200 PRINT 205 PRINT "COMMAND:"; 210 INPUT F$ 220 IF CODE(TL$(F$))=34 THEN LET T(CODE(F$)-38)=CODE(TL$(TL$(F$))) 222 IF F$="F" THEN GOTO 400 240 GOTO 100
400 CLS 410 GOSUB 990 460 LET N=CODE(T$)-38 470 IF N=-37 THEN GOTO 500 480 IF N<0 OR N>25 THEN GOTO 485 483 LET T(N)=T(N)+K 485 LET T$=TL$(T$) 490 GOTO 460
500 FOR X=0 TO 12 505 LET S=T(X)-(T(X)/K)*K 506 LET S2=T(X+13)-(T(X+13)/K)*K 510 PRINT CHR$(X+38+27);"(";CHR$(S+27);"):";T(X)/K;" ";CHR$(X+51+27);"(";CHR$(S2+27);"):";T(X+13)/K 520 LET T(X)=S 525 LET T(X+13)=S2 530 NEXT X 540 GOTO 200
990 LET T$="UVQ JVQQXZX KQ JQYGZKZ UBKV YWJVBPZX WJJZGKX KVZ JQ PMBKBQPX QC XFWDZLH" 999 RETURN
function TL$(x$) TL$=right$(x$,len(x$)-1) end function
function CODE(x$) CODE=asc(x$)-27 if CODE=-27 then CODE=1 end function
|
|
|
Post by Chris Iverson on Mar 2, 2020 12:23:10 GMT -5
One more transcription error.
"JQ PMBKBQPX" in the encoded text is supposed to be one word. "JQPMBKBQPX".
I've not had it fail to do a substitution yet, (although keep in mind that you always have to reference a letter by the original letter in it's place), but I do have it forget what's been decoded so far if you bring up the freq distribution again.
It also seems to change what glyph it uses for the not-yet-decoded letters, and I'm not sure what's supposed to be in the parenthesis on the freq distribution chart.
Using the code as-is, however, I've actually gotten everything decoded except for the last word.
EDIT: Got it now. Still poking at the code to see how different parts are arranged.
|
|
|
Post by sarossell on Mar 2, 2020 14:18:42 GMT -5
You guys are amazing! I had no idea such an old program would be so much trouble. I was never formally trained in programming. My first computer was a ZX81 and I never really had the time to focus on learning that as well as I could. Now, with a lot of time on my hands, I've actually started exactly where I was 40 years ago, with the very first published program in the very first published issue of the Syntax ZX80 newsletter, AND IT KICKED MY BUTT. :@(
But I'm learning a lot now. Thanks guys!
|
|
|
Post by Carl Gundel on Mar 2, 2020 14:21:03 GMT -5
You guys are amazing! I had no idea such an old program would be so much trouble. I was never formally trained in programming. My first computer was a ZX81 and I never really had the time to focus on learning that as well as I could. Now, with a lot of time on my hands, I've actually started exactly where I was 40 years ago, with the very first published program in the very first published issue of the Syntax ZX80 newsletter, AND IT KICKED MY BUTT. :@( But I'm learning a lot now. Thanks guys! The more memory constrained the computer was, the more they did funny things to the BASIC in the machine to make the most of RAM. The ZX80 shared program memory with video RAM, so your 1K was used up really fast! Sinclair BASIC is a very clever implementation, but kind of obtuse.
|
|
|
Post by sarossell on Mar 2, 2020 14:32:23 GMT -5
You guys are amazing! I had no idea such an old program would be so much trouble. I was never formally trained in programming. My first computer was a ZX81 and I never really had the time to focus on learning that as well as I could. Now, with a lot of time on my hands, I've actually started exactly where I was 40 years ago, with the very first published program in the very first published issue of the Syntax ZX80 newsletter, AND IT KICKED MY BUTT. :@( But I'm learning a lot now. Thanks guys! The more memory constrained the computer was, the more they did funny things to the BASIC in the machine to make the most of RAM. The ZX80 shared program memory with video RAM, so your 1K was used up really fast! Sinclair BASIC is a very clever implementation, but kind of obtuse. Absolutely. the ZX80 was about as subtle as a bullet wound. And the ZX81 was the same gun shot, but you at least felt like you were wearing a bullet-proof vest to temper the blow. That is, until the 16K RAM pack wiggled...Arg!! Ah, the early years...
|
|
|
Post by Rod on Mar 2, 2020 14:37:04 GMT -5
It reminds me of why I was mightily glad to move on from Sinclair, the listings were always unfathomable! And finally to a liberating BASIC, bliss.
|
|
|
Post by sarossell on Mar 2, 2020 15:13:46 GMT -5
It reminds me of why I was mightily glad to move on from Sinclair, the listings were always unfathomable! And finally to a liberating BASIC, bliss. Exactly. Well punned, sir! :@)
|
|
|
Post by jgerrie on Feb 24, 2024 16:22:34 GMT -5
I have that program converted to Micro Color BASIC. Might be easier to convert to Liberty:
Here's the code:
6 CLEAR250:DIM T(90),F(90) 7 K=10 60 FOR X=0 TO 90 65 T(X)=142 70 NEXT X 100 CLS 110 GOSUB 990 120 PRINT T$ 121 FOR C=1 TO LEN(T$) 124 X=ASC(MID$(T$,C,1)) 125 IF X<65 OR X>90 THEN 170 130 PRINT CHR$(T(X)); 140 NEXT C 160 GOTO 200 170 IF X<32 THEN STOP 175 PRINT CHR$(X); 180 GOTO 140 200 PRINT 205 PRINT "COMMAND"; 210 INPUT F$ 220 IF MID$(F$,2,1)="=" THEN T(ASC(F$))=ASC(MID$(F$,3,1)+"Ž"):REM Ž=CHR$(142) WHICH IS THE CODE FOR UNSELECTED/BLANK LETTERS 222 IF F$="F" THEN 400 230 IF F$="" THEN 300 232 IF F$="Q" THEN END 240 GOTO 100 300 PRINT "f=FREQUENCY REPORT" 310 PRINT "enter=HELP" 320 PRINT "A=B SUBSTITUTES A FOR B" 330 PRINT"A= RETURN A TO BLANK" 340 PRINT "q=QUIT" 350 PRINT"MOST COMMON ENGLISH LETTERS:" 360 PRINT "etaonrishdlfcmugypwbvkxjqz" 370 GOTO 200 400 CLS 410 GOSUB 990 420 FOR X=65 TO 90:F(X)=0:NEXT X 430 L=LEN(T$) 440 FOR C=1 TO L 460 N=ASC(MID$(T$,C,1)) 480 IF N<65 OR N>90 THEN L=L-1:GOTO 490 483 F(N)=F(N)+1 490 NEXT C 500 FOR X=65 TO 90 505 S=INT((F(X)*100/L)*K)/K 510 PRINT CHR$(X)"("MID$(STR$(S),2)")", 520 F(X)=S 530 NEXT X 540 GOTO 200 990 T$="UVQ JVQQXZX KQ JQYGZKZ UBKV YWJVBPZX WJJZGKX KVZ JQPMBKBQPX QC XFWDZLH" 995 IFT$=""THENINPUTT$ 999 RETURN
|
|
|
Post by Carl Gundel on Feb 24, 2024 18:38:19 GMT -5
|
|