scene.org File Archive

File download

<root>­/­parties­/­2023­/­vccc23­/­christmas-diamonds/marcosretrobits_zxspectrum_basic_vc3-2023.zip

File size:
873 602 bytes (853.13K)
File date:
2024-01-03 14:15:18
Download count:
all-time: 4

Preview

  • file_id.diz 4.95K
  • result.png 1.18K
  • source.png 1.42K
  • source.txt 111B
  • sweater.png 847.21K
  • TheSnowingChristmasSweater.tap 88B

file_id.diz

TheSnowingChristmasSweater

Author: Marco's Retrobits
Category: Christmas Challenge
System: ZX Spectrum
Language: Sinclair BASIC
Len source code: 63 bytes
Len exe file:    88 bytes (TAP file)
Len code only:   63 bytes
Instructions:
Install Fuse, check that the emulated machine is ZX Spectrum 48K and that automatic media loading is enabled. 
Drag and drop the "TheSnowingChristmasSweater.tap" file into the emulator window, then press either "ENTER" to see the listing or the "R" key and then "ENTER" to run.
Description:
​The program consists of a single line of BASIC code, which implements an endless loop:
3 LET x=RND*VAL "18": PRINT AT x,INT (RND+RND)*VAL "18"-ABS (x+VAL "6"*INT (RND*INT PI)-VAL "15");"*": GO TO PI
In each iteration, a random "*" belonging to the image is printed on the screen.
TL;DR
With this program, I wanted the shape to be drawn as if it were created by snow flakes, (pseudo-)randomly falling on the computer screen.
I arrived step by step at the final version of the program, with each step being a slight improvement of the previous.
In the first step, I just printed an oblique line of asterisks.
At first, I didn't know (or remember) that the PRINT AT statements allows negative values for line and column, but absolute values are actually used for the printing position,
but then I realized that with this trick, I could draw 2 segments with a single FOR loop:
100 FOR x=0 TO 18
200 PRINT AT x,x-3;"*"
300 NEXT x
   *
  *
 *
*
 *
  *
   *
    *
	 *
	  *
	   *
	    *
		 *
		  *
		   *
		    *
			 *
			  *
			   *
Then, iterating the process 3 times, I could actually print half of the desired picture:
90 FOR a=-15 TO -3 STEP 6
100 FOR x=0 TO 18
200 PRINT AT x,a+x;"*"
300 NEXT x
310 NEXT a
   *     *     *
  *     *     *
 *     *     *
*     *     *
 *   *     *
  * *     *
   *     *
  * *   *
 *	 * *
*	  *
 *	 * *
  *	*   *
   *	 *
  *	*	  *
 *	 *	   *
*	  *	    *
 *	   *	 *
  *		*	  *
   * 	 *	   *
The full shape can be simply obtained by adding the same shape, but horizontally flipped, i.e. by printing at each loop another "*" specularly, at column 18 - ABS(current column):
90 FOR a=-15 TO -3 STEP 6
100 FOR x=0 TO 18
200 PRINT AT x,a+x;"*"
210 PRINT AT x,18-ABS (a+x);"*"
300 NEXT x
310 NEXT a
(program size: 116 bytes)
   *     *     *
  * *   * *   * *
 *   * *   * *   *
*     *     *     *
 *   * *   * *   *
  * *   * *   * *
   *     *     *
  * *   * *   * *
 *	 * *   * *   *
*	  *     *     *
 *	 * *   * *   *
  *	*   * *   * *
   *	 *     *
  *	*   * *   * *
 *	 * *   * *   *
*	  *	    *     *
 *	 * *   * *   *
  *	*	* *	  * *
   * 	 *	   *
The effect is nice, but I wanted the "snow flakes" ("*") to randomly appear on the screen. 
So, I changed the program to a 1-liner endless loop in which the "points" belonging to each of the half shapes are chosed randomly at each iteration:
3 LET a=6*INT (RND*INT PI)-15: LET x=INT (RND*19): PRINT AT x,a+x;"*": PRINT AT x,18-ABS (a+x);"*": GO TO PI
(program size: 88 bytes)
The last GO TO statement uses a trick to reduce the code size, in fact the "PI" function requires just one token, whist the "3" number literal would require 6 more bytes (See "Memory" chapter on the Sinclair ZX SPectrum BASIC manual: https://worldofspectrum.net/ZXBasicManual/zxmanchap24.html).
In the next step, I merged the two print statements, in order to randomly chose at each iteration which half of the shape the "*" being printed belongs to.
3 LET a=6*INT (RND*INT PI)-15: LET x=INT (RND*19): PRINT AT x,INT (RND+RND)*18-ABS (a+x);"*": GO TO PI
(program size: 83 bytes)
In the next step, I refactored the program to remove the "a" variable and save some more bytes:
3 LET x=INT (RND*19): PRINT AT x,INT (RND+RND)*18-ABS (x+6*INT (RND*INT PI)-15);"*": GO TO PI
(program size: 78 bytes)
Then, I saved some more bytes by replacing number literals with strings and using the VAL function 
3 LET x=INT (RND*VAL "19"): PRINT AT x,INT (RND+RND)*VAL "18"-ABS (x+VAL "6"*INT (RND*INT PI)-VAL "15");"*": GO TO PI
(program size: 66 bytes)
Finally, with a little change I saved 3 more bytes:
3 LET x=RND*VAL "18": PRINT AT x,INT (RND+RND)*VAL "18"-ABS (x+VAL "6"*INT (RND*INT PI)-VAL "15");"*": GO TO PI
(program size: 63 bytes)
There may still be some bit left to save, but time is missing!
Comments:
Code length is calculated with: PRINT PEEK 23627+256*PEEK 23628-23755 (see ZX Spectrum system variables: https://worldofspectrum.net/ZXBasicManual/zxmanchap25.html).
My release is named TheSnowingChristmasSweater because the shape, with the proper colours (green border, red paper and white ink), could be a Christmas sweater pattern...
...have a look at the sweater.png file (powered by the wildemasche.com designer) and prove me wrong! :D
Coded using BasinC. Thanks Logiker for the challengs and "BASIC on the ZX Spectrum" Facebook group members for inspiration!
A small video presenting the Snowing Christmas Sweater is available here: https://youtu.be/AuqRzSYH6g0