Previously I discussed several approaches to printing out the Christmas tree pattern for this challenge.
The method that produced the smallest Color BASIC program looked like this:
That uses 66 byte of BASIC program space (though will use more RAM for strings as it runs).
It appears there are still optimizations to make! In the comments. Stewart Orchard pointed out this one:
Not a big gain but two bytes can be saved by removing the third argument from MID$().
The two argument version of MID$() returns the remainder of the string starting from the specified position, and ASC() returns its result based on the first character of its argument.– Stewart Orchard
In Color BASIC, MID$ can accept three parameters:
If you had as string of 10 characters, and wanted to print the third character, you could do it like this:
A$="ABCDEFGHIJ" OK PRINT MID$(A$,3,1) C
Stewart pointed out that if you left off the final parameter, it returns the rest of the string:
A$="ABCDEFGHIJ" OK PRINT MID$(A$,3,1) CDEFGHIJ
Now that I look at it, it appears MID$ with two parameters is sort of like an inverted RIGHT$. MID$ would give you all the characters starting at the one you specify, and RIGHT$ gives you the number of ending characters you specify.
PRINT MID$(A$,3) CDEFGHIJ PRINT RIGHT$(A$,3) HIJ
I don’t recall using MID$ like this, but I have simulated the same behavior using RIGHT$ like:
PRINT RIGHT$(A$,LEN(A$)-3+1) CDEFGHIJ PRINT MID$(A$,3) CDEFGHIJ
I am a bit embarrassed to admit I think I even did something like this:
PRINT MID$(A$,3,LEN(A$)-3) CDEFGHIJ
…but let’s not speak of that.
And if MID$ can work like RIGHT$, it can also work like LEFT$:
PRINT LEFT$(A$,3) ABC PRINT MID$(A$,1,3) ABC
But I digress…
If MID$(A$,3,1) gives you one character starting as location 3, and MID$(A$,3) gives you all the characters starting at position 3, how does that work? Stewart explained that ASC will still work if you pass it a string since it only works on the first character of the string. It is even documented that way:
Thus, ASC(“HELLO”) produces the same result as ASC(“H”) — the ASCII value of letter H.
With that in mind, we can remove “,1” from the program and reduce it by two bytes:
Thank you, Stewart, for leaving that comment.
Until next time…
I use the 2 argument ASC(MID$(A$,N)) technique in combination in many of my games. It’s a real speedup.
It would be nice to get rid of the “-64” part after the ASC() function, as this would save another 3 bytes, reducing the program size from 64 to 61 bytes.
All you have to do is to replace the characters inside the string with lower ASCII values just as needed, like &H01, &H03, &H05 and so on. You cannot use the keyboard to edit the string in this way, but I did write some self-modifying code that replaced the characters directly in program memory. After this, you can erase the extra code and you are left with a fully functional version that is 61 bytes long. This is the code:
20 ‘FIND FIRST STRING IN THE BASIC PROGRAM MEMORY AND HACK IT!
30 S=PEEK(25)256+PEEK(26) ‘START OF BASIC CODE IN MEMORY
40 E=PEEK(27)256+PEEK(28) ‘END OF BASIC CODE IN MEMORY
50 FOR A=S TO E
60 IF F THEN READ V : IF V<0 THEN END ELSE POKE A,V
70 IF PEEK(A)=34 THEN F=-1 ‘TOGGLE FLAG UPON REACHING THE FIRST QUOTATION MARK
80 NEXT A
90 DATA 1,3,5,7,3,7,11,15,5,11,17,23,3,3,-1
Run it once, then do a DEL 10-90. Run it again to verify it still fulfills the original task, and it does!
1) All tests done in XROAR 1.0.1 emulating a COCO 1 with 32k RAM.
2) I removed the “-64” before modifying the string, but you can also do it afterwards, even though the EDIT function will behave a bit funny while skipping over the non-printable characters in the string constant, but it works. I tested both ways.
3) If one of the characters had been 0 or 34 (quotation mark) this would have not worked. But this was not the case, so I got away with this. I’m not sure if there are other forbidden characters to consider, if somebody knows about this please comment.
4) In order to make sure this was still a valid program, I CSAVE’d it in a virtual cassette file, did a cold restart and reloaded the saved program. It works!
5) If you LIST the program, you’ll see a supposedly empty string inside the MID$() function, however it is not empty! I wrote a small memory monitor to verify this.
6) RENUM function won’t work now, though.
In summary, this trickery allows reduction of the final program size from 64 to 61 bytes.
What a clever approach! A type-able program that then generates a smaller one. I wonder what RENUM doesn’t like. I’ll have to investigate that. Nicely done. I’ll check it out.
May I share your technique/reply in a future posting? With credit, of course.
Yes, of course!
On a different matter, I wanted to comment that just as you can import an ASCII file into XROAR as if it were a BASIC program (using the RUN then CLOAD commands), you can further edit your program in XROAR and then export it out as an ASCII file using the LLIST command. This will output your edited code into a txt file which you can then use for further editing in an external editor.
Some considerations about the above:
1) In the command line when you run XROAR, you can add “-lp-file printer.txt” or any other name that suits you, like “program.bas”.
2) The printer file remains open until you close XROAR or you manually request XROAR to close it by pressing CTRL+SHIFT+P (under windows).
3) This virtual printing is very slow, so I usually press SHIFT+F12 to make XROAR run at max speed while doing this.
This provides a reasonable workflow for developing and testing BASIC code.
Perhaps the most useful feature of being able to export your edited file in XROAR is when you want to use the RENUM feature.
That is a very clever approach for saving a file out without using tape or disk images. I must have used that to get a listing of some of my old programs, because I see a shortcut I made with that option. The keyboard shortcut to flush the file is good to know. I must have missed that, as I also now remember shutting down XRoar to get the file to create. “The more you know…”
Before I learned the CLOAD trick, I had some batch/shell script files I used to copy a text file to a disk image as ASCII or maybe even tokenize it. That worked, but required saving the file as the same name, or having to manually type in the filename as an option. I suppose one could make it just take all the files in a folder and move them over, but i have more than 68 work in files in my BAS directory and that is the limit of file count on a disk.
I think CLOAD still works best, but maybe not as good when the program gets huge and it takes too long.
Pingback: Tackling the Logiker 2022 Vintage Computing Christmas Challenge – part 1 | Sub-Etha Software