--- /dev/null
+# IntelliJ files
+/.idea/
+/qbasicapps.iml
+
+# Volkov Commander
+/VC.COM
+/VC.INI
+
+# Qbasic installation
+/QB45
+
+# Index HTML files are autogenerated anyway
+**/index.html
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>QBasicApps</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ </buildSpec>
+ <natures>
+ </natures>
+</projectDescription>
--- /dev/null
+' This program showcases the rotation of points on an X-Y coordinate\r
+' system using trigonometric functions, specifically sine and cosine. By\r
+' simulating the effect of rotating a collection of grid points around\r
+' the origin, it demonstrates the mathematical principles behind 2D\r
+' rotation.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024, Improved program readability\r
+\r
+DIM SHARED pointXCoordinates(1000) ' Array to store x coordinates of points\r
+DIM SHARED pointYCoordinates(1000) ' Array to store y coordinates of points\r
+DIM SHARED oldPointXCoordinates(1000) ' Array to store previous x coordinates of points\r
+DIM SHARED oldPointYCoordinates(1000) ' Array to store previous y coordinates of points\r
+\r
+SCREEN 13\r
+\r
+numPoints = 0 ' Initialize the number of points\r
+FOR pointXVal = -10 TO 10\r
+ FOR pointYVal = -10 TO 10\r
+ numPoints = numPoints + 1\r
+ pointXCoordinates(numPoints) = pointXVal\r
+ pointYCoordinates(numPoints) = pointYVal\r
+ NEXT pointYVal\r
+NEXT pointXVal\r
+\r
+' Main rotation loop\r
+rotationAngle = 0 ' Initialize the rotation angle to 0\r
+\r
+1\r
+ rotationAngle = rotationAngle + .01 ' Increment the rotation angle by 0.01 radians\r
+ SOUND 0, .5\r
+\r
+ ' Calculate the sine and cosine of the current rotation angle\r
+ sineOfRotationAngle = SIN(rotationAngle)\r
+ cosineOfRotationAngle = COS(rotationAngle)\r
+\r
+ FOR pointIndex = 1 TO numPoints\r
+ PSET (oldPointXCoordinates(pointIndex), oldPointYCoordinates(pointIndex)), 0 ' Clear the previous position\r
+\r
+ xCoordinate = pointXCoordinates(pointIndex)\r
+ yCoordinate = pointYCoordinates(pointIndex)\r
+\r
+ ' Calculate the new x and y coordinate after rotation\r
+ newXCoordinate = xCoordinate * sineOfRotationAngle + yCoordinate * cosineOfRotationAngle\r
+ newYCoordinate = xCoordinate * cosineOfRotationAngle - yCoordinate * sineOfRotationAngle\r
+\r
+ ' Scale and translate the new x and y coordinates to the center of the screen\r
+ newXCoordinate = newXCoordinate * 7 + 160\r
+ newYCoordinate = newYCoordinate * 7 + 100\r
+\r
+ ' Store x and y on-screen coordinates for clearing on next iteration\r
+ oldPointXCoordinates(pointIndex) = newXCoordinate\r
+ oldPointYCoordinates(pointIndex) = newYCoordinate\r
+\r
+ PSET (newXCoordinate, newYCoordinate), 15 ' Draw the point at the new position\r
+ NEXT pointIndex\r
+\r
+IF INKEY$ = "" THEN GOTO 1 ' Continue rotating if no key is pressed\r
+\r
--- /dev/null
+DECLARE SUB paintSurface ()\r
+' Program renders bump mapping animation where light source moves around.\r
+' Based on light source location, different parts of the surface become illuminated.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+\r
+' Changelog:\r
+' ?, Initial version\r
+' 2024, Improved program readability\r
+\r
+DECLARE SUB makeSurface ()\r
+DECLARE SUB animate ()\r
+DECLARE SUB makeDot (x!, y!)\r
+DECLARE SUB paintImage ()\r
+SCREEN 13\r
+\r
+' surface height map\r
+DIM SHARED imgHeight(0 TO 50, 0 TO 50)\r
+\r
+PAINT (0, 0), 1\r
+\r
+makeSurface\r
+paintSurface\r
+animate\r
+\r
+SUB animate\r
+\r
+ frame = 0\r
+1\r
+ SOUND 0, 0.5\r
+\r
+ ' Increment the frame counter\r
+ frame = frame + 5\r
+\r
+ ' Calculate light position based on sine functions\r
+ lightX = SIN(frame / 100) * 20 + 25\r
+ lightY = SIN(frame / 71.32) * 20 + 25\r
+ lightX = lightX + SIN(frame / 34) * 10\r
+ lightY = lightY + SIN(frame / 45) * 10\r
+\r
+ ' Calculate brightness for each pixel based on distance and angle from light\r
+ FOR y = 2 TO 48\r
+ FOR x = 2 TO 48\r
+ distance = SQR((x - lightX) ^ 2 + (y - lightY) ^ 2)\r
+ brightness = (30 - distance) / 4\r
+\r
+ ' Calculate surface inclination relative to light location\r
+ value = imgHeight(x - 1, y) - imgHeight(x, y)\r
+ brightnessX = (lightX - x) * value\r
+\r
+ value = imgHeight(x, y - 1) - imgHeight(x, y)\r
+ brightnessY = (lightY - y) * value\r
+\r
+ brightness = brightness + (brightnessX + brightnessY) / (distance / 2)\r
+\r
+ ' Clamp brightness within valid range\r
+ IF brightness < 0 THEN brightness = 0\r
+ IF brightness > 15 THEN brightness = 15\r
+\r
+ ' Set pixel color based on brightness\r
+ PSET (x + 150, y), 16 + brightness\r
+ NEXT x\r
+ NEXT y\r
+\r
+ ' Draw light source as a circle\r
+ CIRCLE (lightX + 150, lightY), 2, 12\r
+\r
+\r
+ ' Loop back to the start of animation until\r
+ ' no key has been pressed by the user.\r
+ IF INKEY$ = "" THEN GOTO 1\r
+\r
+END SUB\r
+\r
+' Current subroutine creates somewhat fat round dot.\r
+' Center of the dot is fully elevated.\r
+' There is smooth drop-off in elevation from the center.\r
+SUB makeDot (x, y)\r
+\r
+ FOR x1 = -10 TO 10\r
+ FOR y1 = -10 TO 10\r
+ distanceFromCenter = SQR(x1 * x1 + y1 * y1)\r
+ height = 4 - distanceFromCenter\r
+ IF height < 0 THEN height = 0\r
+\r
+ ' Calculate image coordinates\r
+ imgX = x1 + x\r
+ imgY = y1 + y\r
+\r
+ ' Ensure coordinates are within bounds\r
+ IF imgX < 0 THEN imgX = 0\r
+ IF imgY < 0 THEN imgY = 0\r
+ IF imgX > 50 THEN imgX = 50\r
+ IF imgY > 50 THEN imgY = 50\r
+\r
+ ' Add power to the height map\r
+ imgHeight(imgX, imgY) = imgHeight(imgX, imgY) + height\r
+ NEXT y1\r
+ NEXT x1\r
+\r
+END SUB\r
+\r
+SUB makeSurface\r
+\r
+ ' Generate random dots on the surface\r
+ FOR x = 0 TO 10\r
+ CALL makeDot(RND * 50, RND * 50)\r
+ NEXT x\r
+\r
+ ' Add some lines composed from dots\r
+ FOR x = 0 TO 45 STEP 2\r
+ CALL makeDot(x, x / 2 + 5)\r
+ NEXT x\r
+\r
+ FOR x = 5 TO 30 STEP 2\r
+ CALL makeDot(x, -x / 1.2 + 30)\r
+ NEXT x\r
+\r
+END SUB\r
+\r
+SUB paintSurface\r
+\r
+ ' Paint the image based on height map\r
+ FOR x = 0 TO 50\r
+ FOR y = 0 TO 50\r
+ clr = imgHeight(x, y) + 16\r
+ PSET (x, y), clr\r
+ NEXT y\r
+ NEXT x\r
+\r
+END SUB\r
+\r
--- /dev/null
+' Program to render animated DNA as seen in the movies.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' ?, Initial version\r
+' 2024, Improved program readability\r
+\r
+DIM SHARED xCoordinates(1 TO 100)\r
+DIM SHARED yCoordinates(1 TO 100)\r
+DIM SHARED zCoordinates(1 TO 100)\r
+DIM SHARED colorCodes(1 TO 100)\r
+\r
+SCREEN 7, , , 1\r
+\r
+1:\r
+SOUND 0, .5\r
+\r
+b = 0\r
+rotationAngle = rotationAngle + 0.1\r
+FOR a = 1 TO 20\r
+ b = b + 1\r
+ ' Calculate x-coordinate using sine function and add to array\r
+ xCoordinates(b) = SIN(a / 2 + rotationAngle) * 30 + 150\r
+ ' Calculate z-coordinate using sine function and add to array\r
+ zCoordinates(b) = SIN(a / 2 + rotationAngle + 1.6) * 2 + 2\r
+ ' Calculate y-coordinate by multiplying a with 8 and adding z-coordinate\r
+ yCoordinates(b) = a * 8 + zCoordinates(b)\r
+ ' Assign color code to the current point\r
+ colorCodes(b) = 3\r
+\r
+ b = b + 1\r
+ ' Calculate x-coordinate using sine function and add to array\r
+ xCoordinates(b) = SIN(a / 2 + rotationAngle + 2.5) * 30 + 150\r
+ ' Calculate z-coordinate using sine function and add to array\r
+ zCoordinates(b) = SIN(a / 2 + rotationAngle + 1.6 + 2.5) * 2 + 2\r
+ ' Calculate y-coordinate by multiplying a with 8 and adding z-coordinate\r
+ yCoordinates(b) = a * 8 + zCoordinates(b)\r
+ ' Assign color code to the current point\r
+ colorCodes(b) = 4\r
+NEXT a\r
+\r
+' Clear the screen\r
+CLS\r
+\r
+' Draw lines and circles based on z-coordinate\r
+FOR b = 0 TO 4\r
+ IF b = 1 THEN\r
+ FOR a = 1 TO 40 STEP 2\r
+ ' Draw line between consecutive points\r
+ LINE (xCoordinates(a), yCoordinates(a))-(xCoordinates(a + 1), yCoordinates(a + 1)), 15\r
+ NEXT a\r
+ END IF\r
+\r
+ FOR a = 1 TO 40\r
+ ' Check if the current z-coordinate matches the loop variable b\r
+ IF int(zCoordinates(a)) = b THEN\r
+ ' Draw circle with specified color code\r
+ CIRCLE (xCoordinates(a), yCoordinates(a)), b + 5, colorCodes(a)\r
+ PAINT (xCoordinates(a), yCoordinates(a)), colorCodes(a)\r
+ ' Draw an black outline of the circle\r
+ CIRCLE (xCoordinates(a), yCoordinates(a)), b + 5, 0\r
+ END IF\r
+ NEXT a\r
+NEXT b\r
+\r
+' Copy the screen to buffer and clear the screen\r
+PCOPY 0, 1\r
+CLS\r
+\r
+' Check if any key is pressed\r
+IF INKEY$ = "" THEN GOTO 1\r
+\r
+' End the program\r
+SYSTEM\r
--- /dev/null
+' Projects animated particles in orbit around a central point.\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+\r
+' Changelog:\r
+' ?, Initial version\r
+' 2024, Improved program readability\r
+\r
+SCREEN 7, , , 1\r
+RANDOMIZE TIMER\r
+\r
+' Declare shared arrays to store particles\r
+DIM SHARED particleColor(1 TO 100)\r
+DIM SHARED particleX(1 TO 100)\r
+DIM SHARED particleAngle(1 TO 100)\r
+\r
+' Initialize the arrays with random values\r
+FOR a = 1 TO 100\r
+ particleColor(a) = RND * 15\r
+ particleX(a) = RND * 100\r
+ particleAngle(a) = RND * 100\r
+NEXT a\r
+\r
+' Main loop to draw the animated particles\r
+1\r
+CLS\r
+FOR a = 1 TO 50\r
+ ' Get current segment data\r
+ currentColor = particleColor(a)\r
+ currentParticleX = particleX(a)\r
+ currentparticleAngle = particleAngle(a)\r
+\r
+ ' Calculate the x and y coordinates for the current segment\r
+ xCoordinate = SIN(currentparticleAngle) * 25\r
+ yCoordinate = SIN(currentParticleX) * 20\r
+\r
+ ' Scale the coordinates\r
+ scaleFactor = (COS(currentparticleAngle) + 2) * 2\r
+ xCoordinate = xCoordinate * scaleFactor\r
+ yCoordinate = yCoordinate * scaleFactor\r
+\r
+ ' Draw the current particle as a circle\r
+ CIRCLE (xCoordinate + 160, yCoordinate + 100), scaleFactor, currentColor\r
+\r
+ ' Fill the inside of the circle with color\r
+ PAINT (xCoordinate + 160, yCoordinate + 100), currentColor\r
+\r
+ ' Draw a line from the center to the current particle\r
+ LINE (160, 100)-(xCoordinate + 160, yCoordinate + 100), currentColor\r
+\r
+ ' Rotate particle by small amount for next frame\r
+ particleAngle(a) = particleAngle(a) + .1\r
+NEXT a\r
+\r
+' Copy screen buffer 0 to screen buffer 1\r
+PCOPY 0, 1\r
+\r
+' Check for user input and exit if any key is pressed\r
+IF INKEY$ <> "" THEN SYSTEM\r
+\r
+' Use sound function with inaudible 0 Hz but fixed delay to slow down animation\r
+SOUND 0, 1\r
+\r
+' Go back to the main loop\r
+GOTO 1\r
--- /dev/null
+' Texture mapping demonstration.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.04, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+DECLARE SUB Demo3 ()\r
+DECLARE SUB Demo2 ()\r
+DECLARE SUB Demo1 ()\r
+DECLARE SUB HLine (xCoord1!, yCoord!, xCoord2!, textureX1!, textureY1!, textureX2!, textureY2!)\r
+DECLARE SUB Polygon (xCoord1!, yCoord1!, xCoord2!, yCoord2!, xCoord3!, yCoord3!, textureX1!, textureY1!, textureX2!, textureY2!, textureX3!, textureY3!)\r
+DECLARE SUB PLine (xCoord1!, yCoord1!, xCoord2!, yCoord2!, textureX1!, textureY1!, textureX2!, textureY2!)\r
+DECLARE SUB Start ()\r
+\r
+DIM SHARED img(0 TO 100, 0 TO 100)\r
+DIM SHARED bufx(0 TO 199)\r
+DIM SHARED buftx(0 TO 199)\r
+DIM SHARED bufty(0 TO 199)\r
+\r
+Start\r
+Demo1\r
+Demo2\r
+Demo3\r
+SYSTEM\r
+\r
+SUB Demo1\r
+ ' Demonstrates texture mapping by drawing a polygon with predefined vertices and texture coordinates.\r
+ ' It waits for user input and then repeatedly draws polygons with random vertices and predefined texture coordinates.\r
+\r
+ ' Draw a polygon with predefined vertices and texture coordinates\r
+ Polygon 10, 10, 300, 80, 100, 180, 1, 1, 99, 1, 30, 99\r
+\r
+ ' Wait for user input\r
+ userInput$ = INPUT$(1)\r
+\r
+ ' Label to repeat the polygon drawing\r
+RepeatPolygonDrawing:\r
+ ' Generate random vertices for the polygon\r
+ vertexX1 = RND * 300 + 10\r
+ vertexX2 = RND * 300 + 10\r
+ vertexX3 = RND * 300 + 10\r
+ vertexY1 = RND * 180 + 10\r
+ vertexY2 = RND * 180 + 10\r
+ vertexY3 = RND * 180 + 10\r
+\r
+ ' Draw a polygon with random vertices and predefined texture coordinates\r
+ Polygon vertexX1, vertexY1, vertexX2, vertexY2, vertexX3, vertexY3, 1, 1, 99, 1, 30, 99\r
+\r
+ ' Repeat the process until a key is pressed\r
+ IF INKEY$ = "" THEN GOTO RepeatPolygonDrawing\r
+\r
+ ' Clear the screen\r
+ CLS\r
+END SUB\r
+\r
+SUB Demo2\r
+ ' Demonstrates texture mapping by drawing a polygon with vertices calculated using trigonometric functions.\r
+ ' It creates a rotating effect and repeatedly draws polygons with calculated vertices and predefined texture coordinates.\r
+\r
+ ' Initialize the angle variable\r
+ angle = 0\r
+\r
+ ' Label to repeat the polygon drawing\r
+RepeatRotatingPolygonDrawing:\r
+ ' Calculate the vertices of the polygon using trigonometric functions\r
+ vertexX1 = SIN(angle) * 80 + 160\r
+ vertexY1 = COS(angle) * 80 + 100\r
+ vertexX2 = SIN(angle + 2) * 80 + 160\r
+ vertexY2 = COS(angle + 2) * 80 + 100\r
+ vertexX3 = SIN(angle + 4) * 90 + 160\r
+ vertexY3 = COS(angle + 4) * 90 + 100\r
+\r
+ ' Draw a polygon with calculated vertices and predefined texture coordinates\r
+ Polygon vertexX1, vertexY1, vertexX2, vertexY2, vertexX3, vertexY3, 1, 1, 99, 1, 30, 99\r
+\r
+ ' Increment the angle variable\r
+ angle = angle + .1\r
+\r
+ SOUND 0, 0.5\r
+\r
+ ' Repeat the process until a key is pressed\r
+ IF INKEY$ = "" THEN GOTO RepeatRotatingPolygonDrawing\r
+\r
+ ' Clear the screen\r
+ CLS\r
+END SUB\r
+\r
+SUB Demo3\r
+ ' Demonstrates texture mapping by drawing a polygon with fixed vertices and rotating texture coordinates.\r
+ ' It creates a rotating effect for the texture while keeping the polygon location fixed on the screen.\r
+\r
+ ' Initialize the angle variable for texture rotation\r
+ textureAngle = 0\r
+\r
+ ' Label to repeat the polygon drawing with rotating texture coordinates\r
+RepeatTextureRotation:\r
+ ' Calculate the texture coordinates using trigonometric functions to create a rotating effect\r
+ textureX1 = SIN(textureAngle) * 40 + 50\r
+ textureY1 = COS(textureAngle) * 40 + 50\r
+ textureX2 = SIN(textureAngle + 2) * 40 + 50\r
+ textureY2 = COS(textureAngle + 2) * 40 + 50\r
+ textureX3 = SIN(textureAngle + 4) * 40 + 50\r
+ textureY3 = COS(textureAngle + 4) * 40 + 50\r
+\r
+ ' Draw a polygon with fixed vertices and rotating texture coordinates\r
+ Polygon 1, 50, 300, 1, 100, 180, textureX1, textureY1, textureX2, textureY2, textureX3, textureY3\r
+\r
+ ' Increment the texture angle variable\r
+ textureAngle = textureAngle + .1\r
+\r
+ SOUND 0, 0.5\r
+\r
+ ' Repeat the process until a key is pressed\r
+ IF INKEY$ = "" THEN GOTO RepeatTextureRotation\r
+\r
+ ' Clear the screen\r
+ CLS\r
+END SUB\r
+\r
+SUB HLine (xCoord1, yCoord, xCoord2, textureX1, textureY1, textureX2, textureY2)\r
+ ' Draws a horizontal line with texture mapping between two points.\r
+ ' It calculates texture coordinates for each pixel along the line and sets the pixel color accordingly.\r
+\r
+ ' Exit if the horizontal line has zero length\r
+ IF INT(xCoord2) = INT(xCoord1) THEN GOTO ExitHLine\r
+\r
+ ' Determine the direction and initialize variables\r
+ IF xCoord2 > xCoord1 THEN\r
+ normalizedX1 = INT(xCoord1)\r
+ normalizedX2 = INT(xCoord2)\r
+ normalizedTextureX1 = textureX1\r
+ normalizedTextureY1 = textureY1\r
+ normalizedTextureX2 = textureX2\r
+ normalizedTextureY2 = textureY2\r
+ ELSE\r
+ normalizedX1 = INT(xCoord2)\r
+ normalizedX2 = INT(xCoord1)\r
+ normalizedTextureX1 = textureX2\r
+ normalizedTextureY1 = textureY2\r
+ normalizedTextureX2 = textureX1\r
+ normalizedTextureY2 = textureY1\r
+ END IF\r
+\r
+ ' Calculate the line parameters\r
+ horizontalLength = normalizedX2 - normalizedX1\r
+ textureDeltaX = normalizedTextureX2 - normalizedTextureX1\r
+ textureDeltaY = normalizedTextureY2 - normalizedTextureY1\r
+\r
+ FOR pixelOffset = 0 TO horizontalLength\r
+ ' Calculate the texture coordinates for the current pixel\r
+ currentTextureX = textureDeltaX * pixelOffset / horizontalLength + normalizedTextureX1\r
+ currentTextureY = textureDeltaY * pixelOffset / horizontalLength + normalizedTextureY1\r
+\r
+ ' Set the pixel color using texture coordinates\r
+ PSET (pixelOffset + normalizedX1, yCoord), img(currentTextureX, currentTextureY)\r
+ NEXT pixelOffset\r
+\r
+ExitHLine:\r
+END SUB\r
+\r
+SUB PLine (xCoord1, yCoord1, xCoord2, yCoord2, textureX1, textureY1, textureX2, textureY2)\r
+ ' Draws a line with texture mapping between two points.\r
+ ' It calculates intermediate points along the line and uses the HLine subroutine to draw horizontal segments.\r
+\r
+ ' Calculate the number of vertical steps\r
+ verticalSteps = ABS(yCoord2 - yCoord1)\r
+ IF verticalSteps = 0 THEN GOTO ExitPLine\r
+\r
+ ' Calculate the differences in coordinates and texture coordinates\r
+ deltaY = yCoord2 - yCoord1\r
+ deltaX = xCoord2 - xCoord1\r
+ deltaTextureY = textureY2 - textureY1\r
+ deltaTextureX = textureX2 - textureX1\r
+\r
+ ' Loop through each vertical step\r
+ FOR stepCounter = 0 TO verticalSteps\r
+ ' Calculate the intermediate coordinates and texture coordinates\r
+ intermediateX = deltaX * stepCounter / verticalSteps + xCoord1\r
+ intermediateY = deltaY * stepCounter / verticalSteps + yCoord1\r
+ intermediateTextureX = deltaTextureX * stepCounter / verticalSteps + textureX1\r
+ intermediateTextureY = deltaTextureY * stepCounter / verticalSteps + textureY1\r
+\r
+ ' Check if the buffer is empty for this row\r
+ IF bufx(intermediateY) = -1 THEN\r
+ ' Store the intermediate coordinates and texture coordinates in the buffer\r
+ bufx(intermediateY) = intermediateX\r
+ buftx(intermediateY) = intermediateTextureX\r
+ bufty(intermediateY) = intermediateTextureY\r
+ ELSE\r
+ ' Draw a horizontal line using the stored and current intermediate coordinates and texture coordinates\r
+ HLine bufx(intermediateY), intermediateY, intermediateX, buftx(intermediateY), bufty(intermediateY), intermediateTextureX, intermediateTextureY\r
+ END IF\r
+ NEXT stepCounter\r
+\r
+ExitPLine:\r
+END SUB\r
+\r
+SUB Polygon (xCoord1, yCoord1, xCoord2, yCoord2, xCoord3, yCoord3, textureX1, textureY1, textureX2, textureY2, textureX3, textureY3)\r
+ ' Fills a triangular area by connecting the edges with texture mapping.\r
+ ' It uses the PLine subroutine to draw lines connecting the vertices of the polygon.\r
+\r
+ ' Initialize the buffer\r
+ FOR bufferIndex = 0 TO 199\r
+ bufx(bufferIndex) = -1\r
+ NEXT bufferIndex\r
+\r
+ ' Draw three lines connecting the vertices of the polygon\r
+ PLine xCoord1, yCoord1, xCoord2, yCoord2, textureX1, textureY1, textureX2, textureY2\r
+ PLine xCoord1, yCoord1, xCoord3, yCoord3, textureX1, textureY1, textureX3, textureY3\r
+ PLine xCoord3, yCoord3, xCoord2, yCoord2, textureX3, textureY3, textureX2, textureY2\r
+END SUB\r
+\r
+SUB Start\r
+ ' Set the screen mode to 320x200 with 256 colors\r
+ SCREEN 13\r
+\r
+ ' Prepare sample texture to be used later for textured polygons demonstration:\r
+\r
+ ' Draw random circles on the screen\r
+ FOR circleCounter = 1 TO 100\r
+ ' Generate random coordinates and color for each circle\r
+ xCoord = RND * 150\r
+ yCoord = RND * 150\r
+ circleColor = RND * 255\r
+\r
+ ' Draw a circle with random radius and fill it with the same color\r
+ CIRCLE (xCoord, yCoord), RND * 20 + 3, circleColor\r
+ PAINT (xCoord, yCoord), circleColor\r
+ NEXT circleCounter\r
+\r
+ ' Display "Test!" on the screen\r
+ LOCATE 8, 8\r
+ PRINT "Test!"\r
+\r
+ ' Wait for user input\r
+ userInput$ = INPUT$(1)\r
+\r
+ ' Copy the screen content to the image array and clear the screen\r
+ FOR yPixel = 0 TO 100\r
+ FOR xPixel = 0 TO 100\r
+ ' Copy the color of each pixel to the image array\r
+ img(xPixel, yPixel) = POINT(xPixel + 20, yPixel + 20)\r
+ ' Clear the pixel on the screen\r
+ PSET (xPixel + 20, yPixel + 20), 0\r
+ NEXT xPixel\r
+ NEXT yPixel\r
+ CLS\r
+END SUB\r
--- /dev/null
+' Program to render polygons at random locations and random colors.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+\r
+' Changelog:\r
+' 2001, Initial version\r
+' 2024, Improved program readability\r
+\r
+DEFINT A-Z\r
+DECLARE SUB fillPolygon (x1, y1, x2, y2, x3, y3, c)\r
+SCREEN 13\r
+\r
+MainLoop:\r
+ ' Generate random coordinates for the first vertex\r
+ x1 = RND * 318 + 1\r
+ y1 = RND * 198 + 1\r
+\r
+ ' Generate random coordinates for the second vertex\r
+ x2 = RND * 318 + 1\r
+ y2 = RND * 198 + 1\r
+\r
+ ' Generate random coordinates for the third vertex\r
+ x3 = RND * 318 + 1\r
+ y3 = RND * 198 + 1\r
+\r
+ ' Fill the polygon with a random color\r
+ fillPolygon x1, y1, x2, y2, x3, y3, RND * 255\r
+\r
+ ' Add delay\r
+ SOUND 0, 1\r
+\r
+ ' Check if any key is pressed to exit the loop\r
+ IF INKEY$ <> "" THEN SYSTEM\r
+GOTO MainLoop\r
+\r
+SUB fillPolygon (x1, y1, x2, y2, x3, y3, c)\r
+ ' Buffer array to store x-coordinates for each y-index\r
+ DIM yBuffer(-10 TO 210)\r
+\r
+ ' Draw the line between the first and second vertices\r
+ tempX1 = x1\r
+ tempY1 = y1\r
+ tempX2 = x2\r
+ tempY2 = y2\r
+ GOSUB makeLine\r
+\r
+ ' Draw the line between the first and third vertices\r
+ tempX1 = x1\r
+ tempY1 = y1\r
+ tempX2 = x3\r
+ tempY2 = y3\r
+ GOSUB makeLine\r
+\r
+ ' Draw the line between the second and third vertices\r
+ tempX1 = x3\r
+ tempY1 = y3\r
+ tempX2 = x2\r
+ tempY2 = y2\r
+ GOSUB makeLine\r
+\r
+GOTO FillEnd\r
+\r
+makeLine:\r
+ ' Ensure that the start point is always below the end point\r
+ IF tempY2 < tempY1 THEN SWAP tempY1, tempY2: SWAP tempX1, tempX2\r
+\r
+ ' Loop through each y-index from the start to the end\r
+ FOR yIndex = tempY1 TO tempY2 - 1\r
+ ' Calculate the x-position for the current y-index\r
+ xPos = tempX1 + (tempX2 - tempX1) * ((yIndex - tempY1) / (tempY2 - tempY1))\r
+\r
+ ' If the buffer is empty, store the x-position\r
+ IF yBuffer(yIndex) = 0 THEN\r
+ yBuffer(yIndex) = xPos\r
+ ELSE\r
+ ' Otherwise, draw a line between the stored and calculated positions\r
+ LINE (xPos, yIndex)-(yBuffer(yIndex), yIndex), c\r
+ END IF\r
+ NEXT yIndex\r
+RETURN\r
+\r
+FillEnd:\r
+END SUB\r
+\r
--- /dev/null
+' Screensaver\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.04, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+\r
+SCREEN 7, , , 1\r
+\r
+' Main animation loop\r
+1 :\r
+ ' Adjust frame counter if it exceeds a certain threshold\r
+ IF frameCounter > 10000 THEN frameCounter = -10000\r
+\r
+ ' Update the positions of six points based on the frame counter\r
+ FOR pointIndex = 1 TO 6\r
+ OUT &H3C8, pointIndex\r
+ OUT &H3C9, SIN(pointIndex + frameCounter * 3) * 30 + 31\r
+ OUT &H3C9, COS(pointIndex * 1 + frameCounter * 5) * 30 + 31\r
+ OUT &H3C9, SIN(pointIndex * .7 + frameCounter * 2.23) * 30 + 31\r
+ NEXT pointIndex\r
+\r
+ ' Increment the frame counter for the next iteration\r
+ frameCounter = frameCounter + .01\r
+\r
+ ' Render lines connecting points\r
+ FOR objectIndex = 1 TO 10\r
+ ' Determine the color based on the remainder of objectIndex divided by 6\r
+ pointColor = (objectIndex MOD 6) + 1\r
+ ' Calculate the X coordinate for the starting point of the line\r
+ xCoordinate = SIN(objectIndex + frameCounter) * 100 + 150\r
+ ' Calculate the Y coordinate for the starting point of the line\r
+ yCoordinate = COS(objectIndex * 1.2 + frameCounter * 1.81) * 80 + 100\r
+ ' Calculate the sine component for the line's angle\r
+ xSineComponent = SIN(objectIndex * frameCounter * 2.3)\r
+ ' Draw lines from the starting point with varying lengths and angles\r
+ FOR xPositionOffset = -50 TO 50 STEP 10\r
+ ' Calculate the cosine component for the line's angle based on xPositionOffset\r
+ yCosineComponent = COS(xPositionOffset / 60 + frameCounter * 1 + objectIndex) * 50\r
+ ' Draw a line segment with varying thickness and color\r
+ LINE (xCoordinate, yCoordinate)-(xCoordinate + xPositionOffset * xSineComponent, yCoordinate - yCosineComponent), pointColor\r
+ NEXT xPositionOffset\r
+ NEXT objectIndex\r
+\r
+ ' Copy the graphics from the hidden page to the visible page\r
+ PCOPY 0, 1\r
+\r
+ ' Clear the screen for the next frame\r
+ CLS\r
+\r
+ ' Play a sound at a specific frequency and duration\r
+ SOUND 0, .4\r
+\r
+ ' Check if any key is pressed; if so, exit the program\r
+ IF INKEY$ <> "" THEN SYSTEM\r
+\r
+ ' Loop back to the start of the animation\r
+GOTO 1\r
+\r
--- /dev/null
+' Mystery screensaver\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2004.01, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+SCREEN 7, , , 1\r
+\r
+' Main loop for animation\r
+DO\r
+ ' Increment frame counter\r
+ frameCounter = frameCounter + 1\r
+\r
+ ' Calculate scaling factor based on frame counter\r
+ scaleFactor = (SIN(frameCounter / 100) + 1.1) * 2\r
+\r
+ ' Draw lines to create animation effect\r
+ FOR s = 1 TO 20 STEP .1\r
+ ' Calculate x and y coordinates for the first point\r
+ x = SIN(s / 1 + frameCounter / 7) * 100\r
+ y = COS(s / 1 + frameCounter / 10) * 100\r
+\r
+ ' Calculate x and y coordinates for the second point\r
+ x1 = SIN(s / 1 - frameCounter / 8) * 100\r
+ y1 = COS(s / 1 + frameCounter / 15) * 100\r
+\r
+ ' Draw a line between the two points with varying thickness\r
+ LINE (x + 160, y + 100)-(x1 + 160, y1 + 100), s MOD 15\r
+ NEXT s\r
+\r
+ ' Copy screen buffer to display the animation\r
+ PCOPY 0, 1\r
+\r
+ ' Generate a sound effect\r
+ SOUND 0, 1\r
+\r
+ ' Clear the screen for the next frame\r
+ CLS\r
+\r
+ ' Check if a key is pressed and exit if so\r
+ IF INKEY$ <> "" THEN SYSTEM\r
+LOOP\r
--- /dev/null
+' Svjatoslav Agejenko 2003.04\r
+\r
+DEFINT A-Z\r
+DECLARE SUB fall (particleIndex)\r
+DECLARE SUB start ()\r
+\r
+amo = 500\r
+\r
+DIM SHARED fx(1 TO amo)\r
+DIM SHARED fy(1 TO amo)\r
+\r
+' Initialize particle positions\r
+FOR a = 1 TO amo\r
+ fx(a) = RND * 300 + 10\r
+ fy(a) = RND * 100 + 10\r
+NEXT a\r
+\r
+start\r
+\r
+1\r
+' Main loop to simulate snowfall\r
+FOR b = 1 TO 100\r
+ a = INT(RND * amo) + 1\r
+ fall a\r
+NEXT b\r
+SOUND 0, .1\r
+IF INKEY$ <> "" THEN SYSTEM\r
+GOTO 1\r
+\r
+SUB fall (particleIndex)\r
+\r
+t = 0\r
+2\r
+' Draw the particle at its current position\r
+PSET (fx(particleIndex), fy(particleIndex)), 0\r
+\r
+ny = fy(particleIndex) + 1\r
+nx = fx(particleIndex) + INT(RND * 3) - 1\r
+\r
+' Check for collision with another particle\r
+IF POINT(nx, ny) > 0 THEN\r
+ ' If collision detected and t is less than 10, increment t and retry\r
+ IF t < 10 THEN\r
+ t = t + 1\r
+ GOTO 2\r
+ END IF\r
+ ' If collision persists, change particle color to indicate collision\r
+ PSET (fx(particleIndex), fy(particleIndex)), 15\r
+ nx = RND * 300 + 10\r
+ ny = 1\r
+END IF\r
+\r
+' Check if the particle has reached the bottom of the screen\r
+IF fy(particleIndex) > 198 THEN\r
+ PSET (fx(particleIndex), fy(particleIndex)), 15\r
+ nx = RND * 300 + 10\r
+ ny = 1\r
+END IF\r
+\r
+' Update particle position\r
+fx(particleIndex) = nx\r
+fy(particleIndex) = ny\r
+\r
+' Draw the particle at its new position\r
+PSET (fx(particleIndex), fy(particleIndex)), 15\r
+\r
+END SUB\r
+\r
+DEFSNG A-Z\r
+SUB start\r
+SCREEN 13\r
+\r
+' Create nice and curvy surface for snow particles to fall onto.\r
+' Here we draw "SNOW" with big and wobbly letters to the screen\r
+' to serve as an obstacle for snow particles.\r
+\r
+LOCATE 1, 1\r
+PRINT "SNOW"\r
+\r
+FOR y = 0 TO 15 STEP .2\r
+ xp = SIN(y / 1) * 3 + 65\r
+ FOR x = 0 TO 30 STEP .1\r
+ ys = 4 + COS(x / 5)\r
+ yp = COS(x / 4 + 3) * 5 + 130\r
+ c = POINT(x, y)\r
+ ' Draw a line if the point is not black\r
+ IF c > 0 THEN\r
+ LINE (x * 6 + xp, y * ys + yp)-(x * 6 + xp + 1, y * ys + yp + 1), 11, BF\r
+ END IF\r
+ NEXT x\r
+NEXT y\r
+\r
+LOCATE 1, 1\r
+PRINT " "\r
+\r
+END SUB\r
--- /dev/null
+DECLARE SUB setPalette ()\r
+' Render tree that starts with single root and then branches out.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2001, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+\r
+DECLARE SUB start ()\r
+DECLARE SUB show (d%)\r
+DECLARE SUB setpal ()\r
+DECLARE SUB showpal ()\r
+DEFINT A-Y\r
+\r
+DIM SHARED x(1 TO 500)\r
+DIM SHARED y(1 TO 500)\r
+DIM SHARED s(1 TO 500)\r
+\r
+DIM SHARED x4(1 TO 500)\r
+DIM SHARED y4(1 TO 500)\r
+\r
+DIM SHARED z(1 TO 500)\r
+DIM SHARED mitu\r
+\r
+\r
+start\r
+\r
+1\r
+mitu = 1\r
+\r
+x4(1) = -1\r
+y4(1) = -1\r
+x(1) = 420\r
+y(1) = 340\r
+s(1) = 70 * 100\r
+z(1) = 1\r
+\r
+' Main loop to render the tree branches\r
+FOR tr = 1 TO 6\r
+ FOR b = 1 TO 50\r
+ FOR a = 1 TO mitu\r
+ show a\r
+ NEXT a\r
+ NEXT b\r
+\r
+ ' Duplicate existing branches and add randomness\r
+ FOR a = 1 TO mitu\r
+ x(mitu + a) = x(a)\r
+ y(mitu + a) = y(a)\r
+ s(mitu + a) = s(a)\r
+ z(mitu + a) = z(a)\r
+ x4(mitu + a) = RND * 4 - 2\r
+ y4(mitu + a) = RND * 4 - 2\r
+ NEXT a\r
+ mitu = mitu * 2\r
+\r
+NEXT tr\r
+\r
+' Exit application if any key was pressed by user\r
+IF INKEY$ <> "" THEN SYSTEM\r
+\r
+\r
+SLEEP 2\r
+CLS\r
+GOTO 1\r
+\r
+SUB setPalette\r
+ ' Set the palette colors to grayscale\r
+ FOR a = 0 TO 16\r
+ OUT &H3C8, a\r
+ OUT &H3C9, a * 4\r
+ OUT &H3C9, a * 4\r
+ OUT &H3C9, a * 4\r
+ NEXT\r
+END SUB\r
+\r
+SUB show (d)\r
+ ' Retrieve current branch properties\r
+ x1 = x(d)\r
+ y1 = y(d)\r
+ s1 = s(d)\r
+ z1 = z(d)\r
+\r
+ ' Calculate color based on angle\r
+ c = SIN(z1) * 7 + 9\r
+\r
+ ' Draw and fill the circle representing the branch\r
+ CIRCLE (x1, y1), s1 / 100, c\r
+ PAINT (x1, y1), c\r
+\r
+ ' Update position based on current angle and size\r
+ x(d) = x(d) + (SIN(z1) * 1000) / (s1 + 15)\r
+ y(d) = y(d) + (COS(z1) * 1000) / (s1 + 15)\r
+\r
+ ' Decay the size slightly\r
+ s(d) = s(d) / 1.01\r
+\r
+ ' Update angle based on direction\r
+ IF x4(d) >= 0 THEN z(d) = z(d) + .1 ELSE z(d) = z(d) - .1\r
+\r
+ ' Move branch in its random direction\r
+ x(d) = x(d) + x4(d)\r
+ y(d) = y(d) + y4(d)\r
+END SUB\r
+\r
+SUB start\r
+ SCREEN 12\r
+ setPalette\r
+ RANDOMIZE TIMER\r
+END SUB\r
+\r
--- /dev/null
+' Yin and yang animation.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2000, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+DECLARE SUB Cir (x!, y!, r!, c!)\r
+SCREEN 13\r
+pi = 3.141592599999999#\r
+PAINT (1, 1), 1\r
+\r
+' Main animation loop\r
+DO\r
+ ' Calculate the x and y positions for both circles using sine and cosine functions\r
+ x = SIN(a) * 40 + 160\r
+ x1 = SIN(a + pi) * 40 + 160\r
+ y = COS(a) * 34 + 100\r
+ y1 = COS(a + pi) * 34 + 100\r
+\r
+ ' Draw the first circle with color 0 (black)\r
+ Cir x, y, 40, 0\r
+ ' Draw the second circle with color 1 (blue)\r
+ Cir x1, y1, 40, 1\r
+\r
+ ' Increment the angle to animate the circles\r
+ a = a + .05\r
+\r
+ ' Check for user input to exit the program\r
+ IF INKEY$ <> "" THEN SYSTEM\r
+\r
+ ' delay to slow down animation\r
+ SOUND 0, 1\r
+LOOP\r
+\r
+' Subroutine to draw a circle with specified center (x, y), radius r, and color c\r
+SUB Cir (x, y, r, c)\r
+ ' Define colors for the circle outline\r
+ cc1 = 0 ' Black\r
+ cc2 = 15 ' White\r
+\r
+ ' Swap colors if the second color is desired for the inner part of the circle\r
+ IF c = 1 THEN SWAP cc1, cc2\r
+\r
+ ' Draw the circle from radius 1 to r\r
+ FOR a = 1 TO r\r
+ ' Determine the color for the current circle segment\r
+ IF a < r / 2 THEN c1 = cc1 ELSE c1 = cc2\r
+ ' Draw the circle segment with the determined color\r
+ CIRCLE (x, y), a, c1\r
+ NEXT a\r
+END SUB\r
+\r
--- /dev/null
+' Program generates fractal animation that looks like atoms.
+' While it uses a simple formula to calculate the color of every pixel,
+' visual effect is quite impressive. Formula was accidentally discovered.
+'
+' This program is free software: released under Creative Commons Zero (CC0) license
+' by Svjatoslav Agejenko.
+' Email: svjatoslav@svjatoslav.eu
+' Homepage: http://www.svjatoslav.eu
+
+' Changelog:
+' 2002, Original version
+' 2024 - 2025, Improved program readability
+
+SCREEN 13
+DIM SHARED pixelByte AS STRING * 1
+
+zoomFactor = 100
+frameNumber = 0
+fileNameChar1 = 97
+fileNameChar2 = 97
+
+1
+SOUND 0, 4.5
+
+frameNumber = frameNumber + 1
+
+' Calculate transformed screen dimensions based on current zoom level
+transformedScreenWidth = 320 * zoomFactor / 30
+transformedScreenHeight = 200 * zoomFactor / 30
+
+' Calculate starting coordinates to center the fractal pattern
+startCoordinateX = 160 - (transformedScreenWidth / 2)
+startCoordinateY = 100 - (transformedScreenHeight / 2)
+
+' CLS
+
+' Generate fractal pattern pixel by pixel
+FOR currentY = 0 TO 199
+ FOR currentX = 0 TO 319
+ ' Calculate new coordinates with current zoom level
+ newX = startCoordinateX + (transformedScreenWidth * currentX / 320)
+ newY = startCoordinateY + (transformedScreenHeight * currentY / 200)
+
+ ' Calculate color value using fractal formula
+ ' Formula: sin((x² + y²) / 10) * 6 + 23
+ colorValue = SIN((newX ^ 2 + newY ^ 2) / 10) * 6 + 23
+
+ ' Clamp color values to valid range (16-31)
+ IF colorValue < 16 THEN colorValue = 16
+ IF colorValue > 31 THEN colorValue = 31
+ PSET (currentX, currentY), colorValue
+ NEXT currentX
+NEXT currentY
+
+
+' Decrease zoom factor for next frame to create zooming effect
+zoomFactor = zoomFactor / 1.1
+
+' Continue generating frames while zoom factor is above minimum threshold
+IF zoomFactor > 5 THEN GOTO 1
--- /dev/null
+' Program to render animation inspired by Matrix movie.\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.04, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+\r
+DECLARE FUNCTION getCharacter% ()\r
+DECLARE SUB makeSound ()\r
+DEFINT A-Z\r
+DECLARE SUB displayScreen ()\r
+DECLARE SUB showPalette ()\r
+DECLARE SUB initializeGame ()\r
+\r
+DIM SHARED screenBuffer(1 TO 40, 1 TO 25) AS INTEGER\r
+DIM SHARED colorBuffer(1 TO 40, 1 TO 25) AS INTEGER\r
+DIM SHARED soundArray(1 TO 20)\r
+DIM SHARED soundPointer\r
+\r
+initializeGame\r
+'showPalette()\r
+\r
+' Initialize the screen buffer with random characters\r
+FOR row = 1 TO 25\r
+ FOR col = 1 TO 40\r
+ screenBuffer(col, row) = getCharacter\r
+ NEXT col\r
+NEXT row\r
+\r
+' Initialize the color buffer with a default color\r
+FOR row = 1 TO 25\r
+ FOR col = 1 TO 40\r
+ colorBuffer(col, row) = 1\r
+ NEXT col\r
+NEXT row\r
+\r
+actionCounter = 0\r
+\r
+10 ' Main game loop\r
+makeSound\r
+frameCounter = frameCounter + 1\r
+IF frameCounter > 10000 THEN frameCounter = 1\r
+\r
+' Shift the screen buffer contents down by one row\r
+FOR row = 25 TO 2 STEP -1\r
+ FOR col = 1 TO 40\r
+ screenBuffer(col, row) = screenBuffer(col, row - 1)\r
+ NEXT col\r
+NEXT row\r
+makeSound\r
+\r
+' Move the top row to the bottom\r
+FOR col = 1 TO 40\r
+ screenBuffer(col, 1) = screenBuffer(col, 25)\r
+NEXT col\r
+\r
+' Randomly change a character in the buffer\r
+screenBuffer(INT(RND * 39 + 1), INT(RND * 10 + 1)) = getCharacter\r
+actionCounter = actionCounter + 1\r
+displayScreen\r
+\r
+SELECT CASE actionCounter\r
+CASE 1\r
+ ' Initialize sound array with random values\r
+ FOR a = 1 TO 20\r
+ soundArray(a) = 0\r
+ IF RND * 100 < 2 THEN soundArray(a) = INT(RND * 4000 + 4000)\r
+ NEXT a\r
+ ' Set sound frequencies based on sine wave\r
+ b = SIN(frameCounter / 100) * 3 + 6\r
+ FOR a = 1 TO 20 STEP b\r
+ soundArray(a) = 10000\r
+ NEXT a\r
+\r
+CASE 2\r
+ ' Draw a horizontal line with random color\r
+ c = INT(RND * 5)\r
+ x1 = INT(RND * 38 + 1)\r
+ y = INT(RND * 23 + 1)\r
+ x2 = INT(RND * 38 + 1)\r
+ IF x1 > x2 THEN SWAP x1, x2\r
+ FOR x = x1 TO x2\r
+ colorBuffer(x, y) = c\r
+ NEXT x\r
+\r
+CASE 3\r
+ ' Draw a vertical line with random color\r
+ c = INT(RND * 5)\r
+ y1 = INT(RND * 23 + 1)\r
+ x = INT(RND * 38 + 1)\r
+ y2 = INT(RND * 23 + 1)\r
+ IF y1 > y2 THEN SWAP y1, y2\r
+ FOR y = y1 TO y2\r
+ colorBuffer(x, y) = c\r
+ NEXT y\r
+\r
+CASE 4\r
+ ' Decrease the intensity of colors on the screen\r
+ IF RND * 100 < 20 THEN\r
+ FOR y = 1 TO 25\r
+ FOR x = 1 TO 40\r
+ IF colorBuffer(x, y) > 1 THEN colorBuffer(x, y) = colorBuffer(x, y) - 1\r
+ NEXT x\r
+ NEXT y\r
+ END IF\r
+\r
+CASE 5\r
+ ' Reset every second row to default color\r
+ IF RND * 100 < 5 THEN\r
+ FOR y = 1 TO 25 STEP 2\r
+ FOR x = 1 TO 40\r
+ colorBuffer(x, y) = 1\r
+ NEXT x\r
+ NEXT y\r
+ END IF\r
+\r
+CASE 6\r
+ ' Reset every second column to default color\r
+ IF RND * 100 < 5 THEN\r
+ FOR x = 1 TO 40 STEP 2\r
+ FOR y = 1 TO 25\r
+ colorBuffer(x, y) = 1\r
+ NEXT y\r
+ NEXT x\r
+ END IF\r
+\r
+CASE 7\r
+ ' Randomly set some characters to random colors\r
+ FOR a = 1 TO 30\r
+ colorBuffer(INT(RND * 39 + 1), INT(RND * 23 + 1)) = INT(RND * 4 + 1)\r
+ NEXT a\r
+\r
+CASE 8\r
+ ' Check for user input to exit the game\r
+ IF INKEY$ <> "" THEN SYSTEM\r
+ actionCounter = 0\r
+END SELECT\r
+\r
+GOTO 10\r
+\r
+SYSTEM:\r
+' Exit the game\r
+END\r
+\r
+SUB displayScreen\r
+\r
+makeSound\r
+LOCATE 1, 1\r
+\r
+' Display the top half of the screen\r
+FOR y = 1 TO 10\r
+ FOR x = 1 TO 40\r
+ COLOR colorBuffer(x, y), 0\r
+ PRINT CHR$(screenBuffer(x, y));\r
+ NEXT x\r
+NEXT y\r
+\r
+makeSound\r
+' Display the middle part of the screen\r
+FOR y = 11 TO 20\r
+ FOR x = 1 TO 40\r
+ COLOR colorBuffer(x, y), 0\r
+ PRINT CHR$(screenBuffer(x, y));\r
+ NEXT x\r
+NEXT y\r
+\r
+makeSound\r
+' Display the bottom half of the screen\r
+FOR y = 21 TO 25\r
+ FOR x = 1 TO 40\r
+ COLOR colorBuffer(x, y), 0\r
+ PRINT CHR$(screenBuffer(x, y));\r
+ NEXT x\r
+NEXT y\r
+\r
+makeSound\r
+\r
+END SUB\r
+\r
+FUNCTION getCharacter\r
+' Generate a random character based on probability\r
+IF RND * 100 > 50 THEN\r
+ getCharacter = INT(RND * 9 + 48)\r
+ELSE\r
+ getCharacter = INT(RND * 25 + 65)\r
+END IF\r
+IF RND * 100 < 15 THEN getCharacter = 32 ' 15% chance to return a space\r
+END FUNCTION\r
+\r
+SUB initializeGame\r
+\r
+RANDOMIZE TIMER ' Seed the random number generator\r
+CLS ' Clear the screen\r
+WIDTH 40, 25 ' Set screen dimensions\r
+VIEW PRINT 1 TO 25 ' Set the print area\r
+\r
+' Initialize palette registers for color text mode\r
+OUT &H3C8, 0\r
+OUT &H3C9, 0\r
+OUT &H3C9, 0\r
+OUT &H3C9, 0\r
+\r
+' Set up color palettes\r
+FOR a = 1 TO 5\r
+ OUT &H3C8, a\r
+\r
+ b = a * 5\r
+ g = a * 10 + 20\r
+ r = a * 0\r
+\r
+ ' Ensure RGB values do not exceed the maximum value\r
+ IF r > 63 THEN r = 63\r
+ IF g > 63 THEN g = 63\r
+ IF b > 63 THEN b = 63\r
+ OUT &H3C9, r\r
+ OUT &H3C9, g\r
+ OUT &H3C9, b\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB makeSound\r
+' Update the sound pointer and play a sound\r
+soundPointer = soundPointer + 1\r
+IF soundPointer > 20 THEN soundPointer = 1\r
+SOUND soundArray(soundPointer), .07\r
+' SOUND 0, .07 ' Uncomment to play a continuous tone\r
+END SUB\r
+\r
+SUB showPalette\r
+\r
+' Display a palette test on the screen\r
+FOR a = 0 TO 15\r
+ COLOR a\r
+ PRINT a; " Palette test"\r
+NEXT a\r
+a$ = INPUT$(1) ' Wait for user input\r
+\r
+END SUB\r
+\r
--- /dev/null
+#+TITLE: Graphics demos
+#+LANGUAGE: en
+#+LATEX_HEADER: \usepackage[margin=1.0in]{geometry}
+#+LATEX_HEADER: \usepackage{parskip}
+#+LATEX_HEADER: \usepackage[none]{hyphenat}
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+ .flex-center {
+ display: flex; /* activate flexbox */
+ justify-content: center; /* horizontally center anything inside */
+ }
+
+ .flex-center video {
+ width: min(90%, 1000px); /* whichever is smaller wins */
+ height: auto; /* preserve aspect ratio */
+ }
+
+ .responsive-img {
+ width: min(100%, 1000px);
+ height: auto;
+ }
+</style>
+#+end_export
+
+
+* Bump mapping
+
+This QBasic program demonstrates a classic bump mapping technique,
+creating an animation where a light source moves around a textured
+surface. The program visually simulates how different parts of the
+surface become illuminated based on the light source's position. This
+effect is commonly used in computer graphics to add depth and realism
+to surfaces without increasing geometric complexity.
+
+#+begin_export html
+<div class="flex-center">
+ <video width="300" controls loop autoplay>
+ <source src="Bump mapping.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+How It Works:
+
+1. *Surface Generation* : The program starts by generating a height
+ map for the surface using random dots and lines. This height map
+ defines the texture and contours of the surface.
+2. *Light Animation* : A light source is animated to move around the
+ surface using sine functions, creating a smooth, circular motion.
+3. *Brightness Calculation* : For each pixel on the surface, the
+ program calculates the brightness based on the distance and angle
+ from the light source. This involves determining the surface
+ inclination relative to the light position.
+4. *Rendering* : The surface is rendered with varying brightness
+ levels to simulate the effect of the moving light source. The light
+ source itself is drawn as a small circle that moves across the
+ surface.
+
+[[file:Bump mapping.bas][Source code]]
+
+* Tree
+
+This QBasic program renders a fractal tree that starts with a single
+root and branches out into a complex pattern. The program is an
+artistic representation of how simple rules can generate intricate and
+beautiful structures, reminiscent of natural tree growth patterns.
+
+#+begin_export html
+<div class="flex-center">
+ <video width="1000" controls loop autoplay>
+ <source src="Tree.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:Tree.bas][Source code]]
+
+#+INCLUDE: "Tree.bas" src basic-qb45
+
+* Rotation in 2D space using trigonometry functions
+
+This QBasic program demonstrates the rotation of points in a 2D
+coordinate system using trigonometric functions. It simulates the
+rotation of a grid of points around the origin, providing a visual
+representation of how sine and cosine functions can be used to achieve
+2D rotation.
+
+#+begin_export html
+<div class="flex-center">
+ <video width="1000" controls loop autoplay>
+ <source src="2D rotation.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:2D rotation.bas][Source code]]
+
+#+INCLUDE: "2D rotation.bas" src basic-qb45
+
+* Various text mode animation effects
+
+This QBasic program creates visually appealing text mode animations by
+overlaying various graphical effects while scrolling its own source
+code in the background. It is an example of how to manipulate text and
+colors to create dynamic visual effects in a console environment.
+
+#+begin_export html
+<div class="flex-center">
+ <video width="1000" controls loop autoplay>
+ <source src="text mode animation.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+ #+end_export
+
+[[file:text mode animation.bas][Source code]]
+
+* Snowfall
+
+This QBasic program simulates a simple snowfall effect on the
+screen. It creates a visually appealing animation where particles
+(representing snowflakes) fall from the top of the screen to the
+bottom, interacting with obstacles and each other. The program is a
+example of basic animation and collision detection techniques, which
+can be educational for those interested in learning about simple
+physics simulations and graphical programming.
+
+#+begin_export html
+<div class="flex-center">
+ <video width="1000" controls loop autoplay>
+ <source src="Snowfall.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+
+What's in it for the Reader?
+
+- Learning Basic Animation :: This program provides a straightforward
+ example of how to animate objects on the screen, which can be a
+ foundational concept for game development and graphical
+ applications.
+- Collision Detection :: The code includes basic collision detection
+ logic, which is essential for interactive applications and games.
+- Randomization :: The use of randomness in particle movement and
+ positioning can teach how unpredictability can be introduced into
+ simulations.
+- Graphics Handling :: The program demonstrates how to manipulate
+ screen pixels and draw shapes, which is useful for understanding
+ low-level graphics programming.
+
+[[file:Snowfall.bas][Source code]]
+
+#+INCLUDE: "Snowfall.bas" src basic-qb45
+
+* Screensaver
+
+The "Mystery Screensaver" is a visually captivating animation program
+written in QBasic. It creates an intriguing screensaver effect with
+dynamic, flowing lines that continuously change patterns, providing a
+mesmerizing visual experience. This program is an example of how
+simple mathematical functions can be used to create complex and
+engaging visual effects.
+
+#+begin_export html
+<div class="flex-center">
+ <video width="1000" controls loop autoplay>
+ <source src="Screensaver.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:Screensaver.bas][Source code]]
+
+#+INCLUDE: "Screensaver.bas" src basic-qb45
+
+* Screensaver - flying hand fans
+
+This QBasic program is a visually engaging screensaver that creates an
+animated display of colorful lines and patterns. The program is
+designed to produce a dynamic and continuously evolving visual
+experience, reminiscent of classic screensavers from the early days of
+personal computing.
+
+#+begin_export html
+<div class="flex-center">
+ <video width="1000" controls loop autoplay>
+ <source src="Screensaver, flying hand fans.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:Screensaver, flying hand fans.bas][Source code]]
+
+#+INCLUDE: "Screensaver, flying hand fans.bas" src basic-qb45
+
+* Polygon rendering
+
+This QBasic program generates and renders random polygons on the
+screen, each filled with a random color. It's a simple yet effective
+demonstration of basic computer graphics principles, particularly in
+rendering geometric shapes and handling randomness.
+
+#+begin_export html
+<div class="flex-center">
+ <video width="1000" controls loop autoplay>
+ <source src="Polygon.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:Polygon.bas][Source code]]
+
+#+INCLUDE: "Polygon.bas" src basic-qb45
+
+* Textured polygon rendering
+
+The program provides a practical example of texture mapping, a
+fundamental concept in computer graphics. Readers can learn how
+textures are applied to polygons.
+
+
+#+begin_export html
+<div class="flex-center">
+ <video width="1000" controls loop autoplay>
+ <source src="Polygon textured.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:Polygon textured.bas][Source code]]
+
+* Yin and yang animation
+
+Yin and yang is a concept that originated in Chinese philosophy,
+describing an opposite but interconnected, self-perpetuating
+cycle. Yin and yang can be thought of as complementary and at the same
+time opposing forces that interact to form a dynamic system in which
+the whole is greater than the assembled parts and the parts are
+important for cohesion of the whole.
+
+#+begin_export html
+<div class="flex-center">
+ <video width="1000" controls loop autoplay>
+ <source src="Yin and yang.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:Yin and yang.bas][Source code]]
+
+#+INCLUDE: "Yin and yang.bas" src basic-qb45
+
+* Orbiting particles
+
+This QBasic program creates a visually engaging animation of particles
+orbiting around a central point. The particles are rendered as colored
+circles, each moving in a unique orbit, creating a dynamic and
+mesmerizing effect.
+
+#+begin_export html
+<div class="flex-center">
+ <video width="1000" controls loop autoplay>
+ <source src="Orbiting particles.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:Orbiting particles.bas][Source code]]
+
+#+INCLUDE: "Orbiting particles.bas" src basic-qb45
+
+* DNA animation
+
+Animated DNA. Nowhere close to being anatomically correct, but
+resembles animation as seen in the movies :)
+
+#+begin_export html
+<div class="flex-center">
+ <video width="1000" controls loop autoplay>
+ <source src="DNA.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:DNA.bas][Source code]]
+
+#+INCLUDE: "DNA.bas" src basic-qb45
+
+* Matrix
+
+Effect inspired by "The Matrix" movie.
+
+#+begin_export html
+<div class="flex-center">
+ <video width="1000" controls loop autoplay>
+ <source src="matrix.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:matrix.bas][Source code]]
+
+* Hacker
+
+Ultra-realistic hacker screen simulator! Behold da glory of a true
+hacker's terminal, brimming wif mystical green text that cascades like
+a waterfall of knowledge across thy monitor.
+
+#+begin_export html
+<div class="flex-center">
+ <video width="1000" controls loop autoplay>
+ <source src="hacker.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:hacker.bas][Source code]]
--- /dev/null
+' Program renders animation/screensaver.\r
+' It is inspired by The Matrix movie.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2002, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+\r
+DECLARE SUB initializeStream(streamIndex%)\r
+DECLARE SUB drawPixel(x%, y%)\r
+DECLARE SUB addNewPixel(x%, y%)\r
+DECLARE SUB smoothPixels(x1%, y1%, x2%, y2%, recursionDepth%)\r
+DECLARE SUB drawSymbol(x%, y%, symbol%)\r
+DECLARE SUB setColorPalette(paletteIndex%)\r
+DECLARE SUB initializeScreen()\r
+DECLARE SUB loadFonts()\r
+DEFINT A-Z\r
+\r
+' Arrays to store font data and pixel information\r
+DIM SHARED font1(1 TO 400, 1 TO 10)\r
+DIM SHARED font2(1 TO 400, 1 TO 10)\r
+DIM SHARED font3(1 TO 400, 1 TO 10)\r
+DIM SHARED pixelFont(0 TO 20, 0 TO 20)\r
+DIM SHARED pixelPalette(0 TO 20, 0 TO 20)\r
+DIM SHARED pixelAge(0 TO 20, 0 TO 20)\r
+DIM SHARED streamX(0 TO 20)\r
+DIM SHARED streamY(0 TO 20)\r
+DIM SHARED streamUsage(0 TO 20)\r
+DIM SHARED timerValue AS DOUBLE\r
+\r
+' Number of streams or objects in the animation\r
+numberOfStreams = 8\r
+\r
+' Initialize the screen and start the animation\r
+initializeScreen\r
+\r
+' Main loop of the program\r
+MainLoop:\r
+ FOR streamIndex = 1 TO numberOfStreams\r
+ ' Check if the usage count is zero\r
+ IF streamUsage(streamIndex) = 0 THEN initializeStream streamIndex\r
+ ' Add new position to the current object\r
+ addNewPixel streamX(streamIndex), streamY(streamIndex)\r
+ ' Update the y-coordinate of the current object\r
+ streamY(streamIndex) = streamY(streamIndex) + 1\r
+ ' Check if the y-coordinate exceeds the screen height\r
+ IF streamY(streamIndex) > 13 THEN streamY(streamIndex) = 0\r
+ ' Decrease the usage count of the current object\r
+ streamUsage(streamIndex) = streamUsage(streamIndex) - 1\r
+ NEXT streamIndex\r
+\r
+ ' Update the screen\r
+ FOR y = 0 TO 13\r
+ FOR x = 0 TO 18\r
+ ' Get the current pixel value\r
+ currentAge = pixelAge(x, y)\r
+ ' Increment the pixel value\r
+ currentAge = currentAge + 1\r
+ ' Check if the pixel value is equal to 2\r
+ IF currentAge = 2 THEN\r
+ pixelPalette(x, y) = 2\r
+ drawPixel x, y\r
+ ' Check if the pixel value is equal to 5\r
+ ELSEIF currentAge = 5 THEN\r
+ pixelPalette(x, y) = 3\r
+ drawPixel x, y\r
+ ' Check if the pixel value is equal to 30\r
+ ELSEIF currentAge = 30 THEN\r
+ pixelFont(x, y) = 0\r
+ drawPixel x, y\r
+ END IF\r
+ ' Update the pixel value\r
+ pixelAge(x, y) = currentAge\r
+ NEXT x\r
+ NEXT y\r
+\r
+ ' Wait for a short period of time\r
+ WaitLoop:\r
+ IF ABS(timerValue - TIMER) < .1 THEN GOTO WaitLoop\r
+ ' Update the timer\r
+ timerValue = TIMER\r
+ ' Check if any key is pressed\r
+ IF INKEY$ <> "" THEN SYSTEM\r
+ ' Go back to the main loop\r
+ GOTO MainLoop\r
+\r
+SUB addNewPixel(x, y)\r
+ ' Set a random font for the new pixel\r
+ pixelFont(x, y) = RND * 8 + 1\r
+ ' Set the palette index for the new pixel\r
+ pixelPalette(x, y) = 1\r
+ ' Initialize the pixel value\r
+ pixelAge(x, y) = 0\r
+ ' Draw the new pixel on the screen\r
+ drawPixel x, y\r
+END SUB\r
+\r
+SUB initializeStream(streamIndex)\r
+ ' Set random initial positions for the object\r
+ streamX(streamIndex) = RND * 18\r
+ streamY(streamIndex) = RND * 13\r
+ ' Set a random usage count for the object\r
+ streamUsage(streamIndex) = RND * 5 + 3\r
+END SUB\r
+\r
+SUB loadFonts\r
+ ' Load fonts from the screen\r
+ FOR symbolIndex = 1 TO 9\r
+ LOCATE 1, 1\r
+ ' Print the loading progress\r
+ PRINT "Loading: " + STR$(symbolIndex * 10) + "%"\r
+ ' Draw a square on the screen\r
+ LINE (49, 49)-(83, 83), 0, BF\r
+ ' Draw a symbol on the screen\r
+ drawSymbol 50, 50, symbolIndex\r
+ ' Smooth the symbol\r
+ smoothPixels 50, 50, 82, 82, 1\r
+ ' Get the smoothed symbol from the screen\r
+ GET (50, 50)-(82, 82), font1(1, symbolIndex)\r
+ ' Draw another square on the screen\r
+ LINE (49, 49)-(83, 83), 0, BF\r
+ ' Draw another symbol on the screen\r
+ drawSymbol 50, 50, symbolIndex\r
+ ' Smooth the other symbol\r
+ smoothPixels 50, 50, 82, 82, 2\r
+ ' Get the smoothed symbol from the screen\r
+ GET (50, 50)-(82, 82), font2(1, symbolIndex)\r
+ ' Draw yet another square on the screen\r
+ LINE (49, 49)-(83, 83), 0, BF\r
+ ' Draw yet another symbol on the screen\r
+ drawSymbol 50, 50, symbolIndex\r
+ ' Smooth the last symbol\r
+ smoothPixels 50, 50, 82, 82, 3\r
+ ' Get the smoothed symbol from the screen\r
+ GET (50, 50)-(82, 82), font3(1, symbolIndex)\r
+ NEXT symbolIndex\r
+ ' Clear the screen\r
+ CLS\r
+END SUB\r
+\r
+SUB drawPixel(x, y)\r
+ ' Calculate the screen coordinates for the pixel\r
+ x1 = x * 32 + 12\r
+ y1 = y * 32 + 15\r
+ ' Get the current font and palette index\r
+ currentFont = pixelFont(x, y)\r
+ currentPalette = pixelPalette(x, y)\r
+ ' Check if the pixel is empty\r
+ IF currentFont = 0 THEN\r
+ ' Draw an empty square on the screen\r
+ LINE (x1, y1)-(x1 + 32, y1 + 32), 0, BF\r
+ ELSE\r
+ ' Select the appropriate font based on the palette index\r
+ SELECT CASE currentPalette\r
+ CASE 1\r
+ ' Draw the pixel using the first font\r
+ PUT (x1, y1), font1(1, currentFont), PSET\r
+ CASE 2\r
+ ' Draw the pixel using the second font\r
+ PUT (x1, y1), font2(1, currentFont), PSET\r
+ CASE 3\r
+ ' Draw the pixel using the third font\r
+ PUT (x1, y1), font3(1, currentFont), PSET\r
+ END SELECT\r
+ END IF\r
+END SUB\r
+\r
+SUB drawSymbol(x, y, symbol)\r
+ ' Select the appropriate symbol based on the input value\r
+ SELECT CASE symbol\r
+ CASE 1\r
+ ' Draw the first symbol\r
+ LINE (x + 10, y + 5)-(x + 10, y + 20), 14\r
+ LINE (x + 5, y + 15)-(x + 20, y + 15), 14\r
+ LINE (x + 15, y + 25)-(x + 20, y + 25), 14\r
+ LINE (x + 20, y + 25)-(x + 25, y + 20), 14\r
+ LINE (x + 25, y + 20)-(x + 25, y + 5), 14\r
+ CASE 2\r
+ ' Draw the second symbol\r
+ LINE (x + 5, y + 15)-(x + 25, y + 10), 14\r
+ LINE (x + 15, y + 5)-(x + 10, y + 25), 14\r
+ LINE (x + 25, y + 5)-(x + 20, y + 20), 14\r
+ LINE (x + 20, y + 30)-(x + 30, y + 20), 14\r
+ CASE 3\r
+ ' Draw the third symbol\r
+ LINE (x + 5, y + 5)-(x + 5, y + 25), 14\r
+ LINE (x + 5, y + 5)-(x + 25, y + 25), 14\r
+ LINE (x + 5, y + 25)-(x + 25, y + 25), 14\r
+ LINE (x + 10, y + 10)-(x + 25, y + 5), 14\r
+ CASE 4\r
+ ' Draw the fourth symbol\r
+ LINE (x + 10, y + 5)-(x + 20, y + 5), 14\r
+ LINE (x + 20, y + 5)-(x + 25, y + 10), 14\r
+ LINE (x + 25, y + 20)-(x + 20, y + 25), 14\r
+ LINE (x + 20, y + 25)-(x + 10, y + 25), 14\r
+ LINE (x + 10, y + 25)-(x + 10, y + 5), 14\r
+ LINE (x + 5, y + 15)-(x + 20, y + 15), 14\r
+ CASE 5\r
+ ' Draw the fifth symbol\r
+ LINE (x + 5, y + 5)-(x + 10, y + 10), 14\r
+ LINE (x + 10, y + 10)-(x + 10, y + 25), 14\r
+ LINE (x + 10, y + 25)-(x + 5, y + 30), 14\r
+ LINE (x + 10, y + 25)-(x + 15, y + 30), 14\r
+ LINE (x + 15, y + 30)-(x + 25, y + 30), 14\r
+ LINE (x + 10, y + 20)-(x + 25, y + 20), 14\r
+ CASE 6\r
+ ' Draw the sixth symbol\r
+ LINE (x + 5, y + 5)-(x + 10, y + 5), 14\r
+ LINE (x + 5, y + 5)-(x + 5, y + 10), 14\r
+ LINE (x + 10, y + 10)-(x + 10, y + 15), 14\r
+ LINE (x + 10, y + 15)-(x + 20, y + 30), 14\r
+ LINE (x + 20, y + 30)-(x + 25, y + 30), 14\r
+ LINE (x + 5, y + 30)-(x + 10, y + 30), 14\r
+ LINE (x + 25, y + 15)-(x + 10, y + 30), 14\r
+ CASE 7\r
+ ' Draw the seventh symbol\r
+ LINE (x + 5, y + 15)-(x + 10, y + 15), 14\r
+ LINE (x + 10, y + 15)-(x + 25, y + 5), 14\r
+ LINE (x + 5, y + 25)-(x + 10, y + 25), 14\r
+ LINE (x + 10, y + 25)-(x + 15, y + 5), 14\r
+ LINE (x + 20, y + 5)-(x + 20, y + 20), 14\r
+ PSET (x + 15, y + 25), 14\r
+ PSET (x + 22, y + 25), 14\r
+ CASE 8\r
+ ' Draw the eighth symbol\r
+ LINE (x + 15, y + 10)-(x + 15, y + 25), 14\r
+ LINE (x + 20, y + 15)-(x + 20, y + 25), 14\r
+ LINE (x + 5, y + 20)-(x + 10, y + 25), 14\r
+ LINE (x + 10, y + 25)-(x + 25, y + 25), 14\r
+ CASE 9\r
+ ' Draw the ninth symbol\r
+ LINE (x + 5, y + 5)-(x + 25, y + 5), 14\r
+ LINE (x + 15, y + 5)-(x + 5, y + 20), 14\r
+ LINE (x + 15, y + 5)-(x + 25, y + 20), 14\r
+ LINE (x + 15, y + 5)-(x + 15, y + 25), 14\r
+ LINE (x + 5, y + 30)-(x + 20, y + 20), 14\r
+ END SELECT\r
+END SUB\r
+\r
+SUB setColorPalette(paletteIndex)\r
+ ' Set the color palette based on the input value\r
+ SELECT CASE paletteIndex\r
+ CASE 2\r
+ ' Set the colors for palette 2\r
+ FOR colorIndex = 0 TO 14\r
+ OUT &H3C8, colorIndex\r
+ OUT &H3C9, colorIndex * 2\r
+ OUT &H3C9, colorIndex * 4.5\r
+ OUT &H3C9, colorIndex * 3\r
+ NEXT colorIndex\r
+ CASE 1\r
+ ' Set the colors for palette 1\r
+ FOR colorIndex = 0 TO 14\r
+ OUT &H3C8, colorIndex\r
+ OUT &H3C9, 0\r
+ OUT &H3C9, 0\r
+ OUT &H3C9, 0\r
+ NEXT colorIndex\r
+ ' Set the color for the background\r
+ OUT &H3C8, 15\r
+ OUT &H3C9, 20\r
+ OUT &H3C9, 63\r
+ OUT &H3C9, 63\r
+ END SELECT\r
+END SUB\r
+\r
+SUB smoothPixels(x1, y1, x2, y2, recursionDepth)\r
+ ' Initialize the smoothing variable\r
+ smoothingValue = 0\r
+ ' Perform horizontal smoothing\r
+ FOR y = y1 TO y2\r
+ FOR x = x1 TO x2\r
+ ' Get the current pixel value\r
+ currentPixelValue = POINT(x, y)\r
+ ' Update the smoothing variable\r
+ smoothingValue = smoothingValue - 5\r
+ ' Ensure the smoothing variable is non-negative\r
+ IF smoothingValue < 0 THEN smoothingValue = 0\r
+ ' Update the smoothing variable if the current pixel value is greater\r
+ IF currentPixelValue > smoothingValue THEN smoothingValue = currentPixelValue\r
+ ' Set the smoothed pixel value\r
+ PSET (x, y), smoothingValue\r
+ NEXT x\r
+ NEXT y\r
+ ' Perform vertical smoothing\r
+ FOR x = x1 TO x2\r
+ smoothingValue = 0\r
+ FOR y = y1 TO y2\r
+ ' Get the current pixel value\r
+ currentPixelValue = POINT(x, y)\r
+ ' Update the smoothing variable\r
+ smoothingValue = smoothingValue - 5\r
+ ' Ensure the smoothing variable is non-negative\r
+ IF smoothingValue < 0 THEN smoothingValue = 0\r
+ ' Update the smoothing variable if the current pixel value is greater\r
+ IF currentPixelValue > smoothingValue THEN smoothingValue = currentPixelValue\r
+ ' Set the smoothed pixel value\r
+ PSET (x, y), smoothingValue\r
+ NEXT y\r
+ NEXT x\r
+ ' Perform diagonal smoothing\r
+ FOR y = y1 TO y2\r
+ smoothingValue = 0\r
+ FOR x = x1 TO x2\r
+ ' Get the current pixel value\r
+ currentPixelValue = POINT(x, y)\r
+ ' Update the smoothing variable\r
+ smoothingValue = smoothingValue - 5\r
+ ' Ensure the smoothing variable is non-negative\r
+ IF smoothingValue < 0 THEN smoothingValue = 0\r
+ ' Update the smoothing variable if the current pixel value is greater\r
+ IF currentPixelValue > smoothingValue THEN smoothingValue = currentPixelValue\r
+ ' Set the smoothed pixel value\r
+ PSET (x, y), smoothingValue\r
+ NEXT x\r
+ NEXT y\r
+ ' Perform diagonal smoothing in the opposite direction\r
+ FOR x = x1 TO x2\r
+ smoothingValue = 0\r
+ FOR y = y2 TO y1 STEP -1\r
+ ' Get the current pixel value\r
+ currentPixelValue = POINT(x, y)\r
+ ' Update the smoothing variable\r
+ smoothingValue = smoothingValue - 5\r
+ ' Ensure the smoothing variable is non-negative\r
+ IF smoothingValue < 0 THEN smoothingValue = 0\r
+ ' Update the smoothing variable if the current pixel value is greater\r
+ IF currentPixelValue > smoothingValue THEN smoothingValue = currentPixelValue\r
+ ' Set the smoothed pixel value\r
+ PSET (x, y), smoothingValue\r
+ NEXT y\r
+ NEXT x\r
+ ' Check if the recursion depth is equal to 1\r
+ IF recursionDepth = 1 THEN GOTO ExitSmoothing\r
+ ' Increment the recursion depth\r
+ newRecursionDepth = recursionDepth + 1\r
+ ' Perform horizontal smoothing with averaging\r
+ FOR y = y1 TO y2\r
+ smoothingValue = 0\r
+ FOR x = x1 TO x2\r
+ ' Get the current pixel value\r
+ currentPixelValue = POINT(x, y)\r
+ ' Update the smoothed pixel value using averaging\r
+ smoothingValue = (smoothingValue * recursionDepth + currentPixelValue) / newRecursionDepth\r
+ ' Ensure the smoothed pixel value is non-negative\r
+ finalSmoothingValue = smoothingValue - recursionDepth\r
+ IF finalSmoothingValue < 0 THEN finalSmoothingValue = 0\r
+ ' Set the final smoothed pixel value\r
+ PSET (x, y), finalSmoothingValue\r
+ NEXT x\r
+ NEXT y\r
+ ' Perform vertical smoothing with averaging\r
+ FOR x = x1 TO x2\r
+ smoothingValue = 0\r
+ FOR y = y1 TO y2\r
+ ' Get the current pixel value\r
+ currentPixelValue = POINT(x, y)\r
+ ' Update the smoothing variable\r
+ smoothingValue = smoothingValue - 5\r
+ ' Ensure the smoothing variable is non-negative\r
+ IF smoothingValue < 0 THEN smoothingValue = 0\r
+ ' Update the smoothing variable if the current pixel value is greater\r
+ IF currentPixelValue > smoothingValue THEN smoothingValue = currentPixelValue\r
+ ' Set the smoothed pixel value\r
+ PSET (x, y), smoothingValue\r
+ NEXT y\r
+ NEXT x\r
+ ' Perform diagonal smoothing with averaging\r
+ FOR y = y1 TO y2\r
+ smoothingValue = 0\r
+ FOR x = x2 TO x1 STEP -1\r
+ ' Get the current pixel value\r
+ currentPixelValue = POINT(x, y)\r
+ ' Update the smoothing variable\r
+ smoothingValue = smoothingValue - 5\r
+ ' Ensure the smoothing variable is non-negative\r
+ IF smoothingValue < 0 THEN smoothingValue = 0\r
+ ' Update the smoothing variable if the current pixel value is greater\r
+ IF currentPixelValue > smoothingValue THEN smoothingValue = currentPixelValue\r
+ ' Set the smoothed pixel value\r
+ PSET (x, y), smoothingValue\r
+ NEXT x\r
+ NEXT y\r
+ ' Perform diagonal smoothing in the opposite direction with averaging\r
+ FOR x = x1 TO x2\r
+ smoothingValue = 0\r
+ FOR y = y2 TO y1 STEP -1\r
+ ' Get the current pixel value\r
+ currentPixelValue = POINT(x, y)\r
+ ' Update the smoothing variable\r
+ smoothingValue = smoothingValue - 5\r
+ ' Ensure the smoothing variable is non-negative\r
+ IF smoothingValue < 0 THEN smoothingValue = 0\r
+ ' Update the smoothing variable if the current pixel value is greater\r
+ IF currentPixelValue > smoothingValue THEN smoothingValue = currentPixelValue\r
+ ' Set the smoothed pixel value\r
+ PSET (x, y), smoothingValue\r
+ NEXT y\r
+ NEXT x\r
+ExitSmoothing:\r
+END SUB\r
+\r
+SUB initializeScreen\r
+ ' Set the screen mode to 12\r
+ SCREEN 12\r
+ ' Set the color palette to 1\r
+ setColorPalette 1\r
+ ' Load the fonts\r
+ loadFonts\r
+ ' Set the color palette to 2\r
+ setColorPalette 2\r
+END SUB\r
--- /dev/null
+' Program to render animation inspired by opening scene from The Matrix movie.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+\r
+' Changelog:\r
+' 2002, Initial version\r
+' 2024, Improved program readability\r
+\r
+DEFINT A-Z\r
+DECLARE SUB DisplayMatrix ()\r
+DIM SHARED matrixArray(1 TO 20)\r
+DIM SHARED lineLength\r
+DIM SHARED displayMessage$\r
+RANDOMIZE 2\r
+\r
+CLS\r
+COLOR 10, 0\r
+displayMessage$ = ""\r
+frameCounter = 0\r
+iterationCount = 0\r
+DisplayMatrix\r
+\r
+1 : ' Label for looping\r
+\r
+' Creates high-pitch pulsing sound by toggling it on and off while iterating\r
+soundFrequency = 0\r
+IF iterationCount >= 3 THEN soundFrequency = 10000: iterationCount = 0\r
+SOUND soundFrequency, .2\r
+iterationCount = iterationCount + 1\r
+\r
+frameCounter = frameCounter + 1\r
+IF frameCounter > 100 THEN DisplayMatrix: frameCounter = 0\r
+\r
+displayLine$ = ""\r
+lineIndex = 1\r
+FOR column = 1 TO 80\r
+ lineIndex = lineIndex + 1\r
+ randomCharacter$ = CHR$(INT(RND * 9) + 48)\r
+ IF lineIndex > lineLength THEN lineIndex = 1: randomCharacter$ = " "\r
+ displayLine$ = displayLine$ + randomCharacter$\r
+NEXT column\r
+LOCATE 25, 1\r
+PRINT displayLine$\r
+IF INKEY$ <> "" THEN COLOR 7, 0: CLS : SYSTEM\r
+GOTO 1\r
+\r
+SUB DisplayMatrix\r
+ ' Set the viewport to print from line 1 to line 25\r
+ VIEW PRINT 1 TO 25\r
+\r
+ ' Display a message based on the code decoding progress\r
+ SELECT CASE lineLength\r
+ CASE 13\r
+ displayMessage$ = "Are you sure the line is clear?"\r
+ CASE 6\r
+ displayMessage$ = " Then I'll go ..."\r
+ END SELECT\r
+\r
+ ' Clear and print the message at position (1, 30)\r
+ LOCATE 1, 30\r
+ PRINT " "\r
+ LOCATE 1, 30\r
+ PRINT displayMessage$\r
+\r
+ randomValue = INT(RND * 9) + 1\r
+ FOR pass = 1 TO 3\r
+ FOR value = randomValue TO 10\r
+ IF matrixArray(value) = -1 THEN\r
+ ' Assign a random value between 1 and 8 to the array element\r
+ matrixArray(value) = INT(RND * 8) + 1\r
+ lineLength = lineLength - 1\r
+ GOTO 2\r
+ END IF\r
+ NEXT value\r
+ ' Reset randomValue if no valid position is found\r
+ randomValue = 1\r
+ NEXT pass\r
+\r
+ ' Reset the length and initialize the array\r
+ lineLength = 13\r
+ FOR index = 1 TO 20\r
+ matrixArray(index) = -1\r
+ NEXT index\r
+\r
+ CLS\r
+ IF displayMessage$ <> "" THEN SYSTEM\r
+\r
+2 : ' Label for continuing after GOTO\r
+ FOR index = 1 TO 20\r
+ LOCATE 1, index\r
+ ' Display a space if the array element is -1, otherwise display the value\r
+ IF matrixArray(index) = -1 THEN displayChar$ = " " ELSE displayChar$ = STR$(matrixArray(index))\r
+ displayChar$ = RIGHT$(displayChar$, 1)\r
+ PRINT displayChar$\r
+ NEXT index\r
+\r
+ ' Set the viewport to print from line 2 to line 25\r
+ VIEW PRINT 2 TO 25\r
+END SUB\r
+\r
--- /dev/null
+' Render animated 3D maze.\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2002, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+DECLARE FUNCTION getWord& (memoryAddress!)\r
+DECLARE FUNCTION getByte! (memoryAddress!)\r
+DECLARE SUB displayIntroText ()\r
+DECLARE SUB handleUserInput ()\r
+DECLARE SUB writeByteToMemory (memoryAddress!, dataValue!)\r
+DECLARE SUB writeWordToMemory (memoryAddress!, dataValue!)\r
+DECLARE SUB initializeProgram ()\r
+DECLARE SUB renderMaze ()\r
+\r
+DIM SHARED pointX(1 TO 5000)\r
+DIM SHARED pointY(1 TO 5000)\r
+DIM SHARED pointZ(1 TO 5000)\r
+DIM SHARED rotatedPointX(1 TO 5000)\r
+DIM SHARED rotatedPointY(1 TO 5000)\r
+DIM SHARED rotatedPointE(1 TO 5000)\r
+DIM SHARED lineStartIndex(1 TO 5000)\r
+DIM SHARED lineEndIndex(1 TO 5000)\r
+DIM SHARED lineColor(1 TO 5000)\r
+DIM SHARED numberOfLines, numberOfPoints\r
+DIM SHARED angleXZ, angleYZ\r
+DIM SHARED externalSegment, externalAddress\r
+DIM SHARED viewerX, viewerY, viewerZ\r
+DIM SHARED buttonLeft, buttonRight\r
+DIM SHARED maxMovement\r
+\r
+numberOfLines = 0\r
+numberOfPoints = 0\r
+\r
+' Initialize the program and set up the screen\r
+initializeProgram\r
+\r
+' Initialize maze starting point\r
+mazeX = 0\r
+mazeY = 0\r
+mazeZ = 0\r
+numberOfPoints = 1\r
+pointX(1) = 0\r
+pointY(1) = 0\r
+pointZ(1) = 0\r
+\r
+' Main loop\r
+1\r
+frameCounter = frameCounter + 1\r
+viewerX = SIN(frameCounter / 30) * 100\r
+viewerZ = COS(frameCounter / 59) * 100\r
+viewerY = SIN(frameCounter / 300)\r
+angleXZ = SIN(frameCounter / 60)\r
+angleYZ = SIN(frameCounter / 36) / 3\r
+\r
+' Add a new point to the maze\r
+numberOfPoints = numberOfPoints + 1\r
+pointX(numberOfPoints) = mazeX\r
+pointY(numberOfPoints) = mazeY\r
+pointZ(numberOfPoints) = mazeZ\r
+\r
+' Add a new line to the maze\r
+numberOfLines = numberOfLines + 1\r
+lineStartIndex(numberOfLines) = numberOfPoints\r
+lineEndIndex(numberOfLines) = numberOfPoints - 1\r
+lineColor(numberOfLines) = INT(RND * 15) + 1\r
+\r
+' Pick random axis (dimension) where next segment of the maze should appear\r
+mazeGrowthDirection = INT(RND * 3)\r
+SELECT CASE mazeGrowthDirection\r
+ CASE 0\r
+ mazeX = RND * 500 - 250\r
+ CASE 1\r
+ mazeY = RND * 100 - 50\r
+ CASE 2\r
+ mazeZ = RND * 500 - 250\r
+END SELECT\r
+\r
+' Render the maze\r
+renderMaze\r
+\r
+' Copy and clear the screen\r
+PCOPY 0, 1\r
+CLS\r
+\r
+' Limit animation speed by making 0 Hz sound with fixed duration\r
+SOUND 0, 1\r
+\r
+' Exit condition\r
+IF frameCounter > 1200 THEN GOTO 200\r
+GOTO 1\r
+\r
+200\r
+\r
+SUB renderMaze\r
+ ' Calculate sine and cosine values for the rotation angles\r
+ sinAngleXZ = SIN(angleXZ)\r
+ sinAngleYZ = SIN(angleYZ)\r
+ cosAngleXZ = COS(angleXZ)\r
+ cosAngleYZ = COS(angleYZ)\r
+\r
+ ' Rotate and project points\r
+ FOR index = 1 TO numberOfPoints\r
+ x = pointX(index) - viewerX\r
+ y = pointY(index) - viewerY\r
+ z = pointZ(index) - viewerZ\r
+\r
+ ' First rotation around Y axis\r
+ rotatedXAfterFirstRotation = x * cosAngleXZ + z * sinAngleXZ\r
+ rotatedZAfterFirstRotation = z * cosAngleXZ - x * sinAngleXZ\r
+\r
+ ' Second rotation around X axis\r
+ rotatedYAfterSecondRotation = y * cosAngleYZ + rotatedZAfterFirstRotation * sinAngleYZ\r
+ rotatedZAfterSecondRotation = rotatedZAfterFirstRotation * cosAngleYZ - y * sinAngleYZ\r
+\r
+ ' Check if point is behind the viewer\r
+ IF rotatedZAfterSecondRotation > 3 THEN\r
+ rotatedPointE(index) = 1\r
+ rotatedPointX(index) = rotatedXAfterFirstRotation / rotatedZAfterSecondRotation * 130 + 160\r
+ rotatedPointY(index) = rotatedYAfterSecondRotation / rotatedZAfterSecondRotation * 130 + 100\r
+ ELSE\r
+ rotatedPointE(index) = 0\r
+ END IF\r
+ NEXT index\r
+\r
+ ' Draw lines between visible points\r
+ FOR index = 1 TO numberOfLines\r
+ lineStart = lineStartIndex(index)\r
+ lineEnd = lineEndIndex(index)\r
+ IF (rotatedPointE(lineStart) = 1) AND (rotatedPointE(lineEnd) = 1) THEN\r
+ LINE (rotatedPointX(lineStart), rotatedPointY(lineStart))-(rotatedPointX(lineEnd), rotatedPointY(lineEnd)), lineColor(index)\r
+ END IF\r
+ NEXT index\r
+END SUB\r
+\r
+SUB initializeProgram\r
+ ' Set the screen mode and initialize maximum movement value\r
+ SCREEN 7, , , 1\r
+ maxMovement = 50\r
+END SUB\r
--- /dev/null
+' Projects animation of the sun, earth and moon.\r
+' The moon orbits the earth, and the earth orbits the sun.\r
+' The program uses clever trickery to determine\r
+' the drawing order of the objects based on their y-coordinates.\r
+\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+\r
+' Changelog:\r
+' 1999, Initial version\r
+' 2024, Improved program readability\r
+\r
+\r
+DECLARE SUB drawEarthMoonSystem (a2!, b2!, c2!)\r
+\r
+DIM SHARED moonX\r
+DIM SHARED moonY\r
+SCREEN 7, , , 1\r
+\r
+' Initialize the earth rotation angle\r
+earthRotationAngle = 0\r
+\r
+' Main loop to update and draw the objects\r
+1 :\r
+ SOUND 0, .5\r
+\r
+ ' Increment the earthRotationAngle for every frame\r
+ earthRotationAngle = earthRotationAngle + .01\r
+\r
+ ' Calculate the x and y coordinates of the earth\r
+ earthX = SIN(earthRotationAngle) * 100 + 100\r
+ earthY = COS(earthRotationAngle) * 30 + 100\r
+\r
+ ' Because we dont do proper earth, moon and sun Z-sorting,\r
+ ' instead we implement clever trickery to determine, should\r
+ ' sun be drawn before earth-moon system, or after.\r
+ IF earthY >= 100 THEN\r
+ ' Draw the sun\r
+ CIRCLE (100, 100), 50, 12\r
+ PAINT (100, 100), 12\r
+ END IF\r
+\r
+ ' Call the subroutine to draw the earth-moon system\r
+ drawEarthMoonSystem earthX, earthY, (earthY - 70) / 2 + 2\r
+\r
+ IF earthY < 100 THEN\r
+ ' Draw the sun\r
+ CIRCLE (100, 100), 50, 12\r
+ PAINT (100, 100), 12\r
+ END IF\r
+\r
+ ' Copy the screen to buffer\r
+ PCOPY 0, 1\r
+\r
+ ' Clear the screen\r
+ CLS\r
+\r
+ ' Check if a key is pressed\r
+ IF INKEY$ = "" THEN GOTO 1\r
+\r
+' End the program\r
+SYSTEM\r
+\r
+SUB drawEarthMoonSystem (a2, b2, c2)\r
+ moonSize = (b2 - 70) / 2 + 2\r
+\r
+ ' Increment the moon's x and y coordinates\r
+ moonX = moonX + .1\r
+ moonY = moonY + .01\r
+\r
+ ' Calculate the x and y offsets for the moon\r
+ moonOffsetX = SIN(moonX) * moonSize * 2\r
+ moonOffsetY = COS(moonX) * 10\r
+\r
+ ' Because we don't do proper earth and moon Z-sorting,\r
+ ' instead we implement clever trickery to determine, should\r
+ ' earth be drawn before moon or after.\r
+ IF moonOffsetY > 0 THEN\r
+ ' Draw the earth\r
+ CIRCLE (a2, b2), c2, 1\r
+ PAINT (a2, b2), 1\r
+ END IF\r
+\r
+ ' Calculate the x and y coordinates of the moon and draw it\r
+ moonXCoord = moonOffsetX + a2\r
+ moonYCoord = moonOffsetY + b2\r
+ CIRCLE (moonXCoord, moonYCoord), ((moonOffsetY + 20) * moonSize) \ 50, 14\r
+ PAINT (moonXCoord, moonYCoord), 14\r
+\r
+ IF moonOffsetY <= 0 THEN\r
+ ' Draw the earth\r
+ CIRCLE (a2, b2), c2, 1\r
+ PAINT (a2, b2), 1\r
+ END IF\r
+END SUB\r
+\r
--- /dev/null
+' Program to render fancy looking text mode animations.\r
+' Various effects are overlaid on top of each other\r
+' while program scrolls it's own source code in the background.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.10, Initial version\r
+' 2024, Improved program readability\r
+\r
+DECLARE SUB displayScreen ()\r
+DECLARE SUB drawCircle ()\r
+DECLARE SUB drawLines ()\r
+DECLARE SUB fillBuffer ()\r
+DECLARE SUB updateDisplay ()\r
+DIM SHARED pi\r
+DIM SHARED angle\r
+DIM SHARED frameCounter\r
+DIM SHARED buffer2(1 TO 50, 1 TO 80) AS STRING * 1\r
+DIM SHARED buffer(1 TO 50, 1 TO 80) AS STRING * 1\r
+DIM SHARED colors(1 TO 50, 1 TO 80) AS INTEGER\r
+\r
+DIM SHARED verticalLinePosition, horizontalLinePosition\r
+DIM SHARED verticalLineSpeed, horizontalLineSpeed\r
+\r
+WIDTH 80, 50\r
+VIEW PRINT 1 TO 50\r
+pi = 3.14159\r
+OPEN "mkcircle.bas" FOR INPUT AS #1\r
+\r
+CLS\r
+\r
+horizontalLinePosition = 20\r
+horizontalLineSpeed = 1\r
+verticalLinePosition = 20\r
+verticalLineSpeed = 1\r
+\r
+1\r
+frameCounter = frameCounter + 1\r
+\r
+displayScreen\r
+fillBuffer\r
+drawLines\r
+drawCircle\r
+updateDisplay\r
+IF INKEY$ <> "" THEN GOTO 2\r
+GOTO 1\r
+2\r
+CLOSE #1\r
+SYSTEM\r
+\r
+SUB updateDisplay\r
+' This subroutine updates the display with the contents of the buffer\r
+COLOR 7, 0\r
+LOCATE 1, 1\r
+FOR y = 1 TO 50\r
+ FOR x = 1 TO 80\r
+ COLOR colors(y, x)\r
+ PRINT buffer(y, x);\r
+ ' Swap the contents of buffer and buffer2\r
+ buffer(y, x) = buffer2(y, x)\r
+ colors(y, x) = 4\r
+ NEXT x\r
+NEXT y\r
+\r
+END SUB\r
+\r
+SUB fillBuffer\r
+' This subroutine fills the buffer with a pattern\r
+COLOR 4, 0\r
+sizeMultiplier = SIN(frameCounter / 7) + 1.1\r
+\r
+angle = angle + SIN(frameCounter / 30) / 10\r
+radiusXPosition = 50 - SIN(angle + pi / 4) * 12 * 20 * sizeMultiplier\r
+radiusYPosition = 50 - COS(angle + pi / 4) * 12 * 20 * sizeMultiplier\r
+\r
+stepXPosition = SIN(angle) * 6 * sizeMultiplier\r
+stepYPosition = COS(angle) * 6 * sizeMultiplier\r
+radiusStepXPosition = SIN(angle + pi / 2) * 6 * sizeMultiplier\r
+radiusStepYPosition = COS(angle + pi / 2) * 6 * sizeMultiplier\r
+\r
+FOR y = 1 TO 50\r
+ radiusXPosition = radiusXPosition + radiusStepXPosition\r
+ radiusYPosition = radiusYPosition + radiusStepYPosition\r
+\r
+4\r
+IF radiusXPosition > 100 THEN radiusXPosition = radiusXPosition - 100: GOTO 4\r
+IF radiusXPosition < 0 THEN radiusXPosition = radiusXPosition + 100: GOTO 4\r
+IF radiusYPosition > 100 THEN radiusYPosition = radiusYPosition - 100: GOTO 4\r
+IF radiusYPosition < 0 THEN radiusYPosition = radiusYPosition + 100: GOTO 4\r
+\r
+currentXPosition = radiusXPosition\r
+currentYPosition = radiusYPosition\r
+\r
+FOR x = 1 TO 80\r
+ characterCode = 0\r
+ currentXPosition = currentXPosition + stepXPosition\r
+ currentYPosition = currentYPosition + stepYPosition\r
+\r
+3\r
+IF currentXPosition > 100 THEN currentXPosition = currentXPosition - 100: GOTO 3\r
+IF currentXPosition < 0 THEN currentXPosition = currentXPosition + 100: GOTO 3\r
+IF currentYPosition > 100 THEN currentYPosition = currentYPosition - 100: GOTO 3\r
+IF currentYPosition < 0 THEN currentYPosition = currentYPosition + 100: GOTO 3\r
+\r
+IF currentXPosition < 12 OR currentYPosition < 12 THEN buffer(y, x) = "*": colors(y, x) = 9\r
+NEXT x\r
+NEXT y\r
+END SUB\r
+\r
+SUB drawCircle\r
+' This subroutine draws a circle on the screen\r
+circleSize = (SIN(frameCounter / 10) + 1.01) * 30\r
+circleYPosition = SIN(frameCounter / 12) * 30 + 40\r
+circleXPosition = COS(frameCounter / 17) * 15 + 25\r
+\r
+FOR y = 1 TO 50\r
+ xPositionOffset = SIN(y / 5 + frameCounter / 30) * circleSize / 10\r
+\r
+IF (y >= circleYPosition - circleSize) AND (y <= circleYPosition + circleSize) THEN\r
+\r
+halfHeight1 = SQR((y - (circleYPosition - circleSize)) * ((circleYPosition + circleSize) - y))\r
+IF (y >= circleYPosition - circleSize / 2) AND (y <= circleYPosition + circleSize / 2) THEN halfHeight2 = SQR((y - (circleYPosition - circleSize / 2)) * ((circleYPosition + circleSize / 2) - y)) ELSE halfHeight2 = 0\r
+\r
+startXPosition = circleXPosition - halfHeight1 + xPositionOffset\r
+IF startXPosition < 1 THEN startXPosition = 1\r
+endXPosition = circleXPosition - halfHeight2 + xPositionOffset\r
+IF endXPosition > 80 THEN endXPosition = 80\r
+\r
+FOR x = startXPosition TO endXPosition\r
+ buffer(y, x) = CHR$(RND * 40 + 48)\r
+ colors(y, x) = RND * 15\r
+NEXT x\r
+\r
+startXPosition = circleXPosition + halfHeight2 + xPositionOffset\r
+IF startXPosition < 1 THEN startXPosition = 1\r
+endXPosition = circleXPosition + halfHeight1 + xPositionOffset\r
+IF endXPosition > 80 THEN endXPosition = 80\r
+\r
+FOR x = startXPosition TO endXPosition\r
+ buffer(y, x) = CHR$(RND * 200 + 32)\r
+ colors(y, x) = RND * 15\r
+NEXT x\r
+\r
+END IF\r
+\r
+NEXT y\r
+\r
+END SUB\r
+\r
+SUB drawLines\r
+' This subroutine draws vertical and horizontal lines on the screen\r
+verticalLinePosition = verticalLinePosition + verticalLineSpeed\r
+IF verticalLinePosition > 49 THEN verticalLineSpeed = -1\r
+IF verticalLinePosition < 2 THEN verticalLineSpeed = 1\r
+\r
+horizontalLinePosition = horizontalLinePosition + horizontalLineSpeed\r
+IF horizontalLinePosition > 79 THEN horizontalLineSpeed = -1\r
+IF horizontalLinePosition < 2 THEN horizontalLineSpeed = 1\r
+\r
+FOR x = 1 TO 80\r
+ IF buffer(verticalLinePosition, x) = "*" THEN characterCode = 31 ELSE characterCode = 10\r
+ buffer(verticalLinePosition, x) = "#"\r
+ colors(verticalLinePosition, x) = characterCode\r
+NEXT x\r
+\r
+FOR y = 1 TO 50\r
+ IF buffer(y, horizontalLinePosition) = "*" THEN characterCode = 31 ELSE characterCode = 10\r
+ buffer(y, horizontalLinePosition) = "#"\r
+ colors(y, horizontalLinePosition) = characterCode\r
+NEXT y\r
+END SUB\r
+\r
+SUB displayScreen\r
+' This subroutine displays the text from a file on the screen\r
+IF EOF(1) <> 0 THEN\r
+ CLOSE 1\r
+ OPEN "mkcircle.bas" FOR INPUT AS #1\r
+END IF\r
+\r
+LINE INPUT #1, lineText$\r
+\r
+FOR y = 1 TO 49\r
+FOR x = 1 TO 80\r
+ buffer2(y, x) = buffer2(y + 1, x)\r
+NEXT x\r
+NEXT y\r
+\r
+FOR x = 1 TO 80\r
+ buffer2(50, x) = " "\r
+NEXT x\r
+\r
+IF LEN(lineText$) > 80 THEN lineText$ = LEFT$(lineText$, 80)\r
+FOR b = 1 TO LEN(lineText$)\r
+ character$ = RIGHT$(LEFT$(lineText$, b), 1)\r
+ buffer2(50, b) = character$\r
+NEXT b\r
+\r
+END SUB\r
--- /dev/null
+' This application produces beautiful colorful horizontal rainbows on the screen in text mode.\r
+' It works only on CRT monitors, because it accomplishes the effect by changing the color palette\r
+' while the CRT monitor is drawing the screen. As a result, unlimited number of colors can be\r
+' displayed on the screen simultaneously, regardless of the video card's color depth.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+\r
+' Changelog:\r
+' 2003.01, Initial version\r
+' 2024, Improved program readability\r
+\r
+DEFINT A-Z\r
+CLS\r
+COLOR 7\r
+\r
+' Fill background with random colored random numbers.\r
+FOR b = 1 TO 500\r
+ COLOR RND * 15\r
+ PRINT RND;\r
+NEXT b\r
+\r
+' Set the background and text colors\r
+COLOR 0, 1\r
+\r
+' Clear rectangular area\r
+FOR y = 5 TO 20\r
+ FOR x = 20 TO 50\r
+ LOCATE y, x\r
+ PRINT " "\r
+ NEXT x\r
+NEXT y\r
+\r
+' Print "[ TEST ]" at position (10, 25)\r
+LOCATE 10, 25\r
+PRINT "[ TEST ]"\r
+\r
+' Print "[ TEST ]" in color 2 at position (15, 37)\r
+LOCATE 15, 37\r
+COLOR 2\r
+PRINT "[ TEST ]"\r
+\r
+' Initialize variables\r
+wa = 1\r
+p = &H3DA\r
+\r
+' Loop to wait until CRT monitor has drawn single frame\r
+1\r
+' measure how much time was spent waiting for screen redraw to complete\r
+w = w + 1\r
+\r
+' Check if monitor is still drawing frame\r
+a = INP(p)\r
+IF a >= 128 THEN a = a - 128\r
+IF a >= 64 THEN a = a - 64\r
+IF a >= 32 THEN a = a - 32\r
+IF a >= 16 THEN a = a - 16\r
+IF a < 8 THEN GOTO 1\r
+\r
+frm = frm + 1\r
+IF frm > 10000 THEN frm = -10000\r
+\r
+' Adjust the color palette change speed so that it takes approximately all of the time\r
+' when Ray is actually moving along screen surface and is drawing pixels.\r
+' So if we had to wait too long for drawing to complete at the end, it means\r
+' next frame we can be slower with our palette updates.\r
+IF w > 300 THEN wa = wa + 1 ELSE wa = wa - 1\r
+IF w < 250 THEN wa = wa - 5\r
+IF w > 3000 THEN wa = wa + 30\r
+IF w > 1000 THEN wa = wa + 5\r
+\r
+' Check if a key has been pressed\r
+IF INKEY$ <> "" THEN\r
+ ' Reset color palette\r
+ OUT &H3C8, 0\r
+ OUT &H3C9, 0\r
+ OUT &H3C9, 0\r
+ OUT &H3C9, 0\r
+ ' exit application\r
+ SYSTEM\r
+END IF\r
+\r
+' Alter video graphics color palette while CRT screen in drawing scanlines simultaneously\r
+FOR a = 0 TO 70\r
+\r
+ b = a * 6 + frm\r
+\r
+ ' Alter palette within video card\r
+ OUT &H3C8, 0\r
+ OUT &H3C9, SIN(b / 20) * 30 + 30\r
+ OUT &H3C9, SIN(b / 27) * 30 + 30\r
+ OUT &H3C9, SIN(b / 31) * 30 + 30\r
+\r
+ ' Delay to give time for CRT screen to complete horizontal scanlines\r
+ FOR u = 1 TO wa\r
+ NEXT u\r
+NEXT a\r
+\r
+w = 0\r
+GOTO 1\r
--- /dev/null
+DECLARE SUB playSoundEffect (soundEffect$)
+DECLARE SUB initializeGraphics ()
+DECLARE SUB drawEllipse (xCoord!, yCoord!, size!, colorValue!, aspectRatio!)
+DECLARE SUB printMessage (xCoord!, yCoord!, message$, size!, colr!)
+DECLARE SUB addTimerElement (elementIndex!, time!, value!)
+DECLARE SUB initializeTimers ()
+DECLARE SUB processTimers ()
+DECLARE SUB drawFractal (xCoord!, yCoord!, angle!, size!, direction!)
+
+' Program that renders animation that contains fractal composed from circles.
+'
+' This program is free software: released under Creative Commons Zero (CC0) license
+' by Svjatoslav Agejenko.
+' Email: svjatoslav@svjatoslav.eu
+' Homepage: http://www.svjatoslav.eu
+
+
+' Shared variables for global state
+DIM SHARED recursionDepth
+DIM SHARED pi
+
+' Variables to store shapes and timers
+DIM SHARED shapeSize1, shapeSize2, sizeValue1, sizeValue2, horizontalPosition, verticalPosition
+DIM SHARED timerTime(0 TO 50, 0 TO 100)
+DIM SHARED timerValue(0 TO 50, 0 TO 100)
+
+' Variables to store current timer states
+DIM SHARED timerCurrentPlace(0 TO 50)
+DIM SHARED timerCurrentTime(0 TO 50)
+DIM SHARED timerCurrentValue(0 TO 50)
+DIM SHARED timerLastFrameTime
+
+' Initialize pi with a constant value
+pi = 3.14128
+
+' Turn on the screen and initialize timers
+initializeGraphics
+
+' Set up graphics mode
+SCREEN 7, , , 1
+
+' Initialize the timer system
+initializeTimers
+
+' Main loop variable
+frameSize = 50
+
+' Main loop label
+MainLoop:
+ ' Calculate sine and cosine values for animation
+ sinValue = SIN(timerCurrentValue(1) * 1.3) * .5 + 1.1
+ cosValue = COS(timerCurrentValue(1) * 1.3) * .5 + 1.1
+
+ ' Increment frame counter
+ frameCounter = frameCounter + 1
+
+ ' Calculate shape sizes and positions
+ sizeValue1 = 5 * sinValue
+ sizeValue2 = 2
+ verticalPosition = SIN(timerCurrentValue(1) * 1.3)
+ shapeSize1 = 2 * cosValue
+ shapeSize2 = 1.4
+ horizontalPosition = SIN(timerCurrentValue(1)) * .7
+
+ ' Draw the main fractal object
+ drawFractal timerCurrentValue(2), timerCurrentValue(3), timerCurrentValue(4), timerCurrentValue(0), 0
+
+ ' Draw ellipses
+ drawEllipse 100, timerCurrentValue(6), timerCurrentValue(7) + 4, 14, .5
+ drawEllipse 100, timerCurrentValue(6), timerCurrentValue(7) + 2, 10, .5
+ drawEllipse 100, timerCurrentValue(6), timerCurrentValue(7), 0, .5
+
+ ' Print messages
+ printMessage timerCurrentValue(5), 10, "KHK", 7, 250
+ printMessage timerCurrentValue(8), 130, "Infotehno-", 2, 0
+ printMessage timerCurrentValue(8), 150, " loogia", 2, 0
+
+ ' Process the timers
+ processTimers
+ LOCATE 1, 1
+
+ ' Check if the main loop should exit
+ IF timerCurrentTime(0) > 26 THEN SYSTEM
+
+ ' Make off-screen buffer visible
+ PCOPY 0, 1
+
+ ' Clear off-screen buffer with white background color in preparation to draw new frame
+ LINE (0, 0)-(319, 199), 15, BF
+
+ ' Go back to the main loop
+ GOTO MainLoop
+
+' Subroutine to draw an ellipse
+SUB drawEllipse (xCoord!, yCoord!, size!, colorValue!, aspectRatio!)
+ ' Draw an ellipse if xCoord and yCoord are positive
+ IF xCoord > 0 THEN
+ IF yCoord > 0 THEN
+ CIRCLE (xCoord, yCoord), size, colorValue, , , aspectRatio
+ PAINT (xCoord, yCoord), colorValue
+ END IF
+ END IF
+END SUB
+
+' Subroutine to draw animated fractal
+SUB drawFractal (xCoord!, yCoord!, angle!, size!, direction!)
+ ' Variables:
+ ' direction - indicates fractal branch direction
+ ' size - fractal fragment current size
+ ' angle - fractal twist angle
+ ' xCoord and yCoord - fractal fragment current position
+
+ ' Increment fragment depth counter
+ recursionDepth = recursionDepth + 1
+
+ ' If size is less than .2, skip drawing
+ IF size < .2 THEN GOTO SkipDrawing
+
+ ' Determine color based on depth
+ IF recursionDepth / 2 = recursionDepth \ 2 THEN
+ colr = 1
+ ELSE
+ colr = 3
+ END IF
+
+ ' Draw the circle and fill it with the determined color
+ CIRCLE (xCoord, yCoord), size, colr
+ PAINT (xCoord, yCoord), colr
+
+ ' Recursively draw child objects of the fractal if direction is not equal to 1
+ IF direction <> 1 THEN
+ x1 = SIN(angle) * size * 2.5 + xCoord
+ y1 = COS(angle) * size * 2.5 + yCoord
+ ' Change size based on the value of direction
+ IF direction = 3 THEN
+ newSize = size / sizeValue2
+ ELSE
+ newSize = size / sizeValue1
+ END IF
+ drawFractal x1, y1, angle + verticalPosition, newSize, 3
+ END IF
+
+ ' Recursively draw child objects if direction is not equal to 2
+ IF direction <> 2 THEN
+ x1 = SIN(angle - pi / 2) * size * 2.5 + xCoord
+ y1 = COS(angle - pi / 2) * size * 2.5 + yCoord
+ ' Change size based on the value of direction
+ IF direction = 4 THEN
+ newSize = size / shapeSize2
+ ELSE
+ newSize = size / shapeSize1
+ END IF
+ drawFractal x1, y1, angle + horizontalPosition, newSize, 4
+ END IF
+
+ ' Recursively draw child objects if direction is not equal to 3
+ IF direction <> 3 THEN
+ x1 = SIN(angle - pi) * size * 2.5 + xCoord
+ y1 = COS(angle - pi) * size * 2.5 + yCoord
+ ' Change size based on the value of direction
+ IF direction = 1 THEN
+ newSize = size / sizeValue2
+ ELSE
+ newSize = size / sizeValue1
+ END IF
+ drawFractal x1, y1, angle + verticalPosition, newSize, 1
+ END IF
+
+ ' Recursively draw child objects if direction is not equal to 4
+ IF direction <> 4 THEN
+ x1 = SIN(angle - pi * 1.5) * size * 2.5 + xCoord
+ y1 = COS(angle - pi * 1.5) * size * 2.5 + yCoord
+ ' Change size based on the value of direction
+ IF direction = 2 THEN
+ newSize = size / shapeSize2
+ ELSE
+ newSize = size / shapeSize1
+ END IF
+ drawFractal x1, y1, angle + horizontalPosition, newSize, 2
+ END IF
+
+SkipDrawing:
+ ' Decrement depth counter
+ recursionDepth = recursionDepth - 1
+END SUB
+
+' Subroutine to print a message on the screen
+SUB printMessage (xCoord!, yCoord!, message$, size!, colr!)
+ ' Check if xCoord is out of bounds
+ IF xCoord < 0 THEN GOTO PrintMessageExit
+ IF xCoord > 319 THEN GOTO PrintMessageExit
+
+ ' Buffer to save a portion of the screen
+ DIM screenBuffer(10000)
+
+ ' Save a portion of the screen to buffer
+ GET (0, 0)-(100, 7), screenBuffer
+
+ ' Print the message on the screen
+ LOCATE 1, 1
+ PRINT message$
+
+ ' Determine the color for the text
+ textColor = colr
+
+ ' Loop through each character in the message
+ FOR x = 0 TO LEN(message$) * 8 - 1
+ ' Loop through each pixel in the character
+ FOR y = 0 TO 7
+ ' Check if the pixel is part of the character
+ IF POINT(x, y) > 0 THEN
+ ' Calculate the coordinates for the enlarged pixel
+ resizedX = x * size + xCoord
+ resizedY = y * size + yCoord
+ ' Draw the pixel based on the color value
+ IF colr > 100 THEN
+ textColor = RND * 4 + 10
+ ' Draw a solid box or outlined box based on the color value
+ IF colr > 200 THEN
+ LINE (resizedX, resizedY)-(resizedX + size - 1, resizedY + size - 1), textColor, B
+ ELSE
+ LINE (resizedX, resizedY)-(resizedX + size - 1, resizedY + size - 1), textColor, BF
+ END IF
+ END IF
+ END IF
+ NEXT y
+ NEXT x
+
+ ' Restore the saved portion of the screen
+ PUT (0, 0), screenBuffer, PSET
+
+PrintMessageExit:
+END SUB
+
+' Subroutine to add a timer element
+SUB addTimerElement (elementIndex!, time!, value!)
+ ' Loop through each element in the timer array
+ FOR index = 0 TO 100
+ ' Check if the current element is empty
+ IF (timerTime(elementIndex, index) = 0) AND (timerValue(elementIndex, index) = 0) THEN GOTO AddTimerElement
+ NEXT index
+
+AddTimerElement:
+ ' Add the new timer element
+ timerTime(elementIndex, index) = time
+ timerValue(elementIndex, index) = value
+END SUB
+
+' Subroutine to initialize the timer system
+SUB initializeTimers
+ ' Store the current time
+ timerLastFrameTime = TIMER
+
+ ' Set the pause duration
+ pauseDuration = 24
+
+ ' Initialize size values
+ addTimerElement 0, 0, 50
+ addTimerElement 0, 7, 10
+ addTimerElement 0, 20, 10
+ addTimerElement 0, 24, 0
+ addTimerElement 0, 1000, 0
+
+ ' Initialize speed values
+ addTimerElement 1, 0, .1
+ addTimerElement 1, 1000, 1000
+
+ ' Initialize X & Y positions
+ addTimerElement 2, 0, 160
+ addTimerElement 3, 0, 100
+ addTimerElement 2, 5, 160
+ addTimerElement 3, 5, 100
+ addTimerElement 2, 9, 280
+ addTimerElement 3, 9, 160
+ addTimerElement 2, 10, 280
+ addTimerElement 3, 10, 160
+ addTimerElement 2, 20, 40
+ addTimerElement 3, 20, 160
+ addTimerElement 2, 1000, 40
+ addTimerElement 3, 1000, 160
+
+ ' Initialize rotation values
+ addTimerElement 4, 0, .1
+ addTimerElement 4, 10, .1
+ addTimerElement 4, 22, 18
+ addTimerElement 4, 2000, 10000
+
+ ' Initialize KHK message X position
+ addTimerElement 5, 0, -1
+ addTimerElement 5, 5, -1
+ addTimerElement 5, 9, 50
+ addTimerElement 5, 10, 30
+ addTimerElement 5, pauseDuration, 30
+ addTimerElement 5, pauseDuration + 2, 321
+
+ ' Initialize ellips Y & radius
+ addTimerElement 6, 0, -1
+ addTimerElement 6, 4, -1
+ addTimerElement 6, 10, 30
+ addTimerElement 6, 1000, 50
+ addTimerElement 7, 0, 1
+ addTimerElement 7, 6, 1
+ addTimerElement 7, 12, 130
+ addTimerElement 7, pauseDuration, 130
+ addTimerElement 7, pauseDuration + 2, 1
+
+ ' Initialize "Infotehnoloogia" message X position
+ addTimerElement 8, 0, 320
+ addTimerElement 8, 11, 320
+ addTimerElement 8, 20, 100
+ addTimerElement 8, pauseDuration, 100
+ addTimerElement 8, pauseDuration + 1, -1
+END SUB
+
+' Subroutine to process the timers
+SUB processTimers
+ ' Store the current time
+ currentTime = TIMER
+
+ ' Calculate the time difference since last frame
+ timeDifference = currentTime - timerLastFrameTime
+
+ ' Update the last frame time
+ timerLastFrameTime = currentTime
+
+ ' Loop through each timer element
+ FOR elementIndex = 0 TO 50
+ ' Calculate the current time and value of each element
+ currentElementTime = timerCurrentTime(elementIndex) + timeDifference
+ currentElementPlace = timerCurrentPlace(elementIndex)
+
+ProcessTimerElement:
+ ' Check if the next timer element is empty
+ IF timerTime(elementIndex, currentElementPlace + 1) = -1 THEN
+ ' Reset the current time and value
+ currentElementTime = 0
+ currentElementPlace = 0
+ END IF
+
+ ' Update the current time and value of each element
+ IF timerTime(elementIndex, currentElementPlace + 1) < currentElementTime THEN
+ ' Check if the next timer element is empty
+ IF timerTime(elementIndex, currentElementPlace + 1) = 0 THEN
+ ' Set the current value to the current timer value
+ timerCurrentValue(elementIndex) = timerValue(elementIndex, currentElementPlace)
+ GOTO UpdateTimerElement
+ END IF
+ ' Move to the next timer element
+ currentElementPlace = currentElementPlace + 1
+ GOTO ProcessTimerElement
+ END IF
+
+ ' Interpolate the current value based on time difference
+ value1 = timerValue(elementIndex, currentElementPlace)
+ time1 = timerTime(elementIndex, currentElementPlace)
+ value2 = timerValue(elementIndex, currentElementPlace + 1)
+ time2 = timerTime(elementIndex, currentElementPlace + 1)
+
+ IF value1 = value2 THEN
+ ' Set the current value to the first value
+ timerCurrentValue(elementIndex) = value1
+ ELSE
+ ' Calculate the time difference and value difference
+ timeDiff1 = time2 - time1
+ timeDiff2 = currentElementTime - time1
+ valueDiff = value2 - value1
+ ' Interpolate the current value
+ timerCurrentValue(elementIndex) = timeDiff2 / timeDiff1 * valueDiff + value1
+ END IF
+
+UpdateTimerElement:
+ ' Update the current place and time of each element
+ timerCurrentPlace(elementIndex) = currentElementPlace
+ timerCurrentTime(elementIndex) = currentElementTime
+ NEXT elementIndex
+END SUB
+
+' Subroutine to turn on the screen
+SUB initializeGraphics
+ ' Set up graphics mode
+ SCREEN 7, , , 1
+
+ ' Draw initial shapes
+ FOR x = 0 TO 160 STEP 15
+ LINE (160 - x - 5, 90 - 5)-(160 + x + 5, 110 + 5), 1, BF
+ LINE (160 - x - 3, 90 - 3)-(160 + x + 3, 110 + 3), 3, BF
+ LINE (160 - x, 90)-(160 + x, 110), 15, BF
+
+ ' Copy screen buffer and clear the screen
+ PCOPY 0, 1
+ CLS
+
+ ' Use sound function to create delay, to limit animation speed
+ SOUND 0, .5
+ NEXT x
+
+ ' Draw additional shapes
+ FOR y = 10 TO 100 STEP 15
+ CLS
+ LINE (160 - x - 5, 90 - y - 5)-(160 + x + 5, 110 + y + 5), 1, BF
+ LINE (160 - x - 3, 90 - y - 3)-(160 + x + 3, 110 + y + 3), 3, BF
+ LINE (160 - x, 90 - y)-(160 + x, 110 + y), 15, BF
+ PCOPY 0, 1
+ SOUND 0, .5
+ NEXT y
+
+ ' Draw zeroes and ones at random locations for decoration
+ FOR counter = 1 TO 25
+ printMessage RND * 250, RND * 180, STR$(INT(RND * 2)), 3, 0
+
+ ' Copy screen buffer and clear the screen
+ PCOPY 0, 1
+
+ ' Use sound function to create delay, to limit animation speed
+ SOUND 0, 1
+ NEXT counter
+
+ ' Buffer to save parts of the screen
+ DIM screenPartBuffer(1 TO 1000)
+
+ ' Shift parts of the screen randomly
+ FOR shiftCounter = 1 TO 30
+ FOR lineCounter = 0 TO 195
+ threshold = ABS(100 - lineCounter)
+
+ ' Check if a random condition is met
+ IF RND * 50 < threshold THEN
+ GET (1, lineCounter)-(318, lineCounter + 1), screenPartBuffer
+
+ ' Shift the screen buffer
+ IF lineCounter > 100 THEN
+ PUT (0, lineCounter), screenPartBuffer, PSET
+ ELSE
+ PUT (2, lineCounter), screenPartBuffer, PSET
+ END IF
+ END IF
+ NEXT lineCounter
+
+ ' Copy screen buffer and clear the screen
+ PCOPY 0, 1
+ NEXT shiftCounter
+END SUB
--- /dev/null
+DECLARE SUB drawFractal (x!, y!, angle AS SINGLE, size AS SINGLE, w AS INTEGER)\r
+' Renders a spiral fractal made up of circles using recursion.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+' Declare shared variables to be used across the program\r
+DIM SHARED depth AS INTEGER\r
+DIM SHARED pi AS SINGLE\r
+\r
+' Define scaling factors for horizontal and vertical directions\r
+DIM SHARED scaleH1 AS SINGLE, scaleH2 AS SINGLE, scaleV1 AS SINGLE, scaleV2 AS SINGLE\r
+DIM SHARED hp AS SINGLE, vp AS SINGLE\r
+\r
+' Initialize constants\r
+pi = 3.14159\r
+\r
+SCREEN 12 ' Set the screen mode to 12 for better graphics quality\r
+\r
+' Define scaling factors and direction variables\r
+scaleV1 = 5 ' Vertical scale factor for one direction\r
+scaleV2 = 2 ' Vertical scale factor for another direction\r
+vp = .2 ' Vertical angle increment\r
+\r
+scaleH1 = 2 ' Horizontal scale factor for one direction\r
+scaleH2 = 1.4 ' Horizontal scale factor for another direction\r
+hp = .2 ' Horizontal angle increment\r
+\r
+' Start the fractal drawing process from the center of the screen\r
+drawFractal 320, 240, pi - .9, 50, 0\r
+\r
+' Wait for user input to exit the program gracefully\r
+a$ = INPUT$(1)\r
+SYSTEM ' Terminate the program\r
+\r
+SUB drawFractal (x, y, angle AS SINGLE, size AS SINGLE, w AS INTEGER)\r
+ depth = depth + 1 ' Increment the recursion depth\r
+\r
+ IF size < .2 THEN GOTO 1 ' Base case for recursion termination\r
+\r
+ ' Determine color based on the current depth\r
+ IF depth MOD 2 = 0 THEN\r
+ c = 15 ' White\r
+ ELSE\r
+ c = 10 ' Light green\r
+ END IF\r
+\r
+ CIRCLE (x, y), size, c ' Draw a circle at the current position and size with specified color\r
+ PAINT (x, y), c ' Fill the circle to create a solid shape\r
+\r
+ ' Recursive calls for different directions based on the parameter w\r
+ IF w <> 1 THEN\r
+ ' Calculate new coordinates after rotating angle + vp degrees\r
+ x1 = SIN(angle) * size * 2.5 + x\r
+ y1 = COS(angle) * size * 2.5 + y\r
+\r
+ ' Determine scaling factor based on the direction\r
+ IF w = 3 THEN\r
+ newSize = size / scaleV2\r
+ ELSE\r
+ newSize = size / scaleV1\r
+ END IF\r
+\r
+ drawFractal x1, y1, angle + vp, newSize, 3 ' Recursive call to the same subroutine with updated parameters\r
+ END IF\r
+\r
+ IF w <> 2 THEN\r
+ ' Calculate new coordinates after rotating angle - pi/2 degrees\r
+ x1 = SIN(angle - .5 * pi) * size * 2.5 + x\r
+ y1 = COS(angle - .5 * pi) * size * 2.5 + y\r
+\r
+ ' Determine scaling factor based on the direction\r
+ IF w = 4 THEN\r
+ newSize = size / scaleH2\r
+ ELSE\r
+ newSize = size / scaleH1\r
+ END IF\r
+\r
+ drawFractal x1, y1, angle + hp, newSize, 4 ' Recursive call to the same subroutine with updated parameters\r
+ END IF\r
+\r
+ IF w <> 3 THEN\r
+ ' Calculate new coordinates after rotating angle - pi degrees\r
+ x1 = SIN(angle - pi) * size * 2.5 + x\r
+ y1 = COS(angle - pi) * size * 2.5 + y\r
+\r
+ ' Determine scaling factor based on the direction\r
+ IF w = 1 THEN\r
+ newSize = size / scaleV2\r
+ ELSE\r
+ newSize = size / scaleV1\r
+ END IF\r
+\r
+ drawFractal x1, y1, angle + vp, newSize, 1 ' Recursive call to the same subroutine with updated parameters\r
+ END IF\r
+\r
+ IF w <> 4 THEN\r
+ ' Calculate new coordinates after rotating angle - pi*3/2 degrees\r
+ x1 = SIN(angle - 1.5 * pi) * size * 2.5 + x\r
+ y1 = COS(angle - 1.5 * pi) * size * 2.5 + y\r
+\r
+ ' Determine scaling factor based on the direction\r
+ IF w = 2 THEN\r
+ newSize = size / scaleH2\r
+ ELSE\r
+ newSize = size / scaleH1\r
+ END IF\r
+\r
+ drawFractal x1, y1, angle + hp, newSize, 2 ' Recursive call to the same subroutine with updated parameters\r
+ END IF\r
+\r
+1\r
+ depth = depth - 1 ' Decrement recursion depth after all recursive calls are made\r
+END SUB\r
+\r
--- /dev/null
+' Animated fractal that is made of size shifting squares.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.04, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+\r
+DECLARE SUB drawFractal (x!, y!, s!)\r
+DIM SHARED recursionDepth\r
+DIM SHARED factor1, factor2, factor3, factor4\r
+SCREEN 7, , , 1\r
+\r
+recursionDepth = 1\r
+\r
+1\r
+frameCount = frameCount + 1\r
+factor1 = SIN(frameCount / 19) * 1 + 3\r
+factor2 = SIN(frameCount / 12) * 1 + 3\r
+factor3 = SIN(frameCount / 17) * 1 + 3\r
+factor4 = SIN(frameCount / 22) * 1 + 3\r
+PCOPY 0, 1\r
+CLS\r
+drawFractal 160, 100, 40\r
+SOUND 0, .4\r
+userInput$ = INKEY$\r
+IF userInput$ <> "" THEN SYSTEM\r
+GOTO 1\r
+\r
+SUB drawFractal (x, y, s)\r
+ IF s > 1 THEN\r
+ recursionDepth = recursionDepth + 1\r
+ LINE (x - s, y - s)-(x + s, y + s), recursionDepth, BF\r
+ drawFractal x - s, y - s, s / factor1\r
+ drawFractal x + s, y - s, s / factor2\r
+ drawFractal x + s, y + s, s / factor3\r
+ drawFractal x - s, y + s, s / factor4\r
+ recursionDepth = recursionDepth - 1\r
+ END IF\r
+END SUB\r
--- /dev/null
+DECLARE SUB drawFractalPattern (centerX!, centerY!, size!)\r
+DIM SHARED currentColor ' This variable holds the color of the fractal and is accessible within submodules.\r
+\r
+' Program renders fractal that is made from squares.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+\r
+\r
+' Set the screen to high-resolution graphics mode.\r
+SCREEN 12\r
+\r
+' Initialize the fractal color.\r
+currentColor = 10\r
+\r
+' Draw a single fractal pattern at the center of the screen with a size of 127.\r
+drawFractalPattern 320, 240, 127\r
+\r
+' Loop to create a delay using the SOUND command.\r
+FOR iterationCounter = 1 TO 50\r
+ SOUND 0, 1 ' This creates a short delay by generating an inaudible sound.\r
+NEXT iterationCounter\r
+\r
+' Clear the screen to prepare for the next set of drawings.\r
+CLS\r
+\r
+' Loop to draw a series of fractal patterns with varying sizes and random colors.\r
+FOR iterationCounter = 1 TO 128 STEP 5\r
+ currentColor = RND * 7 + 7 ' Set the fractal color to a random value between 7 and 14.\r
+ drawFractalPattern 320, 240, iterationCounter ' Draw the fractal pattern with the current size.\r
+NEXT iterationCounter\r
+\r
+' Loop to create another delay using the SOUND command.\r
+FOR iterationCounter = 1 TO 50\r
+ SOUND 0, 1 ' This creates a short delay by generating an inaudible sound.\r
+NEXT iterationCounter\r
+\r
+' Subroutine to draw a fractal pattern using recursion.\r
+SUB drawFractalPattern (centerX, centerY, size)\r
+ ' Check if the size is greater than or equal to 1 to continue drawing.\r
+ IF size >= 1 THEN\r
+ ' Draw a square (box) centered at (centerX, centerY) with the current color.\r
+ LINE (centerX - size, centerY - size)-(centerX + size, centerY + size), currentColor, B\r
+\r
+ ' Recursively call the subroutine to draw smaller fractal patterns at the corners of the current square.\r
+ drawFractalPattern centerX - size, centerY - size, size / 2.3\r
+ drawFractalPattern centerX + size, centerY - size, size / 2.3\r
+ drawFractalPattern centerX + size, centerY + size, size / 2.3\r
+ drawFractalPattern centerX - size, centerY + size, size / 2.3\r
+ END IF\r
+END SUB\r
--- /dev/null
+' Animated tree fractal.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.04, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+DECLARE SUB generateFractal (x!, y!, s!)\r
+\r
+DECLARE SUB generateArt (x!, y!, s!)\r
+DIM SHARED modifier1, modifier2, modifier3\r
+DIM SHARED vector1X, vector1Y\r
+DIM SHARED vector2X, vector2Y\r
+DIM SHARED vector3X, vector3Y\r
+SCREEN 7, , , 1\r
+\r
+1\r
+frame = frame + 1\r
+modifier1 = SIN(frame / 19) + 3\r
+modifier2 = SIN(frame / 12) + 3\r
+modifier3 = SIN(frame / 17) + 3\r
+\r
+vector1X = SIN(frame / 13) / 3 + 1\r
+vector1Y = SIN(frame / 18) / 3 + 1\r
+\r
+vector2X = SIN(frame / 20) / 3 + 1\r
+vector2Y = SIN(frame / 28) / 3 + 1\r
+\r
+vector3X = SIN(frame / 31) / 3 + 1\r
+vector3Y = SIN(frame / 24) / 3 + 1\r
+\r
+PCOPY 0, 1\r
+CLS\r
+generateFractal 160, 180, 80\r
+SOUND 0, .5\r
+inputKey$ = INKEY$\r
+IF inputKey$ <> "" THEN SYSTEM\r
+GOTO 1\r
+\r
+SUB generateFractal (x, y, s)\r
+ IF s > 1 THEN\r
+ LINE (x, y)-(x - s * vector1X, y - s * vector1Y), 15\r
+ LINE (x, y)-(x + s * vector2X, y - s * vector2Y), 15\r
+ LINE (x, y)-(x, y - s), 15\r
+ generateFractal x - s * vector1X, y - s * vector1Y, s / modifier1\r
+ generateFractal x + s * vector2X, y - s * vector2Y, s / modifier2\r
+ generateFractal x, y - s, s / modifier3\r
+ END IF\r
+END SUB\r
+\r
--- /dev/null
+#+TITLE: Fractals
+#+LANGUAGE: en
+#+LATEX_HEADER: \usepackage[margin=1.0in]{geometry}
+#+LATEX_HEADER: \usepackage{parskip}
+#+LATEX_HEADER: \usepackage[none]{hyphenat}
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+ .flex-center {
+ display: flex; /* activate flexbox */
+ justify-content: center; /* horizontally center anything inside */
+ }
+
+ .flex-center video {
+ width: min(90%, 1000px); /* whichever is smaller wins */
+ height: auto; /* preserve aspect ratio */
+ }
+
+ .responsive-img {
+ width: min(100%, 1000px);
+ height: auto;
+ }
+</style>
+#+end_export
+
+
+* Fractal circles
+
+This QBasic program generates a visually captivating spiral fractal
+composed of circles. It employs a recursive algorithm to create
+intricate patterns that can inspire those interested in fractal
+geometry, recursive programming, and graphical design.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:fractal circles.bas][file:fractal%20circles.png]]
+
+- Color and Depth :: The color of each circle alternates based on the
+ recursion depth, adding visual complexity to the fractal.
+- Termination Condition :: The recursion terminates when the size of
+ the circles becomes too small, ensuring the program doesn't run
+ indefinitely.
+
+[[file:fractal circles.bas][Source code]]
+
+* Fractal circles animated
+
+This QBasic program creates an animated fractal composed of circles,
+demonstrating an engaging visual effect. The program uses a timer
+system to control the animation's progression.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay class="flex-center">
+ <source src="fractal circles animated.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+[[file:fractal circles animated.bas][Source code]]
+
+* Fractal of squares
+
+This QBasic program generates and displays a fractal pattern composed of squares.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:fractal squares.bas][file:fractal%20squares,%201.png]]
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:fractal squares.bas][file:fractal%20squares,%202.png]]
+
+* Fractal of squares animated
+
+This QBasic program generates an animated fractal pattern composed of
+size-shifting squares. The animation creates a visually captivating
+display by continuously redrawing the fractal with varying parameters,
+resulting in a dynamic and ever-changing geometric pattern.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay class="flex-center">
+ <source src="fractal squares animated.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:fractal squares animated.bas][Source code]]
+
+* Fractal of trees
+
+QBasic program that generates a visually appealing fractal tree
+animation. The program creates a dynamic fractal pattern that
+resembles a tree, with branches that grow and change over time.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay class="flex-center">
+ <source src="fractal trees.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+
+[[file:fractal trees.bas][Source code]]
--- /dev/null
+' 2D graphics demonstration.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+\r
+\r
+SCREEN 13\r
+\r
+LOCATE 1, 1\r
+PRINT " Hello friend!"\r
+\r
+' Loop through each pixel in the screen to create an enlarged version of the current screen\r
+FOR x = 0 TO 160\r
+ FOR y = 0 TO 32\r
+ colorVal = POINT(x, y)\r
+ x1 = x * 2\r
+ y1 = y * 2 + 90\r
+ LINE (x1, y1)-(x1 + 1, y1 + 1), colorVal, BF\r
+ NEXT y\r
+NEXT x\r
+\r
+LOCATE 1, 1\r
+PRINT " "\r
+\r
+' Draw a series of circles along the screen\r
+FOR x = 0 TO 320\r
+ CIRCLE (x, 130), 10, 9\r
+ SOUND 0, .1\r
+NEXT x\r
+\r
+' Draw horizontal lines creating an X pattern\r
+FOR y = 0 TO 70\r
+ SOUND 0, .1\r
+ LINE (160 - 70 + y, y)-(160 + 70 - y, y), 9\r
+NEXT y\r
+\r
+\r
--- /dev/null
+' Example slideshow presentation. Includes animated transitions.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2001, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+\r
+DECLARE SUB displaySlide1 ()\r
+DECLARE SUB setink (a!)\r
+DECLARE SUB inke (a$)\r
+DECLARE SUB mkjuku (x!, y!, a!, c!)\r
+DECLARE SUB pr (x!, y!, s!, c!, n!, a$)\r
+DECLARE SUB wpr ()\r
+DECLARE SUB displayEffect7 ()\r
+DECLARE SUB displaySlide6 ()\r
+DECLARE SUB displaySlide5 ()\r
+DECLARE SUB pal4 (c, r!, g!, b!)\r
+DECLARE SUB displaySlide4 ()\r
+DECLARE SUB inpur ()\r
+DECLARE SUB displayEffect5 ()\r
+DECLARE SUB displaySlide3 ()\r
+DECLARE SUB prin (x1!, y1!, s!, c, a$)\r
+DECLARE SUB pal3 (r!, g!, b!)\r
+DECLARE SUB mkfont ()\r
+DECLARE SUB pal2 (r!, g!, b!)\r
+DECLARE SUB box1 (x1!, y1!, x2!, y2!, c!)\r
+DECLARE SUB mkback ()\r
+DECLARE SUB displaySlide2 ()\r
+DECLARE SUB resiz ()\r
+DECLARE SUB pri (x!, y!, a$, c!)\r
+DECLARE SUB deca (xs!, ys!, fx!, fy!)\r
+DECLARE SUB box (xs!, ys!)\r
+DECLARE SUB displayEffect4 ()\r
+DECLARE SUB displayEffect3 ()\r
+DECLARE SUB displayEffect2 ()\r
+DECLARE SUB displayEffect1 ()\r
+DECLARE SUB start ()\r
+DECLARE SUB sc1 ()\r
+DECLARE SUB pal (x!)\r
+DIM SHARED fontt(0 TO 7, 0 TO 7, 0 TO 255)\r
+DIM SHARED tim\r
+DIM SHARED tim2\r
+DIM SHARED jas(1 TO 500)\r
+DIM SHARED pii\r
+DIM SHARED tmr\r
+DIM SHARED ink\r
+DIM SHARED tim$\r
+\r
+start\r
+\r
+CLS\r
+'GOTO 8\r
+\r
+displaySlide1\r
+displayEffect1\r
+displayEffect2\r
+displayEffect3\r
+\r
+displayEffect4\r
+displaySlide2\r
+displaySlide4\r
+8\r
+displaySlide5\r
+displaySlide6\r
+\r
+displayEffect7\r
+displaySlide3\r
+displayEffect5\r
+\r
+SYSTEM\r
+\r
+SUB box (xs, ys)\r
+' Draws a 3D style box border at the top-left corner of the screen\r
+' Parameters:\r
+' xs - width of the box\r
+' ys - height of the box\r
+\r
+LINE (0, 186)-(0 + xs, 186 - ys), 15, B\r
+LINE (1, 187)-(-1 + xs, 187 - ys), 25, B\r
+LINE (2, 188)-(-2 + xs, 188 - ys), 15, B\r
+PSET (0, 188), 0\r
+PSET (0 + xs, 188), 0\r
+PSET (0, 186 - ys), 0\r
+PSET (0 + xs, 186 - ys), 0\r
+END SUB\r
+\r
+DEFINT Z\r
+SUB box1 (x1, y1, x2, y2, c)\r
+\r
+' Draws a shaded box with a 3D effect\r
+' Parameters:\r
+' x1, y1 - top-left corner coordinates\r
+' x2, y2 - bottom-right corner coordinates\r
+' c - type of shading\r
+\r
+IF c = 1 THEN za = 51 ELSE za = 102\r
+\r
+FOR zy = y1 + 7 TO y2 + 7\r
+FOR zx = x1 + 7 TO x2 + 7\r
+zc = POINT(zx, zy)\r
+IF zc < 51 THEN\r
+IF zc > 25 THEN zc = 50 - zc\r
+zc = zc / 2\r
+PSET (zx, zy), zc\r
+END IF\r
+NEXT zx\r
+NEXT zy\r
+\r
+FOR zy = y1 TO y2\r
+FOR zx = x1 TO x2\r
+zc = POINT(zx, zy)\r
+IF zc > 50 THEN zc = zc - 51\r
+PSET (zx, zy), zc + za\r
+NEXT zx\r
+NEXT zy\r
+\r
+END SUB\r
+\r
+DEFSNG Z\r
+SUB deca (xs, ys, fx, fy)\r
+LINE (0, 185 - ys)-(xs, 185 - ys + fy), 0, BF\r
+LINE (xs, 18 - ys)-(xs - fx, 188), 0, BF\r
+xs = xs - fx\r
+ys = ys - fy\r
+box xs, ys\r
+END SUB\r
+\r
+SUB displayEffect1\r
+\r
+pal 3\r
+\r
+DIM buf1(1 TO 10000)\r
+DIM buf2(1 TO 10000)\r
+DIM buf3(1 TO 400)\r
+\r
+FOR a = 1 TO 320\r
+buf3(a) = 200\r
+NEXT a\r
+\r
+b = 0\r
+c1 = 1\r
+setink 10\r
+1\r
+c1 = c1 + 1\r
+IF c1 > 50 THEN c1 = 1\r
+LINE (0, 40)-(0, 43), c1\r
+c2 = c1\r
+IF c2 > 25 THEN c2 = 50 - c2\r
+c2 = c2 - 5\r
+IF c2 < 0 THEN c2 = 0\r
+PSET (0, 39), c2\r
+PSET (0, 44), c2\r
+LINE (319, 76)-(319, 79), c1\r
+PSET (319, 75), c2\r
+PSET (319, 80), c2\r
+\r
+GET (0, 39)-(318, 44), buf1(1)\r
+PUT (1, 39), buf1(1), PSET\r
+\r
+GET (1, 75)-(319, 80), buf1(1)\r
+PUT (0, 75), buf1(1), PSET\r
+\r
+b = b + 1\r
+buf3(271) = SIN(b / 50 + 1.57) * 30 + 160\r
+FOR x = 50 TO 270\r
+PSET (x, buf3(x) - 1), 0\r
+IF x > 50 THEN\r
+PSET (x, buf3(x)), 15\r
+PSET (x, buf3(x) + 1), 20\r
+PSET (x, buf3(x) + 2), 25\r
+END IF\r
+buf3(x) = buf3(x + 1)\r
+NEXT x\r
+\r
+a = 50\r
+FOR x = 65 + 18 TO 270 STEP 40\r
+a = a + 1\r
+IF buf3(x - 1) < 190 THEN\r
+mkjuku x, buf3(x - 1) - 27, x, 0\r
+mkjuku x, buf3(x) - 27, x, a\r
+END IF\r
+NEXT x\r
+\r
+inke a$\r
+SOUND 0, .4\r
+IF a$ = "" THEN GOTO 1\r
+\r
+END SUB\r
+\r
+SUB displayEffect2\r
+\r
+FOR a = 1 TO 30\r
+e = 0\r
+c = (3.8 * (30 - a)) / 30\r
+\r
+FOR f = 0 TO 50\r
+IF f < 25 THEN e = e + 4 ELSE e = e - c\r
+OUT &H3C8, f\r
+OUT &H3C9, e / 4\r
+OUT &H3C9, e / 1.9\r
+OUT &H3C9, e / 3\r
+NEXT f\r
+\r
+FOR b = 1 TO 3\r
+SOUND 0, .3\r
+NEXT b\r
+NEXT a\r
+\r
+FOR a = 20 TO 0 STEP -1\r
+b = (a * 4) / 20\r
+e = 0\r
+FOR f = 0 TO 60\r
+IF f < 25 THEN e = e + b\r
+OUT &H3C8, f\r
+OUT &H3C9, e / 4\r
+OUT &H3C9, e / 1.9\r
+OUT &H3C9, e / 3\r
+NEXT f\r
+\r
+FOR b = 1 TO 2\r
+SOUND 0, .3\r
+NEXT b\r
+\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB displayEffect3\r
+SCREEN 7\r
+SCREEN 7, , , 1\r
+\r
+OUT &H3C8, 1\r
+OUT &H3C9, 64 / 4\r
+OUT &H3C9, 64 / 1.9\r
+OUT &H3C9, 64 / 3\r
+\r
+b = 2\r
+c = .01\r
+2\r
+x = x + 1\r
+y = y + 1\r
+c = c + .01\r
+b = b + c\r
+\r
+FOR a = 0 TO 160 STEP b\r
+LINE (160 + a, 0)-(160 + a, 199), 1\r
+LINE (160 - a, 0)-(160 - a, 199), 1\r
+LINE (0, 100 + a)-(319, 100 + a), 1\r
+LINE (0, 100 - a)-(319, 100 - a), 1\r
+NEXT a\r
+\r
+PCOPY 0, 1\r
+CLS\r
+SOUND 0, .4\r
+IF b < 50 THEN GOTO 2\r
+\r
+SCREEN 13\r
+pal 2\r
+\r
+FOR a = 0 TO 160 STEP b\r
+LINE (160 + a, 0)-(160 + a, 199), 25\r
+LINE (160 - a, 0)-(160 - a, 199), 25\r
+LINE (0, 100 + a)-(319, 100 + a), 25\r
+LINE (0, 100 - a)-(319, 100 - a), 25\r
+NEXT a\r
+\r
+resiz\r
+pal 3\r
+\r
+pri 11, 8, "-* A U T H O R S *-", 55\r
+pri 10, 11, CHR$(254) + " John Doe", 55\r
+pri 10, 13, CHR$(254) + " Jane Doe", 55\r
+pri 10, 15, CHR$(254) + " Anonymous", 55\r
+pri 20, 19, "year 2001", 55\r
+\r
+inpur\r
+CLS\r
+END SUB\r
+\r
+SUB displayEffect4\r
+pal 2\r
+xs = 317\r
+ys = 185\r
+box xs, ys\r
+tey = 20\r
+\r
+DIM buf4(1 TO 10000)\r
+\r
+b = 0\r
+setink 10\r
+COLOR 25\r
+4\r
+b = b + 1\r
+\r
+SELECT CASE b\r
+CASE 50 TO 200\r
+deca xs, ys, 1, 1\r
+\r
+CASE 201\r
+'pal4 255, 63, 45, 0\r
+'prin 10, tey, 2, 255, "Sources:"\r
+tey = tey + 20\r
+\r
+CASE 290\r
+pal4 254, 20, 20, 63\r
+prin 70, tey, 7, 254, "TEST"\r
+tey = tey + 60\r
+\r
+CASE 350\r
+pal4 254, 20, 20, 63\r
+prin 100, tey, 2, 254, "www.12345.com"\r
+tey = tey + 20\r
+\r
+CASE 400\r
+pal4 254, 20, 20, 63\r
+prin 100, tey, 2, 254, CHR$(16) + "Subject 1"\r
+tey = tey + 10\r
+\r
+END SELECT\r
+\r
+FOR a = 2 TO (xs - 5) / 8\r
+LOCATE 23, a\r
+PRINT CHR$(RND * 1 + 48)\r
+NEXT a\r
+\r
+FOR x = 3 TO xs - 3 STEP 8\r
+GET (x, 183 - ys + 14)-(x + 7, 183), buf4(1)\r
+PUT (x, 183 - ys + 6), buf4(1), PSET\r
+NEXT x\r
+\r
+inke a$\r
+\r
+IF a$ <> "" THEN GOTO 3\r
+wpr\r
+GOTO 4\r
+\r
+3\r
+END SUB\r
+\r
+SUB displayEffect5\r
+DIM buf(1 TO 5000)\r
+\r
+FOR a = 1 TO 1000\r
+x = RND * 298 + 1\r
+y = RND * 178 + 1\r
+GET (x, y)-(x + 19, y + 19), buf(1)\r
+IF RND * 100 < 50 THEN x = x + 1 ELSE x = x - 1\r
+IF RND * 100 < 50 THEN y = y + 1\r
+PUT (x, y), buf(1), PSET\r
+SOUND 0, .05\r
+NEXT a\r
+\r
+FOR a = 0 TO 100\r
+LINE (0, a)-(319, a), 0\r
+LINE (0, 200 - a)-(319, 200 - a), 0\r
+SOUND 0, .4\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB displayEffect7\r
+pal 4\r
+mkback\r
+\r
+pal2 0, 0, 32\r
+box1 3, 3, 300, 50, 1\r
+\r
+pal4 255, 50, 50, 0\r
+prin 10, 10, 2, 255, "Et dolore magna"\r
+prin 50, 30, 1, 255, "www.utenimadminim.org"\r
+\r
+pal3 20, 32, 63\r
+box1 20, 40, 290, 180, 2\r
+\r
+pal4 254, 63, 45, 0\r
+b = 25\r
+prin 40, 60, 1, 254, CHR$(254) + " Ut enim ad minim veniam"\r
+a = b\r
+prin 40, 60 + a, 1, 254, CHR$(254) + " Quis nostrud exercitation"\r
+a = a + b\r
+prin 40, 60 + a, 1, 254, CHR$(254) + " Laboris nisi ut aliquip ex"\r
+a = a + b\r
+prin 40, 60 + a, 1, 254, CHR$(254) + " Sed ut perspiciatis unde"\r
+\r
+inpur\r
+\r
+END SUB\r
+\r
+SUB displaySlide1\r
+\r
+pal 2\r
+LOCATE 1, 1\r
+COLOR 1\r
+PRINT "HEADER"\r
+\r
+FOR x = 0 TO 80\r
+FOR y = 0 TO 16\r
+c = POINT(x, y)\r
+IF c > 0 THEN c1 = 50 ELSE c1 = 0\r
+LINE (x * 5 + 35, y * 3 + 50)-(x * 5 + 4 + 35, y * 3 + 2 + 50), c1, BF\r
+NEXT y\r
+NEXT x\r
+\r
+LOCATE 1, 1\r
+PRINT " "\r
+\r
+FOR y = 30 TO 80\r
+FOR x = 0 TO 319\r
+c = POINT(x, y)\r
+c1 = (c1 * 1 + c) / 2\r
+PSET (x, y), c1\r
+NEXT x\r
+NEXT y\r
+\r
+FOR x = 0 TO 319\r
+FOR y = 30 TO 80\r
+c = POINT(x, y)\r
+c1 = (c1 * 1 + c) / 2\r
+PSET (x, y), c1\r
+NEXT y\r
+NEXT x\r
+\r
+FOR y = 30 TO 80\r
+FOR x = 319 TO 0 STEP -1\r
+c = POINT(x, y)\r
+c1 = (c1 * 1 + c) / 2\r
+PSET (x, y), c1\r
+NEXT x\r
+NEXT y\r
+\r
+FOR x = 0 TO 319\r
+FOR y = 80 TO 30 STEP -1\r
+c = POINT(x, y)\r
+c1 = (c1 * 1 + c) / 2\r
+PSET (x, y), c1\r
+NEXT y\r
+NEXT x\r
+\r
+END SUB\r
+\r
+SUB displaySlide2\r
+\r
+CLS\r
+pal 4\r
+mkback\r
+\r
+pal2 40, 64, 63\r
+pal3 0, 0, 0\r
+\r
+box1 30, 30, 290, 170, 1\r
+\r
+prin 65, 50, 3, 0, "Goal:"\r
+\r
+prin 40, 100, 1, 0, CHR$(254) + " Random text"\r
+prin 40, 108, 1, 0, " goes here to test"\r
+prin 40, 116, 1, 0, " text layout."\r
+prin 40, 130, 1, 0, CHR$(254) + " Testing 123."\r
+\r
+inpur\r
+\r
+END SUB\r
+\r
+SUB displaySlide3\r
+mkback\r
+\r
+pal2 64, 64, 0\r
+box1 30, 30, 290, 150, 1\r
+\r
+prin 57, 50, 3, 0, "Thank you"\r
+prin 45, 74, 3, 0, " for"\r
+prin 45, 98, 3, 0, "attention"\r
+inpur\r
+\r
+END SUB\r
+\r
+SUB displaySlide4\r
+\r
+pal 4\r
+mkback\r
+\r
+pal2 0, 0, 32\r
+box1 3, 3, 260, 50, 1\r
+\r
+pal4 255, 50, 50, 0\r
+prin 10, 10, 2, 255, "Random header"\r
+prin 50, 30, 1, 255, "www.randomsite.org"\r
+\r
+pal3 10, 20, 0\r
+box1 20, 40, 290, 180, 2\r
+\r
+pal4 254, 63, 45, 0\r
+\r
+b = 25\r
+prin 40, 60, 1, 254, CHR$(254) + " Lorem ipsum dolor sit amet,"\r
+a = b\r
+prin 40, 60 + a, 1, 254, CHR$(254) + " consectetur adipiscing elit,"\r
+a = a + b\r
+prin 40, 60 + a, 1, 254, CHR$(254) + " sed do eiusmod"\r
+a = a + b\r
+prin 40, 60 + a, 1, 254, CHR$(254) + " tempor incididunt ut labore"\r
+\r
+inpur\r
+\r
+END SUB\r
+\r
+SUB displaySlide5\r
+pal 4\r
+mkback\r
+\r
+pal2 0, 0, 32\r
+box1 3, 3, 300, 50, 1\r
+\r
+pal4 255, 50, 50, 0\r
+prin 10, 10, 2, 255, "Totam rem aperiam"\r
+prin 50, 30, 1, 255, "www.randomurl.org"\r
+\r
+pal3 20, 32, 63\r
+box1 20, 40, 290, 180, 2\r
+\r
+pal4 254, 63, 45, 0\r
+b = 25\r
+prin 40, 60, 1, 254, CHR$(254) + " Nemo enim ipsam voluptatem"\r
+a = b\r
+prin 40, 60 + a, 1, 254, CHR$(254) + " Sed quia consequuntur"\r
+a = a + b\r
+prin 40, 60 + a, 1, 254, CHR$(254) + " Magni dolores eos"\r
+a = a + b\r
+prin 40, 60 + a, 1, 254, CHR$(254) + " Qui ratione voluptatem"\r
+\r
+inpur\r
+\r
+END SUB\r
+\r
+SUB displaySlide6\r
+pal 4\r
+mkback\r
+\r
+pal2 0, 0, 32\r
+box1 3, 3, 300, 50, 1\r
+\r
+pal4 255, 50, 50, 0\r
+prin 10, 10, 2, 255, "H E L L O !"\r
+prin 50, 30, 1, 255, "www.hello.net"\r
+\r
+pal3 30, 20, 10\r
+box1 20, 40, 290, 180, 2\r
+\r
+pal4 254, 63, 45, 0\r
+b = 25\r
+prin 40, 60, 1, 254, CHR$(254) + " Quis autem vel eum"\r
+a = b\r
+prin 40, 60 + a, 1, 254, CHR$(254) + " Iure reprehenderit qui"\r
+a = a + b\r
+prin 40, 60 + a, 1, 254, CHR$(254) + " In ea voluptate velit"\r
+a = a + b\r
+prin 40, 60 + a, 1, 254, CHR$(254) + " Esse quam nihil molestiae"\r
+\r
+inpur\r
+\r
+END SUB\r
+\r
+SUB inke (a$)\r
+IF tim$ <> TIME$ THEN\r
+ink = ink - 1\r
+tim$ = TIME$\r
+END IF\r
+IF (ink <= 0) AND (tmr = 1) THEN a$ = " " ELSE a$ = ""\r
+IF INKEY$ <> "" THEN a$ = " "\r
+END SUB\r
+\r
+SUB inpur\r
+setink 10\r
+11\r
+inke a$\r
+IF a$ = "" THEN GOTO 11\r
+END SUB\r
+\r
+DEFINT A-Z\r
+SUB mkback\r
+CLS\r
+lm1 = 0\r
+lm2 = 50\r
+\r
+s = 2 ^ 7\r
+\r
+7\r
+s = s \ 2\r
+\r
+FOR y = 0 TO 199 STEP s\r
+FOR x = 0 TO 319 STEP s\r
+\r
+c1 = POINT(x, y)\r
+c2 = POINT(x + s, y)\r
+c3 = POINT(x, y + s)\r
+c4 = POINT(x + s, y + s)\r
+\r
+sp = s \ 2\r
+\r
+c5 = (c1 + c2 + c3 + c4) / 4 + RND * s - sp\r
+IF c5 > lm2 THEN c5 = lm2\r
+IF c5 < lm1 THEN c5 = lm1\r
+\r
+c6 = (c2 + c4) / 2 + RND * s - sp\r
+IF c6 > lm2 THEN c6 = lm2\r
+IF c6 < lm1 THEN c6 = lm1\r
+\r
+c7 = (c3 + c4) / 2 + RND * s - sp\r
+IF c7 > lm2 THEN c7 = lm2\r
+IF c7 < lm1 THEN c7 = lm1\r
+\r
+IF INT(RND * 30) = 2 THEN c5 = 50\r
+PSET (x + sp, y + sp), c5\r
+PSET (x + s, y + sp), c6\r
+PSET (x + sp, y + s), c7\r
+\r
+NEXT x\r
+NEXT y\r
+IF s > 2 THEN GOTO 7\r
+END SUB\r
+\r
+DEFSNG A-Z\r
+SUB mkfont\r
+SCREEN 13\r
+FOR a = 0 TO 255\r
+LOCATE 1, 1\r
+IF a <> 7 THEN PRINT CHR$(a)\r
+\r
+FOR y = 0 TO 7\r
+FOR x = 0 TO 7\r
+fontt(x, y, a) = POINT(x, y)\r
+NEXT x\r
+NEXT y\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB mkjuku (x, y, a, c)\r
+jas(a) = jas(a) + .08\r
+IF jas(a) > 30000 THEN jas(a) = 0\r
+b = jas(a)\r
+IF c = 0 THEN b = jas(a) - .08\r
+x1 = x + COS(b) * 10\r
+y1 = y + SIN(b) * 5 + 20\r
+\r
+x2 = x + COS(b) * 5 + 2\r
+y2 = y + SIN(b) * 3 + 10\r
+\r
+x3 = x + COS(b + 1) * 2\r
+y3 = y + SIN(b + 1) * 2 + 2\r
+\r
+LINE (x2, y2)-(x1, y1), c\r
+LINE (x2, y2)-(x3, y3), c\r
+\r
+x1 = x + COS(b + pii) * 10\r
+y1 = y + SIN(b + pii) * 5 + 20\r
+\r
+x2 = x + COS(b + pii) * 5 + 2\r
+y2 = y + SIN(b + pii) * 3 + 10\r
+\r
+LINE (x2, y2)-(x1, y1), c\r
+LINE (x2, y2)-(x3, y3), c\r
+\r
+x4 = x + COS(b + 1.2) * 3 - 1\r
+y4 = y + SIN(b + 1.2) * 1 - 10\r
+\r
+LINE (x4, y4)-(x3, y3), c\r
+\r
+x5 = x + COS(b + .5) * 13 - 3\r
+y5 = y + SIN(b + .5) * 2 + 1\r
+\r
+x6 = x + COS(b + .5) * 15 - 1\r
+y6 = y + SIN(b + .5) * 3 + 4\r
+\r
+LINE (x5, y5)-(x4, y4), c\r
+LINE (x5, y5)-(x6, y6), c\r
+\r
+x5 = x + COS(b + pii) * 13 - 3\r
+y5 = y + SIN(b + pii) * 2 + 1\r
+\r
+x6 = x + COS(b + pii) * 15 - 1\r
+y6 = y + SIN(b + pii) * 3 + 4\r
+\r
+LINE (x5, y5)-(x4, y4), c\r
+LINE (x5, y5)-(x6, y6), c\r
+\r
+x7 = x + COS(b + 1.2) * 2\r
+y7 = y + SIN(b + 1.2) * 1 - 14\r
+\r
+LINE (x7, y7 + 2)-(x4, y4), c\r
+\r
+CIRCLE (x7, y7), 3, c\r
+\r
+\r
+\r
+END SUB\r
+\r
+SUB pal (x)\r
+SELECT CASE x\r
+CASE 1\r
+\r
+FOR f = 0 TO 25\r
+OUT &H3C8, f\r
+OUT &H3C9, f * 4.1\r
+OUT &H3C9, f * 4.1\r
+OUT &H3C9, f * 4.1\r
+NEXT f\r
+\r
+CASE 2\r
+e = 0\r
+FOR f = 0 TO 50\r
+IF f < 25 THEN e = e + 4 ELSE e = e - 3.8\r
+OUT &H3C8, f\r
+OUT &H3C9, e / 4\r
+OUT &H3C9, e / 1.9\r
+OUT &H3C9, e / 3\r
+NEXT f\r
+CASE 3\r
+\r
+FOR f = 51 TO 60\r
+OUT &H3C8, f\r
+OUT &H3C9, SIN(f) * 30 + 30\r
+OUT &H3C9, SIN(f * 2) * 30 + 30\r
+OUT &H3C9, SIN(f * 3) * 30 + 30\r
+NEXT f\r
+\r
+CASE 4\r
+FOR f = 0 TO 25\r
+OUT &H3C8, f\r
+OUT &H3C9, f * 2.5\r
+OUT &H3C9, f * 2.5\r
+OUT &H3C9, f * 1.5\r
+NEXT f\r
+FOR f = 26 TO 50\r
+OUT &H3C8, f\r
+OUT &H3C9, (50 - f) * 2.5\r
+OUT &H3C9, (50 - f) * 2.5\r
+OUT &H3C9, (50 - f) * 1.5\r
+NEXT f\r
+\r
+END SELECT\r
+\r
+END SUB\r
+\r
+SUB pal2 (r, g, b)\r
+FOR f = 0 TO 25\r
+OUT &H3C8, f + 51\r
+OUT &H3C9, (f * 2.5 + r * 1) / 2\r
+OUT &H3C9, (f * 2.5 + g * 1) / 2\r
+OUT &H3C9, (f * 1.5 + b * 1) / 2\r
+NEXT f\r
+FOR f = 26 TO 50\r
+OUT &H3C8, f + 51\r
+OUT &H3C9, ((50 - f) * 2.5 + r * 1) / 2\r
+OUT &H3C9, ((50 - f) * 2.5 + g * 1) / 2\r
+OUT &H3C9, ((50 - f) * 1.5 + b * 1) / 2\r
+NEXT f\r
+END SUB\r
+\r
+SUB pal3 (r, g, b)\r
+FOR f = 0 TO 25\r
+OUT &H3C8, f + 102\r
+OUT &H3C9, (f * 2.5 + r * 1) / 2\r
+OUT &H3C9, (f * 2.5 + g * 1) / 2\r
+OUT &H3C9, (f * 1.5 + b * 1) / 2\r
+NEXT f\r
+FOR f = 26 TO 50\r
+OUT &H3C8, f + 102\r
+OUT &H3C9, ((50 - f) * 2.5 + r * 1) / 2\r
+OUT &H3C9, ((50 - f) * 2.5 + g * 1) / 2\r
+OUT &H3C9, ((50 - f) * 1.5 + b * 1) / 2\r
+NEXT f\r
+END SUB\r
+\r
+SUB pal4 (c, r!, g!, b!)\r
+OUT &H3C8, c\r
+OUT &H3C9, r\r
+OUT &H3C9, g\r
+OUT &H3C9, b\r
+END SUB\r
+\r
+SUB pr (x, y, s, c, n, a$)\r
+IF n > LEN(a$) THEN GOTO 10\r
+a$ = RIGHT$(LEFT$(a$, n), 1)\r
+x1 = n * 8 * s + x\r
+prin x1, y, s, c, a$\r
+10\r
+END SUB\r
+\r
+SUB pri (x, y, a$, c)\r
+COLOR c\r
+FOR a = 1 TO LEN(a$)\r
+b$ = RIGHT$(LEFT$(a$, a), 1)\r
+LOCATE y, x + a\r
+PRINT b$\r
+SOUND 0, 1\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB prin (x1, y1, s, c1, a$)\r
+\r
+FOR a = 1 TO LEN(a$)\r
+b = ASC(RIGHT$(LEFT$(a$, a), 1))\r
+c = (a - 1) * 8 * s + x1\r
+FOR y = 0 TO 7\r
+FOR x = 0 TO 7\r
+IF fontt(x, y, b) > 0 THEN\r
+LINE (x * s + c, y * s + y1)-(x * s + s - 1 + c, y * s + s - 1 + y1), c1, BF\r
+END IF\r
+NEXT x\r
+NEXT y\r
+\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB resiz\r
+\r
+FOR a = 1 TO 10\r
+CIRCLE (160, 100), a, a * 2 + 5\r
+NEXT a\r
+PSET (160, 100), 0\r
+\r
+DIM buff1(1 TO 10000)\r
+DIM buff2(1 TO 10000)\r
+\r
+a = 10\r
+GET (160 - a, 90)-(160, 110), buff1(1)\r
+GET (160, 90)-(160 + a, 110), buff2(1)\r
+5\r
+PUT (159 - a, 90), buff1(1), PSET\r
+PUT (150 + a, 90), buff2(1), PSET\r
+a = a + 1\r
+SOUND 0, .2\r
+IF a < 140 THEN GOTO 5\r
+\r
+a = 1\r
+\r
+GET (20, 90)-(300, 100), buff1(1)\r
+GET (20, 100)-(300, 110), buff2(1)\r
+6\r
+PUT (20, 90 - a), buff1(1), PSET\r
+PUT (20, 100 + a), buff2(1), PSET\r
+\r
+a = a + 1\r
+SOUND 0, .2\r
+IF a < 60 THEN GOTO 6\r
+END SUB\r
+\r
+SUB setink (a!)\r
+ink = a\r
+tim$ = TIME$\r
+END SUB\r
+\r
+SUB start\r
+SCREEN 13\r
+RANDOMIZE TIMER\r
+\r
+mkfont\r
+tim = 0\r
+tim2 = 0\r
+\r
+FOR a = 1 TO 500\r
+jas(a) = RND * 10\r
+NEXT a\r
+\r
+pii = 3.14\r
+IF COMMAND$ = "t" OR COMMAND$ = "T" THEN\r
+tmr = 1\r
+PRINT "timer is on"\r
+SLEEP 1\r
+ELSE\r
+tmr = 0\r
+END IF\r
+END SUB\r
+\r
+SUB wpr\r
+tim = tim + 1\r
+IF tim \ 10 = tim / 10 THEN\r
+a = tim / 10\r
+SELECT CASE tim2\r
+CASE 0\r
+IF a = 10 THEN tim2 = 1: tim = 0: pal4 255, 63, 45, 0\r
+CASE 1\r
+pr 10, 10, 2, 255, a, "Sources:"\r
+\r
+END SELECT\r
+END IF\r
+END SUB\r
+\r
--- /dev/null
+#+TITLE: Spiral series
+#+LANGUAGE: en
+#+LATEX_HEADER: \usepackage[margin=1.0in]{geometry}
+#+LATEX_HEADER: \usepackage{parskip}
+#+LATEX_HEADER: \usepackage[none]{hyphenat}
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+ .flex-center {
+ display: flex; /* activate flexbox */
+ justify-content: center; /* horizontally center anything inside */
+ }
+
+ .flex-center video {
+ width: min(90%, 1000px); /* whichever is smaller wins */
+ height: auto; /* preserve aspect ratio */
+ }
+
+ .responsive-img {
+ width: min(100%, 1000px);
+ height: auto;
+ }
+</style>
+#+end_export
+
+* Spiral with increasing density
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:spiral.png]]
+
+From every point in the spiral, subdivided line is traced. Line
+segments are connected between the neighbors. Line segment count
+progressively increases towards the center.
+
+[[file:spiral.bas]]
+
+#+INCLUDE: "spiral.bas" src basic-qb45
+
+* Spiral with varying height
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:spiral, 2.png]]
+
+From every point in the spiral, subdivided line is traced. Line
+segments are connected between the neighbors. This creates effect
+where lines run from edges towards the center. Center is vertically
+displaced by sinus function where input is the distance to the center.
+
+[[file:spiral, 2.bas]]
+
+#+INCLUDE: "spiral, 2.bas" src basic-qb45
+
+* Shaded spiral
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 800px
+[[file:spiral, 3.png]]
+
+Similar to previous spiral, Line segments are connected between the
+neighbors and sinus from the center decides vertical
+displacement. Attempt of shading is made where brighter areas have
+more detail.
+
+[[file:spiral, 3.bas]]
+
+#+INCLUDE: "spiral, 3.bas" src basic-qb45
+
+* Sphere forming spiral
+
+Similar to previous spiral, Line segments are connected between the
+neighbors. Spiral height and width are calculated such that they form
+multiple linked spherical shapes. Initially point cloud in shown:
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:spiral, 4, 1.png]]
+
+In the next step, points are connected using lines:
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:spiral, 4, 2.png]]
+
+
+[[file:spiral, 4.bas]]
+
+#+INCLUDE: "spiral, 4.bas" src basic-qb45
+
+* Textured spherical spiral
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:spiral, 5.png]]
+
+Similar to previous spiral, Line segments are connected between the
+neighbors. Spiral height and width are calculated such that sphere is
+formed. Sphere is textured. Texture is loaded from file:
+[[file:texture.dat]] .Invisible surface detection and removal is
+attempted.
+
+[[file:spiral, 5.bas]]
+
+#+INCLUDE: "spiral, 5.bas" src basic-qb45
+
+* Textured and shaded spherical spiral
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:spiral, 6.png]]
+
+Similar to previous spiral, Line segments are connected between the
+neighbors. Spiral height and width are calculated such that sphere is
+formed. Sphere is textured. Texture is loaded from file:
+[[file:texture1.dat]] . Invisible surface detection and removal is
+attempted. Sphere is shaded.
+
+[[file:spiral, 6.bas]]
+
+#+INCLUDE: "spiral, 6.bas" src basic-qb45
--- /dev/null
+' Program to render fancy looking spiral.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+DIM SHARED spiralX(1 TO 10000) AS SINGLE ' X coordinates of the spiral points\r
+DIM SHARED spiralY(1 TO 10000) AS SINGLE ' Y coordinates of the spiral points\r
+DIM SHARED pointCount AS INTEGER ' Total number of points plotted\r
+SCREEN 12 ' Set screen resolution to 640x480 with 16 colors\r
+\r
+' Initialize the scale factor for the spiral\r
+scaleFactor = 200\r
+pointCount = 0\r
+\r
+' Calculate and plot each point on the spiral\r
+FOR angle = 1 TO 100 STEP .05\r
+ pointCount = pointCount + 1\r
+ scaleFactor = 100 - angle ' Update the scaling factor as the loop progresses\r
+\r
+ ' Calculate the X and Y coordinates based on the sine and cosine of the angle\r
+ spiralX(pointCount) = SIN(angle) * scaleFactor * 3 + 320\r
+ spiralY(pointCount) = COS(angle) * scaleFactor + 300\r
+\r
+ ' Apply a vertical displacement to create a more dynamic effect\r
+ spiralY(pointCount) = spiralY(pointCount) + (SIN((angle + 20) / 10) * angle)\r
+\r
+ ' Plot the point on the screen\r
+ PSET (spiralX(pointCount), spiralY(pointCount)), 15\r
+NEXT angle\r
+\r
+' Draw lines between points to create the spiral effect\r
+FOR segmentStart = 1 TO pointCount - 125\r
+ LINE (spiralX(segmentStart), spiralY(segmentStart)) - _\r
+ (spiralX(segmentStart + 125), spiralY(segmentStart + 125)), 15\r
+NEXT segmentStart\r
+\r
+' Wait for user input before exiting\r
+a$ = INPUT$(1)\r
+END ' Exit the program\r
--- /dev/null
+' Program to render fancy looking spiral with shaded surface.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+' Declare shared arrays for storing coordinates and sine values\r
+DIM SHARED spiralX(1 TO 10000)\r
+DIM SHARED spiralY(1 TO 10000)\r
+DIM SHARED sineValue1(1 TO 10000)\r
+DIM SHARED sineValue2(1 TO 10000)\r
+\r
+\r
+' Set the screen mode to 640x480 with 16 colors\r
+SCREEN 12\r
+\r
+' Initialize the spiral rotation parameter\r
+DIM spiralRotation AS SINGLE\r
+spiralRotation = 0\r
+\r
+' Generate and draw the spiral points\r
+FOR angle = 0 TO 150 STEP .05\r
+ spiralRotation = spiralRotation + 1\r
+ scaleFactor = 150 - angle\r
+\r
+ ' Calculate the X and Y coordinates for the current point\r
+ spiralX(spiralRotation) = SIN(angle) * scaleFactor * 3 + 320\r
+ spiralY(spiralRotation) = COS(angle) * scaleFactor + 300\r
+\r
+ ' Apply additional vertical displacement based on a secondary sine function\r
+ spiralY(spiralRotation) = spiralY(spiralRotation) + (SIN((angle + 20) / 10) * (angle / 5 + 1))\r
+\r
+ ' Store the current sine values for later use\r
+ sineValue1(spiralRotation) = SIN(angle)\r
+ sineValue2(spiralRotation) = SIN((angle + 20) / 10)\r
+\r
+ ' Draw the current point on the screen\r
+ PSET (spiralX(spiralRotation), spiralY(spiralRotation)), 15\r
+NEXT angle\r
+\r
+' Connect the points to form a continuous line\r
+FOR index = 1 TO spiralRotation - 127\r
+ ' Draw a line segment between points 126 steps apart\r
+ LINE (spiralX(index), spiralY(index))-(spiralX(index + 126), spiralY(index + 126)), 15\r
+\r
+ ' Initialize the line drawing flag\r
+ DIM drawLine AS INTEGER\r
+ drawLine = 1\r
+\r
+ ' Check conditions to determine if a line segment should be drawn\r
+ IF sineValue1(index) > .8 AND sineValue2(index) < sineValue2(index + 125) THEN drawLine = 0\r
+ IF sineValue1(index) < -.2 AND (sineValue2(index) - .4) > sineValue2(index + 125) THEN drawLine = 0\r
+\r
+ ' Draw a line segment if the conditions are met\r
+ IF drawLine = 1 THEN LINE (spiralX(index), spiralY(index))-(spiralX(index + 1), spiralY(index + 1)), 15\r
+\r
+ ' Reset the line drawing flag and check for different conditions\r
+ drawLine = 0\r
+ IF sineValue1(index) > .8 AND sineValue2(index) > sineValue2(index + 125) THEN drawLine = 1\r
+ IF sineValue1(index) < -.2 AND sineValue2(index) < sineValue2(index + 125) THEN drawLine = 1\r
+\r
+ ' Draw a line segment if the conditions are met\r
+ IF drawLine = 1 THEN LINE (spiralX(index), spiralY(index))-(spiralX(index + 127), spiralY(index + 127)), 15\r
+\r
+ ' Reset the line drawing flag and check for another set of conditions\r
+ drawLine = 0\r
+ IF sineValue1(index) > .9 AND sineValue2(index) > sineValue2(index + 125) THEN drawLine = 1\r
+ IF sineValue1(index) < -.5 AND sineValue2(index) < sineValue2(index + 125) THEN drawLine = 1\r
+\r
+ ' Draw a line segment if the conditions are met\r
+ IF drawLine = 1 THEN LINE (spiralX(index), spiralY(index))-(spiralX(index + 125), spiralY(index + 125)), 15\r
+NEXT index\r
+\r
+' Wait for a key press before exiting\r
+a$ = INPUT$(1)\r
+\r
--- /dev/null
+' Program to render fancy looking spiral.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+' Declare shared arrays to hold the x and y coordinates of the spiral\r
+DIM SHARED spiralX(1 TO 10000)\r
+DIM SHARED spiralY(1 TO 10000)\r
+\r
+' Initialize the screen to a graphics mode with 640x480 resolution and 16 colors\r
+SCREEN 12\r
+\r
+' Constants for the initial size and the starting value of the index\r
+CONST InitialSize = 100\r
+CONST StartIndex = 0\r
+\r
+' Variable to keep track of the current position in the spiral arrays\r
+DIM torusIndex AS DOUBLE\r
+torusIndex = StartIndex\r
+\r
+' Loop parameters\r
+DIM angle AS DOUBLE\r
+DIM scaleFactor AS DOUBLE\r
+\r
+' Generate the first arm of the spiral\r
+FOR angle = 0 TO 97.35 STEP .15\r
+ torusIndex = torusIndex + 1\r
+ scaleFactor = SIN(angle / 31) * InitialSize\r
+ spiralX(torusIndex) = SIN(angle) * scaleFactor * 3 + 320\r
+ spiralY(torusIndex) = COS(angle) * scaleFactor + 250\r
+ spiralY(torusIndex) = spiralY(torusIndex) - (COS(angle / 31) * 200)\r
+ PSET (spiralX(torusIndex), spiralY(torusIndex)), 15\r
+NEXT angle\r
+\r
+' Generate the second arm of the spiral\r
+FOR angle = 97.35 TO 0 STEP -.15\r
+ torusIndex = torusIndex + 1\r
+ scaleFactor = SIN(angle / 31) * (InitialSize / 2)\r
+ spiralX(torusIndex) = SIN(angle) * scaleFactor * 3 + 320\r
+ spiralY(torusIndex) = COS(angle) * scaleFactor + 350\r
+ spiralY(torusIndex) = spiralY(torusIndex) - (COS(angle / 31) * 100)\r
+ PSET (spiralX(torusIndex), spiralY(torusIndex)), 15\r
+NEXT angle\r
+\r
+' Generate the third arm of the spiral\r
+FOR angle = 0 TO 97.35 STEP .15\r
+ torusIndex = torusIndex + 1\r
+ scaleFactor = SIN(angle / 31) * (InitialSize / 4)\r
+ spiralX(torusIndex) = SIN(angle) * scaleFactor * 3 + 320\r
+ spiralY(torusIndex) = COS(angle) * scaleFactor + 300\r
+ spiralY(torusIndex) = spiralY(torusIndex) - (COS(angle / 31) * 50)\r
+ PSET (spiralX(torusIndex), spiralY(torusIndex)), 15\r
+NEXT angle\r
+\r
+' Generate the fourth arm of the spiral\r
+FOR angle = 97.35 TO 0 STEP -.15\r
+ torusIndex = torusIndex + 1\r
+ scaleFactor = SIN(angle / 31) * (InitialSize / 8)\r
+ spiralX(torusIndex) = SIN(angle) * scaleFactor * 3 + 320\r
+ spiralY(torusIndex) = COS(angle) * scaleFactor + 325\r
+ spiralY(torusIndex) = spiralY(torusIndex) - (COS(angle / 31) * 25)\r
+ PSET (spiralX(torusIndex), spiralY(torusIndex)), 15\r
+NEXT angle\r
+\r
+' Calculate the number of lines to draw based on the current index\r
+DIM totalSegments AS DOUBLE\r
+totalSegments = (torusIndex - 42) / 4\r
+\r
+a$ = INPUT$(1)\r
+' Clear the screen before drawing the lines\r
+CLS\r
+\r
+' Draw the lines between points in the spiral\r
+FOR angle = 1 TO totalSegments * 4\r
+ LINE (spiralX(angle), spiralY(angle))-(spiralX(angle + 42), spiralY(angle + 42)), 15\r
+ LINE (spiralX(angle), spiralY(angle))-(spiralX(angle + 1), spiralY(angle + 1)), 15\r
+NEXT angle\r
+\r
+' Wait for the user to press a key before exiting\r
+a$ = INPUT$(1)\r
+\r
+' End of program\r
+SYSTEM\r
+\r
--- /dev/null
+' Program to render fancy looking spiral.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+DECLARE SUB FillSegment (x1, y1, x2, y2, xx1, yy1, xx2, yy2)\r
+DIM SHARED spiralX(1 TO 10000)\r
+DIM SHARED spiralY(1 TO 10000)\r
+DIM SHARED angles(1 TO 10000)\r
+DIM SHARED phaseAngles(1 TO 10000)\r
+DIM SHARED spiralLength\r
+SCREEN 12\r
+stepUnit = 200\r
+spiralLength = 0\r
+\r
+' Generate the spiral points\r
+FOR angleIndex = 1 TO 97 STEP .15\r
+ spiralLength = spiralLength + 1\r
+ stepUnit = SIN(angleIndex / 31) * 100\r
+ xPos = SIN(angleIndex) * stepUnit * 3 + 320\r
+ yPos = COS(angleIndex) * stepUnit + 250\r
+ yPos = yPos - (COS(angleIndex / 31) * 200)\r
+ angles(spiralLength) = angleIndex\r
+ phaseAngles(spiralLength) = angleIndex / 31\r
+ spiralX(spiralLength) = xPos\r
+ spiralY(spiralLength) = yPos\r
+ PSET (xPos, yPos), 15\r
+NEXT angleIndex\r
+\r
+' Load texture data from file\r
+OPEN "texture.dat" FOR INPUT AS #1\r
+DIM SHARED textureData$(1 TO 1000)\r
+textureIndex = 0\r
+1\r
+ LINE INPUT #1, textureLine$\r
+ IF LEFT$(textureLine$, 3) = "END" THEN GOTO 2\r
+ textureIndex = textureIndex + 1\r
+ textureData$(textureIndex) = textureLine$\r
+GOTO 1\r
+2\r
+CLS\r
+\r
+' Apply texture to the spiral\r
+textureIndex = 1\r
+FOR charIndex = 1 TO 20\r
+ FOR textCharIndex = 1 TO LEN(textureData$(charIndex))\r
+ textureChar$ = RIGHT$(LEFT$(textureData$(charIndex), textCharIndex), 1)\r
+ textureIndex = textureIndex + 1\r
+ IF textureIndex > spiralLength - 43 THEN GOTO DONE\r
+ teeVal = SIN(angles(textureIndex + 32)) - COS(phaseAngles(textureIndex))\r
+\r
+ ' Draw lines if the condition is met\r
+ IF teeVal <= 0 THEN\r
+ LINE (spiralX(textureIndex), spiralY(textureIndex))-(spiralX(textureIndex + 1), spiralY(textureIndex + 1)), 15\r
+ LINE (spiralX(textureIndex), spiralY(textureIndex))-(spiralX(textureIndex + 42), spiralY(textureIndex + 42)), 15\r
+ ' Fill the segment if the character matches\r
+ IF textureChar$ = "M" THEN\r
+ CALL FillSegment(spiralX(textureIndex), spiralY(textureIndex), spiralX(textureIndex + 1), spiralY(textureIndex + 1), spiralX(textureIndex + 42), spiralY(textureIndex + 42), spiralX(textureIndex + 43), spiralY(textureIndex + 43))\r
+ END IF\r
+ END IF\r
+ NEXT textCharIndex\r
+NEXT charIndex\r
+DONE:\r
+a$ = INPUT$(1)\r
+SYSTEM\r
+\r
+' Subroutine to fill a segment with lines\r
+SUB FillSegment (x1, y1, x2, y2, xx1, yy1, xx2, yy2)\r
+ ' Assign input parameters to local variables\r
+ xStart = x1\r
+ yStart = y1\r
+ xEnd = x2\r
+ yEnd = y2\r
+ xxStart = xx1\r
+ yyStart = yy1\r
+ xxEnd = xx2\r
+ yyEnd = yy2\r
+\r
+ ' Calculate step increments\r
+ j = 10\r
+ xStep = (xEnd - xStart) / j\r
+ yStep = (yEnd - yStart) / j\r
+ xxStep = (xxEnd - xxStart) / j\r
+ yyStep = (yyEnd - yyStart) / j\r
+\r
+ ' Draw lines between the points\r
+ FOR a = 1 TO j\r
+ xStart = xStart + xStep\r
+ yStart = yStart + yStep\r
+ xxStart = xxStart + xxStep\r
+ yyStart = yyStart + yyStep\r
+ LINE (xStart, yStart)-(xxStart, yyStart), 15\r
+ NEXT a\r
+END SUB\r
+\r
--- /dev/null
+' Program to render fancy looking textured and shaded spiral.\r
+' Texture is loaded from file.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+DECLARE SUB fill(x1, y1, x2, y2, xx1, yy1, xx2, yy2, hel)\r
+DIM SHARED torux(1 TO 10000)\r
+DIM SHARED toruy(1 TO 10000)\r
+DIM SHARED sin1(1 TO 10000)\r
+DIM SHARED cos1(1 TO 10000)\r
+DIM SHARED tor\r
+\r
+' Set the screen mode to 12\r
+SCREEN 12\r
+su = 200\r
+tor = 0\r
+\r
+' Calculate points for the spiral\r
+FOR a = 1 TO 97 STEP .15\r
+ tor = tor + 1\r
+ su = SIN(a / 31) * 100\r
+ x = SIN(a) * su * 3 + 320\r
+ y = COS(a) * su + 250\r
+ y = y - (COS(a / 31) * 200)\r
+ sin1(tor) = a\r
+ cos1(tor) = a / 31\r
+ torux(tor) = x\r
+ toruy(tor) = y\r
+ ' Set the pixel at (x, y) to color 15\r
+ PSET (x, y), 15\r
+NEXT a\r
+\r
+' Open the text file for input\r
+OPEN "texture1.dat" FOR INPUT AS #1\r
+DIM SHARED text$(1 TO 1000)\r
+\r
+a = 0\r
+1\r
+' Read a line from the file\r
+LINE INPUT #1, a$\r
+' Check if the line is the end marker\r
+IF LEFT$(a$, 3) = "END" THEN GOTO 2\r
+\r
+' Increment the counter and store the line in the text array\r
+a = a + 1\r
+text$(a) = a$\r
+GOTO 1\r
+2\r
+' Close the file\r
+CLOSE #1\r
+\r
+' Clear the screen\r
+CLS\r
+a = 1\r
+' Loop through each character in the text\r
+FOR c = 1 TO 20\r
+ FOR b = 1 TO LEN(text$(c))\r
+ ' Get the current character\r
+ a$ = RIGHT$(LEFT$(text$(c), b), 1)\r
+\r
+ ' Increment the counter\r
+ a = a + 1\r
+ ' Check if we have reached the end of the points array\r
+ IF a > tor - 43 THEN GOTO 3\r
+\r
+ ' Calculate the angle for the current point\r
+ tee = SIN(sin1(a + 32))\r
+ tee = tee - COS(cos1(a))\r
+\r
+ ' Draw lines based on the calculated angle\r
+ IF tee <= 0 THEN\r
+ LINE (torux(a), toruy(a))-(torux(a + 1), toruy(a + 1)), 15\r
+ LINE (torux(a), toruy(a))-(torux(a + 42), toruy(a + 42)), 15\r
+ hel = 10\r
+ hel1 = COS(cos1(a) - 1) + .5\r
+ hel2 = SIN(sin1(a) + 1) + 1\r
+ ' Adjust brightness based on the angles\r
+ IF hel2 > 1 AND hel1 > 1 THEN\r
+ hel3 = (hel2 - 1) * (hel1 - 1) * 8\r
+ hel = hel / (hel3 + 1)\r
+ END IF\r
+\r
+ ' Adjust brightness if the character is "M"\r
+ IF a$ = "M" THEN hel = hel / 3\r
+\r
+ ' Fill the shape with the calculated brightness\r
+ fillQuadrilateralWithShading torux(a), toruy(a), torux(a + 1), toruy(a + 1), torux(a + 42), toruy(a + 42), torux(a + 43), toruy(a + 43), hel\r
+ END IF\r
+ NEXT b\r
+NEXT c\r
+\r
+' Wait for user input\r
+3\r
+a$ = INPUT$(1)\r
+SYSTEM\r
+\r
+'\r
+' Fills a quadrilateral area using scanline algorithm with variable density\r
+' Creates shaded surface effect by interpolating between opposite edges\r
+'\r
+SUB fillQuadrilateralWithShading (startEdgePointX1, startEdgePointY1, endEdgePointX1, endEdgePointY1, shiftedStartEdgeX1, shiftedStarEdgeY1, shiftedEndEdgeX1, shiftEndEdgeY1, brightnessFactor)\r
+\r
+' This subroutine creates the illusion of a shaded surface by drawing multiple lines\r
+' between two opposite edges of a quadrilateral. The density of these lines is\r
+' controlled by the brightnessFactor parameter - higher values produce sparser lines.\r
+'\r
+' Parameters:\r
+' startEdgePointX1/Y1 and endEdgePointX1/Y1 define one pair of points forming an edge\r
+' shiftedStartEdgeX1/Y1 and shiftedEndEdgeX1/Y1 define the opposite edge\r
+' brightnessFactor controls how densely packed the lines will be drawn\r
+\r
+' Local variables for working with point coordinates\r
+edgePointX1 = startEdgePointX1\r
+edgePointY1 = startEdgePointY1\r
+edgePointX2 = endEdgePointX1\r
+edgePointY2 = endEdgePointY1\r
+oppositePointX1 = shiftedStartEdgeX1\r
+oppositePointY1 = shiftedStarEdgeY1\r
+oppositePointX2 = shiftedEndEdgeX1\r
+oppositePointY2 = shiftEndEdgeY1\r
+\r
+' Calculate distance differences along first edge\r
+deltaX1 = edgePointX1 - edgePointX2\r
+deltaY1 = edgePointY1 - edgePointY2\r
+length1 = SQR((deltaX1 * deltaX1) + (deltaY1 * deltaY1))\r
+\r
+' Calculate distance differences along second edge\r
+deltaX2 = oppositePointX1 - oppositePointX2\r
+deltaY2 = oppositePointY1 - oppositePointY2\r
+length2 = SQR((deltaX2 * deltaX2) + (deltaY2 * deltaY2))\r
+\r
+' Average length determines number of steps based on brightness factor\r
+averageLength = (length1 + length2) / 2\r
+stepCount = averageLength / brightnessFactor\r
+\r
+' Calculate step increments for each axis\r
+xStep1 = (edgePointX2 - edgePointX1) / stepCount\r
+yStep1 = (edgePointY2 - edgePointY1) / stepCount\r
+xStep2 = (oppositePointX2 - oppositePointX1) / stepCount\r
+yStep2 = (oppositePointY2 - oppositePointY1) / stepCount\r
+\r
+' Draw intermediate connecting lines across the shape\r
+FOR stepIndex = 1 TO stepCount\r
+ edgePointX1 = edgePointX1 + xStep1\r
+ edgePointY1 = edgePointY1 + yStep1\r
+ oppositePointX1 = oppositePointX1 + xStep2\r
+ oppositePointY1 = oppositePointY1 + yStep2\r
+\r
+ ' Draw line between current interpolated points\r
+ LINE (edgePointX1, edgePointY1)-(oppositePointX1, oppositePointY1), 15\r
+NEXT stepIndex\r
+\r
+END SUB
\ No newline at end of file
--- /dev/null
+DECLARE SUB DrawLine (startX AS DOUBLE, startY AS DOUBLE, endX AS DOUBLE, endY AS DOUBLE, col AS INTEGER)\r
+\r
+' Program to render fancy looking spiral.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+DIM SHARED lineVertexX(1 TO 100) AS DOUBLE\r
+DIM SHARED lineVertexY(1 TO 100) AS DOUBLE\r
+DIM SHARED depth AS INTEGER\r
+DIM SHARED tempDepth AS INTEGER\r
+SCREEN 12\r
+\r
+' Initialize the scale factor for the spiral\r
+spiralScaleFactor = 200\r
+depth = 0\r
+\r
+' Generate the spiral by iterating through angles and scaling appropriately\r
+FOR angle = 1 TO 30 STEP .1\r
+ ' Calculate the current scale based on the remaining distance to the center\r
+ spiralScaleFactor = (30 - angle) * 7\r
+ ' Convert polar coordinates to cartesian for the current point\r
+ xPosition = SIN(angle) * spiralScaleFactor + 200\r
+ yPosition = COS(angle) * spiralScaleFactor + 200\r
+ ' Store the current depth (z-axis value)\r
+ tempDepth = angle\r
+ ' Draw a line from the previous point to the current point with a color based on depth\r
+ DrawLine xPosition + (xPosition / 2) + (angle * 3), (yPosition - (xPosition / 3)) + (angle * 3), xPosition + 25, yPosition + 25 - (angle * 3), depth\r
+ ' Set the color for the next segment\r
+ depth = 15\r
+NEXT angle\r
+\r
+' Wait for user input to close the program\r
+userInput$ = INPUT$(1)\r
+\r
+SUB DrawLine (startX AS DOUBLE, startY AS DOUBLE, endX AS DOUBLE, endY AS DOUBLE, col AS INTEGER)\r
+ ' Calculate the step increments for x and y based on the depth\r
+ deltaX = (endX - startX) / tempDepth\r
+ deltaY = (endY - startY) / tempDepth\r
+\r
+ FOR segmentIndex = 1 TO tempDepth\r
+ ' If there is a previous vertex, draw a line to the new starting point\r
+ IF lineVertexX(segmentIndex) > 0 THEN LINE (lineVertexX(segmentIndex), lineVertexY(segmentIndex))-(startX, startY), col\r
+ ' Store the current starting point as the next vertex\r
+ lineVertexX(segmentIndex) = startX\r
+ lineVertexY(segmentIndex) = startY\r
+ ' Increment the starting point by the calculated deltas\r
+ startX = startX + deltaX\r
+ startY = startY + deltaY\r
+ ' Draw a line from the stored vertex to the new starting point\r
+ LINE (lineVertexX(segmentIndex), lineVertexY(segmentIndex))-(startX, startY), col\r
+ NEXT segmentIndex\r
+END SUB\r
--- /dev/null
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.\r
+.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M\r
+END\r
+ \r
--- /dev/null
+..........................................\r
+...........................MMM.M.M.MM.....\r
+............................M..MMM.M......\r
+............................M..M.M.MM.....\r
+...................................M......\r
+............................MM.....MM.....\r
+............................M.............\r
+............................MM.MM..MM.....\r
+............................M..M.M.M.M....\r
+............................MM.M.M.MM.....\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+..........................................\r
+END\r
+ \r
--- /dev/null
+' Presentation about how to build stroboscope.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2002, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+DECLARE SUB InitializePresentation ()\r
+DECLARE SUB WaitForKeyPress (keyInput$)\r
+DECLARE SUB MoveModel ()\r
+DEFINT A-Z\r
+DECLARE SUB DrawLines ()\r
+DECLARE SUB Load3DModel ()\r
+DECLARE SUB Animate3DModel ()\r
+DECLARE SUB ClearScreen ()\r
+DECLARE SUB LoadFontPalette ()\r
+DECLARE SUB PrintText (x2%, y%, s%, c%, t$)\r
+DECLARE SUB DisplayClosingPage ()\r
+\r
+DECLARE SUB ProgramStart ()\r
+\r
+DIM SHARED font(0 TO 7, 0 TO 15, 0 TO 207)\r
+DIM SHARED paletteData(1 TO 100)\r
+DIM SHARED originalX1(1 TO 1000)\r
+DIM SHARED originalY1(1 TO 1000)\r
+DIM SHARED originalX2(1 TO 1000)\r
+DIM SHARED originalY2(1 TO 1000)\r
+DIM SHARED previousX1(1 TO 1000)\r
+DIM SHARED previousY1(1 TO 1000)\r
+DIM SHARED previousX2(1 TO 1000)\r
+DIM SHARED previousY2(1 TO 1000)\r
+DIM SHARED lineColor(1 TO 1000)\r
+\r
+DIM SHARED movementX, movementY, zoomLevel\r
+DIM SHARED startX, startY, startZoom\r
+DIM SHARED endX, endY, endZoom\r
+DIM SHARED totalFrames\r
+\r
+DIM SHARED lineCount\r
+\r
+ProgramStart\r
+\r
+InitializePresentation\r
+ClearScreen\r
+Animate3DModel\r
+DisplayClosingPage\r
+END\r
+\r
+DATA 0,0,5,-2\r
+DATA 0,0,5,2\r
+DATA 0, 0, 15, 0\r
+\r
+DATA 15,-2,15,2\r
+DATA 25,-2,25,2\r
+DATA 15,-2,25,-2\r
+DATA 15,2,25,2\r
+\r
+DATA 25,0,35,0\r
+DATA 35,-2,35,2\r
+DATA 35,-2,40,0\r
+DATA 35,2,40,0\r
+DATA 40,-2,40,2\r
+\r
+DATA 40,0,80,0\r
+DATA 50,0,50,19\r
+DATA 48,19,52,19\r
+DATA 48,21,52,21\r
+DATA 50,21,50,35\r
+\r
+DATA 0,35,125,35\r
+DATA 0,35,5,33\r
+DATA 0,35,5,37\r
+\r
+DATA 70,0,70,15\r
+DATA 70,35,70,20\r
+DATA 69,16,71,19\r
+DATA 69,19,71,16\r
+DATA 67,10,73,10\r
+DATA 67,25,73,25\r
+DATA 67,10,67,25\r
+DATA 73,10,73,25\r
+\r
+DATA 75,15,75,25\r
+DATA 75,20,90,20\r
+DATA 90,20,91,21\r
+DATA 91,21,90,22\r
+DATA 90,22,91,23\r
+DATA 91,23,90,24\r
+DATA 90,24,91,25\r
+DATA 91,25,90,26\r
+DATA 90,26,90,35\r
+\r
+DATA 93,18,93,28\r
+DATA 92,18,92,28\r
+\r
+DATA 95,20,94,21\r
+DATA 94,21,95,22\r
+DATA 95,22,94,23\r
+DATA 94,23,95,24\r
+DATA 95,24,94,25\r
+DATA 94,25,95,26\r
+DATA 95,26,95,35\r
+\r
+DATA 95, 20, 115, 20\r
+DATA 115,20,115,15\r
+DATA 115,7,115,0\r
+DATA 125,35,125,26\r
+DATA 123,26,127,26\r
+DATA 123,24,127,24\r
+DATA 125,24,125,0\r
+DATA 125,0,110,0\r
+DATA 110,-2,110,2\r
+DATA 100,-2,100,2\r
+DATA 100,-2,110,-2\r
+DATA 100,2,110,2\r
+\r
+DATA 100,0,90,0\r
+DATA 90,-2,90,2\r
+DATA 80,-2,80,2\r
+DATA 80,-2,90,-2\r
+DATA 80,2,90,2\r
+\r
+DATA 113,5,117,5\r
+DATA 113,17,117,17\r
+DATA 113,5,113,17\r
+DATA 117,5,117,17\r
+DATA 115,11,125,11\r
+\r
+DATA 105,-2,105,-5\r
+DATA 105,-5,113,-5\r
+DATA 113,-5,113,0\r
+DATA 105,-2,104,-4\r
+DATA 105,-2,106,-4\r
+\r
+DATA 999,999,999,999\r
+\r
+SUB Animate3DModel\r
+ ' Set up first animation parameters\r
+ startX = 20\r
+ startY = 15\r
+ startZoom = 100\r
+ endX = 20\r
+ endY = 15\r
+ endZoom = 10\r
+ totalFrames = 20\r
+\r
+ MoveModel\r
+\r
+ ' Print technical information\r
+ PrintText 147, 66, 1, 3, "100 D336B 180k 680k"\r
+ PrintText 180, 120, 1, 3, "50m 450V 1m"\r
+ PrintText 180, 400, 2, 14, "Principal schematic"\r
+\r
+ WaitForKeyPress keyInput$\r
+\r
+ ' Clear screen for next animation\r
+ LINE (0, 0)-(639, 390), 0, BF\r
+\r
+ ' Set up second animation parameters\r
+ startX = 20\r
+ startY = 15\r
+ startZoom = 10\r
+ endX = 80\r
+ endY = 5\r
+ endZoom = 4\r
+ totalFrames = 20\r
+ MoveModel\r
+ WaitForKeyPress keyInput$\r
+\r
+ ' Set up third animation parameters\r
+ startX = 80\r
+ startY = 5\r
+ startZoom = 4\r
+ endX = 40\r
+ endY = 5\r
+ endZoom = 4\r
+ totalFrames = 20\r
+ MoveModel\r
+ WaitForKeyPress keyInput$\r
+\r
+ ' Set up fourth animation parameters\r
+ startX = 40\r
+ startY = 5\r
+ startZoom = 4\r
+ endX = 20\r
+ endY = 15\r
+ endZoom = 10\r
+ totalFrames = 10\r
+ MoveModel\r
+\r
+ ' Redraw technical information\r
+ PrintText 147, 66, 1, 3, "100 D336B 180k 680k"\r
+ PrintText 180, 120, 1, 3, "50m 450V 1m"\r
+ WaitForKeyPress keyInput$\r
+END SUB\r
+\r
+SUB ClearScreen\r
+ ' change screen resolution. This also resets color palette.\r
+ SCREEN 13\r
+ SCREEN 12\r
+END SUB\r
+\r
+SUB DisplayClosingPage\r
+ CLS\r
+ SCREEN 13\r
+ PrintText 35, 100, 2, 14, " Thank you"\r
+ PrintText 35, 140, 2, 14, " for attention!"\r
+\r
+ ' Create closing animation effect\r
+ DIM buffer(1 TO 30000)\r
+ GET (0, 100)-(319, 199), buffer(1)\r
+\r
+ ' Move text down with delay\r
+ FOR y = 100 TO 50 STEP -1\r
+ PUT (0, y), buffer(1), PSET\r
+ SOUND 0, .5\r
+ NEXT y\r
+\r
+ WaitForKeyPress keyInput$\r
+ SYSTEM\r
+END SUB\r
+\r
+SUB DrawLines\r
+ ' Draw all lines in the schematic with current transformation parameters.\r
+ ' First calculate new screen coordinates based on movement and zoom.\r
+ ' Then draw lines by erasing previous positions and drawing new ones.\r
+\r
+ FOR a = 1 TO lineCount\r
+ ' Calculate relative coordinates from original positions\r
+ x1 = originalX1(a) - movementX\r
+ y1 = originalY1(a) - movementY\r
+ x2 = originalX2(a) - movementX\r
+ y2 = originalY2(a) - movementY\r
+\r
+ ' Apply zoom scaling and centering (320x200 screen)\r
+ x1 = x1 * 30 / zoomLevel + 160\r
+ y1 = y1 * 30 / zoomLevel + 100\r
+ x2 = x2 * 30 / zoomLevel + 160\r
+ y2 = y2 * 30 / zoomLevel + 100\r
+\r
+ ' Erase previous line by drawing in black (color 0)\r
+ LINE (previousX1(a), previousY1(a))-(previousX2(a), previousY2(a)), 0\r
+\r
+ ' Draw new line with appropriate color\r
+ LINE (x1, y1)-(x2, y2), lineColor(a)\r
+\r
+ ' Update previous positions for next frame\r
+ previousX1(a) = x1\r
+ previousY1(a) = y1\r
+ previousX2(a) = x2\r
+ previousY2(a) = y2\r
+ NEXT a\r
+END SUB\r
+\r
+SUB InitializePresentation\r
+ ' Set up screen and create title animation\r
+ SCREEN 13\r
+\r
+ ' Configure palette for title animation\r
+ a = 0\r
+ FOR c = 16 TO 31\r
+ OUT &H3C8, c\r
+ OUT &H3C9, a * 3\r
+ OUT &H3C9, a * 4.5\r
+ OUT &H3C9, a * 0\r
+ a = a + 1\r
+ NEXT c\r
+\r
+ ' Set special colors for title effects\r
+ OUT &H3C8, 101\r
+ OUT &H3C9, 63\r
+ OUT &H3C9, 63\r
+ OUT &H3C9, 0\r
+\r
+ OUT &H3C8, 102\r
+ OUT &H3C9, 63\r
+ OUT &H3C9, 10\r
+ OUT &H3C9, 10\r
+\r
+ OUT &H3C8, 103\r
+ OUT &H3C9, 60\r
+ OUT &H3C9, 60\r
+ OUT &H3C9, 0\r
+\r
+ ' Configure palette for background text\r
+ a = 0\r
+ FOR c = 50 TO 65\r
+ OUT &H3C8, c\r
+ OUT &H3C9, a * 4.5\r
+ OUT &H3C9, a * 0\r
+ OUT &H3C9, (15 - a) * 4.5\r
+ a = a + 1\r
+ NEXT c\r
+\r
+ ' Create scrolling title animation\r
+ titleText$ = "Presentation about:"\r
+\r
+ FOR t = 0 TO 400\r
+ ' Scroll title text across screen\r
+ IF t < 320 THEN\r
+ FOR y = 0 TO 199\r
+ c = POINT(319 - t, y)\r
+ IF c < 100 THEN c = c + 34\r
+ PSET (319 - t, y), c\r
+ NEXT y\r
+\r
+ x = 319 - t\r
+ ' Add text to scrolling animation\r
+ IF x / 16 = x \ 16 THEN\r
+ segment = x / 16\r
+ IF segment <= LEN(titleText$) THEN\r
+ char$ = RIGHT$(LEFT$(titleText$, segment), 1)\r
+ PrintText x, 20, 2, 101, char$\r
+ END IF\r
+ END IF\r
+ END IF\r
+\r
+ ' Create second animation phase\r
+ IF (t < 360) AND (t > 39) THEN\r
+ FOR y = 0 TO 13\r
+ c = POINT(359 - t, y)\r
+ IF c < 100 THEN c = c - 34\r
+ PSET (359 - t, y), c\r
+ NEXT y\r
+\r
+ FOR y = 55 TO 199\r
+ c = POINT(359 - t, y)\r
+ IF c < 100 THEN c = c - 34\r
+ PSET (359 - t, y), c\r
+ NEXT y\r
+ END IF\r
+\r
+ ' Frame delay using sound command\r
+ SOUND 0, .2\r
+ NEXT t\r
+\r
+ ' Draw final title text\r
+ PrintText 31, 101, 3, 102, "STROBOSCOPE"\r
+ PrintText 29, 99, 3, 102, "STROBOSCOPE"\r
+ PrintText 30, 100, 3, 103, "STROBOSCOPE"\r
+\r
+ ' Create color flipping effect for title\r
+ FOR x = 0 TO 160\r
+ FOR y = 100 TO 150\r
+ c = POINT(x, y)\r
+ IF c = 102 THEN c = 103: GOTO 2\r
+ IF c = 103 THEN c = 102: GOTO 2\r
+2\r
+ PSET (x, y), c\r
+ NEXT y\r
+ SOUND 0, .1\r
+ NEXT x\r
+\r
+ ' Continue color flipping effect\r
+ FOR y = 199 TO 120 STEP -1\r
+ FOR x = 0 TO 319\r
+ c = POINT(x, y)\r
+ IF c = 102 THEN c = 103: GOTO 3\r
+ IF c = 103 THEN c = 102: GOTO 3\r
+3\r
+ PSET (x, y), c\r
+ NEXT x\r
+ SOUND 0, .1\r
+ NEXT y\r
+\r
+ ' Print author information\r
+ PrintText 49, 179, 1, 0, "autor: Svjatoslav Agejenko"\r
+ PrintText 51, 181, 1, 0, "autor: Svjatoslav Agejenko"\r
+ PrintText 50, 180, 1, 15, "autor: Svjatoslav Agejenko"\r
+\r
+ ' Wait for user input before continuing\r
+ WaitForKeyPress keyInput$\r
+\r
+ ' Create screen border effect\r
+ DIM buffer(1 TO 30000)\r
+ FOR a = 1 TO 320 / 5\r
+ ' Capture and move screen sections\r
+ GET (0, 0)-(314, 100), buffer(1)\r
+ PUT (5, 0), buffer(1), PSET\r
+ LINE (0, 0)-(4, 100), 0, BF\r
+\r
+ GET (5, 101)-(319, 199), buffer(1)\r
+ PUT (0, 101), buffer(1), PSET\r
+ LINE (315, 101)-(319, 199), 0, BF\r
+ NEXT a\r
+END SUB\r
+\r
+SUB LoadFontPalette\r
+ ' Capture pixel data for each character in font array.\r
+ ' Make colors invisible for the human while doing so.\r
+\r
+ FOR c = 0 TO 15\r
+ OUT &H3C8, c\r
+ OUT &H3C9, 0\r
+ OUT &H3C9, 0\r
+ OUT &H3C9, 0\r
+ NEXT c\r
+\r
+ ' Load character pixel patterns into font array\r
+ FOR a = 0 TO 207\r
+ LOCATE 1, 1\r
+ IF (a > 5) AND (a < 14) THEN GOTO 1\r
+ PRINT CHR$(a)\r
+1\r
+ FOR y = 0 TO 15\r
+ FOR x = 0 TO 7\r
+ font(x, y, a) = POINT(x, y)\r
+ NEXT x\r
+ NEXT y\r
+ NEXT a\r
+END SUB\r
+\r
+SUB LoadSchematic\r
+ ' Load 3D model line data from DATA statements\r
+ ' Each line has two endpoints (x1,y1)-(x2,y2) and color\r
+\r
+ lineCount = 0\r
+5\r
+ READ x1, y1, x2, y2\r
+ IF x1 = 999 THEN GOTO 6\r
+ lineCount = lineCount + 1\r
+ originalX1(lineCount) = x1\r
+ originalY1(lineCount) = y1\r
+ originalX2(lineCount) = x2\r
+ originalY2(lineCount) = y2\r
+ lineColor(lineCount) = 11\r
+ GOTO 5\r
+6\r
+END SUB\r
+\r
+SUB MoveModel\r
+ ' Calculate model movement over time frames\r
+ ' Interpolate between start and end positions\r
+\r
+ movementXVelocity = endX - startX\r
+ movementYVelocity = endY - startY\r
+ zoomVelocity = endZoom - startZoom\r
+\r
+ ' Animate model by gradually changing position and zoom\r
+ FOR a = 1 TO totalFrames\r
+ movementX = startX + (movementXVelocity * a / totalFrames)\r
+ movementY = startY + (movementYVelocity * a / totalFrames)\r
+ zoomLevel = startZoom + (zoomVelocity * a / totalFrames)\r
+ DrawLines\r
+ ' Use sound command for sub-second delay (QBasic workaround)\r
+ SOUND 0, 1\r
+ NEXT a\r
+\r
+ ' Draw final position\r
+ DrawLines\r
+END SUB\r
+\r
+SUB PrintText (x2%, y%, s%, c%, t$)\r
+ ' Print text using custom font\r
+ ' Parameters:\r
+ ' x2% - starting x position\r
+ ' y% - starting y position\r
+ ' s% - character size multiplier\r
+ ' c% - color to use\r
+ ' t$ - text string to print\r
+\r
+ currentX = x2\r
+\r
+ ' Process each character in the string\r
+ FOR a = 1 TO LEN(t$)\r
+ charCode = ASC(RIGHT$(LEFT$(t$, a), 1))\r
+\r
+ ' Draw character using font data\r
+ FOR y1 = 0 TO 15\r
+ FOR x1 = 0 TO 7\r
+ IF font(x1, y1, charCode) > 0 THEN\r
+ ' Draw filled rectangle for each pixel in character\r
+ LINE (x1 * s + currentX, y1 * s + y)-(x1 * s + s - 1 + currentX, y1 * s + s - 1 + y), c, BF\r
+ END IF\r
+ NEXT x1\r
+ NEXT y1\r
+\r
+ ' Move to next character position\r
+ currentX = currentX + (8 * s)\r
+ NEXT a\r
+END SUB\r
+\r
+SUB ProgramStart\r
+ ' Initialize program with appropriate screen mode\r
+ SCREEN 12\r
+ LoadSchematic\r
+ LoadFontPalette\r
+\r
+ ' Set initial model parameters\r
+ movementX = 30\r
+ movementY = 15\r
+ zoomLevel = 10\r
+END SUB\r
+\r
+SUB WaitForKeyPress (keyInput$)\r
+ ' Clear keyboard buffer to avoid ghost keys\r
+ FOR a = 1 TO 50\r
+ keyInput$ = INKEY$\r
+ NEXT a\r
+\r
+7\r
+ keyInput$ = INKEY$\r
+ IF keyInput$ = "" THEN GOTO 7\r
+\r
+ ' Wait for another key press after initial one\r
+ FOR a = 1 TO 50\r
+ keyInput$ = INKEY$\r
+ NEXT a\r
+END SUB\r
--- /dev/null
+' Program to render circular wave patterns.\r
+' Algorithm was accidentally discovered while experimenting with sine function.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003, Initial version\r
+' 2025, Improved program readability\r
+\r
+SCREEN 13\r
+\r
+' Initialize the screen mode to 320x200 with 16 colors\r
+\r
+' Outer loop for the vertical axis (y-coordinate)\r
+FOR ycoordinate = 1 TO 199\r
+ ' Inner loop for the horizontal axis (x-coordinate)\r
+ FOR xcoordinate = 1 TO 319\r
+ ' Calculate the sine value based on the squared distances from the origin\r
+ colorvalue = SIN((xcoordinate ^ 2 + ycoordinate ^ 2) / 10) * 10\r
+\r
+ ' Clamp the color value to the range [0, 15]\r
+ IF colorvalue < 0 THEN colorvalue = 0\r
+ IF colorvalue > 15 THEN colorvalue = 15\r
+\r
+ ' Set the pixel color at (xcoordinate, ycoordinate) with an offset to use the full 16-color palette\r
+ PSET (xcoordinate, ycoordinate), colorvalue + 16\r
+ NEXT xcoordinate\r
+NEXT ycoordinate\r
+\r
+' Wait for user key press\r
+WHILE INKEY$ = "": WEND\r
+CLS\r
+END\r
--- /dev/null
+DECLARE SUB DrawPixels (x1 AS INTEGER, y1 AS INTEGER, s AS INTEGER)\r
+' Program to render cloud surface using diamond square algorithm.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+DECLARE SUB DrawBox (x1 AS INTEGER, y1 AS INTEGER, s AS INTEGER)\r
+DECLARE SUB SetPalette ()\r
+DECLARE SUB InitializeProgram ()\r
+DEFINT A-Z\r
+InitializeProgram\r
+\r
+DIM SHARED maxLightness AS INTEGER\r
+maxLightness = 127\r
+\r
+DIM scale AS INTEGER\r
+scale = 2 ^ 8\r
+\r
+1 :\r
+scale = scale \ 2\r
+x1 = (319 \ scale) - 1\r
+y1 = (199 \ scale) - 1\r
+\r
+FOR y = 0 TO y1\r
+ FOR x = 0 TO x1\r
+ DrawPixels x * scale, y * scale, scale\r
+ NEXT x\r
+NEXT y\r
+\r
+IF scale > 2 THEN GOTO 1\r
+WAITa$ = INPUT$(1)\r
+\r
+SUB DrawPixels (x1 AS INTEGER, y1 AS INTEGER, s AS INTEGER)\r
+ ' Get the lightness values for the corners of the box\r
+ c1 = POINT(x1, y1)\r
+ c2 = POINT(x1 + s, y1)\r
+ c3 = POINT(x1, y1 + s)\r
+ c4 = POINT(x1 + s, y1 + s)\r
+\r
+ ' Calculate the midpoint lightness values\r
+ sp = s \ 2\r
+ k = s * 2\r
+ kp = k / 2\r
+\r
+ cc2 = ((c1 + c2) / 2) + (RND * k) - kp\r
+ IF cc2 > maxLightness THEN cc2 = maxLightness\r
+ IF cc2 < 0 THEN cc2 = 0\r
+\r
+ cc3 = ((c1 + c3) / 2) + (RND * k) - kp\r
+ IF cc3 > maxLightness THEN cc3 = maxLightness\r
+ IF cc3 < 0 THEN cc3 = 0\r
+\r
+ cc4 = ((c2 + c4) / 2) + (RND * k) - kp\r
+ IF cc4 > maxLightness THEN cc4 = maxLightness\r
+ IF cc4 < 0 THEN cc4 = 0\r
+\r
+ cc5 = ((c3 + c4) / 2) + (RND * k) - kp\r
+ IF cc5 > maxLightness THEN cc5 = maxLightness\r
+ IF cc5 < 0 THEN cc5 = 0\r
+\r
+ ' Calculate the central lightness value\r
+ cc1 = ((cc2 + cc3 + cc4 + cc5) / 4) + (RND * k) - kp\r
+ IF cc1 > maxLightness THEN cc1 = maxLightness\r
+ IF cc1 < 0 THEN cc1 = 0\r
+\r
+ ' Set the calculated lightness values for the box\r
+ PSET (x1 + sp, y1 + sp), cc1\r
+ PSET (x1 + sp, y1), cc2\r
+ PSET (x1, y1 + sp), cc3\r
+ PSET (x1 + s, y1 + sp), cc4\r
+ PSET (x1 + sp, y1 + s), cc5\r
+END SUB\r
+\r
+SUB InitializeProgram\r
+ ' Set the screen mode and initialize the color palette\r
+ SCREEN 13\r
+ SetPalette\r
+ RANDOMIZE TIMER\r
+END SUB\r
+\r
+SUB SetPalette\r
+ ' Set the color palette for lightness levels\r
+ FOR a = 0 TO 255\r
+ OUT &H3C8, a\r
+ OUT &H3C9, a / 4\r
+ OUT &H3C9, a / 3\r
+ OUT &H3C9, a / 2.3\r
+ NEXT a\r
+END SUB\r
+\r
--- /dev/null
+' Program to render surface resembling old paper.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003, Initial version\r
+' 2025, Improved program readability\r
+\r
+DEFINT A-Z\r
+SCREEN 13\r
+RANDOMIZE TIMER\r
+\r
+' Initialize the color palette to grayscale. Each color index from 0 to 63 has R, G, B values equal to the index,\r
+' creating a smooth grayscale gradient for the 256-color mode.\r
+FOR paletteIndex = 0 TO 63\r
+ OUT &H3C8, paletteIndex\r
+ OUT &H3C9, paletteIndex ' Set red component\r
+ OUT &H3C9, paletteIndex ' Set green component\r
+ OUT &H3C9, paletteIndex ' Set blue component\r
+NEXT paletteIndex\r
+\r
+noiseOffset = 0\r
+\r
+' Generate a paper-like surface by averaging the color of the pixel above with some randomness.\r
+' This creates a procedural texture that mimics the roughness of paper.\r
+FOR y = 1 TO 190\r
+ FOR x = 1 TO 310\r
+ stepCounter = stepCounter + 1\r
+\r
+ ' Approximately every 10 steps, introduce a new random noise offset to create variation in the pattern.\r
+ ' This prevents the surface from becoming too uniform.\r
+ IF stepCounter > 10 THEN\r
+ noiseOffset = RND * currentColor / 20\r
+ stepCounter = stepCounter - (RND * 20 + 10)\r
+ END IF\r
+\r
+ ' Get the color of the pixel directly above the current position.\r
+ topColor = POINT(x, y - 1)\r
+\r
+ ' Calculate the current color as the average of the top color and the previous current color,\r
+ ' plus a small random noise and minus the noise offset. This creates a smooth transition with\r
+ ' controlled randomness.\r
+ currentColor = (topColor + currentColor) \ 2 + ((RND * 2) - noiseOffset)\r
+\r
+ ' Clamp the color value to stay within the valid palette range (0 to 63).\r
+ IF currentColor < 0 THEN currentColor = 0\r
+ IF currentColor > 63 THEN currentColor = 63\r
+\r
+ ' Plot the current pixel at (x-1, y) using the calculated color.\r
+ PSET (x - 1, y), currentColor\r
+ NEXT x\r
+\r
+ ' Set the starting color for the next row to the last calculated color of the current row.\r
+ ' This ensures continuity between rows.\r
+ PSET (0, y + 1), currentColor\r
+NEXT y\r
+\r
+' Wait for a single key press before exiting the program.\r
+inputKey$ = INPUT$(1)\r
+\r
+SYSTEM\r
--- /dev/null
+' Program to render surface resembling wood.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+DECLARE SUB DrawWoodSurface (woodX%, woodY%)\r
+DECLARE SUB DrawPaper (xPos%, y1Pos%)\r
+DEFINT A-Z\r
+SCREEN 12\r
+RANDOMIZE TIMER\r
+\r
+' Set palette colors\r
+FOR colorIndex = 0 TO 15\r
+ OUT &H3C8, colorIndex\r
+ OUT &H3C9, colorIndex * 4\r
+ OUT &H3C9, colorIndex * 3\r
+ OUT &H3C9, colorIndex * 0\r
+NEXT colorIndex\r
+\r
+' Main loop to draw wood at random positions\r
+100:\r
+woodX = RND * 400 + 200\r
+woodY = RND * 100 + 200\r
+CALL DrawWoodSurface(woodX, woodY)\r
+GOTO 100\r
+\r
+' Wait for user input to exit\r
+exitKey$ = INPUT$(1)\r
+\r
+SUB DrawWoodSurface (woodX, woodY)\r
+ DIM lowerY AS INTEGER\r
+ DIM phaseOffset AS INTEGER\r
+ DIM xStepCounter AS INTEGER\r
+ DIM randomOffset AS INTEGER\r
+ DIM newColor AS INTEGER\r
+ DIM upperColor AS INTEGER\r
+ DIM currentColor AS INTEGER\r
+\r
+ ' Draw the outline of the wood\r
+ lowerY = woodY + 1\r
+ LINE (0, 0)-(woodX, woodY), 0, BF ' Black background\r
+ LINE (5, 5)-(woodX - 5, lowerY - 5), 8, BF ' Gray wood outline\r
+ LINE (10, 10)-(woodX - 10, lowerY - 10), 15, BF ' White inner highlight\r
+\r
+ ' Initialize random phase offset for color variation\r
+ phaseOffset = RND * 300\r
+\r
+ ' Draw the wood texture\r
+ FOR y = woodY - 1 TO 0 STEP -1\r
+ FOR x = woodX - 1 TO 0 STEP -1\r
+ xStepCounter = xStepCounter + 1\r
+ IF xStepCounter > woodX THEN\r
+ randomOffset = RND * 13 ' Small random noise for texture variation\r
+ xStepCounter = SIN((y + phaseOffset) / 100) * woodX ' Sine wave to create wavy grain pattern\r
+ END IF\r
+ upperColor = POINT(x, y + 1) ' Get color from upper pixel\r
+ currentColor = POINT(x, y) ' Get color from current pixel\r
+ newColor = (upperColor * 2 + currentColor + newColor * 3 + randomOffset) / 7 + RND * 1\r
+\r
+ ' Ensure color value is within the valid range (0-15)\r
+ IF newColor < 0 THEN newColor = 0\r
+ IF newColor > 15 THEN newColor = 15\r
+\r
+ ' Set the pixel color for the wood texture\r
+ PSET (x + 1, y), newColor\r
+ NEXT x\r
+ NEXT y\r
+\r
+END SUB\r
--- /dev/null
+' Yellow flame.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+\r
+DEFINT A-Z ' Define all variables as integers\r
+SCREEN 13 ' Set graphics mode to 320x200 with 256 colors\r
+RANDOMIZE TIMER ' Seed the random number generator\r
+\r
+' Initialize palette registers with sine wave colors\r
+FOR paletteIndex = 0 TO 255\r
+ OUT &H3C8, paletteIndex\r
+ OUT &H3C9, INT(SIN(paletteIndex / 21) * 30 + 30)\r
+ OUT &H3C9, INT(SIN(paletteIndex / 34) * 30 + 30)\r
+ OUT &H3C9, INT(SIN(paletteIndex / 10) * 30 + 30)\r
+NEXT paletteIndex\r
+\r
+' Generate the surface pattern\r
+FOR y = 1 TO 199\r
+ FOR x = 1 TO 319\r
+ prevPixel = POINT(x, y - 1)\r
+ leftPixel = POINT(x - 1, y)\r
+ diagPixel = POINT(x - 1, y - 1)\r
+ left2Pixel = POINT(x - 2, y)\r
+\r
+ ' Calculate the average of surrounding pixels and add some randomness\r
+ newColor = (prevPixel + leftPixel + diagPixel + left2Pixel) \ 4 + (RND * 5 - 2)\r
+\r
+ ' Clamp the color value within the valid range\r
+ IF newColor < 0 THEN newColor = 0\r
+ IF newColor > 63 THEN newColor = 63\r
+\r
+ ' Set the pixel with the calculated color\r
+ PSET (x, y), newColor\r
+ NEXT x\r
+NEXT y\r
+\r
+' Wait for user input to exit\r
+userInput$ = INPUT$(1)\r
+\r
--- /dev/null
+#+TITLE: Algorithmic textures
+#+LANGUAGE: en
+#+LATEX_HEADER: \usepackage[margin=1.0in]{geometry}
+#+LATEX_HEADER: \usepackage{parskip}
+#+LATEX_HEADER: \usepackage[none]{hyphenat}
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+ .flex-center {
+ display: flex; /* activate flexbox */
+ justify-content: center; /* horizontally center anything inside */
+ }
+ .flex-center video {
+ width: min(90%, 1000px); /* whichever is smaller wins */
+ height: auto; /* preserve aspect ratio */
+ }
+ .responsive-img {
+ width: min(100%, 1000px);
+ height: auto;
+ }
+</style>
+#+end_export
+
+* Circular waves
+
+This QBasic program creates visually captivating circular wave
+patterns by manipulating pixel colors based on sine function
+calculations. It's a simple yet effective demonstration of how
+mathematical functions can be used to generate complex visual
+patterns.
+
+The program uses two nested loops to iterate over each pixel on the
+screen. The outer loop handles the vertical axis (y-coordinate), and
+the inner loop handles the horizontal axis (x-coordinate).
+
+For each pixel, the program calculates a sine value based on the
+squared distance from the origin (0,0). This calculation involves the
+formula:
+
+: colorvalue = SIN((x^2 + y^2) / 10) * 10
+
+This program is a blend of mathematics and art, showcasing how simple
+algorithms can produce intricate and visually appealing results.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Circular waves.png]]
+[[file:Circular waves.bas][Source code]]
+
+#+INCLUDE: "Circular waves.bas" src basic-qb45
+
+* Diamond square clouds
+
+This QBasic program demonstrates the Diamond-Square algorithm, a
+method used to generate fractal terrain or cloud surfaces. The
+algorithm is particularly useful for creating realistic landscapes or
+textures in computer graphics.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Diamond square clouds.png]]
+[[file:Diamond square clouds.bas][Source code]]
+
+#+INCLUDE: "Diamond square clouds.bas" src basic-qb45
+
+* Old paper
+
+This QBasic program generates a procedural texture that simulates the
+appearance of old paper.
+
+The program initializes the screen to a 320x200 resolution with 256
+colors (SCREEN 13 in QBasic) and sets up a grayscale color
+palette. Each color index from 0 to 63 is assigned a shade of gray,
+creating a smooth gradient.
+
+The program generates the texture by iterating over each pixel on the
+screen. For each pixel, it calculates a color value based on the color
+of the pixel directly above it, adding a small amount of random
+noise. This creates a smooth transition between pixels with controlled
+randomness, mimicking the fibrous texture of paper.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Old paper.png]]
+[[file:Old paper.bas][Source code]]
+
+#+INCLUDE: "Old paper.bas" src basic-qb45
+
+* Wood
+
+This QBasic program creates a visually appealing simulation of a wood
+surface. It is designed to generate a realistic wood grain texture
+using simple graphical techniques.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Wood.png]]
+[[file:Wood.bas][Source code]]
+
+#+INCLUDE: "Wood.bas" src basic-qb45
+
+* Yellow flame
+
+"Yellow Flame" is a visually captivating program written in QBasic
+that generates a dynamic flame-like pattern on the screen.
+
+Program initializes the color palette using sine waves to create a
+smooth gradient of colors. This gradient is essential for the flame
+effect.
+
+The core of the program involves generating a surface pattern that
+mimics a flame. It does this by iterating over each pixel on the
+screen and calculating the average color of the surrounding pixels. A
+small amount of randomness is added to this average to create a
+natural, flickering effect.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Yellow flame.png]]
+[[file:Yellow flame.bas][Source code]]
+
+#+INCLUDE: "Yellow flame.bas" src basic-qb45
--- /dev/null
+' Program that draws truncated cone:\r
+' - Top Part: A cylinder (with diagonal hatching).\r
+' - Middle Part: A frustum (truncated cone) – it widens from the bottom cylinder to the top cylinder.\r
+' - Bottom Part: A smaller cylinder.\r
+'\r
+' Goal of this program is to test viability of programming/code to generate images of 3D shapes.\r
+'\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2000, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+\r
+DECLARE SUB DrawLine (x%, y%, l%, clr%)\r
+\r
+DEFINT A-Z\r
+SCREEN 12\r
+\r
+' Set up the palette\r
+FOR a = 0 TO 16\r
+ OUT &H3C8, a\r
+ OUT &H3C9, a * 4\r
+ OUT &H3C9, a * 4\r
+ OUT &H3C9, a * 4\r
+NEXT\r
+\r
+' Draw the pattern\r
+FOR x = 0 TO 200\r
+ y = SQR((200 - x) * x) / 2\r
+ DrawLine x + 200, y + 200, y * 2, t\r
+ LINE (x + 200, y + 202)-(x + 200, y + 250), t\r
+ IF x < 195 THEN\r
+ LINE (300 + ((x - 100) / 2), y / 2 + 328)-(x + 200, y + 252), t\r
+ END IF\r
+ LINE (300 + ((x - 100) / 2), y / 2 + 330)-(300 + ((x - 100) / 2), y / 2 + 370), t\r
+NEXT x\r
+\r
+SUB DrawLine (x, y, l, clr)\r
+ ' Calculate the initial color value\r
+ c = 650 - y - x\r
+\r
+ ' Adjust color to be within a specific range\r
+1 IF c > 30 THEN\r
+ c = c - 30\r
+ GOTO 1\r
+ END IF\r
+\r
+ clr = c\r
+ IF clr > 15 THEN\r
+ clr = 30 - clr\r
+ END IF\r
+\r
+ ' Draw a vertical line with varying colors\r
+ FOR y1 = y TO y - l STEP -1\r
+ c1 = c\r
+ IF c1 > 15 THEN\r
+ c1 = 30 - c1\r
+ END IF\r
+\r
+ PSET (x, y1), c1\r
+\r
+ ' Increment the color and wrap around if necessary\r
+ c = c + 1\r
+ IF c > 30 THEN\r
+ c = c - 30\r
+ END IF\r
+ NEXT y1\r
+END SUB\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>3dSynthezier</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ </buildSpec>
+ <natures>
+ </natures>
+</projectDescription>
--- /dev/null
+' Program that parses special programmable 3D scene description language\r
+' and generates from it 3D objects in Wavefront .obj format.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' ?, Initial version\r
+' 2024, Improved program readability\r
+\r
+' Before running, make sure include path is correct. See below.\r
+\r
+DECLARE SUB parsel (a$)\r
+DECLARE SUB stat2 (b!)\r
+DECLARE SUB stat ()\r
+DECLARE SUB getchc (a$, b!)\r
+DECLARE SUB start ()\r
+DECLARE SUB qui ()\r
+DECLARE SUB flushpoly (a!)\r
+DECLARE SUB usemtl (a$)\r
+DECLARE SUB flushp ()\r
+DECLARE SUB parse (a$)\r
+DECLARE SUB geth (b!)\r
+DECLARE SUB cmd (a$)\r
+DECLARE SUB getson (a$)\r
+\r
+DIM SHARED px(1 TO 1000)\r
+DIM SHARED py(1 TO 1000)\r
+DIM SHARED pz(1 TO 1000)\r
+DIM SHARED nump\r
+DIM SHARED numpa\r
+DIM SHARED numpo\r
+\r
+DIM SHARED fil(1 TO 100)\r
+DIM SHARED mitus\r
+DIM SHARED sona$(1 TO 20)\r
+DIM SHARED res\r
+\r
+DIM SHARED mtlm\r
+DIM SHARED mtl$(1 TO 50)\r
+DIM SHARED mtlp1(1 TO 50, 1 TO 100)\r
+DIM SHARED mtlp2(1 TO 50, 1 TO 100)\r
+DIM SHARED mtlp3(1 TO 50, 1 TO 100)\r
+DIM SHARED mtlp4(1 TO 50, 1 TO 100)\r
+DIM SHARED mtll(1 TO 50)\r
+DIM SHARED cmtl\r
+\r
+DIM SHARED stkf(1 TO 500)\r
+DIM SHARED stks(1 TO 500)\r
+DIM SHARED stkp\r
+DIM SHARED fc\r
+DIM SHARED ipath$\r
+\r
+DIM SHARED chc$(1 TO 10, 1 TO 500)\r
+DIM SHARED chcl(1 TO 10)\r
+DIM SHARED chcf$(1 TO 10)\r
+DIM SHARED chct(1 TO 10)\r
+DIM SHARED chctim\r
+DIM SHARED mtmprs\r
+DIM SHARED tmr\r
+\r
+DIM SHARED var$(0 TO 100)\r
+DIM SHARED flag(1 TO 50, 0 TO 9)\r
+DIM SHARED cstatt\r
+DIM SHARED cstatm\r
+\r
+' Path to include resources from. Adjust according to your installation!\r
+ipath$ = "C:\GRAPHICS\3D\3DSYNT~1\INCLUDE\"\r
+\r
+start\r
+\r
+IF COMMAND$ = "" THEN END\r
+CLS\r
+\r
+cmd "obj ~" + COMMAND$\r
+qui\r
+CLOSE #res\r
+fil(res) = 0\r
+\r
+PRINT "done"\r
+SYSTEM\r
+\r
+SUB cmd (z$)\r
+ a$ = z$\r
+ IF LEFT$(a$, 1) = "?" THEN\r
+ IF flag(mtmprs, VAL(RIGHT$(LEFT$(a$, 2), 1))) = 1 THEN\r
+ a$ = RIGHT$(a$, LEN(a$) - 3)\r
+ ELSE\r
+ GOTO 10\r
+ END IF\r
+ END IF\r
+\r
+ getson a$\r
+\r
+ SELECT CASE sona$(1)\r
+ CASE "end"\r
+ qui\r
+ PRINT "terminated from file"\r
+ SYSTEM\r
+\r
+ CASE "warn"\r
+ COLOR 12\r
+ PRINT sona$(2)\r
+ COLOR 7\r
+ b$ = INPUT$(1)\r
+\r
+ CASE "p"\r
+ nump = nump + 1\r
+ numpa = numpa + 1\r
+ x = VAL(sona$(2))\r
+ y = VAL(sona$(3))\r
+ z = VAL(sona$(4))\r
+\r
+ ' Transform the coordinates based on the stack\r
+ FOR b = stkp TO 1 STEP -1\r
+ SELECT CASE stkf(b)\r
+ CASE 1\r
+ c1 = SIN(stks(b) / fc)\r
+ s1 = COS(stks(b) / fc)\r
+ z1 = x * c1 + z * s1\r
+ x1 = x * s1 - z * c1\r
+ x = x1\r
+ z = z1\r
+\r
+ CASE 2\r
+ c1 = SIN(stks(b) / fc)\r
+ s1 = COS(stks(b) / fc)\r
+ z1 = y * c1 + z * s1\r
+ y1 = y * s1 - z * c1\r
+ y = y1\r
+ z = z1\r
+\r
+ CASE 3\r
+ s1 = SIN(stks(b) / fc)\r
+ c1 = COS(stks(b) / fc)\r
+ y1 = y * c1 + x * s1\r
+ x1 = y * s1 - x * c1\r
+ x = x1\r
+ y = y1\r
+\r
+ CASE 10\r
+ x = x + stks(b)\r
+\r
+ CASE 11\r
+ y = y + stks(b)\r
+\r
+ CASE 12\r
+ z = z + stks(b)\r
+\r
+ CASE 20\r
+ x = x - stks(b)\r
+\r
+ CASE 21\r
+ y = y - stks(b)\r
+\r
+ CASE 22\r
+ z = z - stks(b)\r
+\r
+ CASE 30\r
+ x = x * stks(b)\r
+\r
+ CASE 31\r
+ y = y * stks(b)\r
+\r
+ CASE 32\r
+ z = z * stks(b)\r
+ END SELECT\r
+ NEXT b\r
+\r
+ ' Store the transformed coordinates\r
+ px(nump) = x\r
+ py(nump) = y\r
+ pz(nump) = z\r
+\r
+ IF nump > 900 THEN flushp\r
+\r
+ CASE "here"\r
+ numpo = numpa\r
+\r
+ CASE "mtl"\r
+ usemtl sona$(2)\r
+\r
+ CASE "mtlrnd"\r
+ b = INT(RND * (mitus - 1)) + 2\r
+ usemtl sona$(b)\r
+\r
+ CASE "f"\r
+ IF mtll(cmtl) > 90 THEN flushpoly cmtl\r
+ b = mtll(cmtl)\r
+ b = b + 1\r
+ mtll(cmtl) = b\r
+ mtlp1(cmtl, b) = VAL(sona$(2)) + numpo\r
+ mtlp2(cmtl, b) = VAL(sona$(3)) + numpo\r
+ mtlp3(cmtl, b) = VAL(sona$(4)) + numpo\r
+\r
+ ' Handle the optional fourth vertex\r
+ IF sona$(5) = "" THEN\r
+ mtlp4(cmtl, b) = -32000\r
+ ELSE\r
+ mtlp4(cmtl, b) = VAL(sona$(5)) + numpo\r
+ END IF\r
+\r
+ CASE "obj"\r
+ d = stkp\r
+\r
+ ' Parse the transformation stack\r
+ FOR a = mitus TO 3 STEP -1\r
+ b$ = LEFT$(sona$(a), 2)\r
+ c = VAL(RIGHT$(sona$(a), LEN(sona$(a)) - 2))\r
+ stkp = stkp + 1\r
+ stks(stkp) = c\r
+\r
+ SELECT CASE b$\r
+ CASE "xz"\r
+ stkf(stkp) = 1\r
+\r
+ CASE "yz"\r
+ stkf(stkp) = 2\r
+\r
+ CASE "xy"\r
+ stkf(stkp) = 3\r
+\r
+ CASE "x+"\r
+ stkf(stkp) = 10\r
+\r
+ CASE "y+"\r
+ stkf(stkp) = 11\r
+\r
+ CASE "z+"\r
+ stkf(stkp) = 12\r
+\r
+ CASE "x-"\r
+ stkf(stkp) = 20\r
+\r
+ CASE "y-"\r
+ stkf(stkp) = 21\r
+\r
+ CASE "z-"\r
+ stkf(stkp) = 22\r
+\r
+ CASE "x*"\r
+ stkf(stkp) = 30\r
+\r
+ CASE "y*"\r
+ stkf(stkp) = 31\r
+\r
+ CASE "z*"\r
+ stkf(stkp) = 32\r
+ END SELECT\r
+ NEXT a\r
+\r
+ ' Process the object command\r
+ a$ = sona$(2)\r
+ mtmprs = mtmprs + 1\r
+ cstatt = cstatt + 1\r
+\r
+ LOCATE 10 + mtmprs, 1\r
+ PRINT a$\r
+\r
+ ' Read and execute the next command\r
+ getchc a$, b\r
+ c = 1\r
+\r
+2\r
+ d$ = chc$(b, c)\r
+ cmd d$\r
+\r
+ ' Check if the current command matches the expected one\r
+ IF chcf$(b) <> a$ THEN\r
+ getchc a$, b\r
+ END IF\r
+\r
+ c = c + 1\r
+\r
+ ' Continue reading and executing commands until the stack is empty\r
+ IF c <= chcl(b) THEN GOTO 2\r
+\r
+ tmr = tmr + 1\r
+\r
+ ' If more than 20 commands have been processed, update statistics\r
+ IF tmr > 20 THEN\r
+ tmr = 0\r
+ stat\r
+ END IF\r
+\r
+ LOCATE 10 + mtmprs, 1\r
+ PRINT SPACE$(LEN(a$))\r
+\r
+ ' Decrement the command parser stack\r
+ mtmprs = mtmprs - 1\r
+\r
+ stkp = d\r
+\r
+ CASE "#"\r
+\r
+ CASE "out"\r
+ geth res\r
+ OPEN sona$(2) + ".obj" FOR OUTPUT AS #res\r
+ PRINT #res, "mtllib result.mtl"\r
+\r
+ CASE "rnd"\r
+ b = INT(RND * (mitus - 1)) + 2\r
+ c$ = sona$(b)\r
+\r
+ ' Replace caret characters with spaces\r
+ f$ = ""\r
+ FOR d = 1 TO LEN(c$)\r
+ e$ = RIGHT$(LEFT$(c$, d), 1)\r
+ IF e$ = "^" THEN\r
+ e$ = " "\r
+ END IF\r
+ f$ = f$ + e$\r
+ NEXT d\r
+\r
+ cmd f$\r
+\r
+ CASE "set"\r
+ var$(VAL(sona$(2))) = sona$(3)\r
+\r
+ CASE "cmp"\r
+ ' Compare two strings\r
+ IF sona$(3) = sona$(4) THEN\r
+ b = 1\r
+ ELSE\r
+ b = 0\r
+ END IF\r
+\r
+ ' Store the comparison result in the flag array\r
+ flag(mtmprs, VAL(sona$(2))) = b\r
+\r
+ END SELECT\r
+\r
+10\r
+END SUB\r
+\r
+SUB flushp\r
+\r
+ FOR a = 1 TO nump\r
+ PRINT #res, "v " + STR$(px(a)) + " " + STR$(py(a)) + " " + STR$(-pz(a))\r
+ NEXT a\r
+\r
+ nump = 0\r
+\r
+END SUB\r
+\r
+SUB flushpoly (a)\r
+\r
+ IF mtll(a) = 0 THEN GOTO 5\r
+\r
+ ' Write the material usage line\r
+ PRINT #res, "usemtl " + mtl$(a)\r
+\r
+ ' Write the face definitions\r
+ FOR b = 1 TO mtll(a)\r
+ c$ = "f " + STR$(mtlp1(a, b) + 1) + STR$(mtlp2(a, b) + 1) + STR$(mtlp3(a, b) + 1)\r
+\r
+ ' Handle the optional fourth vertex\r
+ IF mtlp4(a, b) <> -32000 THEN\r
+ c$ = c$ + STR$(mtlp4(a, b) + 1)\r
+ END IF\r
+\r
+ PRINT #res, c$\r
+ NEXT b\r
+ mtll(a) = 0\r
+\r
+5\r
+END SUB\r
+\r
+SUB getchc (a$, b!)\r
+\r
+ ' Search for the command in the cache\r
+ FOR c = 1 TO 10\r
+ IF chcf$(c) = a$ THEN\r
+ b = c\r
+ GOTO 6\r
+ END IF\r
+ NEXT c\r
+\r
+ ' Find the least recently used entry in the cache\r
+ d = 32000\r
+ FOR c = 1 TO 10\r
+ IF chct(c) < d THEN\r
+ d = chct(c)\r
+ e = c\r
+ END IF\r
+ NEXT c\r
+\r
+ ' Load the command file\r
+ g = 0\r
+ geth f\r
+\r
+ cstatm = cstatm + 1\r
+ b$ = a$\r
+\r
+ ' Remove leading tilde if present\r
+ IF LEFT$(b$, 1) = "~" THEN\r
+ b$ = RIGHT$(b$, LEN(b$) - 1)\r
+ ELSE\r
+ b$ = ipath$ + b$\r
+ END IF\r
+\r
+ \r
+ PRINT "File:" + b$\r
+ OPEN b$ + ".3d" FOR INPUT AS #f\r
+\r
+8\r
+\r
+ ' Read commands from the file until EOF\r
+ IF EOF(f) <> 0 THEN GOTO 7\r
+\r
+ LINE INPUT #f, c$\r
+\r
+ ' Skip empty lines\r
+ IF (LEFT$(c$, 1) <> "#") AND (c$ <> SPACE$(LEN(c$))) THEN\r
+ g = g + 1\r
+ chc$(e, g) = c$\r
+ END IF\r
+\r
+ GOTO 8\r
+\r
+7\r
+\r
+ ' Close the file and update statistics\r
+ CLOSE #f\r
+ fil(f) = 0\r
+ chcl(e) = g\r
+\r
+ b = e\r
+ chcf$(e) = a$\r
+\r
+ stat\r
+\r
+6\r
+\r
+ ' Update the cache timestamps\r
+ chctim = chctim + 1\r
+ chct(b) = chctim\r
+\r
+ ' If the cache is full, halve all timestamps\r
+ IF chctim > 10000 THEN\r
+ FOR c = 1 TO 10\r
+ chct(c) = chct(c) / 2\r
+ NEXT c\r
+\r
+ chctim = chctim / 2\r
+ END IF\r
+END SUB\r
+\r
+SUB geth (b!)\r
+\r
+ ' Find an unused file handle\r
+ FOR a = 1 TO 100\r
+ IF fil(a) = 0 THEN\r
+ fil(a) = 1\r
+ b = a\r
+ GOTO 1\r
+ END IF\r
+ NEXT a\r
+\r
+1\r
+END SUB\r
+\r
+SUB getson (a$)\r
+\r
+ ' Prepare the sona array for parsing\r
+ b$ = a$ + " "\r
+\r
+ FOR a = 1 TO 20\r
+ sona$(a) = ""\r
+ NEXT a\r
+\r
+ mitus = 0\r
+\r
+ e = 1\r
+\r
+ ' Parse the input string\r
+ FOR c = 1 TO LEN(b$)\r
+ d$ = RIGHT$(LEFT$(b$, c), 1)\r
+\r
+ IF d$ = " " OR d$ = CHR$(9) THEN\r
+ e = 1\r
+ ELSE\r
+ IF e = 1 THEN\r
+ mitus = mitus + 1\r
+ END IF\r
+\r
+ sona$(mitus) = sona$(mitus) + d$\r
+ e = 0\r
+ END IF\r
+ NEXT c\r
+\r
+ ' Replace variable names with their values\r
+ FOR c = 1 TO mitus\r
+ IF LEFT$(sona$(c), 1) = "%" THEN\r
+ sona$(c) = var$(VAL(RIGHT$(sona$(c), LEN(sona$(c)) - 1)))\r
+ END IF\r
+ NEXT c\r
+END SUB\r
+\r
+SUB qui\r
+\r
+ ' Flush the vertex buffer and write all polygons\r
+ flushp\r
+\r
+ FOR a = 1 TO mtlm\r
+ flushpoly a\r
+ NEXT a\r
+\r
+ stat\r
+END SUB\r
+\r
+SUB start\r
+\r
+ RANDOMIZE TIMER\r
+\r
+ ' Initialize arrays\r
+ FOR a = 1 TO 50\r
+ FOR b = 0 TO 9\r
+ flag(a, b) = 0\r
+ NEXT b\r
+ NEXT a\r
+\r
+ FOR a = 0 TO 100\r
+ var$(a) = ""\r
+ NEXT a\r
+\r
+ ' Initialize command cache\r
+ FOR a = 1 TO 10\r
+ FOR b = 1 TO 500\r
+ chc$(a, b) = ""\r
+ NEXT b\r
+\r
+ chcl(a) = 0\r
+ chcf$(a) = ""\r
+ chct(a) = 0\r
+ NEXT a\r
+\r
+ ' Initialize material lists\r
+ FOR a = 1 TO 50\r
+ mtll(a) = 0\r
+ NEXT a\r
+\r
+ ' Initialize file handles\r
+ FOR a = 1 TO 100\r
+ fil(a) = 0\r
+ NEXT a\r
+\r
+ nump = 0\r
+ numpa = 0\r
+ numpo = 0\r
+ mtlm = 0\r
+ stkp = 0\r
+ fc = 180 / 3.141285\r
+ chctim = 0\r
+ mtmprs = 0\r
+ cstatt = 0\r
+ cstatm = 0\r
+END SUB\r
+\r
+SUB stat\r
+\r
+ ' Display statistics\r
+ LOCATE 1, 1\r
+\r
+ FOR a = 1 TO 10\r
+ PRINT a, chcf$(a), chct(a), chcl(a)\r
+ NEXT a\r
+\r
+ COLOR 10\r
+\r
+ LOCATE 1, 50\r
+ PRINT cstatt; "parsed"\r
+\r
+ LOCATE 2, 50\r
+ PRINT cstatm; "cache miss"\r
+\r
+ LOCATE 3, 50\r
+ PRINT INT(cstatm / cstatt * 100); "% cache miss "\r
+\r
+ COLOR 7\r
+END SUB\r
+\r
+SUB stat2 (b!)\r
+\r
+ ' Display the contents of a specific command cache\r
+ CLS\r
+\r
+ FOR a = 1 TO chcl(b)\r
+ PRINT chc$(b, a)\r
+ NEXT a\r
+\r
+ c$ = INPUT$(1)\r
+END SUB\r
+\r
+SUB usemtl (a$)\r
+\r
+ ' Find the material in the list\r
+ FOR b = 1 TO mtlm\r
+ IF mtl$(b) = a$ THEN\r
+ cmtl = b\r
+ GOTO 4\r
+ END IF\r
+ NEXT b\r
+\r
+ ' If not found, add it to the list\r
+ mtlm = mtlm + 1\r
+ mtl$(mtlm) = a$\r
+ cmtl = mtlm\r
+\r
+4\r
+END SUB\r
+\r
--- /dev/null
+# small city block\r
+\r
+out city1\r
+\r
+obj maja xz90\r
+obj maja xz90 x+48\r
+obj maja xz90 x+96\r
+obj maja x+36 z-84\r
+\r
+# korgel olevad autod\r
+obj cars x+25\r
+obj cars x+27 z-50\r
+obj cars x+26 z-25 y-10\r
+obj cars x+25 z-40 y-20\r
+\r
+obj cars x+73 z-25 y+1\r
+obj cars x+75 z-50 y-2\r
+obj cars xz-90 z-60\r
+obj cars xz-90 z-62 x+50\r
+obj cars xz-90 z+60 x+1\r
+obj cars xz-90 z+61 x+52\r
+\r
+obj cars x+121 z-100 y+1\r
+obj cars x+122 z-70 y-5\r
+obj cars x+123 y+2\r
+obj cars x+122 z-38 y-2\r
+\r
+# allpool olevad autod\r
+obj cars x+25 y-30\r
+obj cars x+27 z-50 y-50\r
+obj cars x+26 z-25 y-40\r
+obj cars x+25 z-40 y-50\r
+\r
+obj cars x+73 z-25 y-34\r
+obj cars x+75 z-50 y-36\r
+obj cars xz-90 z-60 y-43\r
+obj cars xz-90 z-62 x+50 y-29\r
+obj cars xz-90 z+60 x+1 y-37\r
+obj cars xz-90 z+61 x+52 y-33\r
+\r
+obj cars x+121 z-100 y-41\r
+obj cars x+122 z-70 y-45\r
+obj cars x+123 y-32\r
+obj cars x+122 z-38 y-34\r
+\r
+\r
--- /dev/null
+@echo off\r
+\r
+rem This script will instruct generator to make "city1".\r
+rem Note: When specifying source file, avoid extension. \r
+\r
+qb /RUN 3dparse.bas /CMD city1
\ No newline at end of file
--- /dev/null
+# Big city, be prepared to wait ~10 min, on P133.\r
+\r
+out city2\r
+obj blk4 y-145\r
+obj blk4 y-116\r
+obj blk4 y-87\r
+obj blk4 y-58\r
+obj blk4 y-29\r
+obj blk4\r
+\r
+mtl kivi\r
+obj ring x*20 z*20 y+26\r
+mtl glass_transp\r
+obj kuppel x*20 z*20 y*10 y+26\r
+\r
+mtl kivi\r
+obj ring x*20 z*20 y+26 z+64.6412\r
+mtl glass_transp\r
+obj kuppel x*20 z*20 y*10 y+26 z+64.6412\r
+\r
+mtl kivi\r
+obj ring x*20 z*20 y+26 x+55.9809 z+32.3206\r
+mtl glass_transp\r
+obj kuppel x*20 z*20 y*10 y+26 x+55.9809 z+32.3206\r
+\r
+mtl kivi\r
+obj ring x*20 z*20 y+26 x+55.9809 z-32.3206\r
+mtl glass_transp\r
+obj kuppel x*20 z*20 y*10 y+26 x+55.9809 z-32.3206\r
+\r
+mtl kivi\r
+obj ring x*20 z*20 y+26 z-64.6412\r
+mtl glass_transp\r
+obj kuppel x*20 z*20 y*10 y+26 z-64.6412\r
+\r
+mtl kivi\r
+obj ring x*20 z*20 y+26 x-55.9809 z-32.3206\r
+mtl glass_transp\r
+obj kuppel x*20 z*20 y*10 y+26 x-55.9809 z-32.3206\r
+\r
+mtl kivi\r
+obj ring x*20 z*20 y+26 x-55.9809 z+32.3206\r
+mtl glass_transp\r
+obj kuppel x*20 z*20 y*10 y+26 x-55.9809 z+32.3206\r
+\r
--- /dev/null
+@echo off\r
+\r
+rem This script will instruct generator to make "city2".\r
+rem Note: When specifying source file, avoid extension. \r
+\r
+qb /RUN 3dparse.bas /CMD city2
\ No newline at end of file
--- /dev/null
+# Wavefront material file\r
+# Must be in the same directory with parsed modules.\r
+\r
+newmtl default\r
+ Ns 32\r
+ d 1\r
+ illum 2\r
+ Kd 0.4 0.4 0.4\r
+ Ks 0.7 0.7 0.7\r
+ Ka 0.3 0.3 0.3\r
+\r
+newmtl muld\r
+ Ns 32\r
+ d 1\r
+ illum 2\r
+ Kd 0.247843 0.17098 0.158431\r
+ Ks 0 0 0\r
+ Ka 0.185882 0.128235 0.118824\r
+\r
+newmtl kivi\r
+ Ns 32\r
+ d 1\r
+ illum 2\r
+ Kd 0.24935 0.216378 0.24935\r
+ Ks 0 0 0\r
+ Ka 0.128955 0.111903 0.128955\r
+\r
+newmtl klaastume\r
+ Ns 32\r
+ d 1\r
+ illum 2\r
+ Kd 0.139608 0.0313726 0.108235\r
+ Ks 1.6633 0.373775 1.28952\r
+ Ka 0.104706 0.0235294 0.0811765\r
+\r
+newmtl klaashele\r
+ Ns 32\r
+ d 1\r
+ illum 2\r
+ Kd 0.0925798 0.104637 0.109804\r
+ Ks 3.54381 4.00533 4.20313\r
+ Ka 0.737332 0.833356 0.87451\r
+\r
+newmtl seintellis\r
+ Ns 32\r
+ d 1\r
+ illum 2\r
+ Kd 0.476309 0.432511 0.0875971\r
+ Ks 0 0 0\r
+ Ka 0.0642215 0.058316 0.0118108\r
+\r
+newmtl pronks\r
+ Ns 4\r
+ d 1\r
+ illum 2\r
+ Kd 0.238431 0.148435 0.0584391\r
+ Ks 0.636863 0.396478 0.156094\r
+ Ka 0.0627451 0.0390619 0.0153787\r
+\r
+newmtl solar\r
+ Ns 32\r
+ d 1\r
+ illum 2\r
+ Kd 0.189927 0.10519 0.745098\r
+ Ks 1.27451 0.705882 5\r
+ Ka 0.0609766 0.0337716 0.239216\r
+\r
+newmtl metal_yellow\r
+ Ns 32\r
+ d 1\r
+ illum 2\r
+ Kd 0.619608 0.619608 0\r
+ Ks 3.01563 3.01563 0\r
+ Ka 0.3 0.3 0\r
+\r
+newmtl metal_blue\r
+ Ns 32\r
+ d 1\r
+ illum 2\r
+ Kd 0.243137 0.243137 0.666667\r
+ Ks 0.695221 0.695221 1.90625\r
+ Ka 0.109412 0.109412 0.3\r
+\r
+newmtl light_red\r
+ Ns 32\r
+ d 1\r
+ illum 2\r
+ Kd 0.443137 0 0\r
+ Ks 3.8125 0 0\r
+ Ka 0.3 0 0\r
+\r
+\r
+newmtl light_white\r
+ Ns 32\r
+ d 1\r
+ illum 2\r
+ Kd 0.497347 0.528135 0.603922\r
+ Ks 2.35478 2.50055 2.85938\r
+ Ka 0.247059 0.262353 0.3\r
+\r
+newmtl glass_transp\r
+ Ns 39\r
+ d 0.572549\r
+ illum 2\r
+ Kd 0.129412 0.427451 0.776471\r
+ Ks 0.129412 0.427451 0.776471\r
+ Ka 0.000985995 0.00325677 0.00591597\r
+\r
--- /dev/null
+#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
+#+TITLE: 3D Synthezier
+#+LANGUAGE: en
+#+LATEX_HEADER: \usepackage[margin=1.0in]{geometry}
+#+LATEX_HEADER: \usepackage{parskip}
+#+LATEX_HEADER: \usepackage[none]{hyphenat}
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+ .flex-center {
+ display: flex; /* activate flexbox */
+ justify-content: center; /* horizontally center anything inside */
+ }
+
+ .flex-center video {
+ width: min(90%, 1000px); /* whichever is smaller wins */
+ height: auto; /* preserve aspect ratio */
+ }
+
+ .responsive-img {
+ width: min(100%, 1000px);
+ height: auto;
+ }
+</style>
+#+end_export
+
+
+* Operating principle
+
+Parses scene definition language and creates 3D world based on
+it. Result will be in a [[https://en.wikipedia.org/wiki/Wavefront_.obj_file][wavefront obj file]], witch can be then
+visualized using external renderer.
+
+Basic concept of defining scene is:
+- Simple and primitive objects are created on point and polygon level.
+- More complex ones can be created my combinig already existing ones,
+ while applying various transformations on them.
+
+Objects with all its subobjects can be rotated, mirrored or resized
+omong any axis. Generator has built in cache for data input and output
+to minimize file access.
+
+*Examples:*
+
+Download Blender files:
+| file | size |
+|------------------------+--------|
+| [[file:rectangular city.blend][rectangular city.blend]] | 3.6 MB |
+| [[file:hexagonal city.blend][hexagonal city.blend]] | 21 MB |
+
+They were produced by importing generated [[https://en.wikipedia.org/wiki/Wavefront_.obj_file][wavefront obj files]] into
+[[https://www.blender.org/][Blender]].
+
+** Rectangular city
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:rectangular city, 1.jpeg]]
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:rectangular city, 2.jpeg]]
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:rectangular city, 3.jpeg]]
+** Hexagonal city
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:hexagonal city, 1.jpeg]]
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:hexagonal city, 2.jpeg]]
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:hexagonal city, 3.jpeg]]
+* Scene description language
+See also examples.
+** here
+ : here
+ defines new segment
+** p
+ : p x y z
+ defines new point
+** f
+ : f p1 p2 p3 p4
+ defines new polygon, p4 may be unused
+** warn
+ : warn <message>
+ displays warning message, and wait for key
+** end
+ : end
+ terminates parser
+** mtl
+ : mtl material
+ selects material
+** mtlrnd
+ : mtlrnd material ...
+ selects random material from list
+** obj
+ : obj object xz45 xy20 x+3 y*2
+ includes sub object, can be rotated moved or resized, across X Y Z. If
+ object name begin vith ~ then it will be loaded from current
+ directory. if object name ends with ~ then object will be parsed
+ directly from file, and not chached, to allow loading of greater than
+ 500 lines files.
+
+ [[file:rotation.png]]
+** rnd
+ : rnd p^1^2^3 p^7^2^1
+ select random command to execute, ^ will be converted to spaces.
+** #
+ : # whatever text
+ comment
+** out
+ : out file
+ specify output file name, must be first command
+** set
+ : set variable contents
+ set variable contents, variable must be number, contents can be
+ string. max variables is 100. first is 0.
+** variables usage
+ : anycommand %1 anything
+ inserts variable 1 contents info line
+** cmp
+ : cmp flag string1 string2
+ compares strings, and inserts TRUE to flag, if they are equal, else inserts FALSE. max 9 falgs, 0 first. Each subobject has its own flags.
+** ?
+ : ?flag anycommand
+ executes command if flag is true.
+
+ exapmle: ?3 obj car z*2 xy45
+** dum
+ : dum
+ dummy function, does notheing
+
+* Installation
+Edit *bin/3dparse.bas* file and update include path in there.
+
+** System requirements
+
+| software | tested version |
+|----------+----------------|
+| DOS | 6.22 |
+| QBasic | 4.5 |
+
+** Directory layout
+
++ bin ::
+ + 3dparse.bas :: 3D generator main executable
+ + city1.3d :: city with square-like buildings
+ + city2.3d :: city with hexangular buildings
+ + result.mtl :: shared material library
+ + *.bat :: quick launch scripts
+
++ include :: 3D objects used to compose the scene
+
+* Usage
+
+Make sure you have QB binaries in your PATH. Execute
+: bin/city1.bat
+or
+: bin/city2.bat
+to generate example cities. After parsing is finished, appropriate
+*.obj files will appear in the bin directory holding generated scene.
+Visualize scene with your favourite renderer.
--- /dev/null
+# suur 6 nurkse maja kompleks koos korteritega\r
+\r
+obj blk3\r
+set 1 kivi\r
+set 2 0\r
+obj nrk6 x*20 y*5 z*20 y+21\r
--- /dev/null
+# suur 6 nurkse maja kompleks koos korterite ja 2. sillaga\r
+\r
+obj blk3\r
+set 1 kivi\r
+set 2 0\r
+obj nrk6 x*20 y*5 z*20 y+21\r
+obj bridgegl xz-90 y+22.5 x-1.5 z-17.3206\r
+obj bridgegl xz-30 y+22.5 x+14.25 z-9.9593
\ No newline at end of file
--- /dev/null
+# tavaline suur aken\r
+here\r
+p 0 0 0\r
+p 6 0 0\r
+p 6 -3 0\r
+p 0 -3 0\r
+\r
+p 0.5 -0.5 -0.01\r
+p 5.5 -0.5 -0.01\r
+p 5.5 -2 -0.01\r
+p 0.5 -2 -0.01\r
+mtl seintellis\r
+f 0 1 2 3\r
+mtlrnd klaashele klaastume\r
+f 4 5 6 7
\ No newline at end of file
--- /dev/null
+# v2ike aken koosparkimisplatsiga\r
+\r
+# rnd obj^car^xz90^x+4.5^z-1.7^y-2.5 # #\r
+\r
+here\r
+p 0 0 0\r
+p 6 0 0\r
+p 6 -3 0\r
+p 0 -3 0\r
+\r
+p 0.5 -0.5 -0.01\r
+p 2 -0.5 -0.01\r
+p 2 -2 -0.01\r
+p 0.5 -2 -0.01\r
+\r
+p 2.5 -0.5 -0.01\r
+p 5.5 -0.5 -0.01\r
+p 5.5 -3 -0.01\r
+p 2.5 -3 -0.01\r
+\r
+p 0 -3 0\r
+p 6 -3 0\r
+p 6 -3 -3\r
+p 0 -3 -3\r
+\r
+mtl seintellis\r
+f 0 1 2 3\r
+mtlrnd klaashele klaastume\r
+f 4 5 6 7\r
+mtl pronks\r
+f 8 9 10 11\r
+mtl kivi\r
+f 12 13 14 15
\ No newline at end of file
--- /dev/null
+# kuuenurkse maja korterite blokk\r
+\r
+obj krs2\r
+obj krs2 y+3\r
+obj krs2 y+6\r
+obj krs2 y+9\r
+\r
+obj krs2 y+12\r
+obj krs2 y+15\r
+obj krs2 y+18\r
+obj krs2 y+21\r
+\r
+here\r
+p -12 -3 -20.7846\r
+p 12 -3 -20.7846\r
+p 24 -3 0 \r
+p 12 -3 20.7846\r
+p -12 -3 20.7846\r
+p -24 -3 0\r
+\r
+p -12 21 -20.7846\r
+p 12 21 -20.7846\r
+p 24 21 0 \r
+p 12 21 20.7846\r
+p -12 21 20.7846\r
+p -24 21 0\r
+\r
+mtl seintellis\r
+f 0 1 2 3\r
+f 3 4 5 0\r
+f 6 7 8 9\r
+f 9 10 11 6\r
+\r
+\r
--- /dev/null
+# 1 kompleks 7st, 6 nurkselt sildadega uhendatud elamu moodulitest\r
+obj 6nrk0s\r
+obj 6nrk2s z+64.6412\r
+obj 6nrk2s xz-60 x+55.9809 z+32.3206\r
+obj 6nrk2s xz-120 x+55.9809 z-32.3206\r
+obj 6nrk2s xz-180 z-64.6412\r
+obj 6nrk2s xz-240 x-55.9809 z-32.3206\r
+obj 6nrk2s xz-300 x-55.9809 z+32.3206
\ No newline at end of file
--- /dev/null
+obj handrail\r
+obj handrail z+3\r
+set 1 kivi\r
+set 2 0\r
+obj nrk4 x*3.2 y*0.2 xz-90 z+1.5
\ No newline at end of file
--- /dev/null
+obj bridge\r
+obj bridge x+1\r
+obj bridge x+2\r
+obj bridge x+3\r
+obj bridge x+4\r
+\r
+obj bridge x+5\r
+obj bridge x+6\r
+obj bridge x+7\r
+obj bridge x+8\r
+obj bridge x+9\r
+\r
+obj bridge x+10\r
+obj bridge x+11\r
+obj bridge x+12\r
+obj bridge x+13\r
+obj bridge x+14\r
+\r
+obj bridge x+15\r
+obj bridge x+16\r
+obj bridge x+17\r
+obj bridge x+18\r
+obj bridge x+19\r
+\r
+obj bridge x+20\r
+obj bridge x+21\r
+obj bridge x+22\r
+obj bridge x+23\r
+obj bridge x+24\r
+\r
+obj bridge x+25\r
+obj bridge x+26\r
+obj bridge x+27\r
+obj bridge x+28\r
+obj bridge x+29\r
+\r
--- /dev/null
+obj bridge1\r
+set 1 glass_transp\r
+set 2 0\r
+obj nrk8 xz-90 x*30 z*3 z+1.5 y*2 y+1
\ No newline at end of file
--- /dev/null
+obj bus_frnt\r
+obj bus_frnt xz180 z+9\r
+\r
+obj bus_wind x+2.5 y+1 z+2\r
+obj bus_wind x+2.5 y+1 z+3.5\r
+obj bus_wind x+2.5 y+1 z+5\r
+\r
+obj bus_wind x*-1 x-2.5 y+1 z+2\r
+obj bus_wind x*-1 x-2.5 y+1 z+3.5\r
+obj bus_wind x*-1 x-2.5 y+1 z+5\r
+\r
+obj flare_w x+1 z-0.01\r
+obj flare_w x*-1 x-1 z-0.01\r
+obj flare_r x+1 z+9.01\r
+obj flare_r x*-1 x-1 z+9.01\r
+here\r
+p -2.5 1 0.5\r
+p 2.5 1 0.5\r
+p 2.5 -1 0.5\r
+p -2.5 -1 0.5\r
+\r
+p -2.5 1 8.5\r
+p 2.5 1 8.5\r
+p 2.5 -1 8.5\r
+p -2.5 -1 8.5\r
+\r
+p -2.5 1 2\r
+p 2.5 1 2\r
+p -1.5 2 2\r
+p 1.5 2 2\r
+\r
+p -2.5 1 6.5\r
+p 2.5 1 6.5\r
+p -1.5 2 6.5\r
+p 1.5 2 6.5\r
+\r
+\r
+mtl metal_yellow\r
+# f 0 1 5 4\r
+f 1 2 6 5\r
+f 2 3 7 6\r
+f 3 0 4 7\r
+\r
+f 4 5 15 14\r
+f 4 12 14\r
+f 5 13 15\r
+\r
+mtl klaashele\r
+f 0 1 11 10\r
+f 0 8 10\r
+f 1 9 11\r
+\r
--- /dev/null
+here\r
+p -2 -0.5 0\r
+p 2 -0.5 0\r
+p 2 0.5 0\r
+p -2 0.5 0\r
+\r
+p -2.5 -1 0.5\r
+p 2.5 -1 0.5\r
+p 2.5 1 0.5\r
+p -2.5 1 0.5\r
+\r
+mtl metal_yellow\r
+f 0 1 2 3\r
+f 0 1 5 4\r
+f 1 2 6 5\r
+f 2 3 7 6\r
+f 0 3 7 4
\ No newline at end of file
--- /dev/null
+here\r
+p 0 0 0\r
+p -1 1 0\r
+p -1 1 0.5\r
+p 0 0 0.5\r
+\r
+p -1 1 1.5\r
+p 0 0 1.5\r
+\r
+p -2.5 1 0\r
+p -2.5 1 1.5\r
+\r
+mtl metal_yellow\r
+f 0 1 2 3\r
+f 1 4 7 6\r
+mtl klaashele\r
+f 2 3 5 4
\ No newline at end of file
--- /dev/null
+obj car_frnt\r
+obj car_frnt xz180 z+4\r
+obj flare_w x+0.25 z-0.01\r
+obj flare_w x*-1 x-0.25 z-0.01\r
+obj flare_r x+0.25 z+4.01\r
+obj flare_r x*-1 x-0.25 z+4.01\r
+\r
+here\r
+p -1 0.5 1\r
+p 1 0.5 1\r
+p 1 -0.5 1\r
+p -1 -0.5 1\r
+\r
+p -1 0.5 3\r
+p 1 0.5 3\r
+p 1 -0.5 3\r
+p -1 -0.5 3\r
+\r
+p -0.5 1.5 2.5\r
+p 0.5 1.5 2.5\r
+\r
+\r
+\r
+mtl metal_yellow\r
+# f 0 4 5 1\r
+f 1 5 6 2\r
+f 2 6 7 3\r
+f 3 7 4 0\r
+mtl klaashele\r
+f 8 9 1 0\r
+f 8 0 4\r
+f 9 1 5\r
+f 8 9 5 4
\ No newline at end of file
--- /dev/null
+here\r
+p -0.5 0.25 0\r
+p 0.5 0.25 0\r
+p 0.5 -0.25 0\r
+p -0.5 -0.25 0\r
+\r
+p -1 0.5 1\r
+p 1 0.5 1\r
+p 1 -0.5 1\r
+p -1 -0.5 1\r
+\r
+mtl metal_yellow\r
+f 0 1 2 3\r
+f 0 4 5 1\r
+f 1 5 6 2\r
+f 2 6 7 3\r
+f 3 7 4 0
\ No newline at end of file
--- /dev/null
+obj bus xz190 y+1\r
+obj car xz175 z+20 y-0.5\r
+obj car xz182 yz10 x+5 z+50 y-0.2\r
+obj car xz170 yz-5 xy10 x+1 z+60 y-1.3\r
+obj car xz188 yz-2 xy-5 x+3 z+34 y+0.6\r
+\r
+obj car xz5 yz1 xy15 x-5 z+55 y+0.23\r
+obj car xz-2 yz2 xy-3 x-10 z+32 y-1.1\r
+obj car xz-4 yz-8 xy-9 x-5 z+8 y+0.4\r
+rnd obj^car^xz3^yz-2^xy3^x-8^z+57^y+0.1 obj^pol^xz3^yz-2^xy3^x-8^z+57^y+0.1\r
--- /dev/null
+here\r
+p 0 0.3 0\r
+p 0.3 0.3 0\r
+p 0.3 0 0\r
+p 0 0 0\r
+p 0.4 0.15 0\r
+mtl light_red\r
+f 0 1 2 3\r
+f 1 2 4
\ No newline at end of file
--- /dev/null
+here\r
+p 0 0.3 0\r
+p 0.3 0.3 0\r
+p 0.3 0 0\r
+p 0 0 0\r
+p 0.4 0.15 0\r
+mtl light_white\r
+f 0 1 2 3\r
+f 1 2 4
\ No newline at end of file
--- /dev/null
+# size x=1 y=1 z=0.1\r
+\r
+set 1 pronks\r
+set 2 1\r
+obj nrk8 xz-90 y*0.1 z*0.1 y+1\r
+set 2 0\r
+obj nrk8 x*0.07 y*0.07 yz-90 \r
+obj nrk8 x*0.07 y*0.07 yz-90 x+0.5\r
--- /dev/null
+here\r
+p 0 0 0\r
+p 96 0 0\r
+p 96 0 24\r
+p 0 0 24\r
+\r
+mtl kivi\r
+f 0 1 2 3\r
+\r
+obj toru x+12 z+12\r
+obj toru x+36 z+12\r
+obj solar x+72 z+12
\ No newline at end of file
--- /dev/null
+here\r
+p 0 0 0\r
+p 96 0 0\r
+p 96 0 24\r
+p 0 0 24\r
+\r
+mtl kivi\r
+f 0 1 2 3\r
+\r
+obj toru x+12 z+12\r
+# obj toru x*0.2 z*0.2 y*0.5 x+36 z+12\r
+obj toru x*0.4 z*0.4 y*0.5 x+30 z+6\r
+obj toru x*0.4 z*0.4 y*0.5 x+30 z+18\r
+obj toru x*0.4 z*0.4 y*0.5 x+42 z+6\r
+obj toru x*0.4 z*0.4 y*0.5 x+42 z+18\r
+\r
+obj bus x+60 y+1 z+2\r
+obj bus x+70 y+1 z+2\r
+obj bus x+80 y+1 z+2
\ No newline at end of file
--- /dev/null
+here\r
+p 0 0 0\r
+p 96 0 0\r
+p 96 0 24\r
+p 0 0 24\r
+\r
+mtl kivi\r
+f 0 1 2 3\r
+\r
+obj pol y+0.5 x+2 z+1\r
+obj pol y+0.5 x+9 z+1\r
+obj pol y+0.5 x+16 z+1\r
+obj pol y+0.5 x+23 z+1\r
+obj pol y+0.5 x+30 z+1\r
+obj pol y+0.5 x+37 z+1\r
+obj pol y+0.5 x+44 z+1\r
+obj pol y+0.5 x+51 z+1\r
+\r
+obj pol y+0.5 x+2 z+13\r
+obj pol y+0.5 x+9 z+13\r
+obj pol y+0.5 x+16 z+13\r
+obj pol y+0.5 x+23 z+13\r
+obj pol y+0.5 x+30 z+13\r
+obj pol y+0.5 x+37 z+13\r
+obj pol y+0.5 x+44 z+13\r
+obj pol y+0.5 x+51 z+13\r
+\r
+obj bus xz90 y+1 x+70 z+6\r
+obj bus xz90 y+1 x+85 z+6\r
+obj bus xz90 y+1 x+70 z+17\r
+obj bus xz90 y+1 x+85 z+17\r
--- /dev/null
+# neljanurkse maja korrus\r
+\r
+obj seinp1 x-48 z-12\r
+obj seinp1 xz180 x+48 z+12\r
+obj seinl1 xz270 x-48 z+12\r
+obj seinl1 xz90 x+48 z-12
\ No newline at end of file
--- /dev/null
+# kuuenurkse maja 1 korrus\r
+\r
+obj seinl1 x-12 z-20.7846\r
+obj seinl1 xz60 x+12 z-20.7846\r
+obj seinl1 xz120 x+24\r
+obj seinl1 xz180 x+12 z+20.7846\r
+obj seinl1 xz240 x-12 z+20.7846\r
+obj seinl1 xz300 x-24 \r
+\r
--- /dev/null
+here\r
+p 0 0 0\r
+p -1.0 0.0 0.0\r
+p -0.965926 0.0 -0.258819 \r
+p -0.965926 0.0 0.258819 \r
+p -0.965926 0.258819 0.0 \r
+p -0.933013 0.258819 -0.250000 \r
+p -0.933013 0.258819 0.250000 \r
+p -0.866025 0.0 -0.500000 \r
+p -0.866025 0.0 0.500000 \r
+p -0.866025 0.500000 0.0 \r
+p -0.836516 0.258819 -0.482963 \r
+p -0.836516 0.258819 0.482963 \r
+p -0.836516 0.500000 -0.224144 \r
+p -0.836516 0.500000 0.224144 \r
+p -0.750000 0.500000 -0.433013 \r
+p -0.750000 0.500000 0.433013 \r
+p -0.707107 0.0 -0.707107 \r
+p -0.707107 0.0 0.707107 \r
+p -0.707107 0.707107 0.0 \r
+p -0.683013 0.258819 -0.683013 \r
+p -0.683013 0.258819 0.683013 \r
+p -0.683013 0.707107 -0.183013 \r
+p -0.683013 0.707107 0.183013 \r
+p -0.612372 0.500000 -0.612372 \r
+p -0.612372 0.500000 0.612372 \r
+p -0.612372 0.707107 -0.353553 \r
+p -0.612372 0.707107 0.353553 \r
+p -0.500000 0.0 -0.866025 \r
+p -0.500000 0.0 0.866025 \r
+p -0.500000 0.866025 0.0 \r
+p -0.500000 0.707107 -0.500000 \r
+p -0.500000 0.707107 0.500000 \r
+p -0.482963 0.258819 -0.836516 \r
+p -0.482963 0.258819 0.836516 \r
+p -0.482963 0.866025 -0.129410 \r
+p -0.482963 0.866025 0.129410 \r
+p -0.433013 0.500000 -0.750000 \r
+p -0.433013 0.500000 0.750000 \r
+p -0.433013 0.866025 -0.250000 \r
+p -0.433013 0.866025 0.250000 \r
+p -0.353553 0.707107 -0.612372 \r
+p -0.353553 0.707107 0.612372 \r
+p -0.353553 0.866025 -0.353553 \r
+p -0.353553 0.866025 0.353553 \r
+p -0.258819 0.0 -0.965926 \r
+p -0.258819 0.0 0.965926 \r
+p -0.258819 0.965926 0.0 \r
+p -0.250000 0.258819 -0.933013 \r
+p -0.250000 0.258819 0.933013 \r
+p -0.250000 0.866025 -0.433013 \r
+p -0.250000 0.866025 0.433013 \r
+p -0.250000 0.965926 -0.066987 \r
+p -0.250000 0.965926 0.066987 \r
+p -0.224144 0.500000 -0.836516 \r
+p -0.224144 0.500000 0.836516 \r
+p -0.224144 0.965926 -0.129410 \r
+p -0.224144 0.965926 0.129410 \r
+p -0.183013 0.707107 -0.683013 \r
+p -0.183013 0.707107 0.683013 \r
+p -0.183013 0.965926 -0.183013 \r
+p -0.183013 0.965926 0.183013 \r
+p -0.129410 0.866025 -0.482963 \r
+p -0.129410 0.866025 0.482963 \r
+p -0.129410 0.965926 -0.224144 \r
+p -0.129410 0.965926 0.224144 \r
+p -0.066987 0.965926 -0.250000 \r
+p -0.066987 0.965926 0.250000 \r
+p 0.0 0.0 1.0 \r
+p 0.0 0.258819 0.965926 \r
+p 0.0 0.500000 0.866025 \r
+p 0.0 0.707107 0.707107 \r
+p 0.0 0.866025 0.500000 \r
+p 0.0 0.965926 0.258819 \r
+p 0.0 1.0 0.0 \r
+p 0.0 0.965926 -0.258819 \r
+p 0.0 0.866025 -0.500000 \r
+p 0.0 0.707107 -0.707107 \r
+p 0.0 0.500000 -0.866025 \r
+p 0.0 0.258819 -0.965926 \r
+p 0.0 0.0 -1.0 \r
+p 0.066987 0.965926 -0.250000 \r
+p 0.066987 0.965926 0.250000 \r
+p 0.129410 0.866025 -0.482963 \r
+p 0.129410 0.866025 0.482963 \r
+p 0.129410 0.965926 -0.224144 \r
+p 0.129410 0.965926 0.224144 \r
+p 0.183013 0.707107 -0.683013 \r
+p 0.183013 0.707107 0.683013 \r
+p 0.183013 0.965926 -0.183013 \r
+p 0.183013 0.965926 0.183013 \r
+p 0.224144 0.500000 -0.836516 \r
+p 0.224144 0.500000 0.836516 \r
+p 0.224144 0.965926 -0.129410 \r
+p 0.224144 0.965926 0.129410 \r
+p 0.250000 0.258819 -0.933013 \r
+p 0.250000 0.258819 0.933013 \r
+p 0.250000 0.866025 -0.433013 \r
+p 0.250000 0.866025 0.433013 \r
+p 0.250000 0.965926 -0.066987 \r
+p 0.250000 0.965926 0.066987 \r
+p 0.258819 0.0 -0.965926 \r
+p 0.258819 0.0 0.965926 \r
+p 0.258819 0.965926 0.0 \r
+p 0.353553 0.707107 -0.612372 \r
+p 0.353553 0.707107 0.612372 \r
+p 0.353553 0.866025 -0.353553 \r
+p 0.353553 0.866025 0.353553 \r
+p 0.433013 0.500000 -0.750000 \r
+p 0.433013 0.500000 0.750000 \r
+p 0.433013 0.866025 -0.250000 \r
+p 0.433013 0.866025 0.250000 \r
+p 0.482963 0.258819 -0.836516 \r
+p 0.482963 0.258819 0.836516 \r
+p 0.482963 0.866025 -0.129410 \r
+p 0.482963 0.866025 0.129410 \r
+p 0.500000 0.707107 -0.500000 \r
+p 0.500000 0.707107 0.500000 \r
+p 0.500000 0.0 -0.866025 \r
+p 0.500000 0.0 0.866025 \r
+p 0.500000 0.866025 0.0 \r
+p 0.612372 0.500000 -0.612372 \r
+p 0.612372 0.500000 0.612372 \r
+p 0.612372 0.707107 -0.353553 \r
+p 0.612372 0.707107 0.353553 \r
+p 0.683013 0.258819 -0.683013 \r
+p 0.683013 0.258819 0.683013 \r
+p 0.683013 0.707107 -0.183013 \r
+p 0.683013 0.707107 0.183013 \r
+p 0.707107 0.0 -0.707107 \r
+p 0.707107 0.0 0.707107 \r
+p 0.707107 0.707107 0.0 \r
+p 0.750000 0.500000 -0.433013 \r
+p 0.750000 0.500000 0.433013 \r
+p 0.836516 0.258819 -0.482963 \r
+p 0.836516 0.258819 0.482963 \r
+p 0.836516 0.500000 -0.224144 \r
+p 0.836516 0.500000 0.224144 \r
+p 0.866025 0.0 -0.500000 \r
+p 0.866025 0.0 0.500000 \r
+p 0.866025 0.500000 0.0 \r
+p 0.933013 0.258819 -0.250000 \r
+p 0.933013 0.258819 0.250000 \r
+p 0.965926 0.0 -0.258819 \r
+p 0.965926 0.0 0.258819 \r
+p 0.965926 0.258819 0.0 \r
+p 1.0 0.0 0.0 \r
+\r
+f 73 102 98\r
+f 102 119 113 98\r
+f 119 130 126 113\r
+f 130 139 135 126\r
+f 139 144 140 135\r
+f 144 145 142 140\r
+f 73 98 92\r
+f 98 113 109 92\r
+f 113 126 122 109\r
+f 126 135 131 122\r
+f 135 140 133 131\r
+f 140 142 137 133\r
+f 73 92 88\r
+f 92 109 105 88\r
+f 109 122 115 105\r
+f 122 131 120 115\r
+f 131 133 124 120\r
+f 133 137 128 124\r
+f 73 88 84\r
+f 88 105 96 84\r
+f 105 115 103 96\r
+f 115 120 107 103\r
+f 120 124 111 107\r
+f 124 128 117 111\r
+f 73 84 80\r
+f 84 96 82 80\r
+f 96 103 86 82\r
+f 103 107 90 86\r
+f 107 111 94 90\r
+f 111 117 100 94\r
+f 73 80 74\r
+f 80 82 75 74\r
+f 82 86 76 75\r
+f 86 90 77 76\r
+f 90 94 78 77\r
+f 94 100 79 78\r
+f 73 74 65\r
+f 74 75 61 65\r
+f 75 76 57 61\r
+f 76 77 53 57\r
+f 77 78 47 53\r
+f 78 79 44 47\r
+f 73 65 63\r
+f 65 61 49 63\r
+f 61 57 40 49\r
+f 57 53 36 40\r
+f 53 47 32 36\r
+f 47 44 27 32\r
+f 73 63 59\r
+f 63 49 42 59\r
+f 49 40 30 42\r
+f 40 36 23 30\r
+f 36 32 19 23\r
+f 32 27 16 19\r
+f 73 59 55\r
+f 59 42 38 55\r
+f 42 30 25 38\r
+f 30 23 14 25\r
+f 23 19 10 14\r
+f 19 16 7 10\r
+f 73 55 51\r
+f 55 38 34 51\r
+f 38 25 21 34\r
+f 25 14 12 21\r
+f 14 10 5 12\r
+f 10 7 2 5\r
+f 73 51 46\r
+f 51 34 29 46\r
+f 34 21 18 29\r
+f 21 12 9 18\r
+f 12 5 4 9\r
+f 5 2 1 4\r
+f 73 46 52\r
+f 46 29 35 52\r
+f 29 18 22 35\r
+f 18 9 13 22\r
+f 9 4 6 13\r
+f 4 1 3 6\r
+f 73 52 56\r
+f 52 35 39 56\r
+f 35 22 26 39\r
+f 22 13 15 26\r
+f 13 6 11 15\r
+f 6 3 8 11\r
+f 73 56 60\r
+f 56 39 43 60\r
+f 39 26 31 43\r
+f 26 15 24 31\r
+f 15 11 20 24\r
+f 11 8 17 20\r
+f 73 60 64\r
+f 60 43 50 64\r
+f 43 31 41 50\r
+f 31 24 37 41\r
+f 24 20 33 37\r
+f 20 17 28 33\r
+f 73 64 66\r
+f 64 50 62 66\r
+f 50 41 58 62\r
+f 41 37 54 58\r
+f 37 33 48 54\r
+f 33 28 45 48\r
+f 73 66 72\r
+f 66 62 71 72\r
+f 62 58 70 71\r
+f 58 54 69 70\r
+f 54 48 68 69\r
+f 48 45 67 68\r
+f 73 72 81\r
+f 72 71 83 81\r
+f 71 70 87 83\r
+f 70 69 91 87\r
+f 69 68 95 91\r
+f 68 67 101 95\r
+f 73 81 85\r
+f 81 83 97 85\r
+f 83 87 104 97\r
+f 87 91 108 104\r
+f 91 95 112 108\r
+f 95 101 118 112\r
+f 73 85 89\r
+f 85 97 106 89\r
+f 97 104 116 106\r
+f 104 108 121 116\r
+f 108 112 125 121\r
+f 112 118 129 125\r
+f 73 89 93\r
+f 89 106 110 93\r
+f 106 116 123 110\r
+f 116 121 132 123\r
+f 121 125 134 132\r
+f 125 129 138 134\r
+f 73 93 99\r
+f 93 110 114 99\r
+f 110 123 127 114\r
+f 123 132 136 127\r
+f 132 134 141 136\r
+f 134 138 143 141\r
+f 73 99 102\r
+f 99 114 119 102\r
+f 114 127 130 119\r
+f 127 136 139 130\r
+f 136 141 144 139\r
+f 141 143 145 144\r
--- /dev/null
+obj krs1 y-90\r
+obj krs1 y-87\r
+obj krs1 y-84\r
+obj krs1 y-81\r
+obj krs1 y-78\r
+obj krs1 y-75\r
+obj krs1 y-72\r
+obj krs1 y-69\r
+obj krs1 y-66\r
+obj krs1 y-63\r
+obj krs1 y-60\r
+obj krs1 y-57\r
+obj krs1 y-54\r
+obj krs1 y-51\r
+obj krs1 y-48\r
+obj krs1 y-45\r
+obj krs1 y-42\r
+obj krs1 y-39\r
+obj krs1 y-36\r
+obj krs1 y-33\r
+obj krs1 y-30\r
+obj krs1 y-27\r
+obj krs1 y-24\r
+obj krs1 y-21\r
+obj krs1 y-18\r
+obj krs1 y-15\r
+obj krs1 y-12\r
+obj krs1 y-9\r
+obj krs1 y-6\r
+obj krs1 y-3\r
+obj krs1\r
+obj krs1 y+3\r
+rnd obj^katus^x-48^z-12^y+3 obj^katus2^x-48^z-12^y+3 obj^katus3^x-48^z-12^y+3\r
--- /dev/null
+# 1 -body material\r
+# 2 = 1 -ends filled\r
+#\r
+# 0--1\r
+# | | Y\r
+# 3--2\r
+#\r
+# X\r
+\r
+here\r
+p -0.5 0.5 0\r
+p 0.5 0.5 0\r
+p 0.5 -0.5 0\r
+p -0.5 -0.5 0\r
+\r
+p -0.5 0.5 1\r
+p 0.5 0.5 1\r
+p 0.5 -0.5 1\r
+p -0.5 -0.5 1\r
+\r
+mtl %1\r
+f 0 1 5 4\r
+f 1 2 6 5\r
+f 2 3 7 6\r
+f 3 0 4 7\r
+\r
+cmp 0 %2 1\r
+?0 f 0 1 2 3\r
+?0 f 4 5 6 7\r
--- /dev/null
+# 1 -body material\r
+# 2 = 1 -ends filled\r
+\r
+here\r
+p -0.5 0 0.866\r
+p 0.5 0 0.866\r
+p 1 0 0\r
+p 0.5 0 -0.866\r
+p -0.5 0 -0.866\r
+p -1 0 0\r
+\r
+p -0.5 1 0.866\r
+p 0.5 1 0.866\r
+p 1 1 0\r
+p 0.5 1 -0.866\r
+p -0.5 1 -0.866\r
+p -1 1 0\r
+\r
+mtl %1\r
+f 0 1 7 6\r
+f 1 2 8 7\r
+f 2 3 9 8\r
+f 3 4 10 9\r
+f 4 5 11 10\r
+f 5 0 6 11\r
+\r
+cmp 0 %2 1\r
+?0 f 0 1 2 3\r
+?0 f 3 4 5 0\r
+?0 f 6 7 8 9\r
+?0 f 9 10 11 6\r
+\r
+\r
--- /dev/null
+# 1 -body material\r
+# 2 = 1 -ends filled\r
+#\r
+# 0--1\r
+# 7/ \2\r
+# | * | Y\r
+# 6\ /3\r
+# 5--4\r
+#\r
+# X\r
+\r
+here\r
+p -0.333 1 0\r
+p 0.333 1 0\r
+p 1 0.333 0\r
+p 1 -0.333 0\r
+p 0.333 -1 0\r
+p -0.333 -1 0\r
+p -1 -0.333 0\r
+p -1 0.333 0\r
+\r
+p -0.333 1 1\r
+p 0.333 1 1\r
+p 1 0.333 1\r
+p 1 -0.333 1\r
+p 0.333 -1 1\r
+p -0.333 -1 1\r
+p -1 -0.333 1\r
+p -1 0.333 1\r
+\r
+mtl %1\r
+f 0 1 9 8\r
+f 1 2 10 9\r
+f 2 3 11 10\r
+f 3 4 12 11\r
+f 4 5 13 12\r
+f 5 6 14 13\r
+f 6 7 15 14\r
+f 7 0 8 15\r
+\r
+cmp 0 %2 1\r
+?0 f 0 1 4 5\r
+?0 f 1 2 3 4\r
+?0 f 0 5 6 7\r
+?0 f 8 9 12 13\r
+?0 f 9 10 11 12\r
+?0 f 8 13 14 15
\ No newline at end of file
--- /dev/null
+here\r
+p -0.1 -0.01 -0.1\r
+p 0.1 -0.01 -0.1\r
+p 0.1 -0.01 0.1\r
+p -0.1 -0.01 0.1\r
+\r
+p -0.1 0.01 -0.1\r
+p 0.1 0.01 -0.1\r
+p 0.1 0.01 0.1\r
+p -0.1 0.01 0.1\r
+\r
+mtl kivi\r
+f 0 1 2 3\r
+f 4 5 6 7\r
+\r
+f 0 1 5 4\r
+f 1 2 6 5\r
+f 2 3 7 6\r
+f 3 0 4 7
\ No newline at end of file
--- /dev/null
+obj pol_frnt\r
+obj pol_frnt z*-1 z+5\r
+obj pol_ceil x*1.5 z+1.5 y+0.5\r
+obj flare_w x+0.5 z-0.01 y-0.1\r
+obj flare_w x*-1 x-0.5 z-0.01 y-0.1\r
+obj flare_r x+0.5 z+5.01 y-0.1\r
+obj flare_r x*-1 x-0.5 z+5.01 y-0.1\r
+\r
+here\r
+p -1.25 0.5 0.5\r
+p 1.25 0.5 0.5\r
+p 1.5 0.25 0.5\r
+p 1.5 -0.25 0.5\r
+p 1.25 -0.5 0.5\r
+p -1.25 -0.5 0.5\r
+p -1.5 -0.25 0.5\r
+p -1.5 0.25 0.5\r
+\r
+p -1.25 0.5 4.5\r
+p 1.25 0.5 4.5\r
+p 1.5 0.25 4.5\r
+p 1.5 -0.25 4.5\r
+p 1.25 -0.5 4.5\r
+p -1.25 -0.5 4.5\r
+p -1.5 -0.25 4.5\r
+p -1.5 0.25 4.5\r
+ \r
+mtl metal_blue\r
+f 0 1 9 8\r
+f 1 2 10 9\r
+f 2 3 11 10\r
+f 3 4 12 11\r
+f 4 5 13 12\r
+f 5 6 14 13\r
+f 6 7 15 14\r
+f 7 0 8 15\r
+\r
--- /dev/null
+here\r
+p -0.5 0.5 0.75\r
+p 0.5 0.5 0.75\r
+p 0.5 0 0\r
+p -0.5 0 0\r
+p -0.75 0 0.75\r
+p 0.75 0 0.75\r
+\r
+p -0.5 0.5 2.25\r
+p 0.5 0.5 2.25\r
+p 0.5 0 2.25\r
+p -0.5 0 2.25\r
+mtl klaashele\r
+f 0 1 2 3\r
+f 0 3 4\r
+f 1 2 5\r
+\r
+f 0 1 7 6\r
+f 1 5 8 7\r
+f 0 4 9 6\r
+f 6 7 8 9
\ No newline at end of file
--- /dev/null
+here\r
+p -1.25 0.25 0\r
+p 1.25 0.25 0\r
+p 1.25 -0.25 0\r
+p -1.25 -0.25 0\r
+\r
+p -1.25 0.5 0.5\r
+p 1.25 0.5 0.5\r
+p 1.5 0.25 0.5\r
+p 1.5 -0.25 0.5\r
+p 1.25 -0.5 0.5\r
+p -1.25 -0.5 0.5\r
+p -1.5 -0.25 0.5\r
+p -1.5 0.25 0.5\r
+mtl metal_blue\r
+f 0 1 2 3\r
+f 0 4 5 1\r
+f 1 5 6\r
+f 1 6 7 2\r
+f 2 7 8\r
+f 2 8 9 3\r
+f 3 9 10\r
+f 3 10 11 0\r
+f 0 11 4
\ No newline at end of file
--- /dev/null
+here\r
+p 0 0 0\r
+p -1.0 0.0 0.0\r
+p -0.965926 0.0 -0.258819 \r
+p -0.965926 0.0 0.258819 \r
+p -0.866025 0.0 -0.500000 \r
+p -0.866025 0.0 0.500000 \r
+p -0.707107 0.0 -0.707107 \r
+p -0.707107 0.0 0.707107 \r
+p -0.500000 0.0 -0.866025 \r
+p -0.500000 0.0 0.866025 \r
+p -0.258819 0.0 -0.965926 \r
+p -0.258819 0.0 0.965926 \r
+p 0.0 0.0 -1.0 \r
+p 0.0 0.0 0.0 \r
+p 0.0 0.0 1.0 \r
+p 0.258819 0.0 0.965926 \r
+p 0.258819 0.0 -0.965926 \r
+p 0.500000 0.0 0.866025 \r
+p 0.500000 0.0 -0.866025 \r
+p 0.707107 0.0 -0.707107 \r
+p 0.707107 0.0 0.707107 \r
+p 0.866025 0.0 -0.500000 \r
+p 0.866026 0.0 0.500000 \r
+p 0.965926 0.0 -0.258819 \r
+p 0.965926 0.0 0.258819 \r
+p 1.0 0.0 0.0 \r
+\r
+f 13 25 23\r
+f 13 23 21\r
+f 13 21 19\r
+f 13 19 18\r
+f 13 18 16\r
+f 13 16 12\r
+f 13 12 10\r
+f 13 10 8\r
+f 13 8 6\r
+f 13 6 4\r
+f 13 4 2\r
+f 13 2 1\r
+f 13 1 3\r
+f 13 3 5\r
+f 13 5 7\r
+f 13 7 9\r
+f 13 9 11\r
+f 13 11 14\r
+f 13 14 15\r
+f 13 15 17\r
+f 13 17 20\r
+f 13 20 22\r
+f 13 22 24\r
+f 13 24 25\r
--- /dev/null
+obj blk1\r
+obj blk2 x+6\r
+obj blk2 x+12\r
+obj blk1 x+18\r
+\r
+rnd obj^pol^xz-92^z-6^x+1 dum dum dum dum\r
+rnd obj^car^xz91^z-10^x+5 dum dum dum dum\r
+rnd obj^car^xz87^z-8^x+19 dum dum dum dum\r
+rnd obj^bus^xz-90^z-12^x+10 dum dum dum dum dum dum dum dum
\ No newline at end of file
--- /dev/null
+obj blk1\r
+obj blk1 x+6\r
+obj blk1 x+12\r
+obj blk2 x+18\r
+\r
+obj blk2 x+24\r
+obj blk1 x+30\r
+obj blk1 x+36\r
+obj blk1 x+42\r
+\r
+obj blk1 x+48\r
+obj blk1 x+54\r
+obj blk1 x+60\r
+obj blk2 x+66\r
+\r
+obj blk2 x+72\r
+obj blk1 x+78\r
+obj blk1 x+84\r
+obj blk1 x+90\r
--- /dev/null
+here\r
+p -3 0 -3\r
+p 3 0 -3\r
+p 3 0 3\r
+p -3 0 3\r
+\r
+p -3 15 -3\r
+p 3 15 -3\r
+p 3 15 3\r
+p -3 15 3\r
+\r
+p -20 6 -9\r
+p 20 6 -9\r
+p 10 24 9\r
+p -10 24 9\r
+\r
+mtl pronks\r
+f 0 1 5 4\r
+f 1 2 6 5\r
+f 2 3 7 6\r
+f 3 0 4 7\r
+mtl solar\r
+f 8 9 10 11
\ No newline at end of file
--- /dev/null
+here\r
+p 0 0 10\r
+p 0 5 10\r
+\r
+p 7.071067 0 7.071069\r
+p 7.071067 5 7.071069\r
+\r
+p 10 0 3.139165E-06\r
+p 10 5 3.139165E-06\r
+\r
+p 7.071071 0 -7.071064\r
+p 7.071071 5 -7.071064\r
+\r
+p 6.27833E-06 0 -10\r
+p 6.27833E-06 5 -10\r
+\r
+p -7.071062 0 -7.071074\r
+p -7.071062 5 -7.071074\r
+\r
+p -10 0 -9.417495E-06\r
+p -10 5 -9.417495E-06\r
+\r
+p -7.071075 0 7.07106\r
+p -7.071075 5 7.07106\r
+mtl pronks\r
+f 0 1 3 2\r
+f 2 3 5 4\r
+f 4 5 7 6\r
+f 6 7 9 8\r
+\r
+f 8 9 11 10\r
+f 10 11 13 12\r
+f 12 13 15 14\r
+f 14 15 1 0\r
+\r
+f 1 3 5 7\r
+f 1 7 9 15\r
+f 9 11 13 15
\ No newline at end of file
--- /dev/null
+obj plaat xz20 x+0 y+0 z+1\r
+obj plaat xz18.42122 x+.3894183 y+.1333333 z+.921061\r
+obj plaat xz13.93413 x+.7173561 y+.2666667 z+.6967067\r
+obj plaat xz7.247154 x+.9320391 y+.4 z+.3623577\r
+obj plaat xz-.5839909 x+.9995736 y+.5333334 z-2.919955E-02\r
+obj plaat xz-8.322937 x+.9092974 y+.6666667 z-.4161468\r
+obj plaat xz-14.74788 x+.6754631 y+.8 z-.7373938\r
+obj plaat xz-18.84445 x+.334988 y+.9333334 z-.9422224\r
+obj plaat xz-19.96589 x-5.837443E-02 y+1.066667 z-.9982948\r
+obj plaat xz-17.93517 x-.4425208 y+1.2 z-.8967583\r
+obj plaat xz-13.07286 x-.7568028 y+1.333333 z-.6536433\r
+obj plaat xz-6.146646 x-.9516022 y+1.466667 z-.3073323\r
+obj plaat xz1.749993 x-.9961646 y+1.6 z+8.749965E-02\r
+obj plaat xz9.370347 x-.8834543 y+1.733334 z+.4685173\r
+obj plaat xz15.51133 x-.631266 y+1.866667 z+.7755664\r
+obj plaat xz19.20341 x-.2794146 y+2 z+.9601706\r
+obj plaat xz19.8637 x+.1165502 y+2.133334 z+.9931848\r
+obj plaat xz17.38794 x+.4941143 y+2.266667 z+.8693969\r
+obj plaat xz12.16701 x+.7936686 y+2.4 z+.6083503\r
+obj plaat xz5.025171 x+.96792 y+2.533334 z+.2512586\r
+obj plaat xz-2.910019 x+.9893581 y+2.666667 z-.145501\r
+obj plaat xz-10.38578 x+.8545986 y+2.8 z-.5192891\r
+obj plaat xz-16.22186 x+.584917 y+2.933333 z-.8110932\r
+obj plaat xz-19.49687 x+.2228901 y+3.066667 z-.9748436\r
+obj plaat xz-19.69376 x-.1743262 y+3.2 z-.984688\r
+obj plaat xz-16.78144 x-.5440203 y+3.333333 z-.839072\r
+obj plaat xz-11.21971 x-.8278257 y+3.466666 z-.5609854\r
+obj plaat xz-3.886632 x-.9809359 y+3.599999 z-.1943316\r
+obj plaat xz4.060056 x-.9791781 y+3.733333 z+.2030028\r
+obj plaat xz11.36575 x-.82283 y+3.866666 z+.5682876\r
+obj plaat xz16.87705 x-.5365753 y+3.999999 z+.8438524\r
+obj plaat xz19.72383 x-.1656074 y+4.133332 z+.9861917\r
+obj plaat xz19.45667 x+.2315063 y+4.266665 z+.9728334\r
+obj plaat xz16.11773 x+.5920703 y+4.399999 z+.8058863\r
+obj plaat xz10.23416 x+.8591596 y+4.533332 z+.5117078\r
+obj plaat xz2.734839 x+.9906067 y+4.666665 z+.1367419\r
+obj plaat xz-5.196248 x+.9656591 y+4.799998 z-.2598124\r
+obj plaat xz-12.30696 x+.7882555 y+4.933331 z-.6153481\r
+obj plaat xz-17.47468 x+.4864039 y+5.066665 z-.8737341\r
+obj plaat xz-19.88354 x+.1077599 y+5.199998 z-.9941769\r
+obj plaat xz-19.15323 x-.2878969 y+5.333331 z-.9576614\r
+obj plaat xz-15.39904 x-.638102 y+5.466665 z-.7699519\r
+obj plaat xz-9.213687 x-.8875641 y+5.599998 z-.4606843\r
+obj plaat xz-1.573701 x-.9968995 y+5.733331 z-7.868504E-02\r
+obj plaat xz6.314738 x-.9488468 y+5.866664 z+.3157369\r
+obj plaat xz13.20622 x-.7509923 y+5.999998 z+.660311\r
+obj plaat xz18.01273 x-.4345728 y+6.133331 z+.9006367\r
+obj plaat xz19.97544 x-4.954402E-02 y+6.266664 z+.998772\r
+obj plaat xz18.78447 x+.3433067 y+6.399997 z+.9392233\r
+obj plaat xz14.62785 x+.6819569 y+6.53333 z+.7313923\r
+obj plaat xz8.161816 x+.9129413 y+6.666664 z+.4080908\r
--- /dev/null
+DECLARE SUB DrawQuadrilateral (xCoord1%, yCoord1%, xCoord2%, yCoord2%, xCoord3%, yCoord3%, xCoord4%, yCoord4%, colorVal%)\r
+' Program to render 3D shaded landscape with perspective and distortion effects.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 1999, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+DECLARE SUB SetPalette ()\r
+DEFINT A-Z\r
+' Declare shared arrays for X and Y coordinates\r
+DIM SHARED xCoordinates(1 TO 40, 1 TO 40)\r
+DIM SHARED yCoordinates(1 TO 40, 1 TO 40)\r
+\r
+' Set screen mode to 12: 640x480 pixels, 16 colors\r
+SCREEN 12\r
+\r
+' Initialize color palette\r
+SetPalette\r
+\r
+' Set initial scaling factor\r
+scalingFactor = 1.5\r
+\r
+' Main loop start\r
+1 :\r
+' Loop through each point in the grid\r
+FOR rowIndex = 1 TO 40\r
+ FOR colIndex = 1 TO 40\r
+ ' Calculate the position with distortion\r
+ xPos = 120 + (colIndex * 10)\r
+ yPos = 200 + (rowIndex * 3)\r
+ \r
+ ' Apply a cosine distortion based on distance from center\r
+ yPos = yPos - COS(SQR((colIndex - 20) ^ 2 + (rowIndex - 20) ^ 2) / scalingFactor) * 20\r
+\r
+ ' Apply perspective transformation\r
+ xPos = (xPos - 320) * (rowIndex + 50) / 50 + 320\r
+ yPos = (yPos - 240) * (rowIndex + 50) / 50 + 240\r
+\r
+ ' Store the transformed coordinates\r
+ xCoordinates(colIndex, rowIndex) = xPos\r
+ yCoordinates(colIndex, rowIndex) = yPos\r
+ NEXT colIndex\r
+NEXT rowIndex\r
+\r
+' Draw grid based on the stored coordinates\r
+FOR rowIndex = 1 TO 39\r
+ FOR colIndex = 1 TO 39\r
+ ' Alternate colors for each box\r
+ IF (colIndex + rowIndex) \ 2 <> (colIndex + rowIndex + 1) \ 2 THEN colorIndex = 0 ELSE colorIndex = 5\r
+ \r
+ ' Calculate a brightness factor\r
+ brightnessFactor = rowIndex + (colIndex / 3)\r
+ \r
+ ' Draw the quadrilateral with the calculated color and brightness\r
+ DrawQuadrilateral xCoordinates(colIndex, rowIndex), yCoordinates(colIndex, rowIndex), xCoordinates(colIndex + 1, rowIndex), yCoordinates(colIndex + 1, rowIndex), xCoordinates(colIndex, rowIndex + 1), yCoordinates(colIndex, rowIndex + 1), _\r
+xCoordinates(colIndex + 1, rowIndex + 1), yCoordinates(colIndex + 1, rowIndex + 1), colorIndex\r
+ NEXT colIndex\r
+NEXT rowIndex\r
+\r
+' Wait for user input and adjust the scaling factor\r
+userInput$ = INPUT$(1)\r
+scalingFactor = scalingFactor * 1.9\r
+\r
+' Clear the screen for the next iteration\r
+CLS\r
+\r
+' If the scaling factor is too large, exit the program\r
+IF scalingFactor > 10 THEN SYSTEM\r
+\r
+' Jump back to the main loop start\r
+GOTO 1\r
+\r
+' Subroutine to draw a filled box using line drawing\r
+SUB DrawQuadrilateral (xCoord1, yCoord1, xCoord2, yCoord2, xCoord3, yCoord3, xCoord4, yCoord4, colorVal)\r
+ ' Fills a quadrilateral area by connecting the edges.\r
+ ' It uses a scanline approach, storing intersection points, then drawing horizontal lines between those intersection points.\r
+ ' Adjust color index based on position and brightness factor\r
+ colorVal = colorVal + (yCoord2 - yCoord1) / 3.5 + (brightnessFactor / 8) + 4\r
+ ' Ensure the color index is within valid range\r
+ IF colorVal < 0 THEN colorVal = 0\r
+ IF colorVal > 15 THEN colorVal = 15\r
+ ' Calculate the length of the longer side\r
+ sideLength1 = SQR((xCoord1 - xCoord2) ^ 2 + (yCoord1 - yCoord2) ^ 2)\r
+ sideLength2 = SQR((xCoord3 - xCoord4) ^ 2 + (yCoord3 - yCoord4) ^ 2)\r
+ IF sideLength2 < sideLength1 THEN sideLength2 = sideLength1\r
+ ' Draw the box using lines\r
+ FOR lineIndex = 1 TO sideLength2\r
+ xCoord5 = (xCoord2 - xCoord1) * lineIndex / sideLength2 + xCoord1\r
+ yCoord5 = (yCoord2 - yCoord1) * lineIndex / sideLength2 + yCoord1\r
+ xCoord6 = (xCoord4 - xCoord3) * lineIndex / sideLength2 + xCoord3\r
+ yCoord6 = (yCoord4 - yCoord3) * lineIndex / sideLength2 + yCoord3\r
+ ' Draw two adjacent lines to create a filled effect\r
+ LINE (xCoord5, yCoord5)-(xCoord6, yCoord6), colorVal\r
+ LINE (xCoord5 + 1, yCoord5)-(xCoord6 + 1, yCoord6), colorVal\r
+ NEXT lineIndex\r
+END SUB\r
+\r
+' Subroutine to initialize color palette\r
+SUB SetPalette\r
+ ' Initializes the color palette for the screen.\r
+ ' It sets the RGB values for each color index in the palette.\r
+ FOR paletteIndex = 1 TO 16\r
+ ' Set the color values for each palette entry\r
+ OUT &H3C8, paletteIndex\r
+ OUT &H3C9, paletteIndex * 4\r
+ OUT &H3C9, paletteIndex * 4\r
+ OUT &H3C9, paletteIndex * 3\r
+ NEXT paletteIndex\r
+END SUB\r
+\r
--- /dev/null
+' Projects realtime anaglyph with bouncing cubes. Colored glasses required to view stereo effect.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+\r
+' Changelog:\r
+' 2004.07, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+' Controls:\r
+' arrow keys - move around\r
+' 2, 6, 4, 8 - look around\r
+' - - fly up\r
+' + - fly down\r
+' q, w - change horizontal distance between left and right view\r
+\r
+DECLARE SUB DrawLine (x1%, y1%, x2%, y2%)\r
+DECLARE SUB CreateCube ()\r
+DECLARE SUB PlaceCubes ()\r
+DECLARE SUB RenderScene ()\r
+DECLARE SUB InitializeEnvironment ()\r
+DECLARE SUB InitializeProgram ()\r
+\r
+DIM SHARED originalPointCount, originalLineCount, currentPointCount, currentLineCount\r
+DIM SHARED pointX(1 TO 1000)\r
+DIM SHARED pointY(1 TO 1000)\r
+DIM SHARED pointZ(1 TO 1000)\r
+\r
+DIM SHARED projectedX(1 TO 1000)\r
+DIM SHARED projectedXRight(1 TO 1000)\r
+DIM SHARED projectedY(1 TO 1000)\r
+\r
+DIM SHARED originalProjectedX(1 TO 1000)\r
+DIM SHARED originalProjectedXRight(1 TO 1000)\r
+DIM SHARED originalProjectedY(1 TO 1000)\r
+DIM SHARED originalProjectedPointCount\r
+DIM SHARED lineStart(1 TO 1000)\r
+DIM SHARED lineEnd(1 TO 1000)\r
+DIM SHARED lineColor(1 TO 1000)\r
+DIM SHARED originalLineStart(1 TO 1000)\r
+DIM SHARED originalLineEnd(1 TO 1000)\r
+DIM SHARED originalProjectedLineCount\r
+\r
+DIM SHARED cameraX, cameraY, cameraZ\r
+DIM SHARED cameraXSpeed, cameraYSpeed, cameraZSpeed\r
+DIM SHARED rotationAngle1, rotationAngle2\r
+DIM SHARED rotationAngle1Speed, rotationAngle2Speed\r
+DIM SHARED cubeX(1 TO 10)\r
+DIM SHARED cubeY(1 TO 10)\r
+DIM SHARED cubeZ(1 TO 10)\r
+DIM SHARED cubeXSpeed(1 TO 10)\r
+DIM SHARED cubeYSpeed(1 TO 10)\r
+DIM SHARED cubeZSpeed(1 TO 10)\r
+DIM SHARED cubeCount\r
+DIM SHARED horizontalViewDistance\r
+\r
+DIM SHARED movementSpeed\r
+\r
+movementSpeed = 4\r
+'ON ERROR GOTO 2\r
+\r
+InitializeProgram\r
+InitializeEnvironment\r
+PlaceCubes\r
+horizontalViewDistance = -.1\r
+1\r
+PCOPY 0, 1\r
+CLS\r
+\r
+currentPointCount = originalPointCount\r
+currentLineCount = originalLineCount\r
+\r
+CreateCube\r
+RenderScene\r
+\r
+cameraX = cameraX + cameraXSpeed\r
+cameraY = cameraY + cameraYSpeed\r
+cameraZ = cameraZ + cameraZSpeed\r
+rotationAngle1 = rotationAngle1 + rotationAngle1Speed\r
+rotationAngle2 = rotationAngle2 + rotationAngle2Speed\r
+\r
+inputKey$ = INKEY$\r
+IF inputKey$ <> "" THEN\r
+ IF inputKey$ = CHR$(0) + "H" THEN\r
+ ' Move forward\r
+ cameraZSpeed = cameraZSpeed - SIN(rotationAngle1) / 100\r
+ cameraXSpeed = cameraXSpeed - COS(rotationAngle1) / 100\r
+ END IF\r
+ IF inputKey$ = CHR$(0) + "P" THEN\r
+ ' Move backward\r
+ cameraZSpeed = cameraZSpeed + SIN(rotationAngle1) / 100\r
+ cameraXSpeed = cameraXSpeed + COS(rotationAngle1) / 100\r
+ END IF\r
+ IF inputKey$ = CHR$(0) + "M" THEN\r
+ ' Strafe left\r
+ cameraZSpeed = cameraZSpeed + COS(rotationAngle1) / 100\r
+ cameraXSpeed = cameraXSpeed - SIN(rotationAngle1) / 100\r
+ END IF\r
+ IF inputKey$ = CHR$(0) + "K" THEN\r
+ ' Strafe right\r
+ cameraZSpeed = cameraZSpeed - COS(rotationAngle1) / 100\r
+ cameraXSpeed = cameraXSpeed + SIN(rotationAngle1) / 100\r
+ END IF\r
+\r
+ IF inputKey$ = "6" THEN rotationAngle1Speed = rotationAngle1Speed - .01\r
+ IF inputKey$ = "4" THEN rotationAngle1Speed = rotationAngle1Speed + .01\r
+ IF inputKey$ = "8" THEN rotationAngle2Speed = rotationAngle2Speed - .01\r
+ IF inputKey$ = "2" THEN rotationAngle2Speed = rotationAngle2Speed + .01\r
+ IF inputKey$ = "+" THEN cameraYSpeed = cameraYSpeed - .01\r
+ IF inputKey$ = "-" THEN cameraYSpeed = cameraYSpeed + .01\r
+ IF inputKey$ = "q" THEN horizontalViewDistance = horizontalViewDistance - .01\r
+ IF inputKey$ = "w" THEN horizontalViewDistance = horizontalViewDistance + .01\r
+ IF inputKey$ = " " THEN\r
+ ' Slow down movements\r
+ cameraXSpeed = cameraXSpeed / 2\r
+ cameraYSpeed = cameraYSpeed / 2\r
+ cameraZSpeed = cameraZSpeed / 2\r
+\r
+ rotationAngle1Speed = rotationAngle1Speed / 2\r
+ rotationAngle2Speed = rotationAngle2Speed / 2\r
+ END IF\r
+ IF inputKey$ = CHR$(27) THEN SYSTEM\r
+END IF\r
+GOTO 1\r
+2\r
+END\r
+RESUME\r
+\r
+SUB InitializeEnvironment\r
+\r
+' This subroutine initializes the environment by creating points and lines.\r
+FOR worldZ = -5 TO 5\r
+ FOR worldX = -5 TO 5\r
+ currentPointCount = currentPointCount + 1\r
+ pointX(currentPointCount) = worldX\r
+ pointY(currentPointCount) = SIN(SQR(worldX * worldX + worldZ * worldZ) / 2)\r
+ pointZ(currentPointCount) = worldZ\r
+ IF worldX > -5 THEN\r
+ currentLineCount = currentLineCount + 1\r
+ lineStart(currentLineCount) = currentPointCount\r
+ lineEnd(currentLineCount) = currentPointCount - 1\r
+ lineColor(currentLineCount) = 3\r
+ END IF\r
+ IF worldZ > -5 THEN\r
+ currentLineCount = currentLineCount + 1\r
+ lineStart(currentLineCount) = currentPointCount\r
+ lineEnd(currentLineCount) = currentPointCount - 11\r
+ lineColor(currentLineCount) = 3\r
+ END IF\r
+ NEXT worldX\r
+NEXT worldZ\r
+\r
+originalPointCount = currentPointCount\r
+originalLineCount = currentLineCount\r
+\r
+END SUB\r
+\r
+SUB InitializeEnvironment1\r
+\r
+' This subroutine initializes the environment with a simple setup.\r
+currentPointCount = 1\r
+pointX(currentPointCount) = -2\r
+pointY(currentPointCount) = 0\r
+pointZ(currentPointCount) = 0\r
+\r
+currentPointCount = currentPointCount + 1\r
+pointX(currentPointCount) = 2\r
+pointY(currentPointCount) = 0\r
+pointZ(currentPointCount) = 0\r
+\r
+currentLineCount = 1\r
+lineStart(currentLineCount) = 1\r
+lineEnd(currentLineCount) = 2\r
+lineColor(currentLineCount) = 14\r
+\r
+END SUB\r
+\r
+SUB DrawLine (x1%, y1%, x2%, y2%)\r
+\r
+' This subroutine draws a line between two points using a custom algorithm.\r
+' It calculates intermediate points and sets pixels with appropriate colors.\r
+' The color is inverted if the point is already set to avoid overwriting.\r
+\r
+lineLength = ABS(x1% - x2%)\r
+lineLength2 = ABS(y1% - y2%)\r
+IF lineLength2 > lineLength THEN lineLength = lineLength2\r
+IF lineLength < 2 THEN GOTO 101\r
+\r
+xDelta = x2% - x1%\r
+yDelta = y2% - y1%\r
+\r
+FOR stp% = 1 TO lineLength\r
+ x = xDelta * stp% / lineLength + x1%\r
+ y = yDelta * stp% / lineLength + y1%\r
+ currentColor = POINT(x, y)\r
+ IF currentColor = 0 THEN PSET (x, y), 2\r
+ IF currentColor = 1 THEN PSET (x, y), 3\r
+NEXT stp%\r
+101\r
+END SUB\r
+\r
+SUB DrawLineRight (x1, y1, x2, y2)\r
+' This subroutine draws a line using the LINE statement for the right eye view.\r
+LINE (x1, y1)-(x2, y2), 1\r
+END SUB\r
+\r
+SUB CreateCube\r
+\r
+' This subroutine updates the positions of the cubes and adds their edges to the environment.\r
+FOR cubeIndex = 1 TO cubeCount\r
+ worldX = cubeX(cubeIndex)\r
+ worldY = cubeY(cubeIndex)\r
+ worldZ = cubeZ(cubeIndex)\r
+\r
+ velocityX = cubeXSpeed(cubeIndex)\r
+ velocityY = cubeYSpeed(cubeIndex)\r
+ velocityZ = cubeZSpeed(cubeIndex)\r
+\r
+ ' Apply gravity to the cube's vertical movement\r
+ velocityY = velocityY - .01\r
+\r
+ ' Calculate new positions based on velocity and speed\r
+ worldX = worldX + velocityX / movementSpeed\r
+ worldY = worldY + velocityY / movementSpeed\r
+ worldZ = worldZ + velocityZ / movementSpeed\r
+\r
+ ' Bounce from boundaries\r
+ IF worldX > 5 THEN velocityX = -.1\r
+ IF worldZ > 5 THEN velocityZ = -.1\r
+ IF worldX < -5 THEN velocityX = .1\r
+ IF worldZ < -5 THEN velocityZ = .1\r
+ IF worldY < .5 THEN velocityY = RND * .2 + .1\r
+\r
+ ' Add cube edges to the environment\r
+ currentLineCount = currentLineCount + 1\r
+ lineStart(currentLineCount) = currentPointCount + 1\r
+ lineEnd(currentLineCount) = currentPointCount + 2\r
+ lineColor(currentLineCount) = 14\r
+\r
+ currentLineCount = currentLineCount + 1\r
+ lineStart(currentLineCount) = currentPointCount + 3\r
+ lineEnd(currentLineCount) = currentPointCount + 2\r
+ lineColor(currentLineCount) = 14\r
+\r
+ currentLineCount = currentLineCount + 1\r
+ lineStart(currentLineCount) = currentPointCount + 3\r
+ lineEnd(currentLineCount) = currentPointCount + 4\r
+ lineColor(currentLineCount) = 14\r
+\r
+ currentLineCount = currentLineCount + 1\r
+ lineStart(currentLineCount) = currentPointCount + 1\r
+ lineEnd(currentLineCount) = currentPointCount + 4\r
+ lineColor(currentLineCount) = 14\r
+\r
+ currentLineCount = currentLineCount + 1\r
+ lineStart(currentLineCount) = currentPointCount + 1\r
+ lineEnd(currentLineCount) = currentPointCount + 5\r
+ lineColor(currentLineCount) = 14\r
+\r
+ currentLineCount = currentLineCount + 1\r
+ lineStart(currentLineCount) = currentPointCount + 2\r
+ lineEnd(currentLineCount) = currentPointCount + 6\r
+ lineColor(currentLineCount) = 14\r
+\r
+ currentLineCount = currentLineCount + 1\r
+ lineStart(currentLineCount) = currentPointCount + 3\r
+ lineEnd(currentLineCount) = currentPointCount + 7\r
+ lineColor(currentLineCount) = 14\r
+\r
+ currentLineCount = currentLineCount + 1\r
+ lineStart(currentLineCount) = currentPointCount + 4\r
+ lineEnd(currentLineCount) = currentPointCount + 8\r
+ lineColor(currentLineCount) = 14\r
+\r
+ currentLineCount = currentLineCount + 1\r
+ lineStart(currentLineCount) = currentPointCount + 5\r
+ lineEnd(currentLineCount) = currentPointCount + 6\r
+ lineColor(currentLineCount) = 14\r
+\r
+ currentLineCount = currentLineCount + 1\r
+ lineStart(currentLineCount) = currentPointCount + 7\r
+ lineEnd(currentLineCount) = currentPointCount + 6\r
+ lineColor(currentLineCount) = 14\r
+\r
+ currentLineCount = currentLineCount + 1\r
+ lineStart(currentLineCount) = currentPointCount + 7\r
+ lineEnd(currentLineCount) = currentPointCount + 8\r
+ lineColor(currentLineCount) = 14\r
+\r
+ currentLineCount = currentLineCount + 1\r
+ lineStart(currentLineCount) = currentPointCount + 5\r
+ lineEnd(currentLineCount) = currentPointCount + 8\r
+ lineColor(currentLineCount) = 14\r
+\r
+ ' Add cube vertices to the environment\r
+ currentPointCount = currentPointCount + 1\r
+ pointX(currentPointCount) = worldX - .5\r
+ pointY(currentPointCount) = worldY - .5\r
+ pointZ(currentPointCount) = worldZ - .5\r
+\r
+ currentPointCount = currentPointCount + 1\r
+ pointX(currentPointCount) = worldX + .5\r
+ pointY(currentPointCount) = worldY - .5\r
+ pointZ(currentPointCount) = worldZ - .5\r
+\r
+ currentPointCount = currentPointCount + 1\r
+ pointX(currentPointCount) = worldX + .5\r
+ pointY(currentPointCount) = worldY + .5\r
+ pointZ(currentPointCount) = worldZ - .5\r
+\r
+ currentPointCount = currentPointCount + 1\r
+ pointX(currentPointCount) = worldX - .5\r
+ pointY(currentPointCount) = worldY + .5\r
+ pointZ(currentPointCount) = worldZ - .5\r
+\r
+ currentPointCount = currentPointCount + 1\r
+ pointX(currentPointCount) = worldX - .5\r
+ pointY(currentPointCount) = worldY - .5\r
+ pointZ(currentPointCount) = worldZ + .5\r
+\r
+ currentPointCount = currentPointCount + 1\r
+ pointX(currentPointCount) = worldX + .5\r
+ pointY(currentPointCount) = worldY - .5\r
+ pointZ(currentPointCount) = worldZ + .5\r
+\r
+ currentPointCount = currentPointCount + 1\r
+ pointX(currentPointCount) = worldX + .5\r
+ pointY(currentPointCount) = worldY + .5\r
+ pointZ(currentPointCount) = worldZ + .5\r
+\r
+ currentPointCount = currentPointCount + 1\r
+ pointX(currentPointCount) = worldX - .5\r
+ pointY(currentPointCount) = worldY + .5\r
+ pointZ(currentPointCount) = worldZ + .5\r
+\r
+ ' Update cube positions and velocities\r
+ cubeX(cubeIndex) = worldX\r
+ cubeY(cubeIndex) = worldY\r
+ cubeZ(cubeIndex) = worldZ\r
+ cubeXSpeed(cubeIndex) = velocityX\r
+ cubeYSpeed(cubeIndex) = velocityY\r
+ cubeZSpeed(cubeIndex) = velocityZ\r
+NEXT cubeIndex\r
+\r
+END SUB\r
+\r
+SUB PlaceCubes\r
+\r
+' This subroutine initializes the positions and velocities of the cubes.\r
+scaleFactor = 1\r
+FOR cubeIndex = 1 TO cubeCount\r
+ cubeX(cubeIndex) = RND * 10 - 5\r
+ cubeY(cubeIndex) = 2\r
+ cubeZ(cubeIndex) = RND * 10 - 5\r
+ cubeXSpeed(cubeIndex) = (RND * .5 - .25) / scaleFactor\r
+ cubeYSpeed(cubeIndex) = (RND * .5 + .1) / scaleFactor\r
+ cubeZSpeed(cubeIndex) = (RND * .5 - .25) / scaleFactor\r
+NEXT cubeIndex\r
+\r
+END SUB\r
+\r
+SUB RenderScene\r
+' This subroutine renders the environment by projecting 3D points onto a 2D plane.\r
+' It applies rotation and perspective projection to create the anaglyph effect.\r
+\r
+sinAngle1 = SIN(rotationAngle1)\r
+cosAngle1 = COS(rotationAngle1)\r
+sinAngle2 = SIN(rotationAngle2)\r
+cosAngle2 = COS(rotationAngle2)\r
+\r
+' Project each 3D point to 2D screen coordinates\r
+FOR pointIndex = 1 TO currentPointCount\r
+ worldX = pointX(pointIndex) + cameraX\r
+ worldY = pointY(pointIndex) - cameraY\r
+ worldZ = pointZ(pointIndex) + cameraZ\r
+\r
+ ' First rotation around Y-axis (horizontal rotation)\r
+ rotatedX = worldX * sinAngle1 - worldZ * cosAngle1\r
+ rotatedZ = worldX * cosAngle1 + worldZ * sinAngle1\r
+\r
+ ' Second rotation around X-axis (vertical rotation)\r
+ rotatedY = worldY * sinAngle2 - rotatedZ * cosAngle2\r
+ depth = worldY * cosAngle2 + rotatedZ * sinAngle2\r
+\r
+ ' Apply perspective projection if point is in view\r
+ IF depth < .1 THEN\r
+ projectedX(pointIndex) = -1\r
+ ELSE\r
+ projectedX(pointIndex) = 160 + ((rotatedX + horizontalViewDistance) / depth * 200)\r
+ projectedXRight(pointIndex) = 160 + ((rotatedX - horizontalViewDistance) / depth * 200)\r
+ projectedY(pointIndex) = 100 - (rotatedY / depth * 200)\r
+ END IF\r
+NEXT pointIndex\r
+\r
+' Draw lines between projected points for left eye view\r
+FOR lineIndex = 1 TO currentLineCount\r
+ startPoint = lineStart(lineIndex)\r
+ endPoint = lineEnd(lineIndex)\r
+ IF projectedX(startPoint) = -1 OR projectedX(endPoint) = -1 THEN\r
+ ' Skip drawing if either point is out of view\r
+ ELSE\r
+ LINE (projectedX(startPoint), projectedY(startPoint))-(projectedX(endPoint), projectedY(endPoint)), 1\r
+ END IF\r
+NEXT lineIndex\r
+\r
+' Draw lines between projected points for right eye view\r
+FOR lineIndex = 1 TO currentLineCount\r
+ startPoint = lineStart(lineIndex)\r
+ endPoint = lineEnd(lineIndex)\r
+ IF projectedX(startPoint) = -1 OR projectedX(endPoint) = -1 THEN\r
+ ' Skip drawing if either point is out of view\r
+ ELSE\r
+ DrawLine INT(projectedXRight(startPoint)), INT(projectedY(startPoint)), INT(projectedXRight(endPoint)), INT(projectedY(endPoint))\r
+ END IF\r
+NEXT lineIndex\r
+\r
+END SUB\r
+\r
+SUB InitializeProgram\r
+SCREEN 7, , , 1\r
+\r
+OUT &H3C8, 0\r
+OUT &H3C9, 63\r
+OUT &H3C9, 63\r
+OUT &H3C9, 63\r
+\r
+OUT &H3C8, 1\r
+OUT &H3C9, 63\r
+OUT &H3C9, 0\r
+OUT &H3C9, 0\r
+\r
+OUT &H3C8, 2\r
+OUT &H3C9, 0\r
+OUT &H3C9, 63\r
+OUT &H3C9, 63\r
+\r
+OUT &H3C8, 3\r
+OUT &H3C9, 0\r
+OUT &H3C9, 0\r
+OUT &H3C9, 0\r
+\r
+originalPointCount = 0\r
+originalLineCount = 0\r
+currentPointCount = originalPointCount\r
+currentLineCount = originalLineCount\r
+cubeCount = 9\r
+\r
+cameraX = 0\r
+cameraY = 4\r
+cameraZ = 7\r
+rotationAngle1 = 3.14 / 2\r
+rotationAngle2 = rotationAngle1 + .6\r
+\r
+FOR pointIndex = 1 TO 1000\r
+ lineColor(pointIndex) = 4\r
+NEXT pointIndex\r
+\r
+FOR lineIndex = 1 TO 1000\r
+ originalLineStart(lineIndex) = 1\r
+ originalLineEnd(lineIndex) = 1\r
+NEXT lineIndex\r
+\r
+END SUB\r
--- /dev/null
+0 -10 -5\r
+0 -10 5\r
+-20 -10 -5\r
+-20 -10 5\r
+-20 0 -5\r
+-20 0 5\r
+0 10 -5\r
+0 10 5\r
+30 10 0\r
+10 0 -5\r
+10 0 5\r
+30 0 0\r
+40 10 0\r
+40 20 0\r
+-30 15 -3\r
+-30 15 3\r
+30 15 -3\r
+30 15 3\r
+999 999 999\r
+0 1\r
+2 3\r
+0 2\r
+1 3\r
+4 5\r
+2 4\r
+3 5\r
+4 0\r
+5 1\r
+6 7\r
+4 6\r
+5 7\r
+6 0\r
+7 1\r
+6 8\r
+7 8\r
+9 10\r
+6 9\r
+7 10\r
+0 9\r
+1 10\r
+9 11\r
+10 11\r
+11 12\r
+12 13\r
+13 8\r
+14 15\r
+16 17\r
+14 17\r
+15 16\r
+999 999
\ No newline at end of file
--- /dev/null
+DECLARE SUB DisplayScene1 ()\r
+DECLARE SUB DisplayScene2 ()\r
+DECLARE SUB DisplayScene3 ()\r
+DECLARE SUB InitializeProgram ()\r
+DECLARE SUB DrawRoundedBox (topLeftX!, topLeftY!, bottomRightX!, bottomRightY!)\r
+DECLARE SUB GetAngle (firstPointX!, firstPointY!, secondPointX!, secondPointY!, angleBetween!)\r
+DECLARE SUB RotatePoint (rotationCenterX!, rotationCenterY!, pointX!, pointY!, rotationAngle!)\r
+DECLARE SUB InitializeFont ()\r
+DECLARE SUB WaitForInput ()\r
+DECLARE SUB MakeBackground ()\r
+DECLARE SUB SetPalette (red!, green!, blue!, colorIndex!)\r
+DECLARE SUB PrintText (posX!, posY!, scale!, colorValue!, textString$)\r
+' Presentation demonstrating realtime 3D graphics.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2002, Initial version\r
+' 2025, Improved program readability\r
+\r
+DIM SHARED globalPiValue\r
+DIM SHARED globalPi\r
+DIM SHARED globalAngleOne\r
+DIM SHARED globalAngleTwo\r
+\r
+' Holds the captured font bitmap\r
+DIM SHARED fontData(0 TO 7, 0 TO 7, 32 TO 150)\r
+\r
+InitializeProgram\r
+DisplayScene1\r
+DisplayScene2\r
+DisplayScene3\r
+\r
+SUB ComputeShadeValue (firstPointX, firstPointY, firstPointZ, secondPointX, secondPointY, secondPointZ, thirdPointX, thirdPointY, thirdPointZ, shadeValue)\r
+ '\r
+ ' Computes a brightness value for a 3D triangle based on distance from viewer.\r
+ ' The algorithm:\r
+ ' 1. Makes local copies of the three points\r
+ ' 2. Applies three sequential rotations to simulate 3D perspective\r
+ ' 3. Calculates distance from viewer to determine shading\r
+ '\r
+\r
+ ' Create local copies of the points\r
+ localFirstPointX = firstPointX\r
+ localFirstPointY = firstPointY\r
+ localFirstPointZ = firstPointZ\r
+ localSecondPointX = secondPointX\r
+ localSecondPointY = secondPointY\r
+ localSecondPointZ = secondPointZ\r
+ localThirdPointX = thirdPointX\r
+ localThirdPointY = thirdPointY\r
+ localThirdPointZ = thirdPointZ\r
+\r
+ ' First rotation around Y-axis\r
+ GetAngle localFirstPointX, localFirstPointY, localSecondPointX, localSecondPointY, tempAngle1\r
+ RotatePoint localFirstPointX, localFirstPointY, localSecondPointX, localSecondPointY, -tempAngle1\r
+ RotatePoint localFirstPointX, localFirstPointY, localThirdPointX, localThirdPointY, -tempAngle1\r
+\r
+ ' Second rotation around X-axis\r
+ GetAngle localFirstPointY, localFirstPointZ, localSecondPointY, localSecondPointZ, tempAngle2\r
+ tempAngle2 = tempAngle2 + globalPi / 2\r
+ RotatePoint localFirstPointY, localFirstPointZ, localSecondPointY, localSecondPointZ, -tempAngle2\r
+ RotatePoint localFirstPointY, localFirstPointZ, localThirdPointY, localThirdPointZ, -tempAngle2\r
+\r
+ ' Third rotation around Z-axis\r
+ GetAngle localFirstPointX, localFirstPointZ, localThirdPointX, localThirdPointZ, tempAngle3\r
+ tempAngle3 = tempAngle3 + globalPi / 2\r
+ RotatePoint localFirstPointX, localFirstPointZ, localSecondPointX, localSecondPointZ, -tempAngle3\r
+ RotatePoint localFirstPointX, localFirstPointZ, localThirdPointX, localThirdPointZ, -tempAngle3\r
+\r
+ ' Calculate distance from viewer to determine shading\r
+ viewerX = localFirstPointX\r
+ viewerY = localFirstPointY\r
+ viewerZ = localFirstPointZ + 30\r
+ RotatePoint localFirstPointX, localFirstPointZ, viewerX, viewerZ, tempAngle3\r
+ RotatePoint localFirstPointY, localFirstPointZ, viewerY, viewerZ, tempAngle2\r
+ RotatePoint localFirstPointX, localFirstPointY, viewerX, viewerY, tempAngle1\r
+\r
+ ' Compute distance from viewer to first point\r
+ distanceX = firstPointX + 20\r
+ distanceY = firstPointY + 10\r
+ distance = SQR((distanceX - viewerX) ^ 2 + (distanceY - viewerY) ^ 2)\r
+ shadeValue = 49 - distance\r
+ IF shadeValue < 0 THEN shadeValue = 0\r
+END SUB\r
+\r
+SUB DisplayScene1\r
+ '\r
+ ' Builds a fractal backdrop, prints short text lines\r
+ \r
+ RANDOMIZE 1\r
+ MakeBackground\r
+ DrawRoundedBox 30, 50, 290, 150\r
+ SetPalette 32, 64, 32, 250\r
+ yOffset = 0\r
+ PrintText 30, 70 + yOffset, 1, 250, "Next will be animated helicopter."\r
+ yOffset = yOffset + 16\r
+ PrintText 30, 70 + yOffset, 1, 250, "Helicopter chooses and picks up"\r
+ yOffset = yOffset + 20\r
+ PrintText 30, 70 + yOffset, 1, 250, "random pyramids. Press any key"\r
+ yOffset = yOffset + 16\r
+ PrintText 30, 70 + yOffset, 1, 250, "to proceed to next slide."\r
+ WaitForInput\r
+END SUB\r
+\r
+SUB DisplayScene2\r
+ '\r
+ ' Simple transitional effect: draws horizontal lines across the screen\r
+ ' in steps, clearing or darkening each row to black.\r
+ '\r
+\r
+ SetPalette 0, 0, 0, 0\r
+ FOR outerIndex = 0 TO 19\r
+ FOR drawY = outerIndex TO 199 STEP 20\r
+ LINE (0, drawY)-(319, drawY), 0\r
+ NEXT drawY\r
+ SOUND 0, .5\r
+ NEXT outerIndex\r
+END SUB\r
+\r
+SUB DisplayScene3\r
+ '\r
+ ' A more complex 3D scene:\r
+ ' Terrain with various heights.\r
+ ' Helicopter hovers over terrain.\r
+ ' Helicopter randomly chooses small pyramids that are scattered around terrain,\r
+ ' flies to pyramids and picks them up one-by-one.\r
+ ' Press any key to transition to next slide.\r
+\r
+ FOR fadeIndex = 1 TO 50\r
+ SetPalette 0, 0, 0, fadeIndex\r
+ NEXT fadeIndex\r
+\r
+ DIM mainX(0 TO 800)\r
+ DIM mainY(0 TO 800)\r
+ DIM mainZ(0 TO 800)\r
+ DIM lineStart(0 TO 1000)\r
+ DIM lineEnd(0 TO 1000)\r
+ DIM lineColor(0 TO 1000)\r
+ DIM lineBufferXOne(1 TO 1000)\r
+ DIM lineBufferYOne(1 TO 1000)\r
+ DIM lineBufferXTwo(1 TO 1000)\r
+ DIM lineBufferYTwo(1 TO 1000)\r
+ DIM projectedX(0 TO 800)\r
+ DIM projectedY(0 TO 800)\r
+ DIM holdX(1 TO 50)\r
+ DIM holdY(1 TO 50)\r
+ DIM holdZ(1 TO 50)\r
+ DIM helicopterAngle\r
+ DIM helicopterRotorAngle\r
+ DIM holdNumber\r
+ DIM helicopterPointer\r
+ DIM holdAx, holdAy, holdAz\r
+ DIM moveX, moveZ, moveY\r
+ DIM destinationX, destinationZ\r
+ DIM destinationAngle\r
+ DIM totalPoints, totalLines\r
+ DIM angleOne, angleTwo\r
+ DIM timeCounter\r
+ DIM incVal\r
+ DIM miniCount\r
+ DIM minutesVal\r
+\r
+ minutesVal = 0\r
+ miniCount = 25\r
+ timeCounter = 0\r
+ incVal = 1\r
+ angleOne = 0\r
+ angleTwo = 0\r
+ totalPoints = 0\r
+ totalLines = 0\r
+\r
+ RANDOMIZE 100\r
+ blockSize = 64\r
+\r
+FractalSubLoop:\r
+ halfBlock = blockSize / 2\r
+ FOR rowY = 0 TO 100 STEP blockSize\r
+ FOR rowX = 0 TO 100 STEP blockSize\r
+ color1 = POINT(rowX, rowY)\r
+ color2 = POINT(rowX + blockSize, rowY)\r
+ color3 = POINT(rowX, rowY + blockSize)\r
+ color4 = POINT(rowX + blockSize, rowY + blockSize)\r
+ color5 = (color1 + color2 + color3 + color4) / 4 + RND * blockSize * 6 - halfBlock * 7\r
+ color6 = (color2 + color4) / 2 + RND * blockSize * 6 - halfBlock * 7\r
+ color7 = (color3 + color4) / 2 + RND * blockSize * 6 - halfBlock * 7\r
+\r
+ IF color5 > 50 THEN color5 = 50\r
+ IF color5 < 0 THEN color5 = 0\r
+ IF color6 > 50 THEN color6 = 50\r
+ IF color6 < 0 THEN color6 = 0\r
+ IF color7 > 50 THEN color7 = 50\r
+ IF color7 < 0 THEN color7 = 0\r
+\r
+ PSET (rowX + halfBlock, rowY + halfBlock), color5\r
+ PSET (rowX + blockSize, rowY + halfBlock), color6\r
+ PSET (rowX + halfBlock, rowY + blockSize), color7\r
+ NEXT rowX\r
+ NEXT rowY\r
+\r
+ blockSize = blockSize / 2\r
+ IF blockSize > 1 THEN GOTO FractalSubLoop\r
+\r
+ ' Build mesh points in mainX(), mainY(), mainZ()\r
+ FOR zLoop = 1 TO 400 STEP 20\r
+ FOR xLoop = 1 TO 400 STEP 20\r
+ totalPoints = totalPoints + 1\r
+ mainX(totalPoints) = xLoop\r
+ mainY(totalPoints) = POINT(zLoop / 20 + 10, xLoop / 20 + 10) * 2\r
+ mainZ(totalPoints) = zLoop\r
+\r
+ IF xLoop > 1 THEN\r
+ totalLines = totalLines + 1\r
+ lineStart(totalLines) = totalPoints\r
+ lineEnd(totalLines) = totalPoints - 1\r
+ lineColor(totalLines) = 1\r
+ END IF\r
+\r
+ IF zLoop > 1 THEN\r
+ totalLines = totalLines + 1\r
+ lineStart(totalLines) = totalPoints\r
+ lineEnd(totalLines) = totalPoints - 20\r
+ lineColor(totalLines) = 1\r
+ END IF\r
+ NEXT xLoop\r
+ NEXT zLoop\r
+\r
+ LINE (0, 0)-(319, 199), 0, BF\r
+ SetPalette 0, 0, 0, 0\r
+ SetPalette 0, 40, 10, 1\r
+ SetPalette 0, 32, 64, 2\r
+ SetPalette 50, 50, 0, 3\r
+ SetPalette 64, 20, 0, 4\r
+\r
+ moveX = 200\r
+ moveZ = 200\r
+ distanceScale = 1000\r
+ holdAx = 200\r
+ holdAy = 0\r
+ holdAz = 200\r
+ destinationX = 200\r
+ destinationZ = 200\r
+\r
+ ' Load helicopter model\r
+ OPEN "copter.dat" FOR INPUT AS #1\r
+ indexA = 0\r
+ indexB = 0\r
+ helicopterPointer = totalPoints + 1\r
+\r
+ReadLoop:\r
+ INPUT #1, fileX, fileY, fileZ\r
+ IF fileX = 999 THEN GOTO CheckLines\r
+ indexA = indexA + 1\r
+ holdX(indexA) = fileX\r
+ holdY(indexA) = -fileY\r
+ holdZ(indexA) = fileZ\r
+ GOTO ReadLoop\r
+\r
+CheckLines:\r
+ INPUT #1, readA, readB\r
+ IF readA = 999 THEN GOTO CloseData\r
+ totalLines = totalLines + 1\r
+ lineStart(totalLines) = readA + totalPoints + 1\r
+ lineEnd(totalLines) = readB + totalPoints + 1\r
+ lineColor(totalLines) = 2\r
+ GOTO CheckLines\r
+\r
+CloseData:\r
+ CLOSE #1\r
+ totalPoints = totalPoints + indexA\r
+ holdNumber = indexA\r
+\r
+ RANDOMIZE 10\r
+ colorVal = 3\r
+\r
+ FOR indexA = 1 TO 25\r
+ randPick = RND * 396 + 2\r
+ xBox = mainX(randPick)\r
+ zBox = mainZ(randPick)\r
+ yBox = mainY(randPick) - 4\r
+\r
+ mainX(totalPoints + 1) = xBox - 5\r
+ mainY(totalPoints + 1) = yBox\r
+ mainZ(totalPoints + 1) = zBox - 5\r
+ mainX(totalPoints + 2) = xBox + 5\r
+ mainY(totalPoints + 2) = yBox\r
+ mainZ(totalPoints + 2) = zBox - 5\r
+ mainX(totalPoints + 3) = xBox + 5\r
+ mainY(totalPoints + 3) = yBox\r
+ mainZ(totalPoints + 3) = zBox + 5\r
+ mainX(totalPoints + 4) = xBox - 5\r
+ mainY(totalPoints + 4) = yBox\r
+ mainZ(totalPoints + 4) = zBox + 5\r
+ mainX(totalPoints + 5) = xBox\r
+ mainY(totalPoints + 5) = yBox - 5\r
+ mainZ(totalPoints + 5) = zBox\r
+\r
+ lineStart(totalLines + 1) = totalPoints + 1\r
+ lineEnd(totalLines + 1) = totalPoints + 2\r
+ lineColor(totalLines + 1) = colorVal\r
+ lineStart(totalLines + 2) = totalPoints + 2\r
+ lineEnd(totalLines + 2) = totalPoints + 3\r
+ lineColor(totalLines + 2) = colorVal\r
+ lineStart(totalLines + 3) = totalPoints + 3\r
+ lineEnd(totalLines + 3) = totalPoints + 4\r
+ lineColor(totalLines + 3) = colorVal\r
+ lineStart(totalLines + 4) = totalPoints + 4\r
+ lineEnd(totalLines + 4) = totalPoints + 1\r
+ lineColor(totalLines + 4) = colorVal\r
+ lineStart(totalLines + 5) = totalPoints + 1\r
+ lineEnd(totalLines + 5) = totalPoints + 5\r
+ lineColor(totalLines + 5) = colorVal\r
+ lineStart(totalLines + 6) = totalPoints + 2\r
+ lineEnd(totalLines + 6) = totalPoints + 5\r
+ lineColor(totalLines + 6) = colorVal\r
+ lineStart(totalLines + 7) = totalPoints + 3\r
+ lineEnd(totalLines + 7) = totalPoints + 5\r
+ lineColor(totalLines + 7) = colorVal\r
+ lineStart(totalLines + 8) = totalPoints + 4\r
+ lineEnd(totalLines + 8) = totalPoints + 5\r
+ lineColor(totalLines + 8) = colorVal\r
+\r
+ totalPoints = totalPoints + 5\r
+ totalLines = totalLines + 8\r
+ NEXT indexA\r
+\r
+MainLoop:\r
+ SOUND 0, 1\r
+ IF INKEY$ <> "" THEN minutesVal = 1\r
+ IF minutesVal > 150 THEN GOTO FinalArea\r
+ IF minutesVal <> 0 THEN minutesVal = minutesVal + 7\r
+\r
+ moveX = holdAx\r
+ moveY = 50 - holdAy - minutesVal\r
+ moveZ = holdAz\r
+\r
+ SELECT CASE incVal\r
+ CASE 1\r
+ destinationX = mainX(totalPoints)\r
+ destinationZ = mainZ(totalPoints)\r
+ GetAngle destinationX, destinationZ, holdAx, holdAz, destinationAngle\r
+\r
+ IF destinationAngle - helicopterAngle > globalPi THEN destinationAngle = destinationAngle - (globalPi * 2)\r
+ IF helicopterAngle - destinationAngle > globalPi THEN destinationAngle = destinationAngle + (globalPi * 2)\r
+\r
+ incVal = 2\r
+\r
+ FOR indexA = totalLines - 7 TO totalLines\r
+ lineColor(indexA) = 4\r
+ NEXT indexA\r
+\r
+ CASE 2\r
+ angleDiff = destinationAngle - helicopterAngle\r
+ IF destinationAngle = helicopterAngle THEN incVal = 3\r
+ IF angleDiff > .05 THEN angleDiff = .05\r
+ IF angleDiff < -.05 THEN angleDiff = -.05\r
+ helicopterAngle = helicopterAngle + angleDiff\r
+\r
+ CASE 3\r
+ diffX = destinationX - holdAx\r
+ diffZ = destinationZ - holdAz\r
+ distVal = SQR(diffX * diffX + diffZ * diffZ)\r
+ IF distVal < 5 THEN incVal = 4\r
+ distVal = distVal / 2\r
+ holdAx = holdAx + diffX / distVal\r
+ holdAz = holdAz + diffZ / distVal\r
+\r
+ CASE 4\r
+ FOR indexA = totalPoints - 4 TO totalPoints\r
+ mainY(indexA) = mainY(indexA) - 1\r
+ NEXT indexA\r
+\r
+ IF mainY(totalPoints) < 3 - holdAy THEN\r
+ FOR indexA = totalLines - 7 TO totalLines\r
+ LINE (lineBufferXOne(indexA), lineBufferYOne(indexA))-(lineBufferXTwo(indexA), lineBufferYTwo(indexA)), 0\r
+ NEXT indexA\r
+\r
+ totalPoints = totalPoints - 5\r
+ totalLines = totalLines - 8\r
+ miniCount = miniCount - 1\r
+ incVal = 6\r
+\r
+ IF miniCount <= 0 THEN incVal = 7\r
+ END IF\r
+\r
+ CASE 6\r
+ incVal = 5\r
+\r
+ CASE 5\r
+ incVal = 1\r
+ END SELECT\r
+\r
+\r
+ ' Place helicopter on the scene\r
+ localYVal = 60 - mainY(INT((holdAz + 10) / 20) * 20 + INT((holdAx + 10) / 20))\r
+\r
+ IF holdAy > localYVal + 5 THEN holdAy = holdAy - 1\r
+ IF holdAy < localYVal THEN holdAy = holdAy + 1\r
+ IF holdAy > localYVal + 25 THEN holdAy = holdAy - 1\r
+ IF holdAy < localYVal - 20 THEN holdAy = holdAy + 1\r
+\r
+ sinVal = SIN(helicopterAngle)\r
+ cosVal = COS(helicopterAngle)\r
+\r
+ FOR indexA = 0 TO holdNumber - 5\r
+ tempX = holdX(indexA + 1)\r
+ tempZ = holdZ(indexA + 1)\r
+ mainX(indexA + helicopterPointer) = tempX * sinVal + tempZ * cosVal + holdAx\r
+ mainY(indexA + helicopterPointer) = holdY(indexA + 1) - holdAy\r
+ mainZ(indexA + helicopterPointer) = tempZ * sinVal - tempX * cosVal + holdAz\r
+ NEXT indexA\r
+\r
+ ' Rotate helicopter rotor\r
+ helicopterRotorAngle = helicopterRotorAngle + .5\r
+ sinVal = SIN(helicopterRotorAngle)\r
+ cosVal = COS(helicopterRotorAngle)\r
+\r
+ FOR indexA = holdNumber - 4 TO holdNumber - 1\r
+ tempX = holdX(indexA + 1)\r
+ tempZ = holdZ(indexA + 1)\r
+ mainX(indexA + helicopterPointer) = tempX * sinVal + tempZ * cosVal + holdAx\r
+ mainY(indexA + helicopterPointer) = holdY(indexA + 1) - holdAy\r
+ mainZ(indexA + helicopterPointer) = tempZ * sinVal - tempX * cosVal + holdAz\r
+ NEXT indexA\r
+\r
+ timeCounter = timeCounter + 1\r
+ angleOne = angleOne + SIN(timeCounter / 100) / 20\r
+ angleTwo = SIN(timeCounter / 42) * .3 + 1.15\r
+ sin1 = SIN(angleOne)\r
+ cos1 = COS(angleOne)\r
+ sin2 = SIN(angleTwo)\r
+ cos2 = COS(angleTwo)\r
+\r
+ ' Project all points to 2D\r
+ FOR indexA = 0 TO totalPoints\r
+ shiftX = mainX(indexA) - moveX\r
+ shiftY = mainY(indexA) - moveY\r
+ shiftZ = mainZ(indexA) - moveZ\r
+ zIntermediate = shiftZ * sin1 + shiftX * cos1\r
+ xIntermediate = shiftX * sin1 - shiftZ * cos1\r
+ zProject = zIntermediate * sin2 + shiftY * cos2\r
+ yProject = shiftY * sin2 - zIntermediate * cos2\r
+ zProject = zProject + distanceScale\r
+\r
+ IF zProject < 1 THEN projectedX(indexA) = -1: GOTO Skip2D\r
+\r
+ xProject = xIntermediate / zProject * 74 * 2\r
+ yProject = yProject / zProject * 65 * 2\r
+ projectedX(indexA) = xProject + 160\r
+ projectedY(indexA) = yProject + 80\r
+\r
+Skip2D:\r
+ NEXT indexA\r
+\r
+ ' Erase old lines and draw new ones\r
+ FOR indexA = 1 TO totalLines\r
+ startIndex = lineStart(indexA)\r
+ endIndex = lineEnd(indexA)\r
+ x1Temp = projectedX(startIndex)\r
+ x2Temp = projectedX(endIndex)\r
+ LINE (lineBufferXOne(indexA), lineBufferYOne(indexA))-(lineBufferXTwo(indexA), lineBufferYTwo(indexA)), 0\r
+\r
+ IF (x1Temp = -1) OR (x2Temp = -1) THEN GOTO SkipDrawing\r
+\r
+ y1Temp = projectedY(startIndex)\r
+ y2Temp = projectedY(endIndex)\r
+ LINE (x1Temp, y1Temp)-(x2Temp, y2Temp), lineColor(indexA)\r
+ lineBufferXOne(indexA) = x1Temp\r
+ lineBufferYOne(indexA) = y1Temp\r
+ lineBufferXTwo(indexA) = x2Temp\r
+ lineBufferYTwo(indexA) = y2Temp\r
+\r
+SkipDrawing:\r
+ NEXT indexA\r
+\r
+ IF distanceScale > 200 THEN distanceScale = distanceScale - 10\r
+ IF timeCounter < 28000 THEN GOTO MainLoop\r
+\r
+FinalArea:\r
+END SUB\r
+\r
+SUB DrawRoundedBox (topLeftX, topLeftY, bottomRightX, bottomRightY)\r
+ '\r
+ ' Draws a soft-edged rectangular box by fading pixel colors around its edges.\r
+ ' This creates a gentle "rounded" or "blurred" border appearance.\r
+ '\r
+\r
+ FOR currentY = topLeftY TO bottomRightY\r
+ fadeSize = 10\r
+ ' Fade in the upper boundary region\r
+ IF currentY - topLeftY <= 10 THEN\r
+ fadeSize = (SQR((20 - (currentY - topLeftY)) * (currentY - topLeftY)))\r
+ END IF\r
+ ' Fade in the lower boundary region\r
+ IF bottomRightY - currentY <= 10 THEN\r
+ fadeSize = (SQR((20 - (bottomRightY - currentY)) * (bottomRightY - currentY)))\r
+ END IF\r
+ FOR currentX = topLeftX - fadeSize TO bottomRightX + fadeSize\r
+ colorVal = POINT(currentX, currentY)\r
+ IF colorVal <= 127 THEN\r
+ colorVal = colorVal + 127\r
+ IF colorVal > 245 THEN colorVal = 245\r
+ PSET (currentX, currentY), colorVal\r
+ END IF\r
+ NEXT currentX\r
+ NEXT currentY\r
+END SUB\r
+\r
+SUB FillPolygon (vertex1X, vertex1Y, vertex2X, vertex2Y, vertex3X, vertex3Y, fillColor)\r
+ '\r
+ ' Fills a triangular area using a scanline algorithm.\r
+ ' 1. Finds intersection points between edges and horizontal scanlines\r
+ ' 2. Draws horizontal lines between pairs of intersections\r
+ '\r
+\r
+ DIM scanIntersection(-100 TO 300)\r
+ startX = vertex1X\r
+ startY = vertex1Y\r
+ endX = vertex2X\r
+ endY = vertex2Y\r
+ GOSUB DrawEdges\r
+ startX = vertex1X\r
+ startY = vertex1Y\r
+ endX = vertex3X\r
+ endY = vertex3Y\r
+ GOSUB DrawEdges\r
+ startX = vertex3X\r
+ startY = vertex3Y\r
+ endX = vertex2X\r
+ endY = vertex2Y\r
+ GOSUB DrawEdges\r
+ GOTO FinishPolygon\r
+\r
+DrawEdges:\r
+ ' Swap points if needed to ensure we draw from top to bottom\r
+ IF endY < startY THEN\r
+ SWAP startY, endY\r
+ SWAP startX, endX\r
+ END IF\r
+ ' For each scanline between the two points\r
+ FOR scanY = startY TO endY - 1\r
+ ' Calculate x position along the edge\r
+ scanX = startX + (endX - startX) * ((scanY - startY) / (endY - startY))\r
+ ' Store first intersection point\r
+ IF scanIntersection(scanY) = 0 THEN\r
+ scanIntersection(scanY) = scanX\r
+ ELSE\r
+ ' Draw horizontal line between intersections\r
+ LINE (scanX, scanY)-(scanIntersection(scanY), scanY), fillColor\r
+ END IF\r
+ NEXT scanY\r
+ RETURN\r
+\r
+FinishPolygon:\r
+END SUB\r
+\r
+SUB GetAngle (firstPointX, firstPointY, secondPointX, secondPointY, angleBetween)\r
+ '\r
+ ' Calculates the angle between two 2D points in radians.\r
+ ' Used for rotation calculations in 3D rendering.\r
+ '\r
+\r
+ IF firstPointY = secondPointY THEN\r
+ IF secondPointX > firstPointX THEN\r
+ angleBetween = globalPi / 2\r
+ ELSE\r
+ angleBetween = globalPi * 1.5\r
+ END IF\r
+ GOTO SkipSpecialCases\r
+ END IF\r
+\r
+ IF secondPointY > firstPointY THEN\r
+ IF secondPointX = firstPointX THEN\r
+ angleBetween = globalPi\r
+ GOTO SkipSpecialCases\r
+ END IF\r
+ IF secondPointX > firstPointX THEN\r
+ angleBetween = (globalPi * 1) - ATN((secondPointX - firstPointX) / (secondPointY - firstPointY))\r
+ ELSE\r
+ angleBetween = globalPi + ATN((firstPointX - secondPointX) / (secondPointY - firstPointY))\r
+ END IF\r
+ ELSE\r
+ IF secondPointX = firstPointX THEN\r
+ angleBetween = 0\r
+ GOTO SkipSpecialCases\r
+ END IF\r
+ IF secondPointX > firstPointX THEN\r
+ angleBetween = ATN((secondPointX - firstPointX) / (firstPointY - secondPointY))\r
+ ELSE\r
+ angleBetween = globalPi * 2 - ATN((firstPointX - secondPointX) / (firstPointY - secondPointY))\r
+ END IF\r
+ END IF\r
+\r
+SkipSpecialCases:\r
+END SUB\r
+\r
+SUB InitializeFont\r
+ '\r
+ ' Captures the current text font into fontData() for later use in PrintText.\r
+ ' This is done by printing each ASCII character (32..150) and reading its bits.\r
+ '\r
+\r
+ SetPalette 0, 0, 0, 70\r
+ COLOR 70\r
+ FOR asciiCode = 32 TO 150\r
+ LOCATE 1, 1\r
+ PRINT CHR$(asciiCode);\r
+ FOR rowY = 0 TO 7\r
+ FOR rowX = 0 TO 7\r
+ fontData(rowX, rowY, asciiCode) = POINT(rowX, rowY)\r
+ NEXT rowX\r
+ NEXT rowY\r
+ NEXT asciiCode\r
+END SUB\r
+\r
+SUB InitializeProgram\r
+ '\r
+ ' Initializes the environment:\r
+ ' 1) Switches to SCREEN 13\r
+ ' 2) Sets globalPi and globalPiI\r
+ ' 3) Calculates a shared factor (fac) for angles\r
+ ' 4) Calls InitializeFont to capture system font data\r
+ '\r
+\r
+ SCREEN 13\r
+ globalPi = 3.141592\r
+ globalPiValue = globalPi\r
+ angleFactor = 360 / (globalPi * 2)\r
+ InitializeFont\r
+END SUB\r
+\r
+DEFINT A-Z\r
+SUB MakeBackground\r
+ '\r
+ ' Creates a fractal-like landscape in the background by iteratively sampling\r
+ ' and perturbing pixel values. The result is a random terrain effect.\r
+ '\r
+\r
+ CLS\r
+ SetPalette 0, 5, 5, 250\r
+ SetPalette 0, 5, 5, 251\r
+ SetPalette 0, 5, 5, 252\r
+ SetPalette 0, 5, 5, 253\r
+ SetPalette 0, 5, 5, 254\r
+ SetPalette 0, 5, 5, 255\r
+\r
+ ' Set custom RGB values for palette entries 0..127\r
+ FOR colorIndex = 0 TO 127\r
+ OUT &H3C8, colorIndex\r
+ OUT &H3C9, SIN(colorIndex / 22) * 30 + 30\r
+ OUT &H3C9, SIN(colorIndex / 18) * 5 + 5\r
+ OUT &H3C9, COS(colorIndex / 12) * 10 + 10\r
+ NEXT colorIndex\r
+\r
+ ' Palette entries 128..245\r
+ FOR colorIndex = 128 TO 245\r
+ OUT &H3C8, colorIndex\r
+ offsetIndex = colorIndex - 128\r
+ OUT &H3C9, SIN(offsetIndex / 22) * 4 + 10\r
+ OUT &H3C9, SIN(offsetIndex / 18) * 4 + 10\r
+ OUT &H3C9, COS(offsetIndex / 12) * 4 + 10\r
+ NEXT colorIndex\r
+\r
+ maxValue = 127\r
+ blockSize = 2 ^ 8\r
+\r
+FractalLoop:\r
+ blockSize = blockSize \ 2\r
+ numXSteps = (319 \ blockSize) - 1\r
+ numYSteps = (199 \ blockSize) - 1\r
+\r
+ ' Subdivide squares in the image to add random variations\r
+ FOR rowY = 0 TO numYSteps\r
+ FOR rowX = 0 TO numXSteps\r
+ topLeftX = rowX * blockSize\r
+ topLeftY = rowY * blockSize\r
+ topLeftColor = POINT(topLeftX, topLeftY)\r
+ topRightColor = POINT(topLeftX + blockSize, topLeftY)\r
+ bottomLeftColor = POINT(topLeftX, topLeftY + blockSize)\r
+ bottomRightColor = POINT(topLeftX + blockSize, topLeftY + blockSize)\r
+\r
+ midTopColor = ((topLeftColor + topRightColor) / 2) + (RND * 6) - 3\r
+ IF midTopColor > maxValue THEN midTopColor = maxValue\r
+\r
+ midLeftColor = ((topLeftColor + bottomLeftColor) / 2) + (RND * 6) - 3\r
+ IF midLeftColor > maxValue THEN midLeftColor = maxValue\r
+\r
+ midRightColor = ((topRightColor + bottomRightColor) / 2) + (RND * 6) - 3\r
+ IF midRightColor > maxValue THEN midRightColor = maxValue\r
+\r
+ midBottomColor = ((bottomLeftColor + bottomRightColor) / 2) + (RND * 6) - 3\r
+ IF midBottomColor > maxValue THEN midBottomColor = maxValue\r
+\r
+ centerColor = ((midTopColor + midLeftColor + midRightColor + midBottomColor) / 4) + (RND * 6) - 3\r
+ IF centerColor > maxValue THEN centerColor = maxValue\r
+\r
+ PSET (topLeftX + blockSize / 2, topLeftY + blockSize / 2), centerColor\r
+ PSET (topLeftX + blockSize / 2, topLeftY), midTopColor\r
+ PSET (topLeftX, topLeftY + blockSize / 2), midLeftColor\r
+ PSET (topLeftX + blockSize, topLeftY + blockSize / 2), midRightColor\r
+ PSET (topLeftX + blockSize / 2, topLeftY + blockSize), midBottomColor\r
+ NEXT rowX\r
+ NEXT rowY\r
+\r
+ IF blockSize > 2 THEN GOTO FractalLoop\r
+END SUB\r
+\r
+DEFSNG A-Z\r
+SUB PrintText (posX, posY, scale, colorValue, textString$)\r
+ '\r
+ ' Renders text at (posX, posY) using the captured fontData().\r
+ ' Currently supports scale=1 for normal size. If scale=1, each character\r
+ ' is drawn 1:1 from the font data.\r
+ '\r
+\r
+ IF scale = 1 THEN\r
+ currentX = posX\r
+ FOR charIndex = 1 TO LEN(textString$)\r
+ asciiVal = ASC(RIGHT$(LEFT$(textString$, charIndex), 1))\r
+ IF asciiVal > 150 OR asciiVal < 32 THEN GOTO SkipCharacter\r
+ FOR rowY = 0 TO 7\r
+ FOR rowX = 0 TO 7\r
+ pixelVal = fontData(rowX, rowY, asciiVal)\r
+ IF pixelVal > 0 THEN PSET (rowX + currentX, rowY + posY), colorValue\r
+ NEXT rowX\r
+ NEXT rowY\r
+SkipCharacter:\r
+ currentX = currentX + 8\r
+ NEXT charIndex\r
+ END IF\r
+END SUB\r
+\r
+SUB RotatePoint (rotationCenterX, rotationCenterY, pointX, pointY, rotationAngle)\r
+ '\r
+ ' Rotates a 2D point around a center using standard rotation formulas.\r
+ ' X' = (X - CX)*cos - (Y - CY)*sin + CX\r
+ ' Y' = (X - CX)*sin + (Y - CY)*cos + CY\r
+ '\r
+\r
+ deltaX = pointX - rotationCenterX\r
+ deltaY = pointY - rotationCenterY\r
+ sinAngle = SIN(rotationAngle)\r
+ cosAngle = COS(rotationAngle)\r
+ pointX = deltaX * cosAngle - deltaY * sinAngle + rotationCenterX\r
+ pointY = deltaX * sinAngle + deltaY * cosAngle + rotationCenterY\r
+END SUB\r
+\r
+SUB SetPalette (red, green, blue, colorIndex)\r
+ '\r
+ ' Sets palette entry 'colorIndex' to (red,green,blue).\r
+ ' Each component 0..63.\r
+ '\r
+\r
+ IF red < 0 THEN red = 0\r
+ IF green < 0 THEN green = 0\r
+ IF blue < 0 THEN blue = 0\r
+ IF red > 63 THEN red = 63\r
+ IF green > 63 THEN green = 63\r
+ IF blue > 63 THEN blue = 63\r
+\r
+ OUT &H3C8, colorIndex\r
+ OUT &H3C9, red\r
+ OUT &H3C9, green\r
+ OUT &H3C9, blue\r
+END SUB\r
+\r
+SUB WaitForInput\r
+ '\r
+ ' Waits for exactly one keystroke and stores it into inputKey$.\r
+ '\r
+\r
+ inputKey$ = INPUT$(1)\r
+END SUB\r
+\r
--- /dev/null
+' 3D Wireframe Exclamation Mark.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Usage:\r
+' Up, Down, Left, Right, w, z - rotate exclamation mark\r
+' <space> - slow down rotation\r
+' q - quit program\r
+'\r
+' Changelog:\r
+' ~2000 - Initial version\r
+\r
+DECLARE SUB LoadVertexAndLineData ()\r
+' Loads vertex and line data from DATA statements into arrays.\r
+' It reads coordinates and line indices, and determines the count of vertices and lines.\r
+\r
+DECLARE SUB NormalizeCoordinates ()\r
+' Normalizes coordinates to fit the screen by scaling them.\r
+' It finds the maximum absolute value among the coordinates and scales all coordinates accordingly.\r
+\r
+DECLARE SUB Render3DWireframe ()\r
+' Renders the 3D wireframe of an exclamation mark.\r
+' It updates rotation angles, rotates and projects vertices, and draws lines between them.\r
+' It also handles user input to control the rotation and exit the program.\r
+\r
+DECLARE SUB PrecomputeTrigonometricValues ()\r
+' Precomputes sine and cosine values for angles from 0 to 360 degrees.\r
+' This allows for faster computation during the rendering process.\r
+\r
+DEFINT A-Z\r
+\r
+' Arrays to store vertex coordinates and projected coordinates\r
+DIM SHARED vertexX(100), vertexY(100), vertexZ(100)\r
+DIM SHARED startX(100), startY(100), endX(100), endY(100)\r
+DIM SHARED x(100), y(100), z(100), lineStartIndex(100), lineEndIndex(100)\r
+\r
+' Arrays to store precomputed sine and cosine values\r
+DIM SHARED cosineValue&(360), sineValue&(360)\r
+\r
+' Variables to store the number of vertices and lines, and rotation angles\r
+DIM SHARED vertexCount, lineCount\r
+DIM SHARED angleX, angleY\r
+\r
+' Initialize rotation angles\r
+angleX = 0\r
+angleY = 0\r
+\r
+' Set screen mode and clear the screen\r
+SCREEN 12\r
+CLS\r
+\r
+' Precompute sine and cosine values for faster rendering\r
+PrecomputeTrigonometricValues\r
+\r
+' Load vertex and line data from DATA statements\r
+LoadVertexAndLineData\r
+\r
+' Normalize coordinates to fit the screen\r
+NormalizeCoordinates\r
+\r
+' Render the 3D wireframe\r
+Render3DWireframe\r
+\r
+' Vertex data\r
+DATA 5,-60,-10\r
+DATA 15,-50,-10\r
+DATA 15,0,-10\r
+DATA 5,10,-10\r
+DATA -5,10,-10\r
+DATA -15,0,-10\r
+DATA -15,-50,-10\r
+DATA -5,-60,-10\r
+DATA 5,-60,10\r
+DATA 15,-50,10\r
+DATA 15,0,10\r
+DATA 5,10,10\r
+DATA -5,10,10\r
+DATA -15,0,10\r
+DATA -15,-50,10\r
+DATA -5,-60,10\r
+DATA 5,20,10\r
+DATA 15,30,10\r
+DATA 15,40,10\r
+DATA 5,50,10\r
+DATA -5,50,10\r
+DATA -15,40,10\r
+DATA -15,30,10\r
+DATA -5,20,10\r
+DATA 5,20,-10\r
+DATA 15,30,-10\r
+DATA 15,40,-10\r
+DATA 5,50,-10\r
+DATA -5,50,-10\r
+DATA -15,40,-10\r
+DATA -15,30,-10\r
+DATA -5,20,-10\r
+DATA 999,999,999\r
+\r
+' Line data\r
+DATA 0,1\r
+DATA 1,2\r
+DATA 2,3\r
+DATA 3,4\r
+DATA 4,5\r
+DATA 5,6\r
+DATA 6,7\r
+DATA 7,0\r
+DATA 8,9\r
+DATA 9,10\r
+DATA 10,11\r
+DATA 11,12\r
+DATA 12,13\r
+DATA 13,14\r
+DATA 14,15\r
+DATA 15,8\r
+DATA 0,8\r
+DATA 1,9\r
+DATA 2,10\r
+DATA 3,11\r
+DATA 4,12\r
+DATA 5,13\r
+DATA 6,14\r
+DATA 7,15\r
+DATA 16,17\r
+DATA 17,18\r
+DATA 18,19\r
+DATA 19,20\r
+DATA 20,21\r
+DATA 21,22\r
+DATA 22,23\r
+DATA 23,16\r
+DATA 24,25\r
+DATA 25,26\r
+DATA 26,27\r
+DATA 27,28\r
+DATA 28,29\r
+DATA 29,30\r
+DATA 30,31\r
+DATA 31,24\r
+DATA 24,16\r
+DATA 25,17\r
+DATA 26,18\r
+DATA 27,19\r
+DATA 28,20\r
+DATA 29,21\r
+DATA 30,22\r
+DATA 31,23\r
+DATA 999,999\r
+\r
+SUB LoadVertexAndLineData\r
+ ' Load vertex coordinates from DATA statements into arrays x, y, and z.\r
+ ' The loop continues until a sentinel value (999) is encountered.\r
+ FOR i = 0 TO 10000\r
+ READ x(i), y(i), z(i)\r
+ IF x(i) = 999 THEN x(i) = 0: y(i) = 0: z(i) = 0: GOTO EndVertexData\r
+ NEXT i\r
+\r
+EndVertexData:\r
+ vertexCount = i\r
+\r
+ ' Load line data from DATA statements into arrays lineStartIndex and lineEndIndex.\r
+ ' The loop continues until a sentinel value (999) is encountered.\r
+ FOR i = 0 TO 10000\r
+ READ lineStartIndex(i), lineEndIndex(i)\r
+ IF lineStartIndex(i) = 999 THEN GOTO EndLineData\r
+ NEXT i\r
+\r
+EndLineData:\r
+ lineCount = i\r
+END SUB\r
+\r
+SUB NormalizeCoordinates\r
+ ' Normalize coordinates to fit the screen by scaling them.\r
+ ' First, find the maximum absolute value among the coordinates.\r
+ maxValue = 0\r
+ FOR i = 0 TO vertexCount\r
+ IF ABS(x(i)) > maxValue THEN maxValue = ABS(x(i))\r
+ IF ABS(y(i)) > maxValue THEN maxValue = ABS(y(i))\r
+ IF ABS(z(i)) > maxValue THEN maxValue = ABS(z(i))\r
+ NEXT i\r
+\r
+ ' Scale all coordinates by a factor of 100 / maxValue to fit the screen.\r
+ scaleFactor = 100 / maxValue\r
+ FOR i = 0 TO vertexCount\r
+ x(i) = x(i) * scaleFactor\r
+ y(i) = y(i) * scaleFactor\r
+ z(i) = z(i) * scaleFactor\r
+ NEXT i\r
+END SUB\r
+\r
+SUB PrecomputeTrigonometricValues\r
+ ' Precompute sine and cosine values for angles from 0 to 360 degrees.\r
+ ' This allows for faster computation during the rendering process.\r
+ FOR angle! = 0 TO 359 / 57.29577950999999# STEP 1 / 57.29577950999999#\r
+ cosineValue&(angle) = INT(.5 + COS(angle!) * 1024)\r
+ sineValue&(angle) = INT(.5 + SIN(angle!) * 1024)\r
+ angle = angle + 1\r
+ NEXT angle!\r
+END SUB\r
+\r
+SUB Render3DWireframe\r
+ DO\r
+ ' Update rotation angles based on user input\r
+ angleX = angleX + deltaX\r
+ angleY = angleY + deltaY\r
+ angleZ = angleZ + deltaZ\r
+ SOUND 0, 1\r
+\r
+ ' Ensure rotation angles stay within the range of 0 to 359 degrees\r
+ IF angleX <= 0 THEN angleX = angleX + 360\r
+ IF angleY <= 0 THEN angleY = angleY + 360\r
+ IF angleZ <= 0 THEN angleZ = angleZ + 360\r
+ IF angleX >= 360 THEN angleX = angleX - 360\r
+ IF angleY >= 360 THEN angleY = angleY - 360\r
+ IF angleZ >= 360 THEN angleZ = angleZ - 360\r
+\r
+ ' Get precomputed sine and cosine values for the rotation angles\r
+ cosX& = cosineValue&(angleX): sinX& = sineValue&(angleX)\r
+ cosY& = cosineValue&(angleY): sinY& = sineValue&(angleY)\r
+ cosZ& = cosineValue&(angleZ): sinZ& = sineValue&(angleZ)\r
+\r
+ ' Rotate and project vertices onto the 2D screen\r
+ FOR i = 0 TO vertexCount - 1\r
+ originalX = x(i): originalY = y(i): originalZ = z(i)\r
+ rotatedX = (originalX * cosX& - originalY * sinX&) \ 1024\r
+ rotatedY = (originalX * sinX& + originalY * cosX&) \ 1024\r
+ tempX& = (rotatedX * cosY& - originalZ * sinY&) \ 1024\r
+ tempZ = (rotatedX * sinY& + originalZ * cosY&) \ 1024\r
+ tempY& = (rotatedY * cosZ& - tempZ * sinZ&) \ 1024\r
+ finalZ = (rotatedY * sinZ& + tempZ * cosZ&) \ 1024\r
+\r
+ ' Adjust the Z-coordinate to add perspective\r
+ finalZ = finalZ + 300\r
+\r
+ ' Project the 3D coordinates onto the 2D screen\r
+ vertexX(i) = 320 + (tempX& / finalZ * 500)\r
+ vertexY(i) = 240 + (tempY& / finalZ * 500)\r
+ NEXT i\r
+\r
+ ' Draw lines between the projected vertices\r
+ FOR i = 0 TO lineCount - 1\r
+ startVertex = lineStartIndex(i)\r
+ endVertex = lineEndIndex(i)\r
+ startXCoord = vertexX(startVertex)\r
+ startYCoord = vertexY(startVertex)\r
+ endXCoord = vertexX(endVertex)\r
+ endYCoord = vertexY(endVertex)\r
+\r
+ ' Erase the previous line\r
+ LINE (startX(i), startY(i))-(endX(i), endY(i)), 0\r
+\r
+ ' Draw the new line\r
+ LINE (endXCoord, endYCoord)-(startXCoord, startYCoord), 15\r
+\r
+ ' Store the current coordinates for the next iteration\r
+ startX(i) = endXCoord: startY(i) = endYCoord\r
+ endX(i) = startXCoord: endY(i) = startYCoord\r
+ NEXT i\r
+\r
+ ' Handle user input to control the rotation\r
+ keyPressed$ = INKEY$\r
+ IF keyPressed$ <> "" THEN\r
+ SELECT CASE keyPressed$\r
+ CASE CHR$(0) + CHR$(72) ' Up arrow\r
+ deltaX = deltaX + 1\r
+ CASE CHR$(0) + CHR$(80) ' Down arrow\r
+ deltaX = deltaX - 1\r
+ CASE CHR$(0) + CHR$(75) ' Left arrow\r
+ deltaY = deltaY - 1\r
+ CASE CHR$(0) + CHR$(77) ' Right arrow\r
+ deltaY = deltaY + 1\r
+ CASE "w"\r
+ deltaZ = deltaZ - 1\r
+ CASE "z"\r
+ deltaZ = deltaZ + 1\r
+ CASE " " ' Space bar\r
+ deltaX = deltaX / 2\r
+ deltaY = deltaY / 2\r
+ deltaZ = deltaZ / 2\r
+ CASE CHR$(27) ' Escape key\r
+ SYSTEM\r
+ END SELECT\r
+ END IF\r
+ LOOP\r
+END SUB\r
+\r
--- /dev/null
+' 3D animation of point-cloud ball bouncing around the screen\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 1999, Initial version.\r
+' 2024 - 2025, Improved code readability.\r
+\r
+DECLARE SUB InitializeScene ()\r
+DECLARE SUB UpdateOrientation ()\r
+DECLARE SUB DisplayPoints (angle1 AS SINGLE, angle2 AS SINGLE, angle3 AS SINGLE)\r
+RANDOMIZE TIMER\r
+SCREEN 12\r
+\r
+' Shared arrays to hold the positions of points in 3D space\r
+DIM SHARED pointX(1 TO 1000) AS SINGLE\r
+DIM SHARED pointY(1 TO 1000) AS SINGLE\r
+DIM SHARED pointZ(1 TO 1000) AS SINGLE\r
+\r
+' Shared arrays to hold the previous on-screen positions of points\r
+DIM SHARED prevX(1 TO 1000) AS INTEGER\r
+DIM SHARED prevY(1 TO 1000) AS INTEGER\r
+\r
+' Shared variables for simulation control\r
+DIM SHARED totalPoints AS INTEGER\r
+DIM SHARED ballX\r
+DIM SHARED ballY\r
+DIM SHARED ballVelocityX\r
+DIM SHARED ballVelocityY\r
+\r
+' Shared variables for rotation angles and their velocities\r
+DIM SHARED rotationAngle1\r
+DIM SHARED rotationAngle2\r
+DIM SHARED rotationAngle3\r
+DIM SHARED angularVelocity1\r
+DIM SHARED angularVelocity2\r
+DIM SHARED angularVelocity3\r
+\r
+' Initialize the total number of points to be displayed\r
+totalPoints = 500\r
+\r
+CALL InitializeScene\r
+\r
+' Initialization of rotation angles and ball position\r
+rotationAngle1 = 0\r
+rotationAngle2 = 0\r
+rotationAngle3 = 0\r
+\r
+' Main loop\r
+DO\r
+ SOUND 0, .5\r
+\r
+ CALL DisplayPoints(rotationAngle1, rotationAngle2, rotationAngle3)\r
+\r
+ ' Update the rotation angles based on their velocities\r
+ rotationAngle1 = rotationAngle1 + angularVelocity1\r
+ rotationAngle2 = rotationAngle2 + angularVelocity2\r
+ rotationAngle3 = rotationAngle3 + angularVelocity3\r
+\r
+ ' Add force of gravity\r
+ ballVelocityY = ballVelocityY + .1\r
+\r
+ ' Update the ball's position and velocity\r
+ ballY = ballY + ballVelocityY\r
+ ballX = ballX + ballVelocityX\r
+\r
+ ' Check for ball bounce conditions\r
+ IF ballY > 160 THEN\r
+ ballVelocityY = -ballVelocityY\r
+ ballVelocityX = ballVelocityX + (RND * 2 - 1)\r
+ CALL UpdateOrientation\r
+ END IF\r
+\r
+ IF ballX < -200 OR ballX > 200 THEN\r
+ ballVelocityX = -ballVelocityX\r
+ CALL UpdateOrientation\r
+ END IF\r
+\r
+ ' Check for user input to exit the program\r
+ a$ = INKEY$\r
+ IF a$ <> "" THEN\r
+ CLS\r
+ SYSTEM\r
+ END IF\r
+LOOP\r
+\r
+' Subroutine to display the points on the screen\r
+SUB DisplayPoints (angle1 AS SINGLE, angle2 AS SINGLE, angle3 AS SINGLE)\r
+\r
+ ' Calculate the sine and cosine for rotation angles\r
+ s1 = SIN(angle1)\r
+ c1 = COS(angle1)\r
+ s2 = SIN(angle2)\r
+ c2 = COS(angle2)\r
+ s3 = SIN(angle3)\r
+ c3 = COS(angle3)\r
+\r
+ ' For each point, apply rotation transformations and project to 2D\r
+ FOR a = 1 TO totalPoints\r
+ x = pointX(a)\r
+ y = pointY(a)\r
+ z = pointZ(a)\r
+\r
+ x1 = x * s1 + y * c1\r
+ y1 = x * c1 - y * s1\r
+\r
+ z1 = z * s2 + y1 * c2\r
+ y2 = z * c2 - y1 * s2\r
+\r
+ z2 = z1 * s3 + x1 * c3\r
+ x2 = z1 * c3 - x1 * s3\r
+\r
+ ' Perspective projection\r
+ z2 = z2 + 200\r
+\r
+ ' Convert to screen coordinates and apply ball offset\r
+ xScreen = x2 / z2 * 320 + 320 + ballX\r
+ yScreen = y2 / z2 * 300 + 240 + ballY\r
+\r
+ ' Erase the previous point position and draw the new one\r
+ PSET (prevX(a), prevY(a)), 0\r
+ PSET (xScreen, yScreen), 3\r
+\r
+ ' Update the previous on-screen positions\r
+ prevX(a) = xScreen\r
+ prevY(a) = yScreen\r
+ NEXT a\r
+END SUB\r
+\r
+' Subroutine to initialize the 3D points and ball properties\r
+SUB InitializeScene\r
+ PRINT "Calculating coordinates"\r
+ PRINT "Please wait....."\r
+\r
+ ' Generate random 3D coordinates for each point\r
+ FOR a = 1 TO totalPoints\r
+ ang1 = RND * 100\r
+ ang2 = RND * 100\r
+ ang3 = RND * 100\r
+\r
+ s1 = SIN(ang1)\r
+ c1 = COS(ang1)\r
+ s2 = SIN(ang2)\r
+ c2 = COS(ang2)\r
+ s3 = SIN(ang3)\r
+ c3 = COS(ang3)\r
+\r
+ ' Apply rotation transformations to the point\r
+ x = 50\r
+ y = 0\r
+ z = 0\r
+\r
+ x1 = x * s1 + y * c1\r
+ y1 = x * c1 - y * s1\r
+\r
+ z1 = z * s2 + y1 * c2\r
+ y2 = z * c2 - y1 * s2\r
+\r
+ z2 = z1 * s3 + x1 * c3\r
+ x2 = z1 * c3 - x1 * s3\r
+\r
+ pointX(a) = x2\r
+ pointY(a) = y2\r
+ pointZ(a) = z2\r
+ NEXT a\r
+\r
+ ' Set the initial ball velocity\r
+ ballVelocityX = 2 + RND\r
+ ballY = -100\r
+\r
+ CALL UpdateOrientation\r
+\r
+ CLS\r
+END SUB\r
+\r
+' Subroutine to update the angular velocities for rotation\r
+SUB UpdateOrientation\r
+ angularVelocity1 = (RND - .5) / 16\r
+ angularVelocity2 = (RND - .5) / 16\r
+ angularVelocity3 = (RND - .5) / 16\r
+END SUB\r
+\r
--- /dev/null
+' Renders 3D text within 3D room.
+' User can freely fly around the room and observe the text from different angles.
+'
+' This program is free software: released under Creative Commons Zero (CC0) license
+' by Svjatoslav Agejenko.
+' Email: svjatoslav@svjatoslav.eu
+' Homepage: http://www.svjatoslav.eu
+'
+' Changelog:
+' 2003, Initial version
+' 2024 - 2025, Improved program readability
+'
+' Keyboard controls:
+' cursor keys and to z, w - rotate
+' <SPACE> - slow down
+' q and <ESC> - quit program
+' + / - - move up / down
+
+
+DECLARE SUB defineOctagon (x!, y!, z!, size!)
+DECLARE SUB printText (x AS SINGLE, y AS SINGLE, text AS STRING)
+DECLARE SUB renderCharacter (x AS SINGLE, y AS SINGLE, character AS STRING)
+DECLARE SUB readFontData ()
+DECLARE SUB defineSquare (x AS SINGLE, y AS SINGLE, z AS SINGLE, size AS SINGLE)
+DECLARE SUB defineRectangle (x AS SINGLE, y AS SINGLE, z AS SINGLE, size AS SINGLE)
+DECLARE SUB createFloor ()
+DECLARE SUB addPoint (x AS INTEGER, y AS INTEGER, z AS INTEGER)
+DECLARE SUB initializeProgram ()
+DECLARE SUB addSquare (x1 AS INTEGER, y1 AS INTEGER, z1 AS INTEGER)
+DECLARE SUB defineCubeAndRectangle ()
+DECLARE SUB multiplyCoordinates ()
+DECLARE SUB render3DScene ()
+DECLARE SUB calculateSineCosine ()
+
+DIM SHARED pointX(4000) AS SINGLE, pointY(4000) AS SINGLE, pointZ(4000) AS SINGLE
+DIM SHARED x(4000) AS SINGLE, y(4000) AS SINGLE, z(4000) AS SINGLE
+DIM SHARED oldPointX(4000) AS SINGLE, oldPointY(4000) AS SINGLE, oldPointZ(4000) AS SINGLE
+DIM SHARED lineStart(4000) AS INTEGER, lineEnd(4000) AS INTEGER
+DIM SHARED lineColor(4000) AS INTEGER
+DIM SHARED numPoints AS INTEGER, numLines AS INTEGER
+DIM SHARED userX AS SINGLE, userY AS SINGLE, userZ AS SINGLE, userSpeed AS SINGLE, userDirection AS SINGLE
+DIM SHARED fontPointX(0 TO 10, 0 TO 255) AS SINGLE, fontPointY(0 TO 10, 0 TO 255) AS SINGLE
+DIM SHARED fontLineStart(0 TO 10, 0 TO 255) AS INTEGER, fontLineEnd(0 TO 10, 0 TO 255) AS INTEGER
+
+userX = 0
+userY = 0
+userZ = -100
+
+initializeProgram
+render3DScene
+
+SUB createFloor
+' Create the floor of the 3D room using hexagons and squares
+FOR x = -100 TO 0 STEP 12.067 + .3
+ FOR z = -100 TO 0 STEP 12.067 + .3
+ defineOctagon x, -125, z, 6.53
+ defineRectangle x + 6.033 + .15, -125, z + 6.033 + .15, 3.111 + .3
+ NEXT z
+NEXT x
+
+' Loop to create squares
+FOR y = -100 TO 0 STEP 20.3
+ FOR x = -100 TO 0 STEP 20.3
+ defineSquare x, y, 200, 10
+ NEXT x
+NEXT y
+END SUB
+
+SUB defineCubeAndRectangle
+' Define the corners of a cube
+pointX(numPoints + 1) = -150
+pointY(numPoints + 1) = -125
+pointZ(numPoints + 1) = -200
+pointX(numPoints + 2) = 150
+pointY(numPoints + 2) = -125
+pointZ(numPoints + 2) = -200
+pointX(numPoints + 3) = 150
+pointY(numPoints + 3) = 125
+pointZ(numPoints + 3) = -200
+pointX(numPoints + 4) = -150
+pointY(numPoints + 4) = 125
+pointZ(numPoints + 4) = -200
+pointX(numPoints + 5) = -150
+pointY(numPoints + 5) = -125
+pointZ(numPoints + 5) = 200
+pointX(numPoints + 6) = 150
+pointY(numPoints + 6) = -125
+pointZ(numPoints + 6) = 200
+pointX(numPoints + 7) = 150
+pointY(numPoints + 7) = 125
+pointZ(numPoints + 7) = 200
+pointX(numPoints + 8) = -150
+pointY(numPoints + 8) = 125
+pointZ(numPoints + 8) = 200
+
+' Define the lines connecting the corners
+lineStart(numLines + 1) = numPoints + 1
+lineEnd(numLines + 1) = numPoints + 2
+lineStart(numLines + 2) = numPoints + 2
+lineEnd(numLines + 2) = numPoints + 3
+lineStart(numLines + 3) = numPoints + 3
+lineEnd(numLines + 3) = numPoints + 4
+lineStart(numLines + 4) = numPoints + 4
+lineEnd(numLines + 4) = numPoints + 1
+lineStart(numLines + 5) = numPoints + 5
+lineEnd(numLines + 5) = numPoints + 6
+lineStart(numLines + 6) = numPoints + 6
+lineEnd(numLines + 6) = numPoints + 7
+lineStart(numLines + 7) = numPoints + 7
+lineEnd(numLines + 7) = numPoints + 8
+lineStart(numLines + 8) = numPoints + 8
+lineEnd(numLines + 8) = numPoints + 5
+lineStart(numLines + 9) = numPoints + 5
+lineEnd(numLines + 9) = numPoints + 1
+lineStart(numLines + 10) = numPoints + 6
+lineEnd(numLines + 10) = numPoints + 2
+lineStart(numLines + 11) = numPoints + 7
+lineEnd(numLines + 11) = numPoints + 3
+lineStart(numLines + 12) = numPoints + 8
+lineEnd(numLines + 12) = numPoints + 4
+
+numPoints = numPoints + 8
+numLines = numLines + 12
+
+' Define the corners of rectangle
+pointX(numPoints + 1) = -150
+pointY(numPoints + 1) = -125 + 201
+pointZ(numPoints + 1) = 0
+pointX(numPoints + 2) = -150
+pointY(numPoints + 2) = -125 + 201
+pointZ(numPoints + 2) = 89
+pointX(numPoints + 3) = -150
+pointY(numPoints + 3) = -125
+pointZ(numPoints + 3) = 89
+pointX(numPoints + 4) = -150
+pointY(numPoints + 4) = -125
+pointZ(numPoints + 4) = 0
+
+' Define the lines connecting these corners
+lineStart(numLines + 1) = numPoints + 1
+lineEnd(numLines + 1) = numPoints + 2
+lineStart(numLines + 2) = numPoints + 2
+lineEnd(numLines + 2) = numPoints + 3
+lineStart(numLines + 3) = numPoints + 3
+lineEnd(numLines + 3) = numPoints + 4
+lineStart(numLines + 4) = numPoints + 4
+lineEnd(numLines + 4) = numPoints + 1
+
+numPoints = numPoints + 4
+numLines = numLines + 4
+
+printText 0, 0, "three dimensional "
+printText 0, -3, "text example"
+printText 0, -6, "etc etc etc"
+END SUB
+
+SUB defineOctagon (x, y, z, size)
+' Initialize variables
+b = 0
+f = .3925
+
+' Loop to create points of the octagon
+FOR a = 0 + f TO 6 + f STEP 6.28 / 8
+ x1 = SIN(a) * size
+ y1 = COS(a) * size
+ b = b + 1
+ ' Store the points in the shared arrays
+ pointX(numPoints + b) = x1 + x
+ pointY(numPoints + b) = y
+ pointZ(numPoints + b) = y1 + z
+NEXT a
+
+' Define the lines connecting these points
+lineStart(numLines + 1) = numPoints + 1
+lineEnd(numLines + 1) = numPoints + 2
+lineColor(numLines + 1) = 12
+lineStart(numLines + 2) = numPoints + 2
+lineEnd(numLines + 2) = numPoints + 3
+lineColor(numLines + 2) = 12
+lineStart(numLines + 3) = numPoints + 3
+lineEnd(numLines + 3) = numPoints + 4
+lineColor(numLines + 3) = 12
+lineStart(numLines + 4) = numPoints + 4
+lineEnd(numLines + 4) = numPoints + 5
+lineColor(numLines + 4) = 12
+lineStart(numLines + 5) = numPoints + 5
+lineEnd(numLines + 5) = numPoints + 6
+lineColor(numLines + 5) = 12
+lineStart(numLines + 6) = numPoints + 6
+lineEnd(numLines + 6) = numPoints + 7
+lineColor(numLines + 6) = 12
+lineStart(numLines + 7) = numPoints + 7
+lineEnd(numLines + 7) = numPoints + 8
+lineColor(numLines + 7) = 12
+lineStart(numLines + 8) = numPoints + 8
+lineEnd(numLines + 8) = numPoints + 1
+lineColor(numLines + 8) = 12
+
+numPoints = numPoints + b
+numLines = numLines + 8
+END SUB
+
+SUB defineRectangle (x AS SINGLE, y AS SINGLE, z AS SINGLE, size AS SINGLE)
+' Define the corners of the rectangle
+pointX(numPoints + 1) = x
+pointY(numPoints + 1) = y
+pointZ(numPoints + 1) = z + size
+pointX(numPoints + 2) = x + size
+pointY(numPoints + 2) = y
+pointZ(numPoints + 2) = z
+pointX(numPoints + 3) = x
+pointY(numPoints + 3) = y
+pointZ(numPoints + 3) = z - size
+pointX(numPoints + 4) = x - size
+pointY(numPoints + 4) = y
+pointZ(numPoints + 4) = z
+
+' Define the lines connecting these corners
+lineStart(numLines + 1) = numPoints + 1
+lineEnd(numLines + 1) = numPoints + 2
+lineColor(numLines + 1) = 10
+lineStart(numLines + 2) = numPoints + 2
+lineEnd(numLines + 2) = numPoints + 3
+lineColor(numLines + 2) = 10
+lineStart(numLines + 3) = numPoints + 3
+lineEnd(numLines + 3) = numPoints + 4
+lineColor(numLines + 3) = 10
+lineStart(numLines + 4) = numPoints + 4
+lineEnd(numLines + 4) = numPoints + 1
+lineColor(numLines + 4) = 10
+
+' Update the counters
+numPoints = numPoints + 4
+numLines = numLines + 4
+END SUB
+
+SUB defineSquare (x AS SINGLE, y AS SINGLE, z AS SINGLE, size AS SINGLE)
+' Define the corners of the square
+pointX(numPoints + 1) = x - size
+pointY(numPoints + 1) = y - size
+pointZ(numPoints + 1) = z
+pointX(numPoints + 2) = x + size
+pointY(numPoints + 2) = y - size
+pointZ(numPoints + 2) = z
+pointX(numPoints + 3) = x + size
+pointY(numPoints + 3) = y + size
+pointZ(numPoints + 3) = z
+pointX(numPoints + 4) = x - size
+pointY(numPoints + 4) = y + size
+pointZ(numPoints + 4) = z
+
+' Define the lines connecting these corners
+lineStart(numLines + 1) = numPoints + 1
+lineEnd(numLines + 1) = numPoints + 2
+lineColor(numLines + 1) = 14
+lineStart(numLines + 2) = numPoints + 2
+lineEnd(numLines + 2) = numPoints + 3
+lineColor(numLines + 2) = 14
+lineStart(numLines + 3) = numPoints + 3
+lineEnd(numLines + 3) = numPoints + 4
+lineColor(numLines + 3) = 14
+lineStart(numLines + 4) = numPoints + 4
+lineEnd(numLines + 4) = numPoints + 1
+lineColor(numLines + 4) = 14
+
+' Update the counters
+numPoints = numPoints + 4
+numLines = numLines + 4
+END SUB
+
+SUB initializeProgram
+' Initialize the screen and clear it
+SCREEN 12
+CLS
+
+' Set the default color for all points
+FOR a = 1 TO 4000
+ lineColor(a) = 15
+NEXT a
+
+' Initialize counters
+numPoints = 0
+numLines = 0
+
+' Initialize font data
+FOR a = 0 TO 255
+ FOR b = 0 TO 10
+ fontPointX(b, a) = 999
+ fontPointY(b, a) = 999
+ fontLineStart(b, a) = 999
+ fontLineEnd(b, a) = 999
+ NEXT b
+NEXT a
+
+' Read the font data
+readFontData
+
+' Define the corners of the cubes
+defineCubeAndRectangle
+END SUB
+
+SUB printText (x AS SINGLE, y AS SINGLE, text AS STRING)
+' Loop to print each character
+FOR b = 1 TO LEN(text)
+ c$ = RIGHT$(LEFT$(text, b), 1)
+ renderCharacter x + b * 3, y, c$
+NEXT b
+END SUB
+
+SUB readFontData
+' Open the font file
+OPEN "font.dat" FOR INPUT AS #1
+
+' Loop to read the font data
+3
+IF EOF(1) <> 0 THEN GOTO 2
+LINE INPUT #1, a$
+
+IF LEFT$(a$, 1) = "#" THEN
+ chr = ASC(RIGHT$(LEFT$(a$, 3), 1))
+ ' Initialize counters
+ pp = 0
+ lp = 0
+END IF
+
+' Read the points for the character
+IF LEFT$(a$, 1) = "p" THEN
+ fontPointX(pp, chr) = VAL(RIGHT$(LEFT$(a$, 3), 1))
+ fontPointY(pp, chr) = VAL(RIGHT$(LEFT$(a$, 5), 1))
+ pp = pp + 1
+END IF
+
+' Read the lines for the character
+IF LEFT$(a$, 1) = "l" THEN
+ fontLineStart(lp, chr) = VAL(RIGHT$(LEFT$(a$, 3), 1))
+ fontLineEnd(lp, chr) = VAL(RIGHT$(LEFT$(a$, 5), 1))
+ lp = lp + 1
+END IF
+
+GOTO 3
+
+' Close the font file
+2
+CLOSE #1
+END SUB
+
+SUB render3DScene
+' Main loop for the 3D rendering
+1
+SOUND 0, .5
+
+userX = userX + SIN(rotationAngleX) * userSpeed
+userZ = userZ + COS(rotationAngleX) * userSpeed
+userX = userX + COS(rotationAngleX) * userDirection
+userZ = userZ - SIN(rotationAngleX) * userDirection
+rotationAngleX = rotationAngleX + angleIncrementX
+rotationAngleY = rotationAngleY + angleIncrementY
+cosAngleX = COS(rotationAngleX): sinAngleX = SIN(rotationAngleX)
+cosAngleY = COS(rotationAngleY): sinAngleY = SIN(rotationAngleY)
+
+' Transform the coordinates
+FOR a = 1 TO numPoints
+ oldPointX(a) = pointX(a) - userX
+ oldPointY(a) = -pointY(a) - userY
+ oldPointZ(a) = pointZ(a) - userZ
+ x1 = (oldPointX(a) * cosAngleX - oldPointZ(a) * sinAngleX)
+ z1 = (oldPointX(a) * sinAngleX + oldPointZ(a) * cosAngleX)
+ y1 = (oldPointY(a) * cosAngleY - z1 * sinAngleY)
+ z2 = (oldPointY(a) * sinAngleY + z1 * cosAngleY)
+
+ ' Store the transformed coordinates
+ oldPointX(a) = x(a)
+ oldPointY(a) = y(a)
+
+ ' Check if the point is within the view
+ IF z2 < 20 THEN
+ x(a) = -1
+ ELSE
+ ' Apply perspective transformation
+ x(a) = 320 + (x1 / z2 * 500)
+ y(a) = 240 + (y1 / z2 * 500)
+ END IF
+NEXT
+
+' Draw the lines
+FOR a = 1 TO numLines
+ p1 = lineStart(a)
+ p2 = lineEnd(a)
+
+ ' Check if the points are within the view
+ IF oldPointX(p1) = -1 OR oldPointX(p2) = -1 THEN
+ ' Do nothing
+ ELSE
+ ' Erase line at old coordinates
+ LINE (oldPointX(p1), oldPointY(p1))-(oldPointX(p2), oldPointY(p2)), 0
+ END IF
+
+ IF x(p1) = -1 OR x(p2) = -1 THEN
+ ' Do nothing
+ ELSE
+ ' Draw line at new coordinates
+ LINE (x(p1), y(p1))-(x(p2), y(p2)), lineColor(a)
+ END IF
+NEXT
+
+' Handle user input
+userInput$ = INKEY$
+
+IF userInput$ <> "" THEN
+ SELECT CASE userInput$
+ CASE CHR$(0) + "P"
+ userSpeed = userSpeed - 1
+ CASE CHR$(0) + "H"
+ userSpeed = userSpeed + 1
+ CASE CHR$(0) + "M"
+ userDirection = userDirection + 1
+ CASE CHR$(0) + "K"
+ userDirection = userDirection - 1
+ CASE "+"
+ userY = userY + 3
+ CASE "-"
+ userY = userY - 3
+ CASE "6"
+ angleIncrementX = angleIncrementX + .01
+ CASE "4"
+ angleIncrementX = angleIncrementX - .01
+ CASE "8"
+ angleIncrementY = angleIncrementY - .01
+ CASE "2"
+ angleIncrementY = angleIncrementY + .01
+ CASE " "
+ angleIncrementX = angleIncrementX / 2
+ angleIncrementY = angleIncrementY / 2
+ angleIncrementZ = angleIncrementZ / 2
+ userSpeed = userSpeed / 2
+ userDirection = userDirection / 2
+ CASE "q"
+ SYSTEM
+ CASE CHR$(27)
+ SYSTEM
+ END SELECT
+END IF
+
+GOTO 1
+END SUB
+
+SUB renderCharacter (x AS SINGLE, y AS SINGLE, character AS STRING)
+' Initialize variables
+b = ASC(character)
+up = 0
+ul = 0
+
+' Loop to create points for the character
+FOR c = 0 TO 100
+ IF fontPointX(c, b) = 999 THEN GOTO 4
+ up = up + 1
+ pointX(numPoints + up) = x + fontPointX(c, b)
+ pointY(numPoints + up) = y - fontPointY(c, b)
+ pointZ(numPoints + up) = 0
+NEXT c
+
+4
+' Loop to define the lines for the character
+FOR c = 0 TO 100
+ IF fontLineStart(c, b) = 999 THEN GOTO 5
+ ul = ul + 1
+ lineStart(numLines + ul) = fontLineStart(c, b) + numPoints + 1
+ lineEnd(numLines + ul) = fontLineEnd(c, b) + numPoints + 1
+ lineColor(numLines + ul) = 4
+NEXT c
+
+5
+' Update the counters
+numPoints = numPoints + up
+numLines = numLines + ul
+END SUB
+
--- /dev/null
+' Program to render flying and bouncing cubes on top of a grid-like floor\r
+'\r
+' By Svjatoslav Agejenko\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2001, Initial version\r
+' 2024 - 2025, Improved program readability\r
+'\r
+' Navigation controls:\r
+' Arrow keys - Move forward/backward/left/right\r
+' 2,6,4,8 - Look around (up/down/left/right)\r
+' - - Fly upward\r
+' + - Fly downward\r
+\r
+\r
+DECLARE SUB updateColliders()\r
+DECLARE SUB initializeColliders()\r
+DECLARE SUB renderScene()\r
+DECLARE SUB initializeEnvironment()\r
+DECLARE SUB initializeProgram()\r
+\r
+DIM SHARED initialNumPoints, initialNumLines, numPoints, numLines\r
+DIM SHARED pointXCoord(1 TO 1000) AS SINGLE\r
+DIM SHARED pointYCoord(1 TO 1000) AS SINGLE\r
+DIM SHARED pointZCoord(1 TO 1000) AS SINGLE\r
+DIM SHARED renderedXCoord(1 TO 1000) AS SINGLE\r
+DIM SHARED renderedYCoord(1 TO 1000) AS SINGLE\r
+DIM SHARED prevRenderedXCoord(1 TO 1000) AS SINGLE\r
+DIM SHARED prevRenderedYCoord(1 TO 1000) AS SINGLE\r
+DIM SHARED lineStart(1 TO 1000) AS INTEGER\r
+DIM SHARED lineEnd(1 TO 1000) AS INTEGER\r
+DIM SHARED lineColor(1 TO 1000) AS INTEGER\r
+DIM SHARED prevLineStart(1 TO 1000) AS INTEGER\r
+DIM SHARED prevLineEnd(1 TO 1000) AS INTEGER\r
+DIM SHARED prevLineCount AS INTEGER\r
+DIM SHARED cameraXPos AS SINGLE, cameraXSpeed AS SINGLE\r
+DIM SHARED cameraYPos AS SINGLE, cameraYSpeed AS SINGLE\r
+DIM SHARED cameraZPos AS SINGLE, cameraZSpeed AS SINGLE\r
+DIM SHARED cameraAngleX AS SINGLE, cameraAngleXSpeed AS SINGLE\r
+DIM SHARED cameraAngleY AS SINGLE, cameraAngleYSpeed AS SINGLE\r
+DIM SHARED cubeXPos(1 TO 10) AS SINGLE\r
+DIM SHARED cubeYPos(1 TO 10) AS SINGLE\r
+DIM SHARED cubeZPos(1 TO 10) AS SINGLE\r
+DIM SHARED cubeXSpeed(1 TO 10) AS SINGLE\r
+DIM SHARED cubeYSpeed(1 TO 10) AS SINGLE\r
+DIM SHARED cubeZSpeed(1 TO 10) AS SINGLE\r
+DIM SHARED numCubes AS INTEGER\r
+\r
+ON ERROR GOTO ErrorHandler\r
+\r
+initializeProgram\r
+initializeEnvironment\r
+initializeColliders\r
+\r
+' The main loop of the program\r
+MainLoop:\r
+\r
+SOUND 0, .5\r
+\r
+numPoints = initialNumPoints\r
+numLines = initialNumLines\r
+\r
+updateColliders\r
+renderScene\r
+\r
+' Update positions and angles\r
+cameraXPos = cameraXPos + cameraXSpeed\r
+cameraYPos = cameraYPos + cameraYSpeed\r
+cameraZPos = cameraZPos + cameraZSpeed\r
+cameraAngleX = cameraAngleX + cameraAngleXSpeed\r
+cameraAngleY = cameraAngleY + cameraAngleYSpeed\r
+\r
+userInput$ = INKEY$\r
+IF userInput$ <> "" THEN\r
+ ' Handle arrow keys for movement\r
+ IF userInput$ = CHR$(0) + "H" THEN\r
+ cameraZSpeed = cameraZSpeed - SIN(cameraAngleX) / 100\r
+ cameraXSpeed = cameraXSpeed - COS(cameraAngleX) / 100\r
+ END IF\r
+ IF userInput$ = CHR$(0) + "P" THEN\r
+ cameraZSpeed = cameraZSpeed + SIN(cameraAngleX) / 100\r
+ cameraXSpeed = cameraXSpeed + COS(cameraAngleX) / 100\r
+ END IF\r
+ IF userInput$ = CHR$(0) + "M" THEN\r
+ cameraZSpeed = cameraZSpeed + COS(cameraAngleX) / 100\r
+ cameraXSpeed = cameraXSpeed - SIN(cameraAngleX) / 100\r
+ END IF\r
+ IF userInput$ = CHR$(0) + "K" THEN\r
+ cameraZSpeed = cameraZSpeed - COS(cameraAngleX) / 100\r
+ cameraXSpeed = cameraXSpeed + SIN(cameraAngleX) / 100\r
+ END IF\r
+ ' Handle number keys for looking around\r
+ IF userInput$ = "6" THEN cameraAngleXSpeed = cameraAngleXSpeed - 0.01\r
+ IF userInput$ = "4" THEN cameraAngleXSpeed = cameraAngleXSpeed + 0.01\r
+ IF userInput$ = "8" THEN cameraAngleYSpeed = cameraAngleYSpeed - 0.01\r
+ IF userInput$ = "2" THEN cameraAngleYSpeed = cameraAngleYSpeed + 0.01\r
+ ' Handle plus and minus keys for flying up and down\r
+ IF userInput$ = "+" THEN cameraYSpeed = cameraYSpeed - 0.01\r
+ IF userInput$ = "-" THEN cameraYSpeed = cameraYSpeed + 0.01\r
+ ' Exit the program on pressing ESC\r
+ IF userInput$ = CHR$(27) THEN SYSTEM\r
+END IF\r
+\r
+GOTO MainLoop\r
+\r
+ErrorHandler:\r
+END\r
+RESUME\r
+\r
+SUB initializeEnvironment\r
+' This subroutine initializes environment points\r
+FOR z = -5 TO 5\r
+ FOR x = -5 TO 5\r
+ numPoints = numPoints + 1\r
+ pointXCoord(numPoints) = x\r
+ pointYCoord(numPoints) = 0\r
+ pointZCoord(numPoints) = z\r
+ ' Add lines between points\r
+ IF x > -5 THEN\r
+ numLines = numLines + 1\r
+ lineStart(numLines) = numPoints\r
+ lineEnd(numLines) = numPoints - 1\r
+ lineColor(numLines) = 3\r
+ END IF\r
+ IF z > -5 THEN\r
+ numLines = numLines + 1\r
+ lineStart(numLines) = numPoints\r
+ lineEnd(numLines) = numPoints - 11\r
+ lineColor(numLines) = 3\r
+ END IF\r
+ NEXT x\r
+NEXT z\r
+' Store the number of points and lines\r
+initialNumPoints = numPoints\r
+initialNumLines = numLines\r
+END SUB\r
+\r
+SUB updateColliders\r
+' This subroutine updates the positions and angles of colliders\r
+FOR a = 1 TO numCubes\r
+ x = cubeXPos(a)\r
+ y = cubeYPos(a)\r
+ z = cubeZPos(a)\r
+ xs = cubeXSpeed(a)\r
+ ys = cubeYSpeed(a)\r
+ zs = cubeZSpeed(a)\r
+ ' Update the Y-axis position\r
+ ys = ys - 0.01\r
+ ' Update the X and Z positions\r
+ x = x + xs\r
+ y = y + ys\r
+ z = z + zs\r
+ ' Bounce off walls\r
+ IF x > 5 THEN xs = -0.1\r
+ IF z > 5 THEN zs = -0.1\r
+ IF x < -5 THEN xs = 0.1\r
+ IF z < -5 THEN zs = 0.1\r
+ ' Reset Y position if it falls below a threshold\r
+ IF y < 0.5 THEN ys = RND * 0.2 + 0.1\r
+ ' Create lines for visualization\r
+ numLines = numLines + 1\r
+ lineStart(numLines) = numPoints + 1\r
+ lineEnd(numLines) = numPoints + 2\r
+ lineColor(numLines) = 14\r
+ numLines = numLines + 1\r
+ lineStart(numLines) = numPoints + 3\r
+ lineEnd(numLines) = numPoints + 2\r
+ lineColor(numLines) = 14\r
+ numLines = numLines + 1\r
+ lineStart(numLines) = numPoints + 3\r
+ lineEnd(numLines) = numPoints + 4\r
+ lineColor(numLines) = 14\r
+ numLines = numLines + 1\r
+ lineStart(numLines) = numPoints + 1\r
+ lineEnd(numLines) = numPoints + 4\r
+ lineColor(numLines) = 14\r
+ numLines = numLines + 1\r
+ lineStart(numLines) = numPoints + 1\r
+ lineEnd(numLines) = numPoints + 5\r
+ lineColor(numLines) = 14\r
+ numLines = numLines + 1\r
+ lineStart(numLines) = numPoints + 2\r
+ lineEnd(numLines) = numPoints + 6\r
+ lineColor(numLines) = 14\r
+ numLines = numLines + 1\r
+ lineStart(numLines) = numPoints + 3\r
+ lineEnd(numLines) = numPoints + 7\r
+ lineColor(numLines) = 14\r
+ numLines = numLines + 1\r
+ lineStart(numLines) = numPoints + 4\r
+ lineEnd(numLines) = numPoints + 8\r
+ lineColor(numLines) = 14\r
+ numLines = numLines + 1\r
+ lineStart(numLines) = numPoints + 5\r
+ lineEnd(numLines) = numPoints + 6\r
+ lineColor(numLines) = 14\r
+ numLines = numLines + 1\r
+ lineStart(numLines) = numPoints + 7\r
+ lineEnd(numLines) = numPoints + 6\r
+ lineColor(numLines) = 14\r
+ numLines = numLines + 1\r
+ lineStart(numLines) = numPoints + 7\r
+ lineEnd(numLines) = numPoints + 8\r
+ lineColor(numLines) = 14\r
+ numLines = numLines + 1\r
+ lineStart(numLines) = numPoints + 5\r
+ lineEnd(numLines) = numPoints + 8\r
+ lineColor(numLines) = 14\r
+ ' Update the array with new positions and speeds\r
+ numPoints = numPoints + 1\r
+ pointXCoord(numPoints) = x - 0.5\r
+ pointYCoord(numPoints) = y - 0.5\r
+ pointZCoord(numPoints) = z - 0.5\r
+ numPoints = numPoints + 1\r
+ pointXCoord(numPoints) = x + 0.5\r
+ pointYCoord(numPoints) = y - 0.5\r
+ pointZCoord(numPoints) = z - 0.5\r
+ numPoints = numPoints + 1\r
+ pointXCoord(numPoints) = x + 0.5\r
+ pointYCoord(numPoints) = y + 0.5\r
+ pointZCoord(numPoints) = z - 0.5\r
+ numPoints = numPoints + 1\r
+ pointXCoord(numPoints) = x - 0.5\r
+ pointYCoord(numPoints) = y + 0.5\r
+ pointZCoord(numPoints) = z - 0.5\r
+ numPoints = numPoints + 1\r
+ pointXCoord(numPoints) = x - 0.5\r
+ pointYCoord(numPoints) = y - 0.5\r
+ pointZCoord(numPoints) = z + 0.5\r
+ numPoints = numPoints + 1\r
+ pointXCoord(numPoints) = x + 0.5\r
+ pointYCoord(numPoints) = y - 0.5\r
+ pointZCoord(numPoints) = z + 0.5\r
+ numPoints = numPoints + 1\r
+ pointXCoord(numPoints) = x + 0.5\r
+ pointYCoord(numPoints) = y + 0.5\r
+ pointZCoord(numPoints) = z + 0.5\r
+ numPoints = numPoints + 1\r
+ pointXCoord(numPoints) = x - 0.5\r
+ pointYCoord(numPoints) = y + 0.5\r
+ pointZCoord(numPoints) = z + 0.5\r
+ ' Update the collider array with new positions and speeds\r
+ cubeXPos(a) = x\r
+ cubeYPos(a) = y\r
+ cubeZPos(a) = z\r
+ cubeXSpeed(a) = xs\r
+ cubeYSpeed(a) = ys\r
+ cubeZSpeed(a) = zs\r
+NEXT a\r
+END SUB\r
+\r
+SUB initializeColliders\r
+' This subroutine initializes colliders with random positions and speeds\r
+FOR a = 1 TO numCubes\r
+ cubeXPos(a) = RND * 10 - 5\r
+ cubeYPos(a) = 2\r
+ cubeZPos(a) = RND * 10 - 5\r
+ cubeXSpeed(a) = RND * 0.5 - 0.25\r
+ cubeYSpeed(a) = RND * 0.5 + 0.1\r
+ cubeZSpeed(a) = RND * 0.5 - 0.25\r
+NEXT a\r
+END SUB\r
+\r
+SUB renderScene\r
+' Calculate sine and cosine for angle rotation\r
+s1 = SIN(cameraAngleX)\r
+c1 = COS(cameraAngleX)\r
+s2 = SIN(cameraAngleY)\r
+c2 = COS(cameraAngleY)\r
+' Loop through all points to render them\r
+FOR a = 1 TO numPoints\r
+ x = pointXCoord(a) + cameraXPos\r
+ y = pointYCoord(a) - cameraYPos\r
+ z = pointZCoord(a) + cameraZPos\r
+ ' Rotate the point\r
+ x1 = x * s1 - z * c1\r
+ z1 = x * c1 + z * s1\r
+ y1 = y * s2 - z1 * c2\r
+ z2 = y * c2 + z1 * s2\r
+ ' Project the 3D point to a 2D screen coordinate\r
+ IF z2 < 0.1 THEN\r
+ renderedXCoord(a) = -1\r
+ ELSE\r
+ renderedXCoord(a) = 320 + (x1 / z2 * 400)\r
+ renderedYCoord(a) = 240 - (y1 / z2 * 400)\r
+ END IF\r
+NEXT a\r
+' Render all lines\r
+FOR a = 1 TO numLines\r
+ l1 = prevLineStart(a)\r
+ l2 = prevLineEnd(a)\r
+ ' Skip rendering if either end of the line is out of view\r
+ IF prevRenderedXCoord(l1) = -1 OR prevRenderedXCoord(l2) = -1 THEN\r
+ ELSE\r
+ LINE (prevRenderedXCoord(l1), prevRenderedYCoord(l1))-(prevRenderedXCoord(l2), prevRenderedYCoord(l2)), 0\r
+ END IF\r
+ ' Update line indices for next frame\r
+ l1 = lineStart(a)\r
+ l2 = lineEnd(a)\r
+ ' Skip rendering if either end of the line is out of view\r
+ IF renderedXCoord(l1) = -1 OR renderedXCoord(l2) = -1 THEN\r
+ ELSE\r
+ LINE (renderedXCoord(l1), renderedYCoord(l1))-(renderedXCoord(l2), renderedYCoord(l2)), lineColor(a)\r
+ END IF\r
+NEXT\r
+' Handle lines that were added during the frame\r
+IF numLines < prevLineCount THEN\r
+ FOR a = numLines + 1 TO prevLineCount\r
+ l1 = prevLineStart(a)\r
+ l2 = prevLineEnd(a)\r
+ ' Skip rendering if either end of the line is out of view\r
+ IF prevRenderedXCoord(l1) = -1 OR prevRenderedXCoord(l2) = -1 THEN\r
+ ELSE\r
+ LINE (prevRenderedXCoord(l1), prevRenderedYCoord(l1))-(prevRenderedXCoord(l2), prevRenderedYCoord(l2)), 0\r
+ END IF\r
+ NEXT\r
+END IF\r
+' Save the current frame's points and lines for next frame\r
+FOR a = 1 TO numPoints\r
+ prevRenderedXCoord(a) = renderedXCoord(a)\r
+ prevRenderedYCoord(a) = renderedYCoord(a)\r
+NEXT a\r
+FOR a = 1 TO numLines\r
+ prevLineStart(a) = lineStart(a)\r
+ prevLineEnd(a) = lineEnd(a)\r
+NEXT a\r
+prevLineCount = numLines\r
+END SUB\r
+\r
+SUB initializeProgram\r
+' Initialize the screen and variables\r
+SCREEN 12\r
+initialNumPoints = 0\r
+initialNumLines = 0\r
+numPoints = initialNumPoints\r
+numLines = initialNumLines\r
+numCubes = 9\r
+cameraXPos = 0\r
+cameraYPos = 4\r
+cameraZPos = 7\r
+cameraAngleX = 3.14 / 2\r
+cameraAngleY = cameraAngleX + 0.6\r
+' Initialize all lines to have a thickness of 4\r
+FOR a = 1 TO 1000\r
+ lineColor(a) = 4\r
+NEXT a\r
+' Store the initial state of all lines\r
+FOR a = 1 TO 1000\r
+ prevLineStart(a) = 1\r
+ prevLineEnd(a) = 1\r
+NEXT a\r
+END SUB\r
--- /dev/null
+' Program to demonstrate 3x3 matrix math for coordinate rotation in 3D space.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.03, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+' Use keys:\r
+' 7 9 - change alpha angle\r
+' 4 6 - change beta angle\r
+' 1 3 - change gamma angle\r
+' ESC - quit program\r
+\r
+DECLARE SUB graphicalCoordinates (xVal AS Single, yVal AS Single, zVal AS Single, x1Val AS Single, y1Val AS Single)\r
+DECLARE SUB setAngles (alphaVal AS Single, betaVal AS Single, gammaVal AS Single)\r
+DIM SHARED matrixX1 AS Single, matrixY1 AS Single, matrixZ1 AS Single\r
+DIM SHARED matrixX2 AS Single, matrixY2 AS Single, matrixZ2 AS Single\r
+DIM SHARED matrixX3 AS Single, matrixY3 AS Single, matrixZ3 AS Single\r
+\r
+SCREEN 7, , , 1\r
+\r
+' Main loop starts here\r
+DO\r
+ CALL setAngles(angleAlpha, angleBeta, angleGamma)\r
+\r
+ FOR y = -70 TO 70 STEP 5\r
+ FOR x = -70 TO 70 STEP 5\r
+ CALL graphicalCoordinates(x, y, SIN((ABS(x) + ABS(y)) / 30) * 30, x1Val, y1Val)\r
+ PSET (x1Val, y1Val), 15\r
+ NEXT x\r
+ NEXT y\r
+ PCOPY 0, 1\r
+ CLS\r
+ inputChar$ = INPUT$(1)\r
+\r
+ ' Adjust rotation angles based on user input\r
+ IF inputChar$ = "7" THEN angleAlpha = angleAlpha + 0.1\r
+ IF inputChar$ = "9" THEN angleAlpha = angleAlpha - 0.1\r
+ IF inputChar$ = "4" THEN angleBeta = angleBeta + 0.1\r
+ IF inputChar$ = "6" THEN angleBeta = angleBeta - 0.1\r
+ IF inputChar$ = "1" THEN angleGamma = angleGamma + 0.1\r
+ IF inputChar$ = "3" THEN angleGamma = angleGamma - 0.1\r
+ IF inputChar$ = CHR$(27) THEN SYSTEM ' Exit program if ESC key is pressed\r
+LOOP\r
+\r
+SUB graphicalCoordinates (xVal AS Single, yVal AS Single, zVal AS Single, x1Val AS Single, y1Val AS Single)\r
+ ' Perform matrix transformation to rotate coordinates\r
+ rxVal = xVal * matrixX1 + yVal * matrixY1 + zVal * matrixZ1\r
+ ryVal = xVal * matrixX2 + yVal * matrixY2 + zVal * matrixZ2\r
+ rzVal = xVal * matrixX3 + yVal * matrixY3 + zVal * matrixZ3\r
+\r
+ ' Apply perspective calculation to give the illusion of depth\r
+ rzVal = rzVal + 100\r
+ x1Val = rxVal / rzVal * 120 + 160\r
+ y1Val = ryVal / rzVal * 120 + 100\r
+END SUB\r
+\r
+SUB setAngles (alphaVal AS Single, betaVal AS Single, gammaVal AS Single)\r
+ ' Calculate the elements of the rotation matrix based on the angles\r
+ matrixX1 = SIN(gammaVal) * SIN(betaVal) * SIN(alphaVal) + COS(gammaVal) * COS(alphaVal)\r
+ matrixY1 = COS(betaVal) * SIN(alphaVal)\r
+ matrixZ1 = SIN(gammaVal) * COS(alphaVal) - COS(gammaVal) * SIN(betaVal) * SIN(alphaVal)\r
+\r
+ matrixX2 = SIN(gammaVal) * SIN(betaVal) * COS(alphaVal) - COS(gammaVal) * SIN(alphaVal)\r
+ matrixY2 = COS(betaVal) * COS(alphaVal)\r
+ matrixZ2 = -COS(gammaVal) * SIN(betaVal) * COS(alphaVal) - SIN(gammaVal) * SIN(alphaVal)\r
+\r
+ matrixX3 = -SIN(gammaVal) * COS(betaVal)\r
+ matrixY3 = SIN(betaVal)\r
+ matrixZ3 = COS(gammaVal) * COS(betaVal)\r
+END SUB
\ No newline at end of file
--- /dev/null
+' Evolving 3D Maze explorer.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Note: This program requires special Terminate and Stay Resident (TSR) mouse driver\r
+' to be loaded *before* starting the current QBasic program itself.\r
+' Here you can read about TSR mouse driver and download needed qbext.com binary:\r
+' https://www3.svjatoslav.eu/projects/qbasicapps/Miscellaneous/Mouse%20driver/index.html\r
+'\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024 - 2025, Improved program readability\r
+'\r
+' Navigation:\r
+' WASD - move around\r
+' Drag mouse - look around\r
+' Press left and right mouse buttons simultaneously while dragging mouse - move in X and Z axis\r
+' Press right mouse button while dragging mouse - move in Y axis\r
+'\r
+' Press 'q' to quit the program\r
+\r
+DECLARE SUB verifyTsrIsLoaded ()\r
+DECLARE SUB startText ()\r
+DECLARE SUB handleInput ()\r
+DECLARE SUB putByte (addr!, dat!)\r
+DECLARE SUB putWord (addr!, dat!)\r
+DECLARE FUNCTION getWord! (addr!)\r
+DECLARE FUNCTION getByte! (addr!)\r
+DECLARE SUB initializeProgram ()\r
+DECLARE SUB render3DScene ()\r
+\r
+DIM SHARED pointX(1 TO 500)\r
+DIM SHARED pointY(1 TO 500)\r
+DIM SHARED pointZ(1 TO 500)\r
+DIM SHARED renderedPointX(1 TO 500)\r
+DIM SHARED renderedPointY(1 TO 500)\r
+DIM SHARED renderedPointEnabled(1 TO 500)\r
+\r
+DIM SHARED lineStart(1 TO 500)\r
+DIM SHARED lineEnd(1 TO 500)\r
+DIM SHARED lineColor(1 TO 500)\r
+\r
+DIM SHARED lineCount, pointCount\r
+\r
+DIM SHARED angleY, angleX, angleZ\r
+\r
+DIM SHARED frameTime\r
+\r
+DIM SHARED extensionSegment, extensionAddress\r
+\r
+DIM SHARED cameraX, cameraY, cameraZ\r
+DIM SHARED cameraXSpeed, cameraYSpeed, cameraZSpeed\r
+DIM SHARED leftMouseButton, rightMouseButton\r
+DIM SHARED maxMove\r
+\r
+lineCount = 0\r
+pointCount = 0\r
+\r
+initializeProgram\r
+\r
+' Initialize position variables\r
+currentX = 0\r
+currentY = 0\r
+currentZ = 0\r
+\r
+pointCount = 1\r
+pointX(pointCount) = currentX\r
+pointY(pointCount) = currentY\r
+pointZ(pointCount) = currentZ\r
+\r
+1\r
+\r
+IF pointCount < 500 THEN\r
+\r
+ ' Increase the number of points and add a new point at the current position\r
+ pointCount = pointCount + 1\r
+ pointX(pointCount) = currentX\r
+ pointY(pointCount) = currentY\r
+ pointZ(pointCount) = currentZ\r
+\r
+ ' Increase the number of lines and define a line between the new point and the previous one\r
+ lineCount = lineCount + 1\r
+ lineStart(lineCount) = pointCount\r
+ lineEnd(lineCount) = pointCount - 1\r
+ lineColor(lineCount) = INT(RND * 15) + 1\r
+\r
+ ' Randomly choose orientation for the next move\r
+ SELECT CASE INT(RND * 3)\r
+ CASE 0\r
+ currentX = RND * 500 - 250\r
+ CASE 1\r
+ currentY = RND * 100 - 50\r
+ CASE 2\r
+ currentZ = RND * 500 - 250\r
+ END SELECT\r
+END IF\r
+\r
+handleInput\r
+render3DScene\r
+\r
+' Copy the current screen to page 1 and clear the screen\r
+PCOPY 0, 1\r
+CLS\r
+GOTO 1\r
+\r
+SUB render3DScene\r
+\r
+' Calculate sine and cosine for Y-axis rotation\r
+sinY = SIN(angleY)\r
+cosY = COS(angleY)\r
+\r
+' Calculate sine and cosine for X-axis rotation\r
+sinX = SIN(angleX)\r
+cosX = COS(angleX)\r
+\r
+' Calculate sine and cosine for Z-axis rotation (not used in current code)\r
+sinZ = SIN(angleZ)\r
+cosZ = COS(angleZ)\r
+\r
+' Project 3D points to 2D screen coordinates\r
+FOR a = 1 TO pointCount\r
+ deltaX = pointX(a) - cameraX\r
+ deltaY = pointY(a) - cameraY\r
+ deltaZ = pointZ(a) - cameraZ\r
+\r
+ ' Rotate around Y axis\r
+ rotatedX = deltaX * cosY + deltaZ * sinY\r
+ rotatedZ = deltaZ * cosY - deltaX * sinY\r
+\r
+ ' Rotate around X axis\r
+ rotatedY = deltaY * cosX + rotatedZ * sinX\r
+ finalZ = rotatedZ * cosX - deltaY * sinX\r
+\r
+ ' Check if the point is in front of the camera (finalZ > 3)\r
+ IF finalZ > 3 THEN\r
+ renderedPointEnabled(a) = 1\r
+ renderedPointX(a) = rotatedX / finalZ * 130 + 160\r
+ renderedPointY(a) = rotatedY / finalZ * 130 + 100\r
+ ELSE\r
+ renderedPointEnabled(a) = 0\r
+ END IF\r
+NEXT a\r
+\r
+' Draw lines between visible points\r
+FOR a = 1 TO lineCount\r
+\r
+ p1 = lineStart(a)\r
+ p2 = lineEnd(a)\r
+ IF (renderedPointEnabled(p1) = 1) AND (renderedPointEnabled(p2) = 1) THEN\r
+ LINE (renderedPointX(p1), renderedPointY(p1))-(renderedPointX(p2), renderedPointY(p2)), lineColor(a)\r
+ END IF\r
+\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB handleInput\r
+\r
+' Read mouse data\r
+IF getByte(8) <> 0 THEN\r
+ putByte 8, 0\r
+ ' Read mouse translation along x axis\r
+ mouseXDelta = getWord(2)\r
+ putWord 2, 0\r
+ ' Read mouse translation along y axis\r
+ mouseYDelta = getWord(4)\r
+ putWord 4, 0\r
+ ' Read pressed mouse buttons\r
+ button = getWord(6)\r
+ putWord 6, 0\r
+\r
+ ' Detect if left, right or both mouse buttons were pressed\r
+ leftMouseButton = 0\r
+ rightMouseButton = 0\r
+ IF button = 1 THEN leftMouseButton = 1\r
+ IF button = 2 THEN rightMouseButton = 1\r
+ IF button = 3 THEN leftMouseButton = 1: rightMouseButton = 1\r
+\r
+ IF rightMouseButton = 1 THEN\r
+ IF leftMouseButton = 1 THEN\r
+ ' If mouse left and right buttons are pressed at the same time,\r
+ ' use mouse translation to move avatar around X and Z axis.\r
+ cameraXSpeed = cameraXSpeed + SIN(angleY) * mouseYDelta / 4\r
+ cameraZSpeed = cameraZSpeed - COS(angleY) * mouseYDelta / 4\r
+ GOTO 3\r
+ END IF\r
+ ' If only right button is pressed, move around Y axis\r
+ cameraYSpeed = cameraYSpeed + mouseYDelta / 4\r
+3\r
+ mouseYDelta = 0\r
+ END IF\r
+\r
+END IF\r
+\r
+' Limit mouse movement to maxMove\r
+IF mouseXDelta < -maxMove THEN mouseXDelta = -maxMove\r
+IF mouseXDelta > maxMove THEN mouseXDelta = maxMove\r
+angleY = angleY - mouseXDelta / 150\r
+\r
+IF mouseYDelta < -maxMove THEN mouseYDelta = -maxMove\r
+IF mouseYDelta > maxMove THEN mouseYDelta = maxMove\r
+angleX = angleX - mouseYDelta / 150\r
+\r
+' Read keyboard input and update player position\r
+keyInput$ = INKEY$\r
+\r
+IF keyInput$ = "a" THEN cameraXSpeed = cameraXSpeed - COS(angleY): cameraZSpeed = cameraZSpeed - SIN(angleY)\r
+IF keyInput$ = "d" THEN cameraXSpeed = cameraXSpeed + COS(angleY): cameraZSpeed = cameraZSpeed + SIN(angleY)\r
+IF keyInput$ = "w" THEN cameraXSpeed = cameraXSpeed - SIN(angleY): cameraZSpeed = cameraZSpeed + COS(angleY)\r
+IF keyInput$ = "s" THEN cameraXSpeed = cameraXSpeed + SIN(angleY): cameraZSpeed = cameraZSpeed - COS(angleY)\r
+IF keyInput$ = "q" THEN SYSTEM\r
+\r
+' Apply friction to player movement\r
+cameraXSpeed = cameraXSpeed / 1.1\r
+cameraYSpeed = cameraYSpeed / 1.1\r
+cameraZSpeed = cameraZSpeed / 1.1\r
+\r
+' Update player position\r
+cameraX = cameraX + cameraXSpeed\r
+cameraZ = cameraZ + cameraZSpeed\r
+cameraY = cameraY + cameraYSpeed\r
+\r
+END SUB\r
+\r
+FUNCTION getByte (addr)\r
+getByte = PEEK(extensionAddress + addr)\r
+END FUNCTION\r
+\r
+FUNCTION getWord (addr)\r
+a = PEEK(extensionAddress + addr)\r
+b = PEEK(extensionAddress + addr + 1)\r
+\r
+' Convert bytes to a hex string and then to an integer\r
+c$ = HEX$(a)\r
+IF LEN(c$) = 1 THEN c$ = "0" + c$\r
+IF LEN(c$) = 0 THEN c$ = "00"\r
+\r
+c = VAL("&H" + HEX$(b) + c$)\r
+\r
+getWord = c\r
+END FUNCTION\r
+\r
+SUB putByte (addr, dat)\r
+POKE (extensionAddress + addr), dat\r
+END SUB\r
+\r
+SUB putWord (addr, dat)\r
+\r
+b$ = HEX$(dat)\r
+\r
+2\r
+IF LEN(b$) < 4 THEN b$ = "0" + b$: GOTO 2\r
+\r
+n1 = VAL("&H" + LEFT$(b$, 2))\r
+n2 = VAL("&H" + RIGHT$(b$, 2))\r
+\r
+POKE (extensionAddress + addr), n2\r
+POKE (extensionAddress + addr + 1), n1\r
+\r
+END SUB\r
+\r
+SUB initializeProgram\r
+verifyTsrIsLoaded\r
+\r
+SCREEN 7, , , 1\r
+\r
+' Set camera speed limit\r
+maxMove = 50\r
+\r
+END SUB\r
+\r
+SUB verifyTsrIsLoaded\r
+\r
+DEF SEG = 0 ' Read first from interrupt table\r
+\r
+extensionSegment = PEEK(&H79 * 4 + 3) * 256\r
+extensionSegment = extensionSegment + PEEK(&H79 * 4 + 2)\r
+\r
+PRINT "Segment is: " + HEX$(extensionSegment)\r
+\r
+extensionAddress = PEEK(&H79 * 4 + 1) * 256\r
+extensionAddress = extensionAddress + PEEK(&H79 * 4 + 0)\r
+\r
+PRINT "relative address is:"; extensionAddress\r
+\r
+DEF SEG = extensionSegment\r
+\r
+' Verify TSR signature\r
+IF getWord(0) <> 1983 THEN\r
+ PRINT "FATAL ERROR: you must load"\r
+ PRINT "QBasic extension TSR first!"\r
+ SYSTEM\r
+END IF\r
+\r
+END SUB\r
--- /dev/null
+' Program to render animated 3D tank driving back and forth on a 3D bridge\r
+' Tank tracks are synchronized with movement. Free camera navigation available.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2000, Initial version\r
+' 2024 - 2025, Improved code readability\r
+'\r
+' Controls:\r
+' Arrow keys - Look around\r
+' +/- - Move forward/backward\r
+' Q - Quit\r
+' Space - Stop movement\r
+\r
+DECLARE SUB InitializeProgram ()\r
+DECLARE SUB SavePosition (x1%, y1%, x2%, y3%)\r
+DECLARE SUB LoadBridgeGeometry ()\r
+DECLARE SUB UpdateTankTracks ()\r
+DECLARE SUB InitializeTrackSegments ()\r
+DECLARE SUB GetTrackSegmentPoints (x1%, y1%, x2%, Y2%)\r
+DECLARE SUB DisplayText ()\r
+DECLARE SUB LoadInitialGeometry ()\r
+DECLARE SUB MultiplyCoordinates ()\r
+DECLARE SUB RenderSceneLoop ()\r
+DECLARE SUB PrecomputeTrigTables ()\r
+\r
+DEFINT A-Y\r
+' Screen coordinate arrays for projected points\r
+DIM SHARED screenX(1000), screenY(1000), depthZ(1000)\r
+' World space coordinates for all 3D points\r
+DIM SHARED worldPointX(2000), worldPointY(2000), worldPointZ(2000)\r
+' Previous frame's rotated point coordinates for motion trails\r
+DIM SHARED prevStartX(1000), prevStartY(1000), prevEndX(1000), prevEndY(1000)\r
+' Line connections between points\r
+DIM SHARED lineStartIndex(1000), lineEndIndex(1000)\r
+' Precomputed sine/cosine tables for fast rotation calculations\r
+DIM SHARED precomputedCosine&(360), precomputedSine&(360)\r
+DIM SHARED totalPoints, totalLines\r
+\r
+' Track system arrays and counters\r
+DIM SHARED trackX(1 TO 3000)\r
+DIM SHARED trackY(1 TO 3000)\r
+DIM SHARED trackSegmentCount\r
+DIM SHARED currentTrackSegmentIndex\r
+\r
+' Geometry pointers for different object types\r
+DIM SHARED trackStartPointIndex ' Point index for first track segment\r
+DIM SHARED trackStartLineIndex ' Line index for first track segment\r
+DIM SHARED bridgeStartPointIndex ' Point index for bridge geometry\r
+DIM SHARED bridgeStartLineIndex ' Line index for bridge geometry\r
+\r
+' Tank position tracking\r
+DIM SHARED tracksXOffset\r
+DIM SHARED tankPosX, tankPosY, tankPosZ\r
+DIM SHARED previousTankPosX, previousTankPosY, previousTankPosZZ\r
+\r
+' Camera rotation angles in degrees\r
+DIM SHARED yawRotationDeg, pitchRotationDeg, rollRotationDeg\r
+DIM SHARED movementSpeed\r
+\r
+DIM SHARED tankMovementDirection\r
+\r
+InitializeProgram\r
+RenderSceneLoop\r
+\r
+' 3D Model Data Section\r
+' Contains coordinates for:\r
+' - Tank body\r
+' - Bridge structure\r
+' - Connection lines between points\r
+DATA -10,-30,-20\r
+DATA 30,-30,-20\r
+DATA 30,-10,-20\r
+DATA -10,-10,-20\r
+\r
+DATA -10,-30,20\r
+DATA 30,-30,20\r
+DATA 30,-10,20\r
+DATA -10,-10,20\r
+\r
+DATA -10,-40,-15\r
+DATA 30,-40,-15\r
+DATA -10,-40,15\r
+DATA 30,-40,15\r
+\r
+DATA -20,-30,-15\r
+DATA -20,-30, 15\r
+\r
+DATA -70,-10,-50\r
+DATA 60,-10, -50\r
+DATA 70, 0, -50\r
+DATA 70, 20, -50\r
+DATA 60, 30, -50\r
+DATA -70,30, -50\r
+DATA -80,20, -50\r
+DATA -80, 0, -50\r
+\r
+DATA -70,-10,-30\r
+DATA 60,-10, -30\r
+DATA 70, 0, -30\r
+DATA 70, 20, -30\r
+DATA 60, 30, -30\r
+DATA -70,30, -30\r
+DATA -80,20, -30\r
+DATA -80, 0, -30\r
+\r
+DATA -70,-10, 50\r
+DATA 60,-10, 50\r
+DATA 70, 0, 50\r
+DATA 70, 20, 50\r
+DATA 60, 30, 50\r
+DATA -70,30, 50\r
+DATA -80,20, 50\r
+DATA -80, 0, 50\r
+\r
+DATA -70,-10, 30\r
+DATA 60,-10, 30\r
+DATA 70, 0, 30\r
+DATA 70, 20, 30\r
+DATA 60, 30, 30\r
+DATA -70,30, 30\r
+DATA -80,20, 30\r
+DATA -80, 0, 30\r
+\r
+DATA -50,-7,-30\r
+DATA 50,-7,-30\r
+DATA 50, 15,-30\r
+DATA -50, 15,-30\r
+\r
+DATA -50,-7, 30\r
+DATA 50,-7, 30\r
+DATA 50, 15,30\r
+DATA -50, 15,30\r
+\r
+DATA -20,-20,-5\r
+DATA -20,-20, 5\r
+DATA -20,-30, 5\r
+DATA -20,-30,-5\r
+\r
+DATA -100,-30,-5\r
+DATA -100,-30, 5\r
+DATA -100,-40, 5\r
+DATA -100,-40,-5\r
+\r
+DATA 999,999,999\r
+\r
+DATA 0,1\r
+DATA 1,2\r
+DATA 2,3\r
+DATA 3,0\r
+\r
+DATA 4,5\r
+DATA 5,6\r
+DATA 6,7\r
+DATA 7,4\r
+\r
+DATA 0,8\r
+DATA 1,9\r
+DATA 4,10\r
+DATA 5,11\r
+\r
+DATA 0,12\r
+DATA 4,13\r
+DATA 12,8\r
+DATA 13,10\r
+\r
+DATA 8,9\r
+DATA 10,11\r
+DATA 8,10\r
+DATA 9,11\r
+\r
+DATA 12,13\r
+DATA 12,3\r
+DATA 13,7\r
+DATA 3,7\r
+DATA 1,5\r
+DATA 2,6\r
+\r
+DATA 14,15\r
+DATA 15,16\r
+DATA 16,17\r
+DATA 17,18\r
+DATA 18,19\r
+DATA 19,20\r
+DATA 20,21\r
+DATA 21,14\r
+\r
+DATA 22,23\r
+DATA 23,24\r
+DATA 24,25\r
+DATA 25,26\r
+DATA 26,27\r
+DATA 27,28\r
+DATA 28,29\r
+DATA 29,22\r
+\r
+DATA 30,31\r
+DATA 31,32\r
+DATA 32,33\r
+DATA 33,34\r
+DATA 34,35\r
+DATA 35,36\r
+DATA 36,37\r
+DATA 37,30\r
+\r
+DATA 38,39\r
+DATA 39,40\r
+DATA 40,41\r
+DATA 41,42\r
+DATA 42,43\r
+DATA 43,44\r
+DATA 44,45\r
+DATA 45,38\r
+\r
+DATA 46,47\r
+DATA 47,48\r
+DATA 48,49\r
+DATA 49,46\r
+\r
+DATA 50,51\r
+DATA 51,52\r
+DATA 52,53\r
+DATA 53,50\r
+\r
+DATA 50,46\r
+DATA 51,47\r
+DATA 52,48\r
+DATA 53,49\r
+\r
+DATA 54,55\r
+DATA 55,56\r
+DATA 56,57\r
+DATA 57,54\r
+\r
+DATA 54,58\r
+DATA 55,59\r
+DATA 56,60\r
+DATA 57,61\r
+\r
+DATA 58,59\r
+DATA 59,60\r
+DATA 60,61\r
+DATA 61,58\r
+\r
+DATA 54,3\r
+DATA 55,7\r
+\r
+DATA 999, 999\r
+' BRIDGE\r
+' right handlebars\r
+DATA 100,0,100\r
+DATA 100,50,100\r
+\r
+DATA 50,0,100\r
+DATA 50,50,100\r
+\r
+DATA 0,0,100\r
+DATA 0,50,100\r
+\r
+DATA -50,0,100\r
+DATA -50,50,100\r
+\r
+DATA -100,0,100\r
+DATA -100,50,100\r
+ ' 5\r
+DATA -150,0,100\r
+DATA -150,50,100\r
+\r
+DATA -200,0,100\r
+DATA -200,50,100\r
+\r
+DATA -250,0,100\r
+DATA -250,50,100\r
+\r
+DATA -300,0,100\r
+DATA -300,50,100\r
+\r
+DATA -350,0,100\r
+DATA -350,50,100\r
+ ' 10\r
+\r
+DATA -400,0,100\r
+DATA -400,50,100\r
+\r
+DATA -450,0,100\r
+DATA -450,50,100\r
+\r
+DATA -500,0,100\r
+DATA -500,50,100\r
+\r
+DATA -550,0,100\r
+DATA -550,50,100\r
+\r
+DATA -600,0,100\r
+DATA -600,50,100\r
+\r
+DATA -650,0,100\r
+DATA -650,50,100\r
+\r
+ ' left handlebars\r
+DATA 100,0,-100\r
+DATA 100,50,-100\r
+\r
+DATA 50,0,-100\r
+DATA 50,50,-100\r
+\r
+DATA 0,0,-100\r
+DATA 0,50,-100\r
+\r
+DATA -50,0,-100\r
+DATA -50,50,-100\r
+\r
+DATA -100,0,-100\r
+DATA -100,50,-100\r
+ ' 5\r
+DATA -150,0,-100\r
+DATA -150,50,-100\r
+\r
+DATA -200,0,-100\r
+DATA -200,50,-100\r
+\r
+DATA -250,0,-100\r
+DATA -250,50,-100\r
+\r
+DATA -300,0,-100\r
+DATA -300,50,-100\r
+\r
+DATA -350,0,-100\r
+DATA -350,50,-100\r
+ ' 10\r
+\r
+DATA -400,0,-100\r
+DATA -400,50,-100\r
+\r
+DATA -450,0,-100\r
+DATA -450,50,-100\r
+\r
+DATA -500,0,-100\r
+DATA -500,50,-100\r
+\r
+DATA -550,0,-100\r
+DATA -550,50,-100\r
+\r
+DATA -600,0,-100\r
+DATA -600,50,-100\r
+\r
+DATA -650,0,-100\r
+DATA -650,50,-100\r
+ ' bottom line\r
+DATA 100,75,-100\r
+DATA -650,75,-100\r
+\r
+DATA 100,75,100\r
+DATA -650,75,100\r
+ ' shore\r
+DATA 75,75,-100\r
+DATA 75,75,100\r
+ 'right\r
+DATA -50,200,-100\r
+DATA -50,200,100\r
+\r
+DATA 75,200,-190\r
+DATA 75,200, 190\r
+ 'left\r
+DATA -525,200,-100\r
+DATA -525,200, 100\r
+\r
+DATA -600,200,-190\r
+DATA -600,200, 190\r
+\r
+'\r
+\r
+DATA 999,999,999\r
+\r
+ 'right handlebars\r
+\r
+DATA 2,3\r
+DATA 4,5\r
+DATA 6,7\r
+DATA 8,9\r
+\r
+DATA 10,11\r
+DATA 12,13\r
+DATA 14,15\r
+DATA 16,17\r
+DATA 18,19\r
+\r
+DATA 20,21\r
+DATA 22,23\r
+DATA 24,25\r
+DATA 26,27\r
+DATA 28,29\r
+\r
+\r
+ 'left handlebars\r
+DATA 34,35\r
+DATA 36,37\r
+DATA 38,39\r
+DATA 40,41\r
+\r
+DATA 42,43\r
+DATA 44,45\r
+DATA 46,47\r
+DATA 48,49\r
+DATA 50,51\r
+\r
+DATA 52,53\r
+DATA 54,55\r
+DATA 56,57\r
+DATA 58,59\r
+DATA 60,61\r
+\r
+' long features\r
+DATA 0,4\r
+DATA 4,8\r
+DATA 8,12\r
+DATA 12,16\r
+DATA 16,20\r
+DATA 20,24\r
+DATA 24,28\r
+DATA 28,30\r
+\r
+DATA 1,5\r
+DATA 5,9\r
+DATA 9,13\r
+DATA 13,17\r
+DATA 17,21\r
+DATA 21,25\r
+DATA 25,29\r
+DATA 29,31\r
+\r
+DATA 32,36\r
+DATA 36,40\r
+DATA 40,44\r
+DATA 44,48\r
+DATA 48,52\r
+DATA 52,56\r
+DATA 56,60\r
+DATA 60,62\r
+\r
+DATA 33,37\r
+DATA 37,41\r
+DATA 41,45\r
+DATA 45,49\r
+DATA 49,53\r
+DATA 53,57\r
+DATA 57,61\r
+DATA 61,63\r
+\r
+'\r
+\r
+' end\r
+\r
+DATA 1,33\r
+DATA 31,63\r
+\r
+DATA 64,65\r
+DATA 66,67\r
+DATA 64,66\r
+DATA 65,67\r
+\r
+DATA 0,66\r
+DATA 32,64\r
+DATA 30,67\r
+DATA 62,65\r
+ ' shore\r
+DATA 68,69\r
+DATA 70,71\r
+DATA 68,70\r
+DATA 69,71\r
+\r
+DATA 72,70\r
+DATA 72,68\r
+\r
+DATA 73,71\r
+DATA 73,69\r
+ 'left\r
+DATA 74,76\r
+DATA 75,77\r
+DATA 74,75\r
+\r
+DATA 74,65\r
+DATA 76,65\r
+\r
+DATA 75,67\r
+DATA 77,67\r
+\r
+DATA 999, 999\r
+\r
+SUB GetTrackSegmentPoints (startX%, startY%, endX%, endY%)\r
+' Calculates evenly spaced points along a straight line between two coordinates\r
+' Used to create smooth tank track paths\r
+dx = ABS(startX - endX)\r
+dy = ABS(endY - startY)\r
+length = SQR(dx ^ 2 + dy ^ 2) * 1.017142857#\r
+\r
+' Calculate direction vectors\r
+directionX = (startX - endX) / length\r
+directionY = (endY - startY) / length\r
+\r
+currentX = startX%\r
+currentY = startY%\r
+\r
+FOR segment = 1 TO length\r
+ currentX = currentX - directionX\r
+ currentY = currentY + directionY\r
+ trackX(trackSegmentCount) = currentX\r
+ trackY(trackSegmentCount) = currentY\r
+ trackSegmentCount = trackSegmentCount + 1\r
+NEXT segment\r
+\r
+END SUB\r
+\r
+SUB InitializeProgram\r
+' Sets up initial program state and loads geometry\r
+SCREEN 12\r
+CLS\r
+movementSpeed = 0\r
+\r
+yawRotationDeg = 210\r
+pitchRotationDeg = 20\r
+rollRotationDeg = 90\r
+\r
+currentTrackSegmentIndex = 1\r
+tracksXOffset = 0\r
+\r
+previousTankPosX = 0\r
+previousTankPosY = 0\r
+previousTankPosZZ = 0\r
+tankPosX = 0\r
+tankPosY = -300\r
+tankPosZ = 100\r
+currentTrackSegmentIndex = 1\r
+\r
+tankMovementDirection = 1\r
+\r
+PrecomputeTrigTables\r
+LoadInitialGeometry\r
+LoadBridgeGeometry\r
+InitializeTrackSegments\r
+\r
+END SUB\r
+\r
+SUB InitializeTrackSegments\r
+' Sets up predefined track path segments connecting key points on the tank chassis\r
+trackSegmentCount = 1\r
+GetTrackSegmentPoints -70, -10, -80, 0\r
+GetTrackSegmentPoints -80, 0, -80, 20\r
+GetTrackSegmentPoints -80, 20, -70, 30\r
+GetTrackSegmentPoints -70, 30, 60, 30\r
+GetTrackSegmentPoints 60, 30, 70, 20\r
+GetTrackSegmentPoints 70, 20, 70, 0\r
+GetTrackSegmentPoints 70, 0, 60, -10\r
+GetTrackSegmentPoints 60, -10, -70, -10\r
+\r
+END SUB\r
+\r
+SUB LoadBridgeGeometry\r
+' Loads bridge geometry from DATA statements and adjusts indices\r
+bridgeStartLineIndex = totalLines\r
+bridgeStartPointIndex = totalPoints\r
+\r
+ReadNextPoint:\r
+READ worldPointX(totalPoints), worldPointY(totalPoints), worldPointZ(totalPoints)\r
+IF worldPointX(totalPoints) = 999 THEN\r
+ worldPointX(totalPoints) = 0: worldPointY(totalPoints) = 0: worldPointZ(totalPoints) = 0: GOTO FoundEndOfBridgePoints\r
+END IF\r
+totalPoints = totalPoints + 1\r
+GOTO ReadNextPoint\r
+\r
+FoundEndOfBridgePoints:\r
+ReadNextLine:\r
+READ lineStartIndex(totalLines), lineEndIndex(totalLines)\r
+IF lineStartIndex(totalLines) = 999 THEN GOTO EndOfBridgeLines\r
+lineStartIndex(totalLines) = lineStartIndex(totalLines) + bridgeStartPointIndex\r
+lineEndIndex(totalLines) = lineEndIndex(totalLines) + bridgeStartPointIndex\r
+totalLines = totalLines + 1\r
+GOTO ReadNextLine\r
+\r
+EndOfBridgeLines:\r
+\r
+END SUB\r
+\r
+SUB LoadInitialGeometry\r
+' Loads all 3D model vertices and connection lines from DATA statements\r
+FOR pointIndex = 0 TO 10000\r
+ READ worldPointX(pointIndex), worldPointY(pointIndex), worldPointZ(pointIndex)\r
+ IF worldPointX(pointIndex) = 999 THEN\r
+ worldPointX(pointIndex) = 0: worldPointY(pointIndex) = 0: worldPointZ(pointIndex) = 0: GOTO FoundEndOfPoints\r
+ END IF\r
+NEXT\r
+\r
+FoundEndOfPoints:\r
+totalPoints = pointIndex\r
+\r
+FOR lineIndex = 0 TO 10000\r
+ READ lineStartIndex(lineIndex), lineEndIndex(lineIndex)\r
+ IF lineStartIndex(lineIndex) = 999 THEN GOTO FoundEndOfLines\r
+NEXT\r
+\r
+FoundEndOfLines:\r
+totalLines = lineIndex\r
+\r
+' Save starting indices for different object types\r
+trackStartPointIndex = totalPoints\r
+trackStartLineIndex = totalLines\r
+\r
+' Initialize space for track segments\r
+FOR segmentIndex = 1 TO 48\r
+ lineStartIndex(totalLines) = totalPoints\r
+ totalPoints = totalPoints + 1\r
+ lineEndIndex(totalLines) = totalPoints\r
+ totalPoints = totalPoints + 1\r
+ totalLines = totalLines + 1\r
+NEXT segmentIndex\r
+\r
+END SUB\r
+\r
+SUB PrecomputeTrigTables\r
+' Precomputes sine and cosine values for 0-360 degrees\r
+' Values are scaled by 1024 to maintain precision with integer math\r
+FOR angleRadians! = 0 TO 359 / 57.29577950999997# STEP 1 / 57.29577950999997#\r
+ precomputedCosine&(angle) = INT(.5 + COS(angleRadians!) * 1024)\r
+ precomputedSine&(angle) = INT(.5 + SIN(angleRadians!) * 1024)\r
+ angle = angle + 1\r
+NEXT\r
+CLS\r
+END SUB\r
+\r
+SUB RenderSceneLoop\r
+' Main rendering loop with camera controls and 3D projection\r
+DO\r
+ SOUND 0, .5\r
+\r
+ ' Update animated tank tracks\r
+ UpdateTankTracks\r
+\r
+ ' Apply rotation deltas to camera angles\r
+ yawRotationDeg = yawRotationDeg + rotationDeltaYaw\r
+ pitchRotationDeg = pitchRotationDeg + rotationDeltaPitch\r
+ rollRotationDeg = rollRotationDeg + rotationDeltaRoll\r
+\r
+ ' Keep angles within 0-360 degree range\r
+ IF yawRotationDeg <= 0 THEN yawRotationDeg = yawRotationDeg + 360\r
+ IF pitchRotationDeg <= 0 THEN pitchRotationDeg = pitchRotationDeg + 360\r
+ IF rollRotationDeg <= 0 THEN rollRotationDeg = rollRotationDeg + 360\r
+\r
+ IF yawRotationDeg >= 360 THEN yawRotationDeg = yawRotationDeg - 360\r
+ IF pitchRotationDeg >= 360 THEN pitchRotationDeg = pitchRotationDeg - 360\r
+ IF rollRotationDeg >= 360 THEN rollRotationDeg = rollRotationDeg - 360\r
+\r
+ ' Lookup precomputed trig values\r
+ cosYaw& = precomputedCosine&(yawRotationDeg)\r
+ sinYaw& = precomputedSine&(yawRotationDeg)\r
+ cosPitch& = precomputedCosine&(pitchRotationDeg)\r
+ sinPitch& = precomputedSine&(pitchRotationDeg)\r
+ cosRoll& = precomputedCosine&(rollRotationDeg)\r
+ sinRoll& = precomputedSine&(rollRotationDeg)\r
+\r
+ ' Update tank position based on movement speed\r
+ tankPosX = tankPosX - (sinYaw& * movementSpeed / 100)\r
+ tankPosY = tankPosY - (cosYaw& * movementSpeed / 100)\r
+ tankPosZ = tankPosZ - (sinPitch& * movementSpeed / 100)\r
+\r
+ ' Transform all points through rotation matrices\r
+ FOR pointIndex = 0 TO totalPoints - 1\r
+ ' Translate point by tank position\r
+ worldX = worldPointX(pointIndex) + tankPosX\r
+ worldY = worldPointY(pointIndex) + tankPosZ\r
+ worldZ = worldPointZ(pointIndex) + tankPosY\r
+\r
+ ' Apply Yaw rotation (around Y axis)\r
+ rotatedX = (worldX * cosYaw& - worldZ * sinYaw&) \ 1024\r
+ rotatedZ = (worldX * sinYaw& + worldZ * cosYaw&) \ 1024\r
+\r
+ ' Apply Pitch rotation (around X axis)\r
+ rotatedY = (worldY * cosPitch& - rotatedZ * sinPitch&) \ 1024\r
+ finalZ = (worldY * sinPitch& + rotatedZ * cosPitch&) \ 1024\r
+\r
+ ' Apply Roll rotation (around Z axis)\r
+ screenXCoord = (rotatedY * cosRoll& - rotatedX * sinRoll&) \ 1024\r
+ screenYCoord = (rotatedY * sinRoll& + rotatedX * cosRoll&) \ 1024\r
+\r
+ ' Perspective projection if point is in front of camera\r
+ IF finalZ > 10 THEN\r
+ screenX(pointIndex) = 320 + (screenXCoord / finalZ * 500)\r
+ screenY(pointIndex) = 240 + (screenYCoord / finalZ * 500)\r
+ ELSE\r
+ screenX(pointIndex) = -1\r
+ END IF\r
+ NEXT\r
+\r
+ ' Draw all connected lines\r
+ FOR lineIndex = 0 TO totalLines - 1\r
+ firstPoint = lineStartIndex(lineIndex)\r
+ secondPoint = lineEndIndex(lineIndex)\r
+\r
+ startX = screenX(firstPoint)\r
+ startY = screenY(firstPoint)\r
+ endX = screenX(secondPoint)\r
+ endY = screenY(secondPoint)\r
+\r
+ ' Erase previous frame's line if it was visible\r
+ IF prevStartX(lineIndex) <> -1 AND prevEndX(lineIndex) <> -1 THEN\r
+ LINE (prevStartX(lineIndex), prevStartY(lineIndex))-(prevEndX(lineIndex), prevEndY(lineIndex)), 0\r
+ END IF\r
+\r
+ ' Draw new line if both points are visible\r
+ IF endX <> -1 AND startX <> -1 THEN\r
+ LINE (endX, endY)-(startX, startY), 15\r
+ END IF\r
+\r
+ ' Save current coordinates for next frame\r
+ prevStartX(lineIndex) = endX\r
+ prevStartY(lineIndex) = endY\r
+ prevEndX(lineIndex) = startX\r
+ prevEndY(lineIndex) = startY\r
+ NEXT\r
+\r
+ ' Handle user input\r
+ keyInput$ = INKEY$\r
+ IF keyInput$ <> "" THEN\r
+ SELECT CASE keyInput$\r
+ ' Camera rotation controls\r
+ CASE CHR$(0) + "M" ' Right arrow\r
+ rotationDeltaYaw = rotationDeltaYaw - 1\r
+ CASE CHR$(0) + "K" ' Left arrow\r
+ rotationDeltaYaw = rotationDeltaYaw + 1\r
+ CASE CHR$(0) + "P" ' Down arrow\r
+ rotationDeltaPitch = rotationDeltaPitch + 1\r
+ CASE CHR$(0) + "H" ' Up arrow\r
+ rotationDeltaPitch = rotationDeltaPitch - 1\r
+ CASE "w" ' W key\r
+ rotationDeltaRoll = rotationDeltaRoll - 1\r
+ CASE "z" ' Z key\r
+ rotationDeltaRoll = rotationDeltaRoll + 1\r
+\r
+ ' Movement controls\r
+ CASE "-"\r
+ movementSpeed = movementSpeed - 1\r
+ CASE "+"\r
+ movementSpeed = movementSpeed + 1\r
+ CASE " " ' Spacebar\r
+ rotationDeltaYaw = 0: rotationDeltaPitch = 0: rotationDeltaRoll = 0\r
+ movementSpeed = 0\r
+ CASE CHR$(27) ' Escape key\r
+ SYSTEM\r
+ END SELECT\r
+ END IF\r
+LOOP\r
+END SUB\r
+\r
+SUB UpdateTankTracks\r
+\r
+' Animates tank tracks by cycling through predefined track segments\r
+tracksXOffset = tracksXOffset + tankMovementDirection\r
+currentTrackSegmentIndex = currentTrackSegmentIndex + tankMovementDirection\r
+\r
+' Wrap segment index at boundaries\r
+IF currentTrackSegmentIndex > 15 THEN currentTrackSegmentIndex = 1\r
+IF currentTrackSegmentIndex < 1 THEN currentTrackSegmentIndex = 15\r
+\r
+segmentIndex = currentTrackSegmentIndex\r
+\r
+' Update right-side track positions\r
+FOR pointIndex = trackStartPointIndex TO trackStartPointIndex + 48 STEP 2\r
+ worldPointX(pointIndex) = trackX(segmentIndex) - tracksXOffset\r
+ worldPointY(pointIndex) = trackY(segmentIndex)\r
+ worldPointZ(pointIndex) = 50\r
+ worldPointX(pointIndex + 1) = trackX(segmentIndex) - tracksXOffset\r
+ worldPointY(pointIndex + 1) = trackY(segmentIndex)\r
+ worldPointZ(pointIndex + 1) = 30\r
+ segmentIndex = segmentIndex + 15\r
+NEXT\r
+\r
+segmentIndex = currentTrackSegmentIndex\r
+\r
+' Update left-side track positions\r
+FOR pointIndex = trackStartPointIndex + 48 TO trackStartPointIndex + 94 STEP 2\r
+ worldPointX(pointIndex) = trackX(segmentIndex) - tracksXOffset\r
+ worldPointY(pointIndex) = trackY(segmentIndex)\r
+ worldPointZ(pointIndex) = -50\r
+ worldPointX(pointIndex + 1) = trackX(segmentIndex) - tracksXOffset\r
+ worldPointY(pointIndex + 1) = trackY(segmentIndex)\r
+ worldPointZ(pointIndex + 1) = -30\r
+ segmentIndex = segmentIndex + 15\r
+NEXT\r
+\r
+' Move entire tank back and forth when hitting boundaries\r
+FOR pointIndex = 0 TO 84\r
+ worldPointX(pointIndex) = worldPointX(pointIndex) - tankMovementDirection\r
+NEXT\r
+\r
+IF worldPointX(84) > 0 THEN tankMovementDirection = 1\r
+IF worldPointX(83) < -400 THEN tankMovementDirection = -1\r
+\r
+END SUB\r
+\r
--- /dev/null
+' Program renders 3D room with various decorative tiles on the wall and on the floor.\r
+' User can freely fly around and look at the room from different angles.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' ?, Initial version\r
+' 2024, Improved program readability\r
+'\r
+' Keyboard controls:\r
+' <left>, <right>, <up>, <down> - move around\r
+' 2, 6, 4, 8 - look around (number pad)\r
+' <SPACE> - speed down\r
+' q - quit\r
+' + / - - move up / down\r
+'\r
+\r
+\r
+DECLARE SUB renderSquare2 (x!, y!, z!, s!)\r
+DECLARE SUB renderSquare (x%, y%, z%, s%)\r
+DECLARE SUB renderHexagon (x!, y!, z!, s!)\r
+DECLARE SUB generateCube ()\r
+\r
+DECLARE SUB start ()\r
+DECLARE SUB addSquare (x1%, y1%, z1%)\r
+DECLARE SUB getCornerVertices ()\r
+DECLARE SUB multiplyCoordinates ()\r
+DECLARE SUB calculateSine ()\r
+DIM SHARED xVertex(4000), yVertex(4000), zVertex(4000)\r
+DIM SHARED xCoordinate(4000), yCoordinate(4000), zCoordinate(4000)\r
+\r
+DIM SHARED xOriginal(4000), yOriginal(4000), zOriginal(4000)\r
+DIM SHARED point1Vertex(4000), point2Vertex(4000)\r
+DIM SHARED col(4000)\r
+DIM SHARED vertexCount, edgeCount\r
+DIM SHARED myx, myy, myz, mye, myk\r
+\r
+myx = 0\r
+myy = 0\r
+myz = -1000\r
+\r
+start\r
+\r
+nait3d\r
+\r
+SUB addSquare (x1%, y1%, z1%)\r
+ c = 1\r
+\r
+ ' Define the vertices of a square in 3D space\r
+ xVertex(vertexCount + 1) = -100 + x1\r
+ yVertex(vertexCount + 1) = y1\r
+ zVertex(vertexCount + 1) = -100 + z1\r
+\r
+ xVertex(vertexCount + 2) = 100 + x1\r
+ yVertex(vertexCount + 2) = y1\r
+ zVertex(vertexCount + 2) = -100 + z1\r
+\r
+ xVertex(vertexCount + 3) = 100 + x1\r
+ yVertex(vertexCount + 3) = y1\r
+ zVertex(vertexCount + 3) = 100 + z1\r
+\r
+ xVertex(vertexCount + 4) = -100 + x1\r
+ yVertex(vertexCount + 4) = y1\r
+ zVertex(vertexCount + 4) = 100 + z1\r
+\r
+ ' Define the edges of the square\r
+ point1Vertex(edgeCount + 1) = vertexCount + 1\r
+ point2Vertex(edgeCount + 1) = vertexCount + 2\r
+ col(edgeCount + 1) = c\r
+\r
+ point1Vertex(edgeCount + 2) = vertexCount + 2\r
+ point2Vertex(edgeCount + 2) = vertexCount + 3\r
+ col(edgeCount + 2) = c\r
+\r
+ point1Vertex(edgeCount + 3) = vertexCount + 3\r
+ point2Vertex(edgeCount + 3) = vertexCount + 4\r
+ col(edgeCount + 3) = c\r
+\r
+ point1Vertex(edgeCount + 4) = vertexCount + 4\r
+ point2Vertex(edgeCount + 4) = vertexCount + 1\r
+ col(edgeCount + 4) = c\r
+\r
+ ' Update the counters for the next square\r
+ vertexCount = vertexCount + 4\r
+ edgeCount = edgeCount + 4\r
+\r
+END SUB\r
+\r
+SUB getCornerVertices\r
+\r
+ ' Define the vertices of a square in 3D space\r
+ xVertex(vertexCount + 1) = -150\r
+ yVertex(vertexCount + 1) = -125\r
+ zVertex(vertexCount + 1) = -200\r
+\r
+ xVertex(vertexCount + 2) = 150\r
+ yVertex(vertexCount + 2) = -125\r
+ zVertex(vertexCount + 2) = -200\r
+\r
+ xVertex(vertexCount + 3) = 150\r
+ yVertex(vertexCount + 3) = 125\r
+ zVertex(vertexCount + 3) = -200\r
+\r
+ xVertex(vertexCount + 4) = -150\r
+ yVertex(vertexCount + 4) = 125\r
+ zVertex(vertexCount + 4) = -200\r
+\r
+ ' Define the edges of the square\r
+ point1Vertex(edgeCount + 1) = vertexCount + 1\r
+ point2Vertex(edgeCount + 1) = vertexCount + 2\r
+\r
+ point1Vertex(edgeCount + 2) = vertexCount + 2\r
+ point2Vertex(edgeCount + 2) = vertexCount + 3\r
+\r
+ point1Vertex(edgeCount + 3) = vertexCount + 3\r
+ point2Vertex(edgeCount + 3) = vertexCount + 4\r
+\r
+ point1Vertex(edgeCount + 4) = vertexCount + 4\r
+ point2Vertex(edgeCount + 4) = vertexCount + 1\r
+\r
+ ' Define the vertices of another square in 3D space\r
+ xVertex(vertexCount + 5) = -150\r
+ yVertex(vertexCount + 5) = -125\r
+ zVertex(vertexCount + 5) = 200\r
+\r
+ xVertex(vertexCount + 6) = 150\r
+ yVertex(vertexCount + 6) = -125\r
+ zVertex(vertexCount + 6) = 200\r
+\r
+ xVertex(vertexCount + 7) = 150\r
+ yVertex(vertexCount + 7) = 125\r
+ zVertex(vertexCount + 7) = 200\r
+\r
+ xVertex(vertexCount + 8) = -150\r
+ yVertex(vertexCount + 8) = 125\r
+ zVertex(vertexCount + 8) = 200\r
+\r
+ ' Define the edges of the second square\r
+ point1Vertex(edgeCount + 5) = vertexCount + 5\r
+ point2Vertex(edgeCount + 5) = vertexCount + 6\r
+\r
+ point1Vertex(edgeCount + 6) = vertexCount + 6\r
+ point2Vertex(edgeCount + 6) = vertexCount + 7\r
+\r
+ point1Vertex(edgeCount + 7) = vertexCount + 7\r
+ point2Vertex(edgeCount + 7) = vertexCount + 8\r
+\r
+ point1Vertex(edgeCount + 8) = vertexCount + 8\r
+ point2Vertex(edgeCount + 8) = vertexCount + 5\r
+\r
+ ' Define the edges connecting the two squares into cube\r
+ point1Vertex(edgeCount + 9) = vertexCount + 5\r
+ point2Vertex(edgeCount + 9) = vertexCount + 1\r
+\r
+ point1Vertex(edgeCount + 10) = vertexCount + 6\r
+ point2Vertex(edgeCount + 10) = vertexCount + 2\r
+\r
+ point1Vertex(edgeCount + 11) = vertexCount + 7\r
+ point2Vertex(edgeCount + 11) = vertexCount + 3\r
+\r
+ point1Vertex(edgeCount + 12) = vertexCount + 8\r
+ point2Vertex(edgeCount + 12) = vertexCount + 4\r
+\r
+ ' Update the counters for the next set of vertices and edges\r
+ vertexCount = vertexCount + 8\r
+ edgeCount = edgeCount + 12\r
+\r
+ ' Define a pyramid in 3D space\r
+ xVertex(vertexCount + 1) = -150\r
+ yVertex(vertexCount + 1) = -125 + 201\r
+ zVertex(vertexCount + 1) = 0\r
+\r
+ xVertex(vertexCount + 2) = -150\r
+ yVertex(vertexCount + 2) = -125 + 201\r
+ zVertex(vertexCount + 2) = 89\r
+\r
+ xVertex(vertexCount + 3) = -150\r
+ yVertex(vertexCount + 3) = -125\r
+ zVertex(vertexCount + 3) = 89\r
+\r
+ xVertex(vertexCount + 4) = -150\r
+ yVertex(vertexCount + 4) = -125\r
+ zVertex(vertexCount + 4) = 0\r
+\r
+ ' Define the edges of the pyramid\r
+ point1Vertex(edgeCount + 1) = vertexCount + 1\r
+ point2Vertex(edgeCount + 1) = vertexCount + 2\r
+\r
+ point1Vertex(edgeCount + 2) = vertexCount + 2\r
+ point2Vertex(edgeCount + 2) = vertexCount + 3\r
+\r
+ point1Vertex(edgeCount + 3) = vertexCount + 3\r
+ point2Vertex(edgeCount + 3) = vertexCount + 4\r
+\r
+ point1Vertex(edgeCount + 4) = vertexCount + 4\r
+ point2Vertex(edgeCount + 4) = vertexCount + 1\r
+\r
+ ' Update the counters for the next set of vertices and edges\r
+ vertexCount = vertexCount + 4\r
+ edgeCount = edgeCount + 4\r
+\r
+porand\r
+\r
+END SUB\r
+\r
+SUB renderHexagon (x, y, z, s)\r
+\r
+b = 0\r
+f = .3925\r
+' Calculate the vertices of a hexagon in 3D space\r
+FOR a = 0 + f TO 6 + f STEP 6.28 / 8\r
+ x1 = SIN(a) * s\r
+ y1 = COS(a) * s\r
+ b = b + 1\r
+\r
+ xVertex(vertexCount + b) = x + x1\r
+ yVertex(vertexCount + b) = y\r
+ zVertex(vertexCount + b) = z + y1\r
+\r
+NEXT a\r
+\r
+' Define the edges of the hexagon\r
+point1Vertex(edgeCount + 1) = vertexCount + 1\r
+point2Vertex(edgeCount + 1) = vertexCount + 2\r
+col(edgeCount + 1) = 12\r
+\r
+point1Vertex(edgeCount + 2) = vertexCount + 2\r
+point2Vertex(edgeCount + 2) = vertexCount + 3\r
+col(edgeCount + 2) = 12\r
+\r
+point1Vertex(edgeCount + 3) = vertexCount + 3\r
+point2Vertex(edgeCount + 3) = vertexCount + 4\r
+col(edgeCount + 3) = 12\r
+\r
+point1Vertex(edgeCount + 4) = vertexCount + 4\r
+point2Vertex(edgeCount + 4) = vertexCount + 5\r
+col(edgeCount + 4) = 12\r
+\r
+point1Vertex(edgeCount + 5) = vertexCount + 5\r
+point2Vertex(edgeCount + 5) = vertexCount + 6\r
+col(edgeCount + 5) = 12\r
+\r
+point1Vertex(edgeCount + 6) = vertexCount + 6\r
+point2Vertex(edgeCount + 6) = vertexCount + 7\r
+col(edgeCount + 6) = 12\r
+\r
+point1Vertex(edgeCount + 7) = vertexCount + 7\r
+point2Vertex(edgeCount + 7) = vertexCount + 8\r
+col(edgeCount + 7) = 12\r
+\r
+point1Vertex(edgeCount + 8) = vertexCount + 8\r
+point2Vertex(edgeCount + 8) = vertexCount + 1\r
+col(edgeCount + 8) = 12\r
+\r
+' Update the counters for the next set of vertices and edges\r
+vertexCount = vertexCount + b\r
+edgeCount = edgeCount + 8\r
+\r
+END SUB\r
+\r
+SUB nait3d\r
+\r
+ ' Main loop to render the 3D scene\r
+1\r
+\r
+ ' Update the position based on rotation\r
+ myx = myx + SIN(deg1) * mye\r
+ myz = myz + COS(deg1) * mye\r
+\r
+ myx = myx + COS(deg1) * myk\r
+ myz = myz - SIN(deg1) * myk\r
+\r
+ ' Update the rotation angles\r
+ deg1 = deg1 + d1\r
+ Deg2 = Deg2 + d2\r
+\r
+ ' Calculate the rotation matrices\r
+ C1 = COS(deg1): S1 = SIN(deg1)\r
+ C2 = COS(Deg2): S2 = SIN(Deg2)\r
+\r
+ ' Apply the rotation to each vertex\r
+ FOR a = 1 TO vertexCount\r
+ xo = xVertex(a) - myx\r
+ yo = -yVertex(a) - myy\r
+ zo = zVertex(a) - myz\r
+\r
+ x1 = (xo * C1 - zo * S1)\r
+ z1 = (xo * S1 + zo * C1)\r
+\r
+ y1 = (yo * C2 - z1 * S2)\r
+ z2 = (yo * S2 + z1 * C2)\r
+\r
+ ' Project the vertex onto the 2D screen\r
+ xOriginal(a) = xCoordinate(a)\r
+ yOriginal(a) = yCoordinate(a)\r
+ IF z2 < 20 THEN\r
+ xCoordinate(a) = -1\r
+ ELSE\r
+ xCoordinate(a) = 320 + (x1 / z2 * 500)\r
+ yCoordinate(a) = 240 + (y1 / z2 * 500)\r
+ END IF\r
+ NEXT\r
+\r
+ ' Draw the edges of each shape\r
+ FOR a = 1 TO edgeCount\r
+ p1 = point1Vertex(a)\r
+ p2 = point2Vertex(a)\r
+ IF xOriginal(p1) = -1 OR xOriginal(p2) = -1 THEN\r
+ ' Skip drawing if the vertex is off-screen\r
+ ELSE\r
+ ' erase edge on old coordinates\r
+ LINE (xOriginal(p1), yOriginal(p1))-(xOriginal(p2), yOriginal(p2)), 0\r
+ END IF\r
+\r
+ IF xCoordinate(p1) = -1 OR xCoordinate(p2) = -1 THEN\r
+ ' Skip drawing if the vertex is off-screen\r
+ ELSE\r
+ ' draw edge on new coordinates\r
+ LINE (xCoordinate(p1), yCoordinate(p1))-(xCoordinate(p2), yCoordinate(p2)), col(a)\r
+ END IF\r
+ NEXT\r
+\r
+ ' Handle user input\r
+ K$ = INKEY$\r
+ IF K$ <> "" THEN\r
+\r
+ SELECT CASE K$\r
+\r
+ CASE CHR$(0) + "P"\r
+ mye = mye - 3\r
+\r
+ CASE CHR$(0) + "H"\r
+ mye = mye + 3\r
+\r
+ CASE CHR$(0) + "M"\r
+ myk = myk + 3\r
+\r
+ CASE CHR$(0) + "K"\r
+ myk = myk - 3\r
+\r
+ CASE "+"\r
+ myy = myy + 3\r
+\r
+ CASE "-"\r
+ myy = myy - 3\r
+\r
+ CASE "6"\r
+ d1 = d1 + .01\r
+\r
+ CASE "4"\r
+ d1 = d1 - .01\r
+\r
+ CASE "8"\r
+ d2 = d2 - .01\r
+\r
+ CASE "2"\r
+ d2 = d2 + .01\r
+\r
+ CASE " "\r
+ d1 = d1 / 2\r
+ d2 = d2 / 2\r
+ d3 = d3 / 2\r
+ mye = mye / 2\r
+ myk = myk / 2\r
+\r
+ CASE "q"\r
+ SYSTEM\r
+\r
+ CASE CHR$(27)\r
+ SYSTEM\r
+ END SELECT\r
+ END IF\r
+\r
+ ' Continue the main loop\r
+ GOTO 1\r
+END SUB\r
+\r
+SUB porand\r
+\r
+ ' Generate a grid of shapes in 3D space\r
+ FOR x = -100 TO 0 STEP 12.067 + .3\r
+ FOR z = -100 TO 0 STEP 12.067 + .3\r
+ renderHexagon x, -125, z, 6.53\r
+ renderSquare x + 6.033 + .15, -125, z + 6.033 + .15, 3.111 + .3\r
+ NEXT z\r
+ NEXT x\r
+\r
+ ' Generate another grid of shapes in 3D space\r
+ FOR y = -100 TO 0 STEP 20.3\r
+ FOR x = -100 TO 0 STEP 20.3\r
+ renderSquare2 x, y, 200, 10\r
+ NEXT x\r
+ NEXT y\r
+\r
+END SUB\r
+\r
+SUB renderSquare (x%, y%, z%, s%)\r
+\r
+ ' Define the vertices of a square in 3D space\r
+ xVertex(vertexCount + 1) = x%\r
+ yVertex(vertexCount + 1) = y%\r
+ zVertex(vertexCount + 1) = z% + s%\r
+\r
+ xVertex(vertexCount + 2) = x% + s%\r
+ yVertex(vertexCount + 2) = y%\r
+ zVertex(vertexCount + 2) = z%\r
+\r
+ xVertex(vertexCount + 3) = x%\r
+ yVertex(vertexCount + 3) = y%\r
+ zVertex(vertexCount + 3) = z% - s%\r
+\r
+ xVertex(vertexCount + 4) = x% - s%\r
+ yVertex(vertexCount + 4) = y%\r
+ zVertex(vertexCount + 4) = z%\r
+\r
+ ' Define the edges of the square\r
+ point1Vertex(edgeCount + 1) = vertexCount + 1\r
+ point2Vertex(edgeCount + 1) = vertexCount + 2\r
+ col(edgeCount + 1) = 10\r
+\r
+ point1Vertex(edgeCount + 2) = vertexCount + 2\r
+ point2Vertex(edgeCount + 2) = vertexCount + 3\r
+ col(edgeCount + 2) = 10\r
+\r
+ point1Vertex(edgeCount + 3) = vertexCount + 3\r
+ point2Vertex(edgeCount + 3) = vertexCount + 4\r
+ col(edgeCount + 3) = 10\r
+\r
+ point1Vertex(edgeCount + 4) = vertexCount + 4\r
+ point2Vertex(edgeCount + 4) = vertexCount + 1\r
+ col(edgeCount + 4) = 10\r
+\r
+ ' Update the counters for the next square\r
+ vertexCount = vertexCount + 4\r
+ edgeCount = edgeCount + 4\r
+\r
+END SUB\r
+\r
+SUB renderSquare2 (x, y, z, s)\r
+\r
+ ' Define the vertices of a square in 3D space\r
+ xVertex(vertexCount + 1) = x - s\r
+ yVertex(vertexCount + 1) = y - s\r
+ zVertex(vertexCount + 1) = z\r
+\r
+ xVertex(vertexCount + 2) = x + s\r
+ yVertex(vertexCount + 2) = y - s\r
+ zVertex(vertexCount + 2) = z\r
+\r
+ xVertex(vertexCount + 3) = x + s\r
+ yVertex(vertexCount + 3) = y + s\r
+ zVertex(vertexCount + 3) = z\r
+\r
+ xVertex(vertexCount + 4) = x - s\r
+ yVertex(vertexCount + 4) = y + s\r
+ zVertex(vertexCount + 4) = z\r
+\r
+ ' Define the edges of the square\r
+ point1Vertex(edgeCount + 1) = vertexCount + 1\r
+ point2Vertex(edgeCount + 1) = vertexCount + 2\r
+ col(edgeCount + 1) = 14\r
+\r
+ point1Vertex(edgeCount + 2) = vertexCount + 2\r
+ point2Vertex(edgeCount + 2) = vertexCount + 3\r
+ col(edgeCount + 2) = 14\r
+\r
+ point1Vertex(edgeCount + 3) = vertexCount + 3\r
+ point2Vertex(edgeCount + 3) = vertexCount + 4\r
+ col(edgeCount + 3) = 14\r
+\r
+ point1Vertex(edgeCount + 4) = vertexCount + 4\r
+ point2Vertex(edgeCount + 4) = vertexCount + 1\r
+ col(edgeCount + 4) = 14\r
+\r
+ ' Update the counters for the next square\r
+ vertexCount = vertexCount + 4\r
+ edgeCount = edgeCount + 4\r
+\r
+END SUB\r
+\r
+SUB start\r
+\r
+ ' Initialize the screen and clear it\r
+ SCREEN 12\r
+ CLS\r
+\r
+ ' Set the initial color of all shapes\r
+ FOR a = 1 TO 4000\r
+ col(a) = 15\r
+ NEXT a\r
+\r
+ ' Initialize counters for vertices and edges\r
+ vertexCount = 0\r
+ edgeCount = 0\r
+\r
+ ' Generate the initial set of shapes\r
+ getCornerVertices\r
+\r
+END SUB\r
--- /dev/null
+# a\r
+p 1 0\r
+p 0 1\r
+p 2 1\r
+p 0 2\r
+p 2 2\r
+l 0 1\r
+l 0 2\r
+l 1 2\r
+l 1 3\r
+l 2 4\r
+# b\r
+p 0 0\r
+p 2 0\r
+p 0 1\r
+p 0 2\r
+p 2 2\r
+l 0 1\r
+l 0 3\r
+l 1 2\r
+l 3 4\r
+l 4 2\r
+# c\r
+p 2 0\r
+p 1 0\r
+p 0 1\r
+p 1 2\r
+p 2 2\r
+l 0 1\r
+l 1 2\r
+l 2 3\r
+l 3 4\r
+# d\r
+p 0 0\r
+p 1 0\r
+p 2 1\r
+p 1 2\r
+p 0 2\r
+l 0 1\r
+l 1 2\r
+l 2 3\r
+l 3 4\r
+l 4 0\r
+# e\r
+p 0 0\r
+p 2 0\r
+p 0 1\r
+p 2 1\r
+p 0 2\r
+p 2 2\r
+l 0 1\r
+l 2 3\r
+l 4 5\r
+l 0 4\r
+# f\r
+p 0 0\r
+p 2 0\r
+p 0 1\r
+p 2 1\r
+p 0 2\r
+l 0 1\r
+l 2 3\r
+l 0 4\r
+# g\r
+p 2 0\r
+p 1 0\r
+p 0 1\r
+p 1 2\r
+p 2 2\r
+p 2 1\r
+p 1 1\r
+l 0 1\r
+l 1 2\r
+l 2 3\r
+l 3 4\r
+l 4 5\r
+l 5 6\r
+# h\r
+p 0 0\r
+p 0 2\r
+p 2 0\r
+p 2 2\r
+p 0 1\r
+p 2 1\r
+l 0 1\r
+l 2 3\r
+l 4 5\r
+# i\r
+p 1 0\r
+p 1 2\r
+l 0 1\r
+# j\r
+p 0 1\r
+p 0 2\r
+p 1 2\r
+p 1 0\r
+l 0 1\r
+l 1 2\r
+l 2 3\r
+# k\r
+p 0 0\r
+p 0 2\r
+p 2 0\r
+p 2 2\r
+p 0 1\r
+l 0 1\r
+l 2 4\r
+l 4 3\r
+# l\r
+p 0 0\r
+p 0 2\r
+p 2 2\r
+l 0 1\r
+l 1 2\r
+# m\r
+p 0 2\r
+p 0 0\r
+p 1 1\r
+p 2 0\r
+p 2 2\r
+l 0 1\r
+l 1 2\r
+l 2 3\r
+l 3 4\r
+# n\r
+p 0 2\r
+p 0 0\r
+p 2 2\r
+p 2 0\r
+l 0 1\r
+l 1 2\r
+l 2 3\r
+# o\r
+p 0 0\r
+p 2 0\r
+p 2 2\r
+p 0 2\r
+l 0 1\r
+l 1 2\r
+l 2 3\r
+l 3 0\r
+# p\r
+p 0 0\r
+p 2 0\r
+p 2 1\r
+p 0 1\r
+p 0 2\r
+l 0 1\r
+l 1 2\r
+l 2 3\r
+l 0 4\r
+# q\r
+p 0 0\r
+p 2 0\r
+p 2 2\r
+p 0 2\r
+p 1 1\r
+l 0 1\r
+l 1 2\r
+l 2 3\r
+l 3 0\r
+l 2 4\r
+# r\r
+p 0 0\r
+p 2 0\r
+p 2 1\r
+p 0 1\r
+p 0 2\r
+p 2 2\r
+l 0 1\r
+l 1 2\r
+l 2 3\r
+l 0 4\r
+l 5 3\r
+# s\r
+p 2 0\r
+p 0 0\r
+p 0 1\r
+p 2 1\r
+p 2 2\r
+p 0 2\r
+l 0 1\r
+l 1 2\r
+l 2 3\r
+l 3 4\r
+l 4 5\r
+# t\r
+p 0 0\r
+p 2 0\r
+p 1 0\r
+p 1 2\r
+l 0 1\r
+l 2 3\r
+# u\r
+p 0 0\r
+p 0 2\r
+p 2 2\r
+p 2 0\r
+l 0 1\r
+l 1 2\r
+l 2 3\r
+# v\r
+p 0 0\r
+p 1 2\r
+p 2 0\r
+l 0 1\r
+l 1 2\r
+# x\r
+p 0 0\r
+p 2 2\r
+p 2 0\r
+p 0 2\r
+l 0 1\r
+l 2 3\r
+# y\r
+p 0 0\r
+p 2 0\r
+p 1 1\r
+p 1 2\r
+l 0 2\r
+l 1 2\r
+l 2 3\r
+# z\r
+p 0 0\r
+p 2 0\r
+p 0 2\r
+p 2 2\r
+l 0 1\r
+l 1 2\r
+l 2 3
\ No newline at end of file
--- /dev/null
+#+TITLE: Miscellaneous 3D graphics demos
+#+LANGUAGE: en
+#+LATEX_HEADER: \usepackage[margin=1.0in]{geometry}
+#+LATEX_HEADER: \usepackage{parskip}
+#+LATEX_HEADER: \usepackage[none]{hyphenat}
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+ .flex-center {
+ display: flex; /* activate flexbox */
+ justify-content: center; /* horizontally center anything inside */
+ }
+
+ .flex-center video {
+ width: min(90%, 1000px); /* whichever is smaller wins */
+ height: auto; /* preserve aspect ratio */
+ }
+
+ .responsive-img {
+ width: min(100%, 1000px);
+ height: auto;
+ }
+</style>
+#+end_export
+
+* Rotating exclamation mark
+
+Wireframe 3D model of a rotating exclamation mark.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="!.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:!.bas][Source code]]
+
+* 3D bouncing ball
+
+This QBasic program creates a visually engaging 3D animation of a
+point-cloud ball bouncing around the screen. The program is an example
+of early computer graphics techniques.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="3D%20ball.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:3D%20ball.bas][Source code]]
+
+* 3D text in a room
+
+Wireframe 3D text hanging in a wireframe 3D room. User can look and
+fly around in all directions.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="3D text.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:3D%20text.bas][Source code]]
+
+* 3D bouncing cubes on grid floor
+
+3D wireframe cubes bouncing on a grid floor, creating an immersive and
+dynamic visual effect.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="Bouncing cubes.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:3D%20GFX/Bouncing%20cubes.bas][Source code]]
+
+* Matrix math for rotation in 3D space
+
+Instead of combining simple 2D rotors, pixels in this 3D space are
+rotated by using matrix multiplications.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="Matrix math.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:Matrix%20math.bas][Source code]]
+
+* Maze explorer
+
+The Evolving 3D Maze Explorer is a QBasic program that generates and
+navigates through a dynamically evolving 3D maze. This program is an
+excellent example of early 3D graphics programming and provides an
+interactive experience where users can explore a maze that grows and
+changes as they navigate through it.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Maze%20explorer.bas][file:Maze%20explorer.png]]
+
+[[file:Maze explorer.bas][Source code]]
+
+* Tank animation
+
+Animated tank driving through the bridge back and forward. User can
+look and fly around in all directions.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="Tank.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:Tank.bas][Source code]]
+
+* Tiled room
+
+Room with some tiles on the wall and on the floor. User can freely fly
+around.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="Tiled room.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:Tiled%20room.bas][Source code]]
--- /dev/null
+DECLARE SUB InitializeProgram ()\r
+DECLARE SUB GenerateLandscape ()\r
+DECLARE SUB DisplayTopDownLandscape ()\r
+DECLARE SUB DisplayFrame ()\r
+DECLARE FUNCTION getcol! (r!, g!, b!)\r
+DECLARE SUB FillSquareArea (x1%, y1%, x2%, y2%, c%, h%)\r
+DECLARE SUB CreateTower (towerX%, towerY%)\r
+DECLARE SUB SetupPalette ()\r
+DECLARE SUB DrawLineFromPlayer (x%, y%, xl%)\r
+' Realtime 3D rendering with ray casting engine.\r
+\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+\r
+' Changelog:\r
+' 2003.03, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+' 3D engine automatically adjusts quality to keep constant framerate at 10 fps.\r
+' When framerate is lower than 10 fps, quality will be decreased to speed up rendering.\r
+\r
+' At least Intel Pentium 200 MHz in DOS mode is required to run this program smoothly.\r
+\r
+' keys to use:\r
+' Arrow keys - move around\r
+' 4, 6 - turn left, right\r
+' 8, 2 - look up, down\r
+' Enter - Toggle full quality\r
+' Space - jump up (fly)\r
+' ESC - exit program\r
+\r
+DEFINT A-Y\r
+\r
+DIM SHARED landh(0 TO 180, 0 TO 180)\r
+DIM SHARED landc(0 TO 180, 0 TO 180)\r
+\r
+DIM SHARED zmyx, zmyy, zmyz\r
+DIM SHARED myx, myy, myz\r
+DIM SHARED zmyan, myan2\r
+DIM SHARED ste, stem, dist\r
+DIM SHARED tim$, frm, frml\r
+\r
+frmrate = 10 ' Desired framerate.\r
+ ' Lower framerate, better quality\r
+\r
+InitializeProgram\r
+GenerateLandscape\r
+\r
+DisplayTopDownLandscape\r
+a$ = INPUT$(1)\r
+1\r
+LOCATE 1, 35\r
+PRINT frml\r
+\r
+' Increment the frame counter\r
+frm = frm + 1\r
+\r
+' Check if a new second has passed\r
+IF tim$ <> TIME$ THEN\r
+ ' Update the time\r
+ tim$ = TIME$\r
+\r
+ ' Adjust the step size based on the current frame rate\r
+ IF frm > frmrate THEN\r
+ ste = ste - 1\r
+ ELSE\r
+ ste = ste + 1\r
+ END IF\r
+\r
+ ' Ensure the step size is within bounds\r
+ IF ste < 1 THEN\r
+ ste = 1\r
+ END IF\r
+\r
+ ' Calculate the previous step size\r
+ stem = ste - 1\r
+\r
+ ' Update the frame rate and reset the frame counter\r
+ frml = frm\r
+ frm = 0\r
+END IF\r
+\r
+' Check for user input\r
+a$ = INKEY$\r
+IF a$ <> "" THEN\r
+ SELECT CASE a$\r
+ CASE "4"\r
+ ' Turn left\r
+ zmyan = zmyan + .1\r
+ CASE "6"\r
+ ' Turn right\r
+ zmyan = zmyan - .1\r
+ CASE "8"\r
+ ' Look up\r
+ myan2 = myan2 + 5\r
+ CASE "2"\r
+ ' Look down\r
+ myan2 = myan2 - 5\r
+ CASE CHR$(0) + "H"\r
+ ' Move forward\r
+ zmyx = SIN(zmyan) * 3 + zmyx\r
+ zmyy = COS(zmyan) * 3 + zmyy\r
+ CASE CHR$(0) + "P"\r
+ ' Move backward\r
+ zmyx = -SIN(zmyan) * 3 + zmyx\r
+ zmyy = -COS(zmyan) * 3 + zmyy\r
+ CASE CHR$(0) + "K"\r
+ ' Move left\r
+ zmyx = COS(zmyan) * 3 + zmyx\r
+ zmyy = -SIN(zmyan) * 3 + zmyy\r
+ CASE CHR$(0) + "M"\r
+ ' Move right\r
+ zmyx = -COS(zmyan) * 3 + zmyx\r
+ zmyy = SIN(zmyan) * 3 + zmyy\r
+ CASE " "\r
+ ' Jump up (fly)\r
+ zmyzs = 2\r
+ CASE CHR$(13)\r
+ ' Toggle full quality\r
+ ste = 1\r
+ CASE CHR$(27)\r
+ ' Exit the program\r
+ SYSTEM\r
+ END SELECT\r
+END IF\r
+\r
+' Ensure the player stays within bounds\r
+IF zmyx > 170 THEN\r
+ zmyx = 170\r
+END IF\r
+IF zmyy > 170 THEN\r
+ zmyy = 170\r
+END IF\r
+IF zmyx < 10 THEN\r
+ zmyx = 10\r
+END IF\r
+IF zmyy < 10 THEN\r
+ zmyy = 10\r
+END IF\r
+\r
+' Handle jumping\r
+zmyz = zmyz + zmyzs\r
+zmyzs = zmyzs - .1\r
+\r
+' Ensure the player does not go below the ground\r
+IF zmyz < landh(myx, myy) + 10 THEN\r
+ zmyz = landh(myx, myy) + 10\r
+ ' Adjust jump speed\r
+ zmyzs = (zmyzs / 2) + .2\r
+END IF\r
+\r
+' Update player position\r
+myz = zmyz\r
+myy = zmyy\r
+myx = zmyx\r
+DisplayFrame\r
+GOTO 1\r
+\r
+SUB CreateTower (towerX%, towerY%)\r
+\r
+' Draw a tower at the specified position\r
+FOR a = 10 TO 0 STEP -1\r
+ ' Fill each level of the tower with color\r
+ FillSquareArea towerX% - a, towerY% - a, towerX% + a, towerY% + a, getcol(100, 0, a * 20), 20 - a\r
+NEXT a\r
+\r
+' Draw the top of the tower\r
+FillSquareArea towerX% - 11, towerY% - 11, towerX% - 9, towerY% - 9, getcol(255, 0, 0), 20\r
+FillSquareArea towerX% + 9, towerY% - 11, towerX% + 11, towerY% - 9, getcol(0, 255, 0), 20\r
+FillSquareArea towerX% - 11, towerY% + 9, towerX% - 9, towerY% + 11, getcol(0, 0, 255), 20\r
+FillSquareArea towerX% + 9, towerY% + 9, towerX% + 11, towerY% + 11, getcol(255, 255, 0), 20\r
+\r
+END SUB\r
+\r
+SUB DisplayFrame\r
+\r
+l = 0\r
+zst = -.0031 * ste\r
+FOR z = .5 TO -.5 STEP zst\r
+ ' Trace a line from the player's perspective\r
+ DrawLineFromPlayer SIN(zmyan + z) * dist + myx, COS(zmyan + z) * dist + myy, l\r
+ l = l + ste\r
+NEXT z\r
+\r
+END SUB\r
+\r
+SUB DisplayTopDownLandscape\r
+\r
+' Draw the landscape from a top-down perspective\r
+FOR z = 0 TO 180\r
+ zs = 1\r
+ IF z > 120 THEN\r
+ ' Adjust the step size for better performance\r
+ zs = .7\r
+ END IF\r
+ IF z > 160 THEN\r
+ ' Further adjust the step size\r
+ zs = .6\r
+ END IF\r
+ FOR zx = 0 TO 180 STEP zs\r
+ y1 = landh(zx, z) - 80\r
+ zx1 = zx - 90\r
+ z1 = 300 - z\r
+ zx2 = zx1 / z1 * 190\r
+ zy2 = y1 / z1 * 190\r
+\r
+ ' Draw a line representing the height of the landscape\r
+ LINE (zx2 + 160, 40 - zy2)-(zx2 + 160, 200), landc(zx, z)\r
+ NEXT zx\r
+NEXT z\r
+\r
+' Display a message to continue\r
+LOCATE 1, 1\r
+PRINT "Press any key to continue..."\r
+\r
+END SUB\r
+\r
+SUB DrawLineFromPlayer (x%, y%, xl%)\r
+\r
+' Trace a line from the player's perspective\r
+IF x < 0 THEN\r
+ ' Calculate the distance to the next point\r
+ zpr = myx / (myx - x)\r
+ x = 0\r
+ y = myy - ((myy - y) * zpr)\r
+END IF\r
+\r
+IF y < 0 THEN\r
+ ' Calculate the distance to the next point\r
+ zpr = myy / (myy - y)\r
+ y = 0\r
+ x = myx - ((myx - x) * zpr)\r
+END IF\r
+\r
+IF x > 180 THEN\r
+ ' Calculate the distance to the next point\r
+ zpr = (180 - myx) / (x - myx)\r
+ x = 180\r
+ y = myy - ((myy - y) * zpr)\r
+END IF\r
+\r
+IF y > 180 THEN\r
+ ' Calculate the distance to the next point\r
+ zpr = (180 - myy) / (y - myy)\r
+ y = 180\r
+ x = myx - ((myx - x) * zpr)\r
+END IF\r
+\r
+' Calculate the distance to the next point\r
+lp% = SQR(ABS(myx - x) ^ 2 + ABS(myy - y) ^ 2)\r
+\r
+' Save the current player position and orientation\r
+imyx% = myx\r
+imyy% = myy\r
+imyz% = myz\r
+xp% = x - imyx%\r
+yp% = y - imyy%\r
+istem% = stem\r
+imyan2% = myan2\r
+\r
+' Draw the line\r
+yo% = 200\r
+FOR a% = 1 TO lp%\r
+ cx% = xp% * a% / lp% + imyx%\r
+ cy% = yp% * a% / lp% + imyy%\r
+ yn% = imyan2% - ((landh(cx%, cy%) - imyz%) / a%) * 300\r
+\r
+ ' Draw the line segment\r
+ IF yn% < yo% THEN\r
+ LINE (xl%, yn%)-(xl% + istem%, yo% - 1), landc(cx%, cy%), BF\r
+ yo% = yn%\r
+ END IF\r
+NEXT a%\r
+\r
+' Draw the final line segment\r
+LINE (xl%, yo% - 1)-(xl% + istem%, 0), 0, BF\r
+\r
+END SUB\r
+\r
+SUB FillSquareArea (x1%, y1%, x2%, y2%, c%, h%)\r
+\r
+' Fill a square area with the specified color and height\r
+FOR y = y1 TO y2\r
+ FOR x = x1 TO x2\r
+ landh(x, y) = h\r
+ landc(x, y) = c\r
+ NEXT x\r
+NEXT y\r
+\r
+END SUB\r
+\r
+SUB GenerateLandscape\r
+\r
+' Create a square landscape\r
+FillSquareArea 0, 0, 180, 180, 15, 0\r
+\r
+' Generate the landscape height and color\r
+FOR y = 0 TO 180\r
+ FOR x = 0 TO 180\r
+ ' Calculate the checkerboard pattern\r
+ x1 = (x \ 10) MOD 2\r
+ y1 = (y \ 10) MOD 2\r
+ c = (x1 + y1) MOD 2\r
+\r
+ IF c = 0 THEN\r
+ ' Set the color to blue\r
+ landc(x, y) = getcol(0, 0, 250)\r
+ ELSE\r
+ ' Set the color to gray\r
+ landc(x, y) = getcol(50, 50, 50)\r
+ END IF\r
+ NEXT x\r
+NEXT y\r
+\r
+' Generate a hill\r
+FOR y = 10 TO 90\r
+ FOR x = 90 TO 170\r
+ ' Calculate the height of the hill\r
+ v = SQR((ABS(50 - y)) ^ 2 + (ABS(130 - x)) ^ 2)\r
+ h = SQR((60 - v) * (60 + v)) - 35\r
+\r
+ ' Ensure the height is positive\r
+ IF h > 0 THEN\r
+ landh(x, y) = h\r
+ END IF\r
+ NEXT x\r
+NEXT y\r
+\r
+' Add towers to the landscape\r
+CreateTower 20, 20\r
+CreateTower 60, 20\r
+CreateTower 40, 60\r
+\r
+' Generate a path\r
+FOR y = 100 TO 150\r
+ FOR x = 0 TO 50\r
+ ' Set the color to a dynamic value\r
+ landc(x, y) = getcol(SIN((x + y) / 2) * 125 + 125, SIN(x / 2) * 125 + 125, SIN(y / 2) * 125 + 125)\r
+ ' Set the height of the path\r
+ landh(x, y) = 50 - x\r
+ NEXT x\r
+NEXT y\r
+\r
+' Generate a spiral path\r
+FOR za = 0 TO 20 STEP .1\r
+ x = SIN(za) * (1 + (za * 2)) + 100\r
+ y = COS(za) * (1 + (za * 2)) + 100\r
+\r
+ ' Set the color of the spiral path\r
+ landc(x, y) = 200\r
+ landc(x + 1, y) = 200\r
+ landc(x, y + 1) = 200\r
+ landc(x + 1, y + 1) = 200\r
+NEXT za\r
+\r
+END SUB\r
+\r
+DEFSNG A-Y\r
+FUNCTION getcol (r, g, b)\r
+IF r < 0 THEN\r
+ ' Ensure the color value is within bounds\r
+ r = 0\r
+END IF\r
+IF g < 0 THEN\r
+ g = 0\r
+END IF\r
+IF b < 0 THEN\r
+ b = 0\r
+END IF\r
+IF r > 255 THEN\r
+ r = 255\r
+END IF\r
+IF g > 255 THEN\r
+ g = 255\r
+END IF\r
+IF b > 255 THEN\r
+ b = 255\r
+END IF\r
+' Calculate the color index\r
+getcol = INT(r / 43) * 36 + INT(g / 43) * 6 + INT(b / 43)\r
+END FUNCTION\r
+\r
+DEFINT A-Y\r
+SUB InitializeProgram\r
+' Set the graphics mode\r
+SCREEN 13\r
+PRINT "please wait..."\r
+\r
+' Initialize the color palette\r
+SetupPalette\r
+\r
+' Initialize player position and orientation\r
+zmyan = 4.14\r
+myan2 = 100\r
+ste = 1\r
+stem = ste - 1\r
+dist = 190\r
+tim$ = TIME$\r
+zmyx = 170\r
+zmyy = 170\r
+zmyz = 20\r
+\r
+END SUB\r
+\r
+SUB SetupPalette\r
+' Initialize the color palette\r
+c = 0\r
+FOR r = 0 TO 5\r
+ FOR g = 0 TO 5\r
+ FOR b = 0 TO 5\r
+ OUT &H3C8, c\r
+ c = c + 1\r
+ OUT &H3C9, r * 12\r
+ OUT &H3C9, g * 12\r
+ OUT &H3C9, b * 12\r
+ NEXT b\r
+ NEXT g\r
+NEXT r\r
+END SUB\r
+\r
--- /dev/null
+' Program to render a 3D point cloud galaxy.
+'
+' This program is free software: released under Creative Commons Zero (CC0) license
+' by Svjatoslav Agejenko.
+' Email: svjatoslav@svjatoslav.eu
+' Homepage: http://www.svjatoslav.eu
+
+' Changelog:
+' 2003, Initial version.
+' 2024, Improved program readability.
+'
+' User can navigate through the galaxy using mouse or keyboard controls.
+'
+' Note: This program requires special Terminate and Stay Resident (TSR) mouse driver
+' to be loaded *before* starting the current QBasic program itself.
+' Here you can read about TSR mouse driver and download needed qbext.com binary:
+' https://www3.svjatoslav.eu/projects/qbasicapps/Miscellaneous/Mouse%20driver/index.html
+'
+' Navigation controls:
+' - Press left and right mouse buttons simultaneously to move in X and Z axis.
+' - Press right mouse button to move in Y axis.
+' - Use keyboard keys 'a', 'd', 'w', 's' to move in X and Z axis.
+' - Press 'q' to quit the program.
+
+DECLARE SUB temp ()
+DECLARE SUB mkGalaxy (x!, y!, z!)
+DECLARE SUB rndInit ()
+DECLARE FUNCTION rn! ()
+DECLARE SUB disp ()
+DECLARE SUB control ()
+DECLARE SUB putByte (addr!, dat!)
+DECLARE SUB putWord (addr!, dat!)
+DECLARE FUNCTION getWord! (addr!)
+DECLARE FUNCTION getByte! (addr!)
+DECLARE SUB start ()
+DECLARE SUB animate ()
+
+DIM SHARED angle1, angle2, angle3
+
+DIM SHARED time
+
+DIM SHARED externalSegment, externalAddress
+
+' Variables for the camera position and movement
+DIM SHARED myX, myY, myZ
+DIM SHARED speedX, speedY, speedZ
+DIM SHARED buttonLeft, buttonRight
+DIM SHARED maxMove
+
+' Variable for zoom level
+DIM SHARED zoom
+
+' Array to store random values
+DIM SHARED randomValue(0 TO 10000)
+DIM SHARED randomPointer
+
+' Arrays to store point coordinates and colors. These points make up galaxy.
+DIM SHARED pointX(1 TO 12000)
+DIM SHARED pointY(1 TO 12000)
+DIM SHARED pointZ(1 TO 12000)
+DIM SHARED pointColor(1 TO 12000)
+DIM SHARED numPoints
+
+' Temporary register array
+DIM SHARED temporaryRegister(0 TO 10)
+
+newLine = 0
+newPage = 0
+
+start
+
+currentX = 0
+currentY = 0
+currentZ = 0
+
+numPoints = 0
+mkGalaxy 0, 0, 0
+1
+
+' Generate a random angle for initial camera position
+variableAngle = INT(RND * 3)
+
+SELECT CASE variableAngle
+CASE 0
+ currentX = RND * 500 - 250
+CASE 1
+ currentY = RND * 100 - 50
+CASE 2
+ currentZ = RND * 500 - 250
+END SELECT
+
+control
+disp
+
+PCOPY 0, 1
+CLS
+GOTO 1
+
+SUB control
+
+' Check for mouse input
+IF getByte(8) <> 0 THEN
+ putByte 8, 0
+ xPosition = getWord(2)
+ putWord 2, 0
+ yPosition = getWord(4)
+ putWord 4, 0
+ button = getWord(6)
+ putWord 6, 0
+
+ ' Reset mouse buttons
+ buttonLeft = 0
+ buttonRight = 0
+
+ ' Handle mouse button states
+ IF button = 1 THEN buttonLeft = 1
+ IF button = 2 THEN buttonRight = 1
+ IF button = 3 THEN buttonLeft = 1: buttonRight = 1
+
+ ' Handle mouse movements
+ IF buttonRight = 1 THEN
+ IF buttonLeft = 1 THEN
+ speedX = speedX + SIN(angle1) * yPosition / 4
+ speedZ = speedZ - COS(angle1) * yPosition / 4
+ GOTO 3
+ END IF
+ speedY = speedY + yPosition / 4
+ 3
+ yPosition = 0
+ END IF
+
+END IF
+
+' Limit the position values to prevent overflow
+IF xPosition < -maxMove THEN xPosition = -maxMove
+IF xPosition > maxMove THEN xPosition = maxMove
+angle1 = angle1 - xPosition / 150
+
+IF yPosition < -maxMove THEN yPosition = -maxMove
+IF yPosition > maxMove THEN yPosition = maxMove
+angle2 = angle2 - yPosition / 150
+
+' Check for keyboard input
+keyInput$ = INKEY$
+
+' Handle keyboard controls
+IF keyInput$ = "a" THEN speedX = speedX - COS(angle1): speedZ = speedZ - SIN(angle1)
+IF keyInput$ = "d" THEN speedX = speedX + COS(angle1): speedZ = speedZ + SIN(angle1)
+IF keyInput$ = "w" THEN speedX = speedX - SIN(angle1): speedZ = speedZ + COS(angle1)
+IF keyInput$ = "s" THEN speedX = speedX + SIN(angle1): speedZ = speedZ - COS(angle1)
+IF keyInput$ = "q" THEN SYSTEM
+
+' Decelerate the movement
+speedX = speedX / 1.1
+speedY = speedY / 1.1
+speedZ = speedZ / 1.1
+
+myX = myX + speedX
+myZ = myZ + speedZ
+myY = myY + speedY
+
+END SUB
+
+SUB disp
+
+' Calculate sine and cosine values for rotation angles
+sinAngle1 = SIN(angle1)
+cosAngle1 = COS(angle1)
+sinAngle2 = SIN(angle2)
+cosAngle2 = COS(angle2)
+
+' Loop through all points to calculate and display their positions
+FOR pointIndex = 1 TO numPoints
+
+ ' Calculate the distance from the camera
+ xCoordinate = pointX(pointIndex) - myX
+ yCoordinate = pointY(pointIndex) - myY
+ zCoordinate = pointZ(pointIndex) - myZ
+
+ ' Rotate the points
+ rotatedX = xCoordinate * cosAngle1 + zCoordinate * sinAngle1
+ rotatedZ = zCoordinate * cosAngle1 - xCoordinate * sinAngle1
+
+ rotatedY = yCoordinate * cosAngle2 + rotatedZ * sinAngle2
+ finalZ = rotatedZ * cosAngle2 - yCoordinate * sinAngle2
+
+ ' Draw points that are sufficiently close
+ IF finalZ > 3 THEN
+ screenX = rotatedX / finalZ * 130 + 160
+ screenY = rotatedY / finalZ * 130 + 100
+ PSET (screenX, screenY), pointColor(pointIndex)
+ END IF
+
+NEXT pointIndex
+END SUB
+
+FUNCTION getByte (address)
+getByte = PEEK(externalAddress + address)
+END FUNCTION
+
+FUNCTION getWord (address)
+firstByte = PEEK(externalAddress + address)
+secondByte = PEEK(externalAddress + address + 1)
+
+' Combine the two bytes into a single value
+combinedHex$ = HEX$(firstByte)
+IF LEN(combinedHex$) = 1 THEN combinedHex$ = "0" + combinedHex$
+IF LEN(combinedHex$) = 0 THEN combinedHex$ = "00"
+
+combinedValue = VAL("&H" + HEX$(secondByte) + combinedHex$)
+
+getWord = combinedValue
+END FUNCTION
+
+SUB mkGalaxy (localX, localY, localZ)
+
+' Generate random angles for stars within galaxy
+randomAngle1 = rn * 10
+randomAngle2 = rn * 10
+
+galaxySin1 = SIN(randomAngle1)
+galaxyCos1 = COS(randomAngle1)
+galaxySin2 = SIN(randomAngle2)
+galaxyCos2 = COS(randomAngle2)
+
+randomPointer = 0
+size = 100
+piValue = 3.14
+spiralBarsMultiplier = 3
+
+FOR pointIndex = 1 TO 10000
+
+ ' Generate a random star distance from the center
+ randomVariable = rn * 10
+ distanceFromCenter = randomVariable * randomVariable / 30
+
+ ' Calculate spiral offset and half of it
+ spiralOffset = rn * (11.5 - randomVariable) / 3
+ halfSpiralOffset = spiralOffset / 2
+
+ ' Generate angle exponent and spiral bar angle
+ angleExponent = rn * (distanceFromCenter / 2) / spiralBarsMultiplier * 2
+ spiralBarAngle = 2 * piValue / spiralBarsMultiplier * INT(rn * spiralBarsMultiplier)
+
+ ' Calculate x, z, and y coordinates
+ xCoordinate = (SIN(randomVariable - spiralBarAngle + angleExponent) * distanceFromCenter + rn * spiralOffset - halfSpiralOffset) * size
+ zCoordinate = (COS(randomVariable - spiralBarAngle + angleExponent) * distanceFromCenter + rn * spiralOffset - halfSpiralOffset) * size
+ yCoordinate = (rn * spiralOffset - halfSpiralOffset) * size
+
+ ' Rotate the coordinates
+ rotatedX = xCoordinate * galaxyCos1 + zCoordinate * galaxySin1
+ rotatedZ = zCoordinate * galaxyCos1 - xCoordinate * galaxySin1
+
+ rotatedY = yCoordinate * galaxyCos2 + rotatedZ * galaxySin2
+ finalZ = rotatedZ * galaxyCos2 - yCoordinate * galaxySin2
+
+ ' Store the point in arrays
+ numPoints = numPoints + 1
+
+ pointX(numPoints) = rotatedX + localX
+ pointY(numPoints) = rotatedY + localY
+ pointZ(numPoints) = finalZ + localZ
+ pointColor(numPoints) = INT(RND * 15) + 1
+NEXT pointIndex
+
+END SUB
+
+SUB putByte (address, dataByte)
+
+POKE (externalAddress + address), dataByte
+END SUB
+
+SUB putWord (address, dataWord)
+
+' Convert the word to a hexadecimal string
+hexValue$ = HEX$(dataWord)
+
+' Ensure the string has at least 4 characters
+2
+IF LEN(hexValue$) < 4 THEN
+ hexValue$ = "0" + hexValue$: GOTO 2
+END IF
+
+' Extract the first and second bytes
+firstByteValue = VAL("&H" + LEFT$(hexValue$, 2))
+secondByteValue = VAL("&H" + RIGHT$(hexValue$, 2))
+
+' Store the bytes in memory
+POKE (externalAddress + address), secondByteValue
+POKE (externalAddress + address + 1), firstByteValue
+
+END SUB
+
+FUNCTION rn
+
+' Increment the random pointer and get a new random value
+randomPointer = randomPointer + 1
+IF randomPointer > 10000 THEN randomPointer = 0
+rn = randomValue(randomPointer)
+
+END FUNCTION
+
+SUB rndInit
+
+' Initialize the array of random values
+FOR index = 0 TO 10000
+ randomValue(index) = RND
+NEXT index
+
+randomPointer = 0
+END SUB
+
+SUB start
+
+starText
+
+' Set up graphics mode
+SCREEN 7, , , 1
+
+' Initialize maximum movement and random values
+maxMove = 50
+rndInit
+
+END SUB
+
+SUB starText
+
+' Read the segment and address from the interrupt table
+DEF SEG = 0 ' read first from interrupt table
+
+externalSegment = PEEK(&H79 * 4 + 3) * 256
+externalSegment = externalSegment + PEEK(&H79 * 4 + 2)
+
+PRINT "Segment is: " + HEX$(externalSegment)
+
+externalAddress = PEEK(&H79 * 4 + 1) * 256
+externalAddress = externalAddress + PEEK(&H79 * 4 + 0)
+
+PRINT "relative address is:"; externalAddress
+
+' Read the word at the specified address
+DEF SEG = externalSegment
+
+IF getWord(0) <> 1983 THEN
+ PRINT "FATAL ERROR: you must load"
+ PRINT "QBasic extension TSR first!"
+ SYSTEM
+END IF
+
+END SUB
--- /dev/null
+' 3D rocket simulator. Rocket takes off from the surface of the planet.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+\r
+' Changelog:\r
+' 2001, Initial version\r
+' 2024 - 2025, Improved program readability\r
+'\r
+' Usage:\r
+' arrow keys - move around\r
+' 2, 6, 4, 8 - look around\r
+' - - fly up\r
+' + - fly down\r
+\r
+DECLARE SUB AddRocketTrailPoints ()\r
+DECLARE SUB AddRocketTrailLine ()\r
+DEFDBL A-Z\r
+DECLARE SUB GenerateRocket ()\r
+DECLARE SUB GenerateEarth ()\r
+DECLARE SUB InitializeScene ()\r
+DECLARE SUB Render3DScene ()\r
+\r
+DIM SHARED pointX(1 TO 1500)\r
+DIM SHARED pointY(1 TO 1500)\r
+DIM SHARED pointZ(1 TO 1500)\r
+DIM SHARED lineStartPoint(1 TO 3000)\r
+DIM SHARED lineEndPoint(1 TO 3000)\r
+DIM SHARED lineColor(1 TO 3000)\r
+DIM SHARED onScreenPointX(1 TO 1900)\r
+DIM SHARED onScreenPointY(1 TO 1900)\r
+DIM SHARED rocketPointX(1 TO 200)\r
+DIM SHARED rocketPointY(1 TO 200)\r
+DIM SHARED rocketPointZ(1 TO 200)\r
+DIM SHARED pointCount, lineCount\r
+DIM SHARED cameraX, cameraY, cameraZ\r
+DIM SHARED cameraXSpeed, cameraYSpeed, cameraZSpeed\r
+DIM SHARED rotationAngleX, rotationAngleY\r
+DIM SHARED oldScreenPointX1(1 TO 2500)\r
+DIM SHARED oldScreenPointY1(1 TO 2500)\r
+DIM SHARED oldScreenPointX2(1 TO 2500)\r
+DIM SHARED oldScreenPointY2(1 TO 2500)\r
+DIM SHARED frameCount, frameCount2, frameRate\r
+DIM SHARED earthRadius, earthStep, rocketScale, rocketStep\r
+DIM SHARED pi\r
+DIM SHARED rocketStartPoint, rocketEndPoint, rocketPointCount\r
+DIM SHARED rocketX, rocketY, rocketZ, rocketXSpeed, rocketYSpeed, rocketZSpeed\r
+DIM SHARED timerString, timeSlice\r
+DIM SHARED lastAddedPoint\r
+\r
+InitializeScene\r
+\r
+rotationAngleX = -pi / 2\r
+\r
+' Initialize the rocket position and velocity\r
+rocketX = 0\r
+rocketY = earthRadius / 2 + .009\r
+rocketZ = 0\r
+cameraX = 0\r
+cameraY = earthRadius / 2\r
+cameraZ = -.05\r
+timeSlice = 0\r
+frameCount2 = 999999\r
+timerString$ = TIME$\r
+\r
+1\r
+frameCount = frameCount + 1\r
+frameCount2 = frameCount2 + 1\r
+\r
+' Display the current values of some variables\r
+LOCATE 1, 1\r
+PRINT pointCount, lineCount, earthRadius, earthStep\r
+LOCATE 2, 1\r
+PRINT rocketStartPoint, rocketEndPoint, TIMER\r
+\r
+' Update rocket position and velocity\r
+rocketX = rocketX + (rocketXSpeed * timeSlice)\r
+rocketY = rocketY + (rocketYSpeed * timeSlice)\r
+rocketZ = rocketZ + (rocketZSpeed * timeSlice)\r
+\r
+' Update the rocket's pitch and roll rates\r
+rocketYSpeed = rocketYSpeed + (.0098 * timeSlice)\r
+rocketXSpeed = SIN(frameCount / 20) / 50\r
+\r
+' Update the points that make up the rocket\r
+FOR a = 1 TO rocketPointCount\r
+ pointX(a + rocketStartPoint - 1) = rocketPointX(a) + rocketX\r
+ pointY(a + rocketStartPoint - 1) = rocketPointY(a) + rocketY\r
+ pointZ(a + rocketStartPoint - 1) = rocketPointZ(a) + rocketZ\r
+NEXT a\r
+\r
+' Update the observer position and velocity\r
+cameraX = cameraX + (cameraXSpeed * timeSlice)\r
+cameraY = cameraY + (cameraYSpeed * timeSlice)\r
+cameraZ = cameraZ + (cameraZSpeed * timeSlice)\r
+\r
+' Draw the 3D scene\r
+Render3DScene\r
+\r
+' Handle user input\r
+a$ = INKEY$\r
+IF a$ <> "" THEN\r
+ IF a$ = CHR$(0) + "H" THEN\r
+ ' Move forward\r
+ cameraZSpeed = cameraZSpeed - SIN(rotationAngleX) / 100\r
+ cameraXSpeed = cameraXSpeed + COS(rotationAngleX) / 100\r
+ END IF\r
+ IF a$ = CHR$(0) + "P" THEN\r
+ ' Move backward\r
+ cameraZSpeed = cameraZSpeed + SIN(rotationAngleX) / 100\r
+ cameraXSpeed = cameraXSpeed - COS(rotationAngleX) / 100\r
+ END IF\r
+ IF a$ = CHR$(0) + "M" THEN\r
+ ' Move right\r
+ cameraZSpeed = cameraZSpeed + COS(rotationAngleX) / 100\r
+ cameraXSpeed = cameraXSpeed + SIN(rotationAngleX) / 100\r
+ END IF\r
+ IF a$ = CHR$(0) + "K" THEN\r
+ ' Move left\r
+ cameraZSpeed = cameraZSpeed - COS(rotationAngleX) / 100\r
+ cameraXSpeed = cameraXSpeed - SIN(rotationAngleX) / 100\r
+ END IF\r
+ ' Change the viewing angle\r
+ IF a$ = CHR$(27) THEN SYSTEM\r
+ IF a$ = "4" THEN rotationAngleX = rotationAngleX + .1\r
+ IF a$ = "6" THEN rotationAngleX = rotationAngleX - .1\r
+ IF a$ = "2" THEN rotationAngleY = rotationAngleY + .1\r
+ IF a$ = "8" THEN rotationAngleY = rotationAngleY - .1\r
+ IF a$ = "-" THEN cameraYSpeed = cameraYSpeed + .01\r
+ IF a$ = "+" THEN cameraYSpeed = cameraYSpeed - .01\r
+ IF a$ = " " THEN cameraZSpeed = cameraZSpeed / 2: cameraXSpeed = cameraXSpeed / 2\r
+END IF\r
+\r
+' Calculate the speed and distance of the rocket\r
+v = SQR(rocketX * rocketX + rocketY * rocketY + rocketZ * rocketZ)\r
+s = SQR(rocketXSpeed * rocketXSpeed + rocketYSpeed * rocketYSpeed + rocketZSpeed * rocketZSpeed)\r
+\r
+' Display the current frame rate and other information\r
+IF timerString$ <> TIME$ THEN\r
+ timerString$ = TIME$\r
+ LOCATE 29, 1\r
+ PRINT "speed"; INT(s * 1000)\r
+ LOCATE 30, 1\r
+ PRINT "fps"; frameRate; "timeslice"; INT(timeSlice * 1000); "distance"; v;\r
+ ' Update the frame rate and time slice\r
+ frameRate = frameCount2\r
+ timeSlice = 1 / frameRate\r
+ frameCount2 = 0\r
+ ' Add new points to the scene\r
+ AddRocketTrailPoints\r
+ AddRocketTrailLine\r
+END IF\r
+GOTO 1\r
+\r
+SUB AddRocketTrailLine\r
+' Adds a new line to the scene to represent the rocket's trail.\r
+' It connects the current rocket position to the last added point, if any.\r
+pointCount = pointCount + 1\r
+pointX(pointCount) = rocketX\r
+pointY(pointCount) = rocketY\r
+pointZ(pointCount) = rocketZ\r
+\r
+' If there was a previous point, add a line connecting the previous point to the current point\r
+IF lastAddedPoint > 0 THEN\r
+ lineCount = lineCount + 1\r
+ lineStartPoint(lineCount) = lastAddedPoint\r
+ lineEndPoint(lineCount) = pointCount\r
+ lineColor(lineCount) = 13\r
+END IF\r
+lastAddedPoint = pointCount\r
+END SUB\r
+\r
+SUB AddRocketTrailPoints\r
+' Adds new points to the scene to represent the rocket's trail.\r
+' It adds three points forming a triangle to visualize the rocket's position.\r
+pointCount = pointCount + 1\r
+pointX(pointCount) = rocketX\r
+pointY(pointCount) = rocketY\r
+pointZ(pointCount) = rocketZ\r
+\r
+pointCount = pointCount + 1\r
+pointX(pointCount) = rocketX - .001\r
+pointY(pointCount) = rocketY - .001\r
+pointZ(pointCount) = rocketZ\r
+\r
+pointCount = pointCount + 1\r
+pointX(pointCount) = rocketX + .001\r
+pointY(pointCount) = rocketY - .001\r
+pointZ(pointCount) = rocketZ\r
+\r
+' Add lines connecting these points to form a triangle\r
+lineCount = lineCount + 1\r
+lineStartPoint(lineCount) = pointCount\r
+lineEndPoint(lineCount) = pointCount - 1\r
+lineColor(lineCount) = 14\r
+\r
+lineCount = lineCount + 1\r
+lineStartPoint(lineCount) = pointCount - 2\r
+lineEndPoint(lineCount) = pointCount - 1\r
+lineColor(lineCount) = 14\r
+\r
+lineCount = lineCount + 1\r
+lineStartPoint(lineCount) = pointCount\r
+lineEndPoint(lineCount) = pointCount - 2\r
+lineColor(lineCount) = 14\r
+END SUB\r
+\r
+SUB GenerateEarth\r
+' Generates the points that make up the earth.\r
+' It uses nested loops to create points in a spherical shape for the earth\r
+' and adds lines to connect these points to form the earth's surface.\r
+tmpp = pointCount\r
+le2 = 0\r
+FOR z = -(earthRadius / 3) TO (earthRadius / 3) STEP earthStep\r
+ le = 0\r
+ le2 = le2 + 1\r
+ FOR x = -(earthRadius / 3) TO (earthRadius / 3) STEP earthStep\r
+ ' Check if the point is within the rocket's radius\r
+ IF SQR(x * x + z * z) > (earthRadius / 2.5) THEN GOTO 4\r
+ le = le + 1\r
+ ' Add the first point of the line\r
+ IF le = 1 THEN\r
+ xs = x / earthStep\r
+ END IF\r
+ pointCount = pointCount + 1\r
+ pointX(pointCount) = x\r
+ v = SQR(x * x + z * z)\r
+ pointY(pointCount) = SQR((v + (earthRadius / 2)) * ((earthRadius / 2) - v))\r
+ pointZ(pointCount) = z\r
+ ' Add the line to the list of lines\r
+ IF le > 1 THEN\r
+ lineCount = lineCount + 1\r
+ lineStartPoint(lineCount) = pointCount\r
+ lineEndPoint(lineCount) = pointCount - 1\r
+ lineColor(lineCount) = 3\r
+ END IF\r
+ ' Add the line to the list of lines if it is part of a circle\r
+ IF le2 > 1 THEN\r
+ IF xso > (x / earthStep) THEN GOTO 4\r
+ IF xso + leo <= (x / earthStep) THEN GOTO 4\r
+ lineCount = lineCount + 1\r
+ lineStartPoint(lineCount) = pointCount\r
+ lineEndPoint(lineCount) = pointCount - leo - xso + xs\r
+ lineColor(lineCount) = 3\r
+ END IF\r
+4\r
+ NEXT x\r
+ ' Update the variables for the next circle\r
+ leo = le\r
+ xso = xs\r
+NEXT z\r
+END SUB\r
+\r
+SUB GenerateRocket\r
+' Generates the points that make up the rocket.\r
+' It uses loops to create points in a cylindrical shape for the rocket body\r
+' and adds lines to connect these points to form the rocket's structure.\r
+' It also adds points and lines for the top and bottom of the rocket.\r
+s = 50\r
+FOR y = -9 TO 10 STEP rocketStep\r
+ st = pi * 2 / 6\r
+ IF y > 5 THEN\r
+ s = s - 3\r
+ END IF\r
+ IF y > 8 THEN\r
+ s = s - 6\r
+ END IF\r
+ FOR a = 0 TO pi * 2 STEP st\r
+ x1 = SIN(a) * s\r
+ z1 = COS(a) * s\r
+ pointCount = pointCount + 1\r
+ pointX(pointCount) = x1 * rocketScale\r
+ pointY(pointCount) = y * 50 * rocketScale\r
+ pointZ(pointCount) = z1 * rocketScale\r
+ ' Add the line to the list of lines\r
+ IF a > 0 THEN\r
+ lineCount = lineCount + 1\r
+ lineStartPoint(lineCount) = pointCount\r
+ lineEndPoint(lineCount) = pointCount - 1\r
+ lineColor(lineCount) = 10\r
+ END IF\r
+ ' Add the line to the list of lines if it is part of a circle\r
+ IF y > -9 THEN\r
+ lineCount = lineCount + 1\r
+ lineStartPoint(lineCount) = pointCount\r
+ lineEndPoint(lineCount) = pointCount - 7\r
+ lineColor(lineCount) = 10\r
+ END IF\r
+ NEXT a\r
+NEXT y\r
+\r
+' Add the points that make up the top of the rocket\r
+pointCount = pointCount + 1\r
+pointX(pointCount) = 0\r
+pointY(pointCount) = 11 * 50 * rocketScale\r
+pointZ(pointCount) = 0\r
+FOR a = 1 TO 6\r
+ lineCount = lineCount + 1\r
+ lineStartPoint(lineCount) = pointCount\r
+ lineEndPoint(lineCount) = pointCount - a\r
+ lineColor(lineCount) = 10\r
+NEXT a\r
+\r
+' Add the points that make up the bottom of the rocket\r
+pointCount = pointCount + 1\r
+pointX(pointCount) = -100 * rocketScale\r
+pointY(pointCount) = -450 * rocketScale\r
+pointZ(pointCount) = 0\r
+pointCount = pointCount + 1\r
+pointX(pointCount) = 100 * rocketScale\r
+pointY(pointCount) = -450 * rocketScale\r
+pointZ(pointCount) = 0\r
+pointCount = pointCount + 1\r
+pointX(pointCount) = 0\r
+pointY(pointCount) = -200 * rocketScale\r
+pointZ(pointCount) = 0\r
+lineCount = lineCount + 1\r
+lineStartPoint(lineCount) = pointCount\r
+lineEndPoint(lineCount) = pointCount - 1\r
+lineColor(lineCount) = 12\r
+lineCount = lineCount + 1\r
+lineStartPoint(lineCount) = pointCount - 2\r
+lineEndPoint(lineCount) = pointCount - 1\r
+lineColor(lineCount) = 12\r
+lineCount = lineCount + 1\r
+lineStartPoint(lineCount) = pointCount\r
+lineEndPoint(lineCount) = pointCount - 2\r
+lineColor(lineCount) = 12\r
+pointCount = pointCount + 1\r
+pointX(pointCount) = 0\r
+pointY(pointCount) = -450 * rocketScale\r
+pointZ(pointCount) = -100 * rocketScale\r
+pointCount = pointCount + 1\r
+pointX(pointCount) = 0\r
+pointY(pointCount) = -450 * rocketScale\r
+pointZ(pointCount) = 100 * rocketScale\r
+lineCount = lineCount + 1\r
+lineStartPoint(lineCount) = pointCount\r
+lineEndPoint(lineCount) = pointCount - 1\r
+lineColor(lineCount) = 12\r
+lineCount = lineCount + 1\r
+lineStartPoint(lineCount) = pointCount - 2\r
+lineEndPoint(lineCount) = pointCount - 1\r
+lineColor(lineCount) = 12\r
+lineCount = lineCount + 1\r
+lineStartPoint(lineCount) = pointCount\r
+lineEndPoint(lineCount) = pointCount - 2\r
+lineColor(lineCount) = 12\r
+END SUB\r
+\r
+SUB InitializeScene\r
+' Initializes the graphics mode and sets up the initial scene.\r
+' It sets up the screen, initializes variables, adds initial points and lines,\r
+' and calls subroutines to generate the earth and the rocket.\r
+SCREEN 12\r
+VIEW PRINT 1 TO 30\r
+earthRadius = 12714\r
+earthStep = 500\r
+rocketStep = 4\r
+pi = 3.142657\r
+rocketScale = .00002\r
+frameCount2 = 0\r
+lastAddedPoint = -1\r
+pointX(1) = -.001\r
+pointY(1) = earthRadius / 2\r
+pointZ(1) = -.001\r
+pointX(2) = .001\r
+pointY(2) = earthRadius / 2\r
+pointZ(2) = -.001\r
+pointX(3) = .001\r
+pointY(3) = earthRadius / 2\r
+pointZ(3) = .001\r
+pointX(4) = -.001\r
+pointY(4) = earthRadius / 2\r
+pointZ(4) = .001\r
+pointCount = 4\r
+\r
+' Set up the initial lines that make up the rocket\r
+lineStartPoint(1) = 1\r
+lineEndPoint(1) = 2\r
+lineColor(1) = 14\r
+lineStartPoint(2) = 2\r
+lineEndPoint(2) = 3\r
+lineColor(2) = 14\r
+lineStartPoint(3) = 3\r
+lineEndPoint(3) = 4\r
+lineColor(3) = 14\r
+lineStartPoint(4) = 4\r
+lineEndPoint(4) = 1\r
+lineColor(4) = 14\r
+lineCount = 4\r
+\r
+' Initialize the observer position and velocity\r
+cameraX = 0\r
+cameraY = earthRadius * 2\r
+cameraZ = -35\r
+GenerateEarth\r
+cameraXSpeed = 0\r
+cameraYSpeed = 0\r
+cameraZSpeed = 0\r
+rotationAngleX = 0\r
+rocketStartPoint = pointCount + 1\r
+GenerateRocket\r
+rocketEndPoint = pointCount\r
+\r
+' Calculate the number of points that make up the rocket\r
+rocketPointCount = rocketEndPoint - rocketStartPoint + 1\r
+\r
+' Copy the initial points to the arrays for the rocket\r
+FOR a = 1 TO rocketPointCount\r
+ p = rocketStartPoint + a - 1\r
+ rocketPointX(a) = pointX(p)\r
+ rocketPointY(a) = pointY(p)\r
+ rocketPointZ(a) = pointZ(p)\r
+NEXT a\r
+END SUB\r
+\r
+SUB Render3DScene\r
+' Converts the 3D points to 2D for drawing on the screen.\r
+' It applies rotation transformations and projects the 3D points to 2D screen coordinates.\r
+' It then draws lines connecting the points if they are within the screen boundaries.\r
+s1 = SIN(rotationAngleX)\r
+c1 = COS(rotationAngleX)\r
+s2 = SIN(rotationAngleY)\r
+c2 = COS(rotationAngleY)\r
+FOR a = 1 TO pointCount\r
+ x = pointX(a) - cameraX\r
+ y = pointY(a) - cameraY\r
+ z = pointZ(a) - cameraZ\r
+ ' Apply the rotation transformations\r
+ x1 = x * s1 + z * c1\r
+ z1 = x * c1 - z * s1\r
+ y1 = z1 * s2 + y * c2\r
+ z2 = z1 * c2 - y * s2\r
+ ' Project the 3D point to 2D\r
+ IF z2 < .00001 THEN\r
+ onScreenPointX(a) = -1\r
+ ELSE\r
+ onScreenPointX(a) = x1 / z2 * 200 + 320\r
+ onScreenPointY(a) = 240 - y1 / z2 * 200\r
+ ' Check if the point is within the screen boundaries\r
+ IF onScreenPointX(a) < -50 OR onScreenPointX(a) > 1000 OR onScreenPointY(a) > 1000 THEN\r
+ onScreenPointX(a) = -1\r
+ END IF\r
+ END IF\r
+NEXT a\r
+\r
+' Draw the lines that make up the rocket\r
+FOR a = 1 TO lineCount\r
+ p1 = lineStartPoint(a)\r
+ p2 = lineEndPoint(a)\r
+ x1 = onScreenPointX(p1)\r
+ y1 = onScreenPointY(p1)\r
+ x2 = onScreenPointX(p2)\r
+ y2 = onScreenPointY(p2)\r
+ ' Check if the line is within the screen boundaries.\r
+ ' If so, erase line at old locations\r
+ IF oldScreenPointX1(a) = -1 OR oldScreenPointX2(a) = -1 THEN\r
+ ELSE\r
+ LINE (oldScreenPointX1(a), oldScreenPointY1(a))-(oldScreenPointX2(a), oldScreenPointY2(a)), 0\r
+ END IF\r
+ ' Draw the line if both endpoints are within the screen boundaries\r
+ IF x1 <> -1 AND x2 <> -1 THEN\r
+ LINE (x1, y1)-(x2, y2), lineColor(a)\r
+ END IF\r
+ ' Update the old endpoints of the line for the next frame\r
+ oldScreenPointX1(a) = x1\r
+ oldScreenPointY1(a) = y1\r
+ oldScreenPointX2(a) = x2\r
+ oldScreenPointY2(a) = y2\r
+NEXT a\r
+END SUB\r
+\r
--- /dev/null
+' 3D Starfield Simulation.0\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.03, Initial version\r
+' 2024 - 2025, Improved code readability\r
+\r
+DECLARE SUB AddStar (xPosition AS SINGLE, yPosition AS SINGLE, zPosition AS SINGLE)\r
+DECLARE SUB CreateGalaxy ()\r
+\r
+Dim Shared totalStars As Integer\r
+Dim Shared maxStars As Integer\r
+\r
+Randomize Timer\r
+maxStars = 2000\r
+totalStars = maxStars\r
+starFieldDepth = 500\r
+\r
+Dim Shared starXPositions(1 To maxStars + 1000) As Single\r
+Dim Shared starYPositions(1 To maxStars + 1000) As Single\r
+Dim Shared starZPositions(1 To maxStars + 1000) As Single\r
+\r
+' Initialize the positions of the stars\r
+For starIndex = 1 To totalStars\r
+ starZPositions(starIndex) = Rnd * starFieldDepth + 20\r
+ angle = Rnd * 100\r
+ starXPositions(starIndex) = Sin(angle) * 20\r
+ starYPositions(starIndex) = Cos(angle) * 20\r
+Next starIndex\r
+\r
+Screen 13\r
+\r
+\r
+Do\r
+\r
+ ' Calculate the camera's rotation and position offsets\r
+ frameCount = frameCount + 1\r
+ cameraRotation = (3.1412 / 2) + Sin(frameCount / 35) / 100 + Sin(frameCount / 21) / 100\r
+ rs1 = Sin(cameraRotation)\r
+ rc1 = Cos(cameraRotation)\r
+\r
+ ' Update and draw each star\r
+ For starIndex = 1 To totalStars\r
+ x = starXPositions(starIndex)\r
+ y = starYPositions(starIndex)\r
+ z = starZPositions(starIndex)\r
+\r
+ ' Project the star's 3D position onto the 2D screen\r
+ projectedX = (x / z) * 160 + 160\r
+ projectedY = (y / z) * 100 + 100\r
+ PSet (projectedX, projectedY), 0 ' Erase the previous position\r
+\r
+ ' Rotate the star's position around the camera\r
+ x5 = x * rs1 - y * rc1\r
+ y5 = x * rc1 + y * rs1\r
+\r
+ ' Update the star's position with camera movement\r
+ x = x5 + Sin(frameCount / 21) * 3\r
+ y = y5 + Sin(frameCount / 18) * 3\r
+\r
+ ' Move the star closer to the viewer and wrap around if too close\r
+ z = z - 3\r
+ If z < 10 Then\r
+ z = Rnd * 300 + 400\r
+ x = Rnd * 800 - 400\r
+ y = Rnd * 800 - 400\r
+ End If\r
+\r
+ ' Project the new position and draw with perspective-based brightness\r
+ projectedX = (x / z) * 160 + 160\r
+ projectedY = (y / z) * 100 + 100\r
+ colorCode = 3000 / z + 15\r
+ If colorCode > 31 Then colorCode = 31\r
+ PSet (projectedX, projectedY), colorCode\r
+\r
+ ' Update the star's array positions\r
+ starXPositions(starIndex) = x\r
+ starYPositions(starIndex) = y\r
+ starZPositions(starIndex) = z\r
+ Next starIndex\r
+\r
+ ' Add new stars to the galaxy if needed\r
+ If maxStars - totalStars > Rnd * 800 + 100 Then CreateGalaxy: totalStars = totalStars + 1\r
+\r
+ ' Remove the two farthest stars and replace them with new ones\r
+ For a = 1 To 2\r
+ starIndex = Int(Rnd * (totalStars - 10)) + 1\r
+ Swap starXPositions(totalStars), starXPositions(starIndex)\r
+ Swap starYPositions(totalStars), starYPositions(starIndex)\r
+ Swap starZPositions(totalStars), starZPositions(starIndex)\r
+\r
+ x = starXPositions(totalStars)\r
+ y = starYPositions(totalStars)\r
+ z = starZPositions(totalStars)\r
+ projectedX = (x / z) * 160 + 160\r
+ projectedY = (y / z) * 100 + 100\r
+ PSet (projectedX, projectedY), 0 ' Erase the star\r
+ totalStars = totalStars - 1\r
+ Next a\r
+\r
+\r
+ ' Check for user input to exit the program\r
+ If InKey$ <> "" Then System\r
+\r
+ ' sleep, to limit framerate\r
+ Sound 0, 1\r
+Loop\r
+\r
+' Subroutine to create a new galaxy of stars\r
+Sub CreateGalaxy\r
+ xForce = Rnd * 4 - 2\r
+ yForce = Rnd * 4 - 2\r
+ xPositionOffset = Rnd * 200 - 100\r
+ yPositionOffset = Rnd * 200 - 100\r
+\r
+ ' Add a new set of stars with varying positions and velocities\r
+ For starIndex = 1 To Int(Rnd * 15) + 10 Step .04\r
+ x = Sin(starIndex) * starIndex * starIndex / 10\r
+ y = Cos(starIndex) * starIndex * starIndex / 10\r
+ AddStar x + RND * starIndex * starIndex / 30 + xPositionOffset, _\r
+ y + RND * starIndex * starIndex / 30 + yPositionOffset, _\r
+ 700 + RND * starIndex * starIndex / 30 + (x * xForce) + (y * yForce)\r
+ Next starIndex\r
+\r
+ ' Play a sound when creating new stars (commented out)\r
+ ' SOUND 1000, 1\r
+End Sub\r
+\r
+' Subroutine to add a new star at the specified position\r
+Sub AddStar (xPosition As Single, yPosition As Single, zPosition As Single)\r
+ totalStars = totalStars + 1\r
+ starIndex = totalStars\r
+\r
+ starXPositions(starIndex) = xPosition\r
+ starYPositions(starIndex) = yPosition\r
+ starZPositions(starIndex) = zPosition\r
+End Sub\r
+\r
--- /dev/null
+' 3D Universe Explorer. User can freely fly around.\r
+' Universe is made of galaxy clusters.\r
+' Galaxy cluster is made of galaxies.\r
+' Galaxies are made of stars.\r
+\r
+' Total amount of stars in the universe is enormous.\r
+' This program implements clever algorithm to dynamically increase\r
+' and decrease level of detail of the universe regions depending\r
+' on where user is in the universe and maintaining reasonable\r
+' quantity of stars to render at any given time.\r
+'\r
+' Note: This program requires special Terminate and Stay Resident (TSR) mouse driver\r
+' to be loaded *before* starting the current QBasic program itself.\r
+' Here you can read about TSR mouse driver and download needed qbext.com binary:\r
+' https://www3.svjatoslav.eu/projects/qbasicapps/Miscellaneous/Mouse%20driver/index.html\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+'\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024, Improved program readability\r
+\r
+DECLARE SUB loadScript (scriptName$)\r
+\r
+DECLARE SUB timerAdd (element!, time!, value!)\r
+DECLARE SUB timerinit ()\r
+DECLARE SUB timerprocess ()\r
+\r
+DECLARE SUB getCloudXYZ (a!, x1!, y1!, z2!)\r
+DECLARE FUNCTION gdist! (x!, y!, z!)\r
+DECLARE SUB mkworld ()\r
+DECLARE SUB galacloud (rx!, ry!, rz!)\r
+DECLARE SUB temp ()\r
+DECLARE SUB mkgalaxy (x!, y!, z!)\r
+DECLARE SUB rndinit ()\r
+DECLARE FUNCTION rn! ()\r
+DECLARE SUB disp ()\r
+DECLARE SUB startext ()\r
+DECLARE SUB control ()\r
+DECLARE SUB putbyte (addr!, dat!)\r
+DECLARE SUB putword (addr!, dat!)\r
+DECLARE FUNCTION getword! (addr!)\r
+DECLARE FUNCTION getbyte! (addr!)\r
+DECLARE SUB start ()\r
+DECLARE SUB animate ()\r
+\r
+DIM SHARED an1, an2, an3\r
+\r
+DIM SHARED tim\r
+\r
+DIM SHARED extSEG, extADDR\r
+\r
+' User position in the universe\r
+DIM SHARED myx, myy, myz\r
+' User velocity in the universe\r
+DIM SHARED myxs, myys, myzs\r
+' User pressed mouse buttons\r
+DIM SHARED buttL, buttR\r
+' Maximum user movement speed\r
+DIM SHARED maxmove\r
+\r
+' Zoom level\r
+DIM SHARED zoom\r
+DIM SHARED rndval(0 TO 10000)\r
+DIM SHARED rndp\r
+\r
+' Star positions and colors\r
+DIM SHARED px(1 TO 10000), py(1 TO 10000), pz(1 TO 10000)\r
+DIM SHARED pc(1 TO 10000)\r
+' Total number of stars\r
+DIM SHARED nump\r
+' User speed multiplier\r
+DIM SHARED myspd\r
+\r
+DIM SHARED tempr(0 TO 10)\r
+\r
+DIM SHARED vd\r
+\r
+DIM SHARED oftcloud(0 TO 3)\r
+\r
+' Galaxy positions\r
+DIM SHARED oftGalaX(0 TO 19), oftGalaY(0 TO 19), oftGalaZ(0 TO 19)\r
+\r
+DIM SHARED timerTime(0 TO 50, 0 TO 100)\r
+DIM SHARED timerValue(0 TO 50, 0 TO 100)\r
+\r
+DIM SHARED timerCplace(0 TO 50)\r
+DIM SHARED timerCtime(0 TO 50)\r
+DIM SHARED timerCvalue(0 TO 50)\r
+DIM SHARED timerLast\r
+\r
+DIM SHARED timerStartScript\r
+DIM SHARED ScriptRunning\r
+\r
+start\r
+\r
+cx = 0\r
+cy = 0\r
+cz = 0\r
+\r
+myx = 123456\r
+myy = 321\r
+myz = 23\r
+\r
+nump = 9999\r
+1\r
+' Initialize the universe\r
+mkworld\r
+\r
+va = INT(RND * 3)\r
+\r
+SELECT CASE va\r
+CASE 0\r
+ cx = RND * 500 - 250\r
+CASE 1\r
+ cy = RND * 100 - 50\r
+CASE 2\r
+ cz = RND * 500 - 250\r
+END SELECT\r
+\r
+' Handle user input and movement\r
+control\r
+\r
+' Display the universe\r
+disp\r
+\r
+' Process timers for scripted movements\r
+timerprocess\r
+\r
+' Copy screen buffer to main screen\r
+PCOPY 0, 1\r
+\r
+' Clear the screen\r
+CLS\r
+\r
+' Loop back to start\r
+GOTO 1\r
+\r
+SUB control\r
+\r
+' Handle mouse input\r
+IF getbyte(8) <> 0 THEN\r
+ putbyte 8, 0\r
+ xp = getword(2)\r
+ putword 2, 0\r
+ yp = getword(4)\r
+ putword 4, 0\r
+ butt = getword(6)\r
+ putword 6, 0\r
+\r
+ ' Determine which mouse buttons are pressed\r
+ buttL = 0\r
+ buttR = 0\r
+ IF butt = 1 THEN buttL = 1\r
+ IF butt = 2 THEN buttR = 1\r
+ IF butt = 3 THEN buttL = 1: buttR = 1\r
+\r
+ ' Handle right mouse button for up/down movement\r
+ IF buttR = 1 THEN\r
+ ' Handle both buttons pressed for back/front movement\r
+ IF buttL = 1 THEN\r
+ myxs = myxs + SIN(an1) * yp / 4\r
+ myzs = myzs - COS(an1) * yp / 4\r
+ GOTO 3\r
+ END IF\r
+\r
+ ' Handle right button for up/down movement\r
+ myys = myys + yp / 4\r
+3\r
+ yp = 0\r
+ END IF\r
+\r
+END IF\r
+\r
+' Clamp user input to maximum movement speed\r
+IF xp < -maxmove THEN xp = -maxmove\r
+IF xp > maxmove THEN xp = maxmove\r
+an1 = an1 - xp / 150\r
+\r
+IF yp < -maxmove THEN yp = -maxmove\r
+IF yp > maxmove THEN yp = maxmove\r
+an2 = an2 - yp / 150\r
+\r
+' Handle keyboard input for movement\r
+a$ = INKEY$\r
+\r
+IF a$ = "a" THEN myxs = myxs - COS(an1): myzs = myzs - SIN(an1)\r
+IF a$ = "d" THEN myxs = myxs + COS(an1): myzs = myzs + SIN(an1)\r
+IF a$ = "w" THEN myxs = myxs - SIN(an1): myzs = myzs + COS(an1)\r
+IF a$ = "s" THEN myxs = myxs + SIN(an1): myzs = myzs - COS(an1)\r
+\r
+' Handle keyboard input for speed multiplier\r
+IF a$ = "1" THEN myspd = .1\r
+IF a$ = "2" THEN myspd = 1\r
+IF a$ = "3" THEN myspd = 10\r
+IF a$ = "4" THEN myspd = 100\r
+IF a$ = "5" THEN myspd = 1000\r
+IF a$ = "6" THEN myspd = 10000\r
+IF a$ = "7" THEN myspd = 100000\r
+IF a$ = "8" THEN myspd = 1000000\r
+\r
+' Handle keyboard input for quitting the program\r
+IF a$ = "q" THEN SYSTEM\r
+\r
+' Handle keyboard input for recording script\r
+IF a$ = " " THEN\r
+ IF timerStartScript = 0 THEN\r
+ OPEN "script.dat" FOR OUTPUT AS #1\r
+ timerStartScript = TIMER\r
+ END IF\r
+ PRINT #1, TIMER - timerStartScript\r
+ PRINT #1, myx; myy; myz; an1; an2\r
+ SOUND 2000, .1\r
+END IF\r
+\r
+' Handle keyboard input for playing script\r
+IF a$ = "r" THEN\r
+ IF ScriptRunning = 0 THEN\r
+ timerinit\r
+ loadScript "script.dat"\r
+ ELSE\r
+ ScriptRunning = 0\r
+ END IF\r
+END IF\r
+\r
+' Friction to dampen movement speed over time\r
+myxs = myxs / 1.1\r
+myys = myys / 1.1\r
+myzs = myzs / 1.1\r
+\r
+' Update user position based on velocity and speed multiplier\r
+myx = myx + myxs * myspd\r
+myz = myz + myzs * myspd\r
+myy = myy + myys * myspd\r
+\r
+' Apply scripted movement if running\r
+IF ScriptRunning = 1 THEN\r
+ myx = timerCvalue(1)\r
+ myy = timerCvalue(2)\r
+ myz = timerCvalue(3)\r
+ an1 = timerCvalue(4)\r
+ an2 = timerCvalue(5)\r
+END IF\r
+\r
+END SUB\r
+\r
+SUB disp\r
+\r
+' Calculate sine and cosine for rotation\r
+s1 = SIN(an1)\r
+c1 = COS(an1)\r
+s2 = SIN(an2)\r
+c2 = COS(an2)\r
+\r
+' Initialize view distance\r
+vdn = 100000000\r
+\r
+' Loop through all stars to calculate their positions\r
+FOR a = 1 TO nump\r
+\r
+ ' Calculate star position relative to user\r
+ x = px(a) - myx\r
+ y = py(a) - myy\r
+ z = pz(a) - myz\r
+\r
+ ' Update view distance if star is closer\r
+ IF ABS(x) < vdn THEN\r
+ IF ABS(y) < vdn THEN\r
+ IF ABS(z) < vdn THEN vdn = SQR(x * x + y * y + z * z)\r
+ END IF\r
+ END IF\r
+\r
+ ' Rotate star position based on user orientation\r
+ x1 = x * c1 + z * s1\r
+ z1 = z * c1 - x * s1\r
+\r
+ y1 = y * c2 + z1 * s2\r
+ z2 = z1 * c2 - y * s2\r
+\r
+ ' Draw star if it is within view distance\r
+ IF z2 > 3 THEN\r
+ PSET (x1 / z2 * 130 + 160, y1 / z2 * 130 + 100), pc(a)\r
+ END IF\r
+\r
+NEXT a\r
+\r
+' Update average view distance\r
+vd = (vd * 5 + vdn) / 6\r
+\r
+END SUB\r
+\r
+SUB galacloud (rx, ry, rz)\r
+\r
+' Generate random cloud position\r
+a = INT(RND * 100)\r
+d = (a + 30) * 500\r
+\r
+x = d\r
+y = 0\r
+z = 0\r
+\r
+' Calculate sine and cosine for rotation\r
+a1 = SIN(a * (123.45 - (rx MOD 1235))) * 100\r
+a2 = SIN(a * 324 + (ry MOD 5431)) * 120\r
+\r
+s1 = SIN(a1)\r
+c1 = COS(a1)\r
+s2 = SIN(a2)\r
+c2 = COS(a2)\r
+\r
+' Rotate cloud position based on user orientation\r
+x1 = x * c1 + z * s1\r
+z1 = z * c1 - x * s1\r
+\r
+y1 = y * c2 + z1 * s2\r
+z2 = z1 * c2 - y * s2\r
+\r
+' Calculate distance from cloud to user\r
+fx = x1 + rx\r
+fy = y1 + ry\r
+fz = z2 + rz\r
+dist = gdist(fx, fy, fz)\r
+\r
+' Add cloud to galaxy list if within view distance\r
+IF dist < 20000 THEN\r
+ pl = INT(RND * 20)\r
+ oftGalaX(pl) = fx\r
+ oftGalaY(pl) = fy\r
+ oftGalaZ(pl) = fz\r
+ mkgalaxy fx, fy, fz\r
+ELSE\r
+ ' Add cloud to galaxy list if random or view distance is high\r
+ IF (RND * 100 < 10) OR (vd > 500000) THEN\r
+ mkgalaxy fx, fy, fz\r
+ END IF\r
+END IF\r
+\r
+END SUB\r
+\r
+FUNCTION gdist (x, y, z)\r
+' Calculate distance from user to given coordinates\r
+gdist = SQR((x - myx) ^ 2 + (y - myy) ^ 2 + (z - myz) ^ 2)\r
+\r
+END FUNCTION\r
+\r
+FUNCTION getbyte (addr)\r
+' Retrieve byte value at given RAM address\r
+getbyte = PEEK(extADDR + addr)\r
+\r
+END FUNCTION\r
+\r
+SUB getCloudXYZ (a, x1, y1, z2)\r
+\r
+d = a * 1000000\r
+\r
+x = d\r
+y = 0\r
+z = 0\r
+\r
+' Calculate sine and cosine for rotation\r
+a1 = SIN(a * 123) * 100\r
+a2 = SIN(a * 975) * 120\r
+\r
+s1 = SIN(a1)\r
+c1 = COS(a1)\r
+s2 = SIN(a2)\r
+c2 = COS(a2)\r
+\r
+' Rotate cloud position based on user orientation\r
+x1 = x * c1 + z * s1\r
+z1 = z * c1 - x * s1\r
+\r
+y1 = y * c2 + z1 * s2\r
+z2 = z1 * c2 - y * s2\r
+\r
+END SUB\r
+\r
+FUNCTION getword (addr)\r
+' Retrieve word value at given RAM address\r
+a = PEEK(extADDR + addr)\r
+b = PEEK(extADDR + addr + 1)\r
+\r
+c$ = HEX$(a)\r
+IF LEN(c$) = 1 THEN c$ = "0" + c$\r
+IF LEN(c$) = 0 THEN c$ = "00"\r
+\r
+c = VAL("&H" + HEX$(b) + c$)\r
+\r
+getword = c\r
+\r
+END FUNCTION\r
+\r
+SUB loadScript (scriptName$)\r
+' Load script from file and start playback\r
+ScriptRunning = 1\r
+rt = 2\r
+\r
+OPEN scriptName$ FOR INPUT AS #2\r
+\r
+5\r
+IF EOF(2) <> 0 THEN GOTO 6\r
+\r
+INPUT #2, t\r
+t = t / 2\r
+rt = rt + 6\r
+FOR a = 1 TO 5\r
+ INPUT #2, b\r
+ timerAdd a, rt, b\r
+NEXT a\r
+\r
+GOTO 5\r
+\r
+6\r
+CLOSE #2\r
+\r
+' Reset all timers to -1\r
+FOR a = 1 TO 5\r
+ timerAdd a, -1, b\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB mkgalaxy (lx, ly, lz)\r
+\r
+' Skip galaxy generation if position is zero\r
+IF (lx = 0) AND (ly = 0) AND (lz = 0) THEN GOTO 4\r
+\r
+' Generate random seed for galaxy\r
+rndp = ABS(lx + ly + lz) MOD 9000\r
+n1 = rn * 100\r
+n2 = rn * 100\r
+n3 = rn * 100\r
+\r
+' Calculate sine and cosine for rotation\r
+gs1 = SIN(n1)\r
+gc1 = COS(n1)\r
+gs2 = SIN(n2)\r
+gc2 = COS(n2)\r
+gs3 = SIN(n3)\r
+gc3 = COS(n3)\r
+\r
+' Calculate galaxy size and temperature\r
+siz = rn * 50 + 75\r
+pi = 3.14\r
+sbm = INT(rn * 3) + 1\r
+\r
+' Calculate distance from galaxy to user\r
+dist = gdist(lx, ly, lz)\r
+\r
+' Determine number of stars based on distance\r
+amo = 1\r
+IF dist < 20000 THEN amo = 1\r
+IF dist < 5000 THEN amo = 2\r
+IF dist < 1000 THEN amo = 10\r
+IF dist < 500 THEN amo = 50\r
+\r
+' Generate stars in galaxy\r
+FOR a = 1 TO amo\r
+\r
+ ' Calculate random values for star position\r
+ b = RND * 10\r
+ s = b * b / 30\r
+\r
+ v1 = RND * (11.5 - b) / 3\r
+ v1p = v1 / 2\r
+\r
+ ane = RND * (s / 2) / sbm * 2\r
+ sba = 2 * pi / sbm * INT(RND * sbm)\r
+\r
+ x = (SIN(b - sba + ane) * s + RND * v1 - v1p) * siz\r
+ z = (COS(b - sba + ane) * s + RND * v1 - v1p) * siz\r
+ y = (RND * v1 - v1p) * siz\r
+\r
+ ' Rotate star position based on galaxy orientation\r
+ x1 = x * gc1 + z * gs1\r
+ z1 = z * gc1 - x * gs1\r
+\r
+ y1 = y * gc2 + z1 * gs2\r
+ z2 = z1 * gc2 - y * gs2\r
+\r
+ y2 = y1 * gc3 + x1 * gs3\r
+ x2 = x1 * gc3 - y1 * gs3\r
+\r
+ ' Add star to universe\r
+ pla = INT(RND * nump) + 1\r
+\r
+ px(pla) = x2 + lx\r
+ py(pla) = y2 + ly\r
+ pz(pla) = z2 + lz\r
+ pc(pla) = INT(RND * 15) + 1\r
+\r
+NEXT a\r
+\r
+4\r
+END SUB\r
+\r
+SUB mkworld\r
+\r
+' Generate initial galaxy clusters\r
+FOR b = 1 TO 10\r
+ a = INT(RND * 100)\r
+ getCloudXYZ a, x, y, z\r
+\r
+ ' Add cloud to galaxy list if within view distance\r
+ IF gdist(x, y, z) < vd * 3 THEN oftcloud(INT(RND * 4)) = a\r
+\r
+ ' Generate galaxy cluster at cloud position\r
+ galacloud x, y, z\r
+NEXT b\r
+\r
+' Add additional galaxy clusters if view distance is high\r
+IF vd < 4000000 THEN\r
+ FOR b = 0 TO 3\r
+ a = oftcloud(b)\r
+ getCloudXYZ a, x, y, z\r
+\r
+ ' Generate galaxy cluster at cloud position\r
+ galacloud x, y, z\r
+ NEXT b\r
+END IF\r
+\r
+' Add galaxies to universe if view distance is low\r
+IF vd < 10000 THEN\r
+\r
+ FOR b = 0 TO 19\r
+ x = oftGalaX(b)\r
+ y = oftGalaY(b)\r
+ z = oftGalaZ(b)\r
+\r
+ ' Generate galaxy at given position\r
+ mkgalaxy x, y, z\r
+ NEXT b\r
+\r
+ELSE\r
+END IF\r
+\r
+END SUB\r
+\r
+SUB putbyte (addr, dat)\r
+\r
+' Store byte value at given RAM address\r
+POKE (extADDR + addr), dat\r
+\r
+END SUB\r
+\r
+SUB putword (addr, dat)\r
+\r
+' Store word value at given RAM address\r
+b$ = HEX$(dat)\r
+\r
+2\r
+IF LEN(b$) < 4 THEN b$ = "0" + b$: GOTO 2\r
+\r
+n1 = VAL("&H" + LEFT$(b$, 2))\r
+n2 = VAL("&H" + RIGHT$(b$, 2))\r
+\r
+POKE (extADDR + addr), n2\r
+POKE (extADDR + addr + 1), n1\r
+\r
+END SUB\r
+\r
+FUNCTION rn\r
+\r
+' Generate random number based on current index\r
+rndp = rndp + 1\r
+IF rndp > 10000 THEN rndp = 0\r
+rn = rndval(rndp)\r
+\r
+END FUNCTION\r
+\r
+SUB rndinit\r
+\r
+' Initialize random number array\r
+FOR a = 0 TO 10000\r
+ rndval(a) = RND\r
+NEXT a\r
+\r
+rndp = 0\r
+\r
+END SUB\r
+\r
+SUB start\r
+\r
+PRINT "Universe Explorer"\r
+PRINT "by Svjatoslav Agejenko, n0@hot.ee"\r
+PRINT "2003.12"\r
+PRINT\r
+\r
+PRINT "Use mouse to aim."\r
+PRINT "Use keys: a, s, d, w to move around,"\r
+PRINT "1 2 3 4 5 6 7 to change speed multiplier."\r
+PRINT "r - to start/stop demo."\r
+\r
+PRINT "right mouse button, to move UP <> DOWN."\r
+PRINT "both right & left mouse buttons pressed to move BACK <> FRONT."\r
+\r
+PRINT "At least P3 500 MHz, would be nice."\r
+PRINT "Better CPU, more details and higher framerate."\r
+PRINT "Requires mouse driver, and QBasic extension TSR"\r
+PRINT "to be loaded first."\r
+\r
+PRINT\r
+\r
+PRINT "In this program:"\r
+\r
+PRINT "Several stars, make up galaxy."\r
+PRINT "Several galaxies makes metagalaxy."\r
+PRINT "Several metagalaxies makes up universe."\r
+\r
+PRINT\r
+\r
+PRINT "Press Any key To Continue."\r
+a$ = INPUT$(1)\r
+\r
+startext\r
+\r
+SCREEN 7, , , 1\r
+\r
+maxmove = 50\r
+rndinit\r
+myspd = 1000000\r
+\r
+END SUB\r
+\r
+SUB startext\r
+\r
+' Read interrupt table to find QBasic extension TSR\r
+DEF SEG = 0\r
+\r
+extSEG = PEEK(&H79 * 4 + 3) * 256\r
+extSEG = extSEG + PEEK(&H79 * 4 + 2)\r
+\r
+PRINT "Segment is: " + HEX$(extSEG)\r
+\r
+extADDR = PEEK(&H79 * 4 + 1) * 256\r
+extADDR = extADDR + PEEK(&H79 * 4 + 0)\r
+\r
+PRINT "relative address is:"; extADDR\r
+\r
+DEF SEG = extSEG\r
+\r
+' Check if QBasic extension TSR is loaded\r
+IF getword(0) <> 1983 THEN\r
+ PRINT "FATAL ERROR: you must load"\r
+ PRINT "QBasic extension TSR first!"\r
+ SYSTEM\r
+END IF\r
+\r
+END SUB\r
+\r
+SUB timerAdd (element, time, value)\r
+\r
+' Add timer event to list\r
+FOR a = 0 TO 100\r
+ IF (timerTime(element, a) = 0) AND (timerValue(element, a) = 0) THEN GOTO timer3\r
+NEXT a\r
+timer3:\r
+\r
+timerTime(element, a) = time\r
+timerValue(element, a) = value\r
+\r
+END SUB\r
+\r
+SUB timerdisp\r
+LOCATE 1, 1\r
+\r
+' Display all active timers\r
+FOR a = 0 TO 10\r
+ PRINT timerCplace(a), timerCtime(a), timerCvalue(a)\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB timerinit\r
+\r
+' Initialize all timers to zero\r
+timerLast = TIMER\r
+\r
+FOR a = 1 TO 50\r
+ FOR b = 1 TO 100\r
+ timerTime(a, b) = 0\r
+ timerValue(a, b) = 0\r
+ NEXT b\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB timerprocess\r
+\r
+' Process all active timers\r
+timerCurrent = TIMER\r
+timerDiff = timerCurrent - timerLast\r
+timerLast = timerCurrent\r
+\r
+FOR a = 0 TO 50\r
+ ctim = timerCtime(a) + timerDiff\r
+ Cplace = timerCplace(a)\r
+timer2:\r
+ IF timerTime(a, Cplace + 1) = -1 THEN\r
+ ctim = 0\r
+ Cplace = 0\r
+ END IF\r
+ IF timerTime(a, Cplace + 1) < ctim THEN\r
+ IF timerTime(a, Cplace + 1) = 0 THEN\r
+ timerCvalue(a) = timerValue(a, Cplace)\r
+ GOTO timer1:\r
+ END IF\r
+ Cplace = Cplace + 1\r
+ GOTO timer2\r
+ END IF\r
+\r
+ v1 = timerValue(a, Cplace)\r
+ t1 = timerTime(a, Cplace)\r
+ v2 = timerValue(a, Cplace + 1)\r
+ t2 = timerTime(a, Cplace + 1)\r
+\r
+ ' Interpolate between two timer values\r
+ IF v1 = v2 THEN\r
+ timerCvalue(a) = v1\r
+ ELSE\r
+ Tdiff1 = t2 - t1\r
+ Tdiff2 = ctim - t1\r
+ Vdiff = v2 - v1\r
+ timerCvalue(a) = Tdiff2 / Tdiff1 * Vdiff + v1\r
+ END IF\r
+timer1:\r
+ timerCplace(a) = Cplace\r
+ timerCtime(a) = ctim\r
+NEXT a\r
+\r
+END SUB\r
--- /dev/null
+qbext\r
+qb /run expluniv.bas
\ No newline at end of file
--- /dev/null
+#+TITLE: Space themed 3D graphics
+#+LANGUAGE: en
+#+LATEX_HEADER: \usepackage[margin=1.0in]{geometry}
+#+LATEX_HEADER: \usepackage{parskip}
+#+LATEX_HEADER: \usepackage[none]{hyphenat}
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+ .flex-center {
+ display: flex; /* activate flexbox */
+ justify-content: center; /* horizontally center anything inside */
+ }
+
+ .flex-center video {
+ width: min(90%, 1000px); /* whichever is smaller wins */
+ height: auto; /* preserve aspect ratio */
+ }
+
+ .responsive-img {
+ width: min(100%, 1000px);
+ height: auto;
+ }
+</style>
+#+end_export
+
+* Galaxy explorer
+
+This QBasic program renders a navigable 3D point cloud galaxy,
+allowing users to explore a virtual galaxy using mouse or keyboard
+controls. The program creates a visually engaging simulation of a
+galaxy with stars distributed in a spiral pattern.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Galaxy%20explorer.bas][file:Galaxy%20explorer.png]]
+
+[[file:!.bas][Source code]]
+
+* Rocket simulator
+
+QBasic program that simulates the takeoff and flight of a rocket from
+the surface of a planet. This program provides a simple yet engaging
+3D visualization of a rocket's journey, allowing users to navigate and
+observe the rocket's trajectory from various angles.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="Rocket simulator.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:Rocket simulator.bas][Source code]]
+
+* Stars
+
+The 3D Starfield Simulation is a QBasic program that creates a
+visually captivating simulation of a starfield in three
+dimensions. This program is designed to render stars moving in space,
+giving the illusion of flying through a galaxy.
+
+How the Program Works:
+
+- Camera Rotation :: The camera's rotation is calculated to give a
+ dynamic view of the starfield.
+- Star Movement :: Each star's position is updated to simulate
+ movement through space. Stars that get too close to the viewer are
+ repositioned to the far distance to create an infinite starfield
+ effect.
+- Projection :: The 3D coordinates of each star are projected onto a
+ 2D screen using perspective projection, which scales the stars based
+ on their distance from the viewer.
+- Brightness and Color :: The brightness of each star is adjusted
+ based on its distance, with closer stars appearing brighter.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="Stars.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:Stars.bas][Source code]]
+
+* Universe explorer
+
+This QBasic program that simulates a navigable 3D universe. Users can
+freely fly through a dynamically generated universe composed of galaxy
+clusters, galaxies, and stars. The program employs a clever algorithm
+to manage the level of detail, dynamically increasing or decreasing
+the complexity of the universe regions based on the user's
+position. This ensures a reasonable quantity of stars is rendered at
+any given time, optimizing performance and visual experience.
+
+What's in it for the Reader?
+
+- Algorithm Insight :: The program provides a practical example of
+ dynamic level-of-detail algorithms, which can be useful for anyone
+ interested in computer graphics, game development, or simulation
+ programming.
+
+- 3D Navigation :: It demonstrates how to implement a 3D navigation
+ system using basic input devices like a mouse and keyboard, offering
+ insights into handling user inputs for movement and interaction in a
+ 3D space.
+
+- Procedural Generation :: The universe is procedurally generated,
+ showcasing how to create complex structures like galaxies and star
+ systems algorithmically.
+
+- Performance Optimization :: The program highlights techniques for
+ optimizing performance in resource-intensive applications, such as
+ limiting the number of rendered objects based on distance.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Universe%20explorer/Universe%20explorer.bas][file:Universe%20explorer/1.png]]
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Universe%20explorer/Universe%20explorer.bas][file:Universe%20explorer/2.png]]
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Universe%20explorer/Universe%20explorer.bas][file:Universe%20explorer/3.png]]
+
+[[file:!.bas][Source code]]
--- /dev/null
+DECLARE SUB createLongLine (x1!, y1!, z1!, x2!, y2!, z2!, c!)\r
+DECLARE SUB makeGrid (x1!, y1!, z1!, x2!, y2!, z2!)\r
+DECLARE SUB prn (a$, x!, y!, z!)\r
+DECLARE SUB fill4 ()\r
+DECLARE SUB loadObject (name$, x!, y!, z!)\r
+DECLARE SUB putChar (a$, x!, y!, z!)\r
+\r
+' 3D engine that can theoretically render infinite wireframe 3D worlds.\r
+' This is accomplished by partitioning world into cube shaped fragments.\r
+' Fragments are dynamically loaded into RAM and offloaded from RAM to disk\r
+' while user moves around in world.\r
+'\r
+' As a result, huge world can be stored on-disk while only necessary part of it\r
+' in close proximity is kept in limited RAM.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Note: This program requires special Terminate and Stay Resident (TSR) mouse driver\r
+' to be loaded *before* starting the current QBasic program itself.\r
+' Here you can read about TSR mouse driver and download needed qbext.com binary:\r
+' https://www3.svjatoslav.eu/projects/qbasicapps/Miscellaneous/Mouse%20driver/index.html\r
+'\r
+' Changelog:\r
+' 2004.1 - Initial version\r
+' 2025 - Improved program readability\r
+\r
+DECLARE SUB fill3 ()\r
+DECLARE SUB fill1 ()\r
+DECLARE SUB fill2 ()\r
+DECLARE SUB addMsg (a$)\r
+DECLARE SUB dispmsg ()\r
+DECLARE SUB loadArea (tx1!, ty1!, tz1!, tx2!, ty2!, tz2!)\r
+DECLARE SUB loadCluster (x!, y!, z!)\r
+DECLARE SUB checkVisibility ()\r
+DECLARE SUB decVisibility ()\r
+DECLARE SUB applyBounds ()\r
+DECLARE SUB clearWorld ()\r
+DECLARE SUB createNewLine (x1!, y1!, z1!, x2!, y2!, z2!, c!)\r
+DECLARE SUB createWorld ()\r
+DECLARE FUNCTION getClustName$ (a!, b!, c!)\r
+DECLARE FUNCTION toStr$ (a!)\r
+\r
+DECLARE SUB insertLine (x1!, y1!, z1!, x2!, y2!, z2!, c!)\r
+DECLARE SUB startext ()\r
+DECLARE SUB control ()\r
+DECLARE SUB putbyte (addr!, dat!)\r
+DECLARE SUB putword (addr!, dat!)\r
+DECLARE FUNCTION getword! (addr!)\r
+DECLARE FUNCTION getbyte! (addr!)\r
+DECLARE SUB start ()\r
+DECLARE SUB render ()\r
+\r
+\r
+DIM SHARED an1, an2\r
+\r
+DIM SHARED extSEG, extADDR\r
+DIM SHARED buttL, buttR\r
+DIM SHARED maxmove\r
+\r
+DIM SHARED linAmo\r
+linAmo = 5000\r
+\r
+DIM SHARED linX1(0 TO linAmo) AS INTEGER\r
+DIM SHARED linY1(0 TO linAmo) AS INTEGER\r
+DIM SHARED linZ1(0 TO linAmo) AS INTEGER\r
+DIM SHARED linX2(0 TO linAmo) AS INTEGER\r
+DIM SHARED linY2(0 TO linAmo) AS INTEGER\r
+DIM SHARED linZ2(0 TO linAmo) AS INTEGER\r
+DIM SHARED linC(0 TO linAmo) AS INTEGER\r
+\r
+DIM SHARED myx, myy, myz\r
+DIM SHARED myxs, myys, myzs\r
+\r
+DIM SHARED curFreeLine\r
+DIM SHARED worldSize\r
+\r
+DIM SHARED usedLines\r
+DIM SHARED desMaxLines\r
+\r
+DIM SHARED visMaxX, visMaxY, visMaxZ\r
+DIM SHARED visMinX, visMinY, visMinZ\r
+\r
+DIM SHARED visDist\r
+DIM SHARED msgs$(1 TO 10)\r
+DIM SHARED frm\r
+\r
+\r
+'DIM SHARED blkData(1 TO 50) AS STRING * 512\r
+'DIM SHARED blkFrag(1 TO 50) AS STRING * 512\r
+\r
+\r
+\r
+\r
+nl = 0\r
+np = 0\r
+\r
+start\r
+\r
+\r
+cx = 0\r
+cy = 0\r
+cz = 0\r
+\r
+np = 1\r
+px(1) = 0\r
+py(1) = 0\r
+pz(1) = 0\r
+\r
+makeGrid -400, -400, -400, 400, 400, 400\r
+\r
+1\r
+frm = frm + 1\r
+\r
+'fill1\r
+fill2\r
+fill3\r
+fill4\r
+\r
+\r
+control\r
+\r
+render\r
+\r
+LOCATE 1, 1\r
+PRINT usedLines, visDist\r
+\r
+checkVisibility\r
+\r
+PCOPY 0, 1\r
+CLS\r
+GOTO 1\r
+\r
+SUB addMsg (a$)\r
+\r
+FOR a = 1 TO 9\r
+ msgs$(a) = msgs$(a + 1)\r
+NEXT a\r
+\r
+msgs$(10) = a$\r
+END SUB\r
+\r
+SUB applyBounds\r
+\r
+FOR a = 0 TO linAmo\r
+ IF linC(a) > 0 THEN\r
+\r
+\r
+ cx = (linX1(a) + linX2(a)) / 2\r
+ cy = (linY1(a) + linY2(a)) / 2\r
+ cz = (linZ1(a) + linZ2(a)) / 2\r
+ \r
+ clx = INT(cx / 100)\r
+ cly = INT(cy / 100)\r
+ clz = INT(cz / 100)\r
+\r
+ IF clx > visMaxX THEN GOTO 8\r
+ IF clx < visMinX THEN GOTO 8\r
+ \r
+ IF cly > visMaxY THEN GOTO 8\r
+ IF cly < visMinY THEN GOTO 8\r
+\r
+ IF clz > visMaxZ THEN GOTO 8\r
+ IF clz < visMinZ THEN GOTO 8\r
+\r
+ GOTO 7\r
+8 linC(a) = -1\r
+ usedLines = usedLines - 1\r
+ END IF\r
+7\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB checkVisibility\r
+\r
+'DIM SHARED visMaxX, visMaxY, visMaxZ\r
+'DIM SHARED visMinX, visMinY, visMinZ\r
+\r
+\r
+mx = INT(myx / 100)\r
+my = INT(myy / 100)\r
+mz = INT(myz / 100)\r
+\r
+\r
+IF mx + visDist > visMaxX THEN\r
+ newX = mx + visDist\r
+ loadArea visMaxX + 1, visMinY, visMinZ, newX, visMaxY, visMaxZ\r
+ visMaxX = newX\r
+ LOCATE 1, 30\r
+ PRINT "1"\r
+END IF\r
+IF mx - visDist < visMinX THEN\r
+ newX = mx - visDist\r
+ loadArea visMinX - 1, visMinY, visMinZ, newX, visMaxY, visMaxZ\r
+ visMinX = newX\r
+ LOCATE 1, 30\r
+ PRINT "2"\r
+END IF\r
+\r
+\r
+IF my + visDist > visMaxY THEN\r
+ newY = my + visDist\r
+ loadArea visMinX, visMaxY + 1, visMinZ, visMaxX, newY, visMaxZ\r
+ visMaxY = newY\r
+ LOCATE 1, 30\r
+ PRINT "3"\r
+END IF\r
+IF my - visDist < visMinY THEN\r
+ newY = my - visDist\r
+ loadArea visMinX, visMinY - 1, visMinZ, visMaxX, newY, visMaxZ\r
+ visMinY = newY\r
+ LOCATE 1, 30\r
+ PRINT "4"\r
+END IF\r
+\r
+\r
+IF mz + visDist > visMaxZ THEN\r
+ newZ = mz + visDist\r
+ loadArea visMinX, visMinY, visMaxZ + 1, visMaxX, visMaxY, newZ\r
+ visMaxZ = newZ\r
+ LOCATE 1, 30\r
+ PRINT "5"\r
+END IF\r
+IF mz - visDist < visMinZ THEN\r
+ newZ = mz - visDist\r
+ loadArea visMinX, visMinY, visMinZ - 1, visMaxX, visMaxY, newZ\r
+ visMinZ = newZ\r
+ LOCATE 1, 30\r
+ PRINT "6"\r
+END IF\r
+\r
+\r
+IF usedLines > desMaxLines THEN decVisibility\r
+\r
+END SUB\r
+\r
+SUB clearWorld\r
+\r
+\r
+CHDIR "world"\r
+\r
+FOR x = -worldSize TO worldSize\r
+\r
+ n$ = "X" + toStr$(x)\r
+ CHDIR n$\r
+\r
+ FOR y = -worldSize TO worldSize\r
+\r
+ n2$ = "Y" + toStr$(y)\r
+ CHDIR n2$\r
+\r
+ PRINT x, y\r
+ FOR z = -worldSize TO worldSize\r
+\r
+ n3$ = "z" + toStr$(z) + ".dat"\r
+ OPEN n3$ FOR OUTPUT AS #1\r
+' PRINT #1, "0"\r
+ CLOSE #1\r
+ NEXT z\r
+\r
+ CHDIR ".."\r
+ NEXT y\r
+\r
+ CHDIR ".."\r
+NEXT x\r
+\r
+CHDIR ".."\r
+\r
+END SUB\r
+\r
+SUB control\r
+\r
+\r
+IF getbyte(8) <> 0 THEN\r
+ putbyte 8, 0\r
+ xp = getword(2)\r
+ putword 2, 0\r
+ yp = getword(4)\r
+ putword 4, 0\r
+ butt = getword(6)\r
+ putword 6, 0\r
+ buttL = 0\r
+ buttR = 0\r
+ IF butt = 1 THEN buttL = 1\r
+ IF butt = 2 THEN buttR = 1\r
+ IF butt = 3 THEN buttL = 1: buttR = 1\r
+\r
+\r
+ IF buttR = 1 THEN\r
+ IF buttL = 1 THEN\r
+ myxs = myxs + SIN(an1) * yp / 4\r
+ myzs = myzs - COS(an1) * yp / 4\r
+ GOTO 3\r
+ END IF\r
+ myys = myys + yp / 4\r
+3\r
+ yp = 0\r
+ END IF\r
+\r
+END IF\r
+\r
+\r
+\r
+\r
+IF xp < -maxmove THEN xp = -maxmove\r
+IF xp > maxmove THEN xp = maxmove\r
+an1 = an1 - xp / 150\r
+\r
+IF yp < -maxmove THEN yp = -maxmove\r
+IF yp > maxmove THEN yp = maxmove\r
+an2 = an2 - yp / 150\r
+\r
+\r
+\r
+a$ = INKEY$\r
+\r
+IF a$ = "a" THEN myxs = myxs - COS(an1): myzs = myzs - SIN(an1)\r
+IF a$ = "d" THEN myxs = myxs + COS(an1): myzs = myzs + SIN(an1)\r
+IF a$ = "w" THEN myxs = myxs - SIN(an1): myzs = myzs + COS(an1)\r
+IF a$ = "s" THEN myxs = myxs + SIN(an1): myzs = myzs - COS(an1)\r
+IF a$ = "q" THEN SYSTEM\r
+\r
+myxs = myxs / 1.1\r
+myys = myys / 1.1\r
+myzs = myzs / 1.1\r
+\r
+myx = myx + myxs\r
+myz = myz + myzs\r
+myy = myy + myys\r
+\r
+END SUB\r
+\r
+SUB createLongLine (x1, y1, z1, x2, y2, z2, c)\r
+d = SQR((x1 - x2) ^ 2 + (y1 - y2) ^ 2 + (z1 - z2) ^ 2)\r
+\r
+IF d < 100 THEN\r
+ createNewLine x1, y1, z1, x2, y2, z2, c\r
+ELSE\r
+ xp = (x1 + x2) / 2\r
+ yp = (y1 + y2) / 2\r
+ zp = (z1 + z2) / 2\r
+ createLongLine x1, y1, z1, xp, yp, zp, c\r
+ createLongLine xp, yp, zp, x2, y2, z2, c\r
+END IF\r
+END SUB\r
+\r
+SUB createNewLine (x1, y1, z1, x2, y2, z2, c)\r
+\r
+cx = (x1 + x2) / 2\r
+cy = (y1 + y2) / 2\r
+cz = (z1 + z2) / 2\r
+\r
+clx = INT(cx / 100)\r
+cly = INT(cy / 100)\r
+clz = INT(cz / 100)\r
+\r
+IF clx >= visMinX THEN\r
+ IF clx <= visMaxX THEN\r
+ IF cly >= visMinY THEN\r
+ IF cly <= visMaxY THEN\r
+ IF clz >= visMinZ THEN\r
+ IF clz <= visMaxZ THEN\r
+ insertLine x1, y1, z1, x2, y2, z2, c\r
+ END IF\r
+ END IF\r
+ END IF\r
+ END IF\r
+ END IF\r
+END IF\r
+\r
+cln$ = getClustName(clx, cly, clz)\r
+\r
+' PRINT "Cluster name:" + cln$\r
+OPEN cln$ FOR APPEND AS #1\r
+ PRINT #1, x1; y1; z1; x2; y2; z2; c\r
+CLOSE #1\r
+\r
+END SUB\r
+\r
+SUB createWorld\r
+\r
+\r
+\r
+CHDIR "world"\r
+\r
+FOR x = -worldSize TO worldSize\r
+ \r
+ n$ = "X" + toStr$(x)\r
+ MKDIR n$\r
+ CHDIR n$\r
+\r
+ FOR y = -worldSize TO worldSize\r
+\r
+ n2$ = "Y" + toStr$(y)\r
+ MKDIR n2$\r
+ CHDIR n2$\r
+\r
+ PRINT x, y\r
+ FOR z = -worldSize TO worldSize\r
+\r
+ n3$ = "z" + toStr$(z) + ".dat"\r
+ OPEN n3$ FOR OUTPUT AS #1\r
+' PRINT #1, "0"\r
+ CLOSE #1\r
+ NEXT z\r
+\r
+ CHDIR ".."\r
+ NEXT y\r
+\r
+ CHDIR ".."\r
+NEXT x\r
+\r
+CHDIR ".."\r
+\r
+END SUB\r
+\r
+SUB decVisibility\r
+\r
+mx = INT(myx / 100)\r
+my = INT(myy / 100)\r
+mz = INT(myz / 100)\r
+\r
+6\r
+de = 0\r
+\r
+IF visMaxX > mx + visDist THEN\r
+ visMaxX = mx + visDist\r
+ de = 1\r
+END IF\r
+\r
+IF visMinX < mx - visDist THEN\r
+ visMinX = mx - visDist\r
+ de = 1\r
+END IF\r
+\r
+\r
+IF visMaxY > my + visDist THEN\r
+ visMaxY = my + visDist\r
+ de = 1\r
+END IF\r
+\r
+IF visMinY < my - visDist THEN\r
+ visMinY = my - visDist\r
+ de = 1\r
+END IF\r
+\r
+\r
+IF visMaxZ > mz + visDist THEN\r
+ visMaxZ = mz + visDist\r
+ de = 1\r
+END IF\r
+\r
+IF visMinZ < mz - visDist THEN\r
+ visMinZ = mz - visDist\r
+ de = 1\r
+END IF\r
+\r
+IF de = 0 THEN\r
+ IF visDist > 3 THEN visDist = visDist - 1: GOTO 6\r
+ELSE\r
+ addMsg "Visibility decareased"\r
+END IF\r
+\r
+\r
+applyBounds\r
+END SUB\r
+\r
+SUB dispmsg\r
+FOR a = 1 TO 10\r
+ LOCATE a, 39 - LEN(msgs$(a))\r
+ PRINT msgs$(a)\r
+NEXT a\r
+END SUB\r
+\r
+SUB fill1\r
+\r
+x1 = RND * 800 - 400\r
+y1 = RND * 800 - 400\r
+z1 = RND * 800 - 400\r
+\r
+x2 = x1 + RND * 20\r
+y2 = y1 + RND * 20\r
+z2 = z1 + RND * 20\r
+\r
+createNewLine x1, y1, z1, x2, y2, z2, INT(RND * 15) + 1\r
+\r
+END SUB\r
+\r
+SUB fill2\r
+\r
+\r
+frmt = frm * 15\r
+\r
+x1 = SIN(frmt / 533) * 300 + SIN(frmt / 53) * 50\r
+y1 = COS(frmt / 422) * 300 + SIN(frmt / 31) * 20\r
+z1 = SIN(frmt / 133) * 300 + SIN(frmt / 39) * 60\r
+\r
+frmt = (frm - 1) * 15\r
+\r
+x2 = SIN(frmt / 533) * 300 + SIN(frmt / 53) * 50\r
+y2 = COS(frmt / 422) * 300 + SIN(frmt / 31) * 20\r
+z2 = SIN(frmt / 133) * 300 + SIN(frmt / 39) * 60\r
+\r
+\r
+\r
+createNewLine x1, y1, z1, x2, y2, z2, INT(RND * 15) + 1\r
+\r
+END SUB\r
+\r
+SUB fill3\r
+\r
+IF frm / 10 = frm \ 10 THEN ELSE GOTO fill31\r
+\r
+c = RND * 15 + 1\r
+\r
+x = RND * 800 - 400\r
+y = RND * 800 - 400\r
+z = RND * 800 - 400\r
+\r
+s = RND * 10 + 3\r
+\r
+createNewLine x - s, y - s, z - s, x + s, y - s, z - s, c\r
+createNewLine x + s, y - s, z - s, x + s, y + s, z - s, c\r
+createNewLine x + s, y + s, z - s, x - s, y + s, z - s, c\r
+createNewLine x - s, y + s, z - s, x - s, y - s, z - s, c\r
+\r
+createNewLine x - s, y - s, z + s, x + s, y - s, z + s, c\r
+createNewLine x + s, y - s, z + s, x + s, y + s, z + s, c\r
+createNewLine x + s, y + s, z + s, x - s, y + s, z + s, c\r
+createNewLine x - s, y + s, z + s, x - s, y - s, z + s, c\r
+\r
+createNewLine x - s, y - s, z - s, x - s, y - s, z + s, c\r
+createNewLine x + s, y - s, z - s, x + s, y - s, z + s, c\r
+createNewLine x + s, y + s, z - s, x + s, y + s, z + s, c\r
+createNewLine x - s, y + s, z - s, x - s, y + s, z + s, c\r
+\r
+xo = x\r
+yo = y\r
+zo = z\r
+\r
+\r
+x = x + RND * 80 - 40\r
+y = y + RND * 80 - 40\r
+z = z + RND * 80 - 40\r
+\r
+s = RND * 10 + 3\r
+\r
+createNewLine x - s, y - s, z - s, x + s, y - s, z - s, c\r
+createNewLine x + s, y - s, z - s, x + s, y + s, z - s, c\r
+createNewLine x + s, y + s, z - s, x - s, y + s, z - s, c\r
+createNewLine x - s, y + s, z - s, x - s, y - s, z - s, c\r
+\r
+createNewLine x - s, y - s, z + s, x + s, y - s, z + s, c\r
+createNewLine x + s, y - s, z + s, x + s, y + s, z + s, c\r
+createNewLine x + s, y + s, z + s, x - s, y + s, z + s, c\r
+createNewLine x - s, y + s, z + s, x - s, y - s, z + s, c\r
+\r
+createNewLine x - s, y - s, z - s, x - s, y - s, z + s, c\r
+createNewLine x + s, y - s, z - s, x + s, y - s, z + s, c\r
+createNewLine x + s, y + s, z - s, x + s, y + s, z + s, c\r
+createNewLine x - s, y + s, z - s, x - s, y + s, z + s, c\r
+\r
+\r
+createNewLine x, y, z, xo, yo, zo, c\r
+\r
+fill31:\r
+END SUB\r
+\r
+SUB fill4\r
+IF RND * 100 < 2 THEN\r
+\r
+b$ = ""\r
+FOR a = 1 TO RND * 3 + 1\r
+b$ = b$ + CHR$(48 + RND * 9)\r
+NEXT a\r
+\r
+'b$ = "Hello, world!"\r
+prn b$, RND * 800 - 400, RND * 800 - 400, RND * 800 - 400\r
+\r
+END IF\r
+END SUB\r
+\r
+FUNCTION getbyte (addr)\r
+getbyte = PEEK(extADDR + addr)\r
+END FUNCTION\r
+\r
+FUNCTION getClustName$ (a, b, c)\r
+\r
+getClustName$ = "WORLD\X" + toStr$(a) + "\Y" + toStr$(b) + "\Z" + toStr$(c) + ".DAT"\r
+\r
+END FUNCTION\r
+\r
+FUNCTION getword (addr)\r
+a = PEEK(extADDR + addr)\r
+b = PEEK(extADDR + addr + 1)\r
+\r
+\r
+c$ = HEX$(a)\r
+IF LEN(c$) = 1 THEN c$ = "0" + c$\r
+IF LEN(c$) = 0 THEN c$ = "00"\r
+\r
+\r
+c = VAL("&H" + HEX$(b) + c$)\r
+\r
+getword = c\r
+END FUNCTION\r
+\r
+SUB importCluster (x, y, z)\r
+\r
+cln$ = getClustName(x, y, z)\r
+'[PRINT cln$\r
+\r
+OPEN cln$ FOR INPUT AS #1\r
+5\r
+IF EOF(1) <> 0 THEN GOTO 4\r
+ \r
+INPUT #1, x1, y1, z1, x2, y2, z2, c\r
+insertLine x1, y1, z1, x2, y2, z2, c\r
+\r
+GOTO 5\r
+4\r
+CLOSE #1\r
+\r
+\r
+END SUB\r
+\r
+SUB insertLine (x1, y1, z1, x2, y2, z2, c)\r
+\r
+insertLine1:\r
+IF linC(curFreeLine) = -1 THEN\r
+ linX1(curFreeLine) = x1\r
+ linY1(curFreeLine) = y1\r
+ linZ1(curFreeLine) = z1\r
+\r
+ linX2(curFreeLine) = x2\r
+ linY2(curFreeLine) = y2\r
+ linZ2(curFreeLine) = z2\r
+ \r
+ linC(curFreeLine) = c\r
+ curFreeLine = curFreeLine + 1\r
+ usedLines = usedLines + 1\r
+ IF curFreeLine > linAmo THEN curFreeLine = 0\r
+ELSE\r
+ curFreeLine = curFreeLine + 1\r
+ IF curFreeLine > linAmo THEN curFreeLine = 0\r
+ GOTO insertLine1\r
+END IF\r
+\r
+\r
+END SUB\r
+\r
+SUB loadArea (tx1, ty1, tz1, tx2, ty2, tz2)\r
+\r
+LOCATE 3, 1\r
+addMsg "Loading Area!"\r
+addMsg toStr$(tx1) + " " + toStr$(ty1) + " " + toStr$(tz1)\r
+addMsg toStr$(tx2) + " " + toStr$(ty2) + " " + toStr$(tz2)\r
+\r
+\r
+'PCOPY 0, 1\r
+'SLEEP\r
+\r
+x1 = tx1\r
+x2 = tx2\r
+\r
+y1 = ty1\r
+y2 = ty2\r
+\r
+z1 = tz1\r
+z2 = tz2\r
+\r
+IF x1 > x2 THEN SWAP x1, x2\r
+IF y1 > y2 THEN SWAP y1, y2\r
+IF z1 > z2 THEN SWAP z1, z2\r
+\r
+FOR x = x1 TO x2\r
+ FOR y = y1 TO y2\r
+ FOR z = z1 TO z2\r
+ loadCluster x, y, z\r
+ NEXT z\r
+ NEXT y\r
+NEXT x\r
+\r
+END SUB\r
+\r
+SUB loadCluster (x, y, z)\r
+\r
+IF ABS(x) > worldSize THEN GOTO 11\r
+IF ABS(y) > worldSize THEN GOTO 11\r
+IF ABS(z) > worldSize THEN GOTO 11\r
+\r
+cln$ = getClustName(x, y, z)\r
+\r
+OPEN cln$ FOR INPUT AS #1\r
+10\r
+IF EOF(1) <> 0 THEN GOTO 9\r
+\r
+INPUT #1, x1, y1, z1, x2, y2, z2, c\r
+insertLine x1, y1, z1, x2, y2, z2, c\r
+\r
+GOTO 10\r
+9\r
+CLOSE #1\r
+\r
+11\r
+\r
+END SUB\r
+\r
+SUB loadObject (name$, x, y, z)\r
+\r
+'SCREEN 13\r
+'PRINT "objects\" + name$ + ".3d"\r
+'END\r
+\r
+OPEN "OBJECTS\" + name$ + ".3d" FOR INPUT AS #2\r
+13\r
+IF EOF(2) <> 0 THEN GOTO 12\r
+INPUT #2, x1, y1, z1, x2, y2, z2, co\r
+createNewLine x1 + x, y1 + y, z1 + z, x2 + x, y2 + y, z2 + z, co\r
+GOTO 13\r
+12\r
+CLOSE #2\r
+\r
+END SUB\r
+\r
+SUB makeGrid (x1, y1, z1, x2, y2, z2)\r
+\r
+s = 100\r
+\r
+FOR x = x1 TO x2 STEP s\r
+ FOR y = y1 TO y2 STEP s\r
+ createLongLine x1, y, x, x2, y, x, 1\r
+ createLongLine x, y1, y, x, y2, y, 1\r
+ createLongLine x, y, z1, x, y, z2, 1\r
+ NEXT y\r
+NEXT x\r
+\r
+END SUB\r
+\r
+SUB mousedemo\r
+\r
+\r
+\r
+cx = 150\r
+cy = 100\r
+maxmove = 50\r
+100\r
+frm = frm + 1\r
+\r
+\r
+LOCATE 1, 1\r
+PRINT cx, cy\r
+PRINT frm\r
+\r
+CIRCLE (cx, cy), 10, 0\r
+xp = getword(2)\r
+putword 2, 0\r
+yp = getword(4)\r
+putword 4, 0\r
+\r
+\r
+IF xp < -maxmove THEN xp = -maxmove\r
+IF xp > maxmove THEN xp = maxmove\r
+cx = cx + xp\r
+\r
+IF yp < -maxmove THEN yp = -maxmove\r
+IF yp > maxmove THEN yp = maxmove\r
+cy = cy + yp\r
+\r
+\r
+CIRCLE (cx, cy), 10, 10\r
+\r
+\r
+\r
+SOUND 0, .05\r
+GOTO 100\r
+\r
+\r
+END SUB\r
+\r
+SUB prn (a$, x, y, z)\r
+\r
+FOR a = 1 TO LEN(a$)\r
+ b$ = RIGHT$(LEFT$(a$, a), 1)\r
+ putChar b$, x + (a - 1) * 8, y, z\r
+NEXT a\r
+END SUB\r
+\r
+SUB putbyte (addr, dat)\r
+\r
+POKE (extADDR + addr), dat\r
+END SUB\r
+\r
+SUB putChar (a$, x, y, z)\r
+\r
+n$ = "FONT\LTR" + toStr(ASC(a$))\r
+loadObject n$, x, y, z\r
+\r
+END SUB\r
+\r
+SUB putword (addr, dat)\r
+\r
+b$ = HEX$(dat)\r
+\r
+2\r
+IF LEN(b$) < 4 THEN b$ = "0" + b$: GOTO 2\r
+\r
+n1 = VAL("&H" + LEFT$(b$, 2))\r
+n2 = VAL("&H" + RIGHT$(b$, 2))\r
+\r
+\r
+POKE (extADDR + addr), n2\r
+POKE (extADDR + addr + 1), n1\r
+\r
+END SUB\r
+\r
+SUB render\r
+\r
+s1 = SIN(an1)\r
+c1 = COS(an1)\r
+\r
+s2 = SIN(an2)\r
+c2 = COS(an2)\r
+\r
+\r
+FOR a = 0 TO linAmo\r
+\r
+ IF linC(a) > 0 THEN\r
+ x11 = linX1(a) - myx\r
+ y11 = linY1(a) - myy\r
+ z11 = linZ1(a) - myz\r
+ \r
+ x21 = linX2(a) - myx\r
+ y21 = linY2(a) - myy\r
+ z21 = linZ2(a) - myz\r
+\r
+\r
+ x12 = x11 * c1 + z11 * s1\r
+ z12 = z11 * c1 - x11 * s1\r
+\r
+\r
+ y12 = y11 * c2 + z12 * s2\r
+ z13 = z12 * c2 - y11 * s2\r
+\r
+\r
+ IF z13 > 3 THEN\r
+ x22 = x21 * c1 + z21 * s1\r
+ z22 = z21 * c1 - x21 * s1\r
+\r
+\r
+ y22 = y21 * c2 + z22 * s2\r
+ z23 = z22 * c2 - y21 * s2\r
+\r
+\r
+ IF z23 > 3 THEN\r
+ \r
+ rx1 = x12 / z13 * 130 + 160\r
+ ry1 = y12 / z13 * 130 + 100\r
+ \r
+ rx2 = x22 / z23 * 130 + 160\r
+ ry2 = y22 / z23 * 130 + 100\r
+ \r
+ LINE (rx1, ry1)-(rx2, ry2), linC(a)\r
+ END IF\r
+ END IF\r
+ END IF\r
+NEXT a\r
+\r
+\r
+'dispmsg\r
+\r
+END SUB\r
+\r
+SUB start\r
+\r
+RANDOMIZE TIMER\r
+\r
+FOR a = 0 TO linAmo\r
+ linC(a) = -1\r
+NEXT a\r
+\r
+\r
+startext\r
+\r
+maxmove = 50\r
+curFreeLine = 0\r
+worldSize = 5\r
+usedLines = 0\r
+desMaxLines = 2000\r
+\r
+visMaxX = worldSize\r
+visMaxY = worldSize\r
+visMaxZ = worldSize\r
+visMinX = -worldSize\r
+visMinY = -worldSize\r
+visMinZ = -worldSize\r
+\r
+visDist = worldSize\r
+\r
+createWorld\r
+\r
+SCREEN 7, , , 1\r
+\r
+\r
+\r
+END SUB\r
+\r
+SUB startext\r
+\r
+DEF SEG = 0 ' read first from interrupt table\r
+\r
+extSEG = PEEK(&H79 * 4 + 3) * 256\r
+extSEG = extSEG + PEEK(&H79 * 4 + 2)\r
+\r
+PRINT "Segment is: " + HEX$(extSEG)\r
+\r
+extADDR = PEEK(&H79 * 4 + 1) * 256\r
+extADDR = extADDR + PEEK(&H79 * 4 + 0)\r
+\r
+PRINT "relative address is:"; extADDR\r
+\r
+DEF SEG = extSEG\r
+\r
+IF getword(0) <> 1983 THEN\r
+ PRINT "FATAL ERROR: you must load"\r
+ PRINT "QBasic extension TSR first!"\r
+ SYSTEM\r
+END IF\r
+\r
+END SUB\r
+\r
+FUNCTION toStr$ (a)\r
+\r
+b$ = STR$(a)\r
+IF LEFT$(b$, 1) = " " THEN b$ = RIGHT$(b$, LEN(b$) - 1)\r
+toStr$ = b$\r
+\r
+END FUNCTION\r
+\r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 3 0 2 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
--- /dev/null
+ 2 3 0 2 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 2 8 0 2 9 0 10 \r
+ 7 8 0 7 9 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 2 9 0 3 9 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
--- /dev/null
+ 5 1 0 5 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 2 8 0 2 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 9 0 3 9 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 8 0 7 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
--- /dev/null
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 3 0 2 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 1 8 0 1 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 1 9 0 2 9 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 9 0 3 9 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 2 3 0 2 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 8 0 8 8 0 10 \r
+ 7 9 0 8 9 0 10 \r
--- /dev/null
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
--- /dev/null
+ 2 3 0 2 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 5 0 8 5 0 10 \r
--- /dev/null
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 2 8 0 2 9 0 10 \r
+ 7 8 0 7 9 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 2 9 0 3 9 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 3 0 1 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 8 0 7 8 0 10 \r
--- /dev/null
+ 5 1 0 5 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 8 0 6 8 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
--- /dev/null
+ 4 2 0 4 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 2 8 0 2 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 9 0 3 9 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
--- /dev/null
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 5 1 0 5 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 3 0 2 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 5 1 0 5 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 1 2 0 1 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 2 0 1 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 2 8 0 2 9 0 10 \r
+ 7 8 0 7 9 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 2 9 0 3 9 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 9 1 0 9 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 8 1 0 9 1 0 10 \r
+ 8 2 0 9 2 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 5 1 0 5 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 2 8 0 2 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 9 0 3 9 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
--- /dev/null
+ 5 1 0 5 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
--- /dev/null
+ 5 2 0 5 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 5 2 0 5 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 2 0 1 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 2 4 0 2 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
--- /dev/null
+ 2 4 0 2 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 7 0 7 7 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
+ 7 9 0 8 9 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 7 8 0 7 9 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 7 0 7 7 0 10 \r
--- /dev/null
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 8 0 1 9 0 10 \r
+ 2 8 0 2 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 1 9 0 2 9 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 9 1 0 9 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 9 7 0 9 8 0 10 \r
+ 1 8 0 1 9 0 10 \r
+ 2 8 0 2 9 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 7 8 0 7 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 1 9 0 2 9 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
+ 7 9 0 8 9 0 10 \r
+ 8 1 0 9 1 0 10 \r
+ 8 2 0 9 2 0 10 \r
+ 8 3 0 9 3 0 10 \r
+ 8 4 0 9 4 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
+ 8 7 0 9 7 0 10 \r
+ 8 8 0 9 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 9 1 0 9 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 9 2 0 9 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 9 4 0 9 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 9 6 0 9 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 9 7 0 9 8 0 10 \r
+ 2 8 0 2 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 9 8 0 9 9 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 9 0 3 9 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
+ 7 9 0 8 9 0 10 \r
+ 8 1 0 9 1 0 10 \r
+ 8 9 0 9 9 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 9 0 6 9 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 9 0 6 9 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 9 0 6 9 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 9 0 8 9 0 10 \r
--- /dev/null
+ 1 5 0 1 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 9 0 8 9 0 10 \r
--- /dev/null
+ 1 3 0 1 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 9 0 6 9 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 9 0 8 9 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 9 0 8 9 0 10 \r
--- /dev/null
+ 1 3 0 1 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 9 0 8 9 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 6 0 6 6 0 10 \r
--- /dev/null
+ 1 5 0 1 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 9 0 6 9 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 1 5 0 1 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 1 5 0 1 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 3 0 9 3 0 10 \r
+ 8 4 0 9 4 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 9 0 8 9 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 3 0 9 3 0 10 \r
+ 8 4 0 9 4 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 3 3 0 3 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 9 0 8 9 0 10 \r
+ 8 3 0 9 3 0 10 \r
+ 8 4 0 9 4 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 3 0 9 3 0 10 \r
+ 8 4 0 9 4 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 1 3 0 1 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 9 0 8 9 0 10 \r
+ 8 3 0 9 3 0 10 \r
+ 8 4 0 9 4 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 9 0 8 9 0 10 \r
+ 8 3 0 9 3 0 10 \r
+ 8 4 0 9 4 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 1 3 0 1 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 3 0 9 3 0 10 \r
+ 8 4 0 9 4 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 9 0 8 9 0 10 \r
+ 8 3 0 9 3 0 10 \r
+ 8 4 0 9 4 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 3 0 9 3 0 10 \r
+ 8 4 0 9 4 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 1 3 0 1 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 3 0 9 3 0 10 \r
+ 8 4 0 9 4 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 1 5 0 1 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 9 0 8 9 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 3 0 9 3 0 10 \r
+ 8 4 0 9 4 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 4 3 0 4 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 3 0 9 3 0 10 \r
+ 8 4 0 9 4 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 3 5 0 3 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 9 0 8 9 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 9 0 8 9 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 3 0 9 3 0 10 \r
+ 8 4 0 9 4 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 6 0 6 6 0 10 \r
--- /dev/null
+ 4 5 0 4 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 9 1 0 9 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 9 2 0 9 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 9 4 0 9 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 9 6 0 9 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 9 7 0 9 8 0 10 \r
+ 1 8 0 1 9 0 10 \r
+ 9 8 0 9 9 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 9 0 2 9 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 9 0 3 9 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 9 0 8 9 0 10 \r
+ 8 1 0 9 1 0 10 \r
+ 8 9 0 9 9 0 10 \r
--- /dev/null
+ 1 5 0 1 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 9 6 0 9 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 9 7 0 9 8 0 10 \r
+ 1 8 0 1 9 0 10 \r
+ 9 8 0 9 9 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 9 0 2 9 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 9 0 3 9 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 9 0 8 9 0 10 \r
+ 8 5 0 9 5 0 10 \r
+ 8 9 0 9 9 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 1 8 0 1 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 9 0 2 9 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 9 0 3 9 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 9 0 5 9 0 10 \r
--- /dev/null
+ 5 1 0 5 2 0 10 \r
+ 9 1 0 9 2 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 9 2 0 9 3 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 9 4 0 9 5 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 9 6 0 9 7 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 9 7 0 9 8 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 9 8 0 9 9 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 9 0 8 9 0 10 \r
+ 8 1 0 9 1 0 10 \r
+ 8 9 0 9 9 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 9 1 0 9 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 9 2 0 9 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 9 3 0 9 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 9 4 0 9 5 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 8 1 0 9 1 0 10 \r
+ 8 5 0 9 5 0 10 \r
--- /dev/null
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 2 0 2 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 1 2 0 1 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
--- /dev/null
+ 1 2 0 1 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 2 0 2 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
--- /dev/null
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 2 2 0 2 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 2 3 0 2 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 9 4 0 9 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 9 5 0 9 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 8 4 0 9 4 0 10 \r
+ 8 6 0 9 6 0 10 \r
--- /dev/null
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 2 0 1 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 5 1 0 5 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 5 1 0 5 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 4 8 0 4 9 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 7 0 6 7 0 10 \r
--- /dev/null
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 2 2 0 2 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
--- /dev/null
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 6 0 6 6 0 10 \r
--- /dev/null
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 9 1 0 9 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 8 1 0 9 1 0 10 \r
+ 8 2 0 9 2 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 5 0 7 5 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
--- /dev/null
+ 2 3 0 2 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 7 0 7 7 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 4 0 7 4 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 4 0 7 4 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 3 0 6 3 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 6 0 6 6 0 10 \r
--- /dev/null
+ 1 2 0 1 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
--- /dev/null
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
--- /dev/null
+ 1 4 0 1 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
--- /dev/null
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 8 0 6 8 0 10 \r
--- /dev/null
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 5 1 0 5 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 4 0 8 4 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 4 2 0 4 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 8 0 7 8 0 10 \r
--- /dev/null
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 3 8 0 3 9 0 10 \r
+ 5 8 0 5 9 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 8 0 6 8 0 10 \r
--- /dev/null
+ 5 1 0 5 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
--- /dev/null
+ 1 3 0 1 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 6 0 8 6 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 3 0 8 3 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 6 8 0 6 9 0 10 \r
+ 8 8 0 8 9 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
+ 7 9 0 8 9 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 3 0 8 3 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 4 7 0 4 8 0 10 \r
+ 5 7 0 5 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 5 0 8 5 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 1 3 0 1 4 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 6 7 0 6 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 2 0 8 2 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 6 1 0 6 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 8 3 0 8 4 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 3 7 0 3 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 4 0 8 4 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 8 1 0 8 2 0 10 \r
+ 1 2 0 1 3 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 8 2 0 8 3 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 3 0 2 3 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 6 0 3 6 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 5 0 6 5 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 1 0 8 1 0 10 \r
+ 7 3 0 8 3 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 2 0 7 2 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 6 8 0 7 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 3 1 0 3 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 3 3 0 3 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 6 0 6 6 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 7 0 7 7 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 2 1 0 2 2 0 10 \r
+ 7 1 0 7 2 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 7 2 0 7 3 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 5 5 0 5 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 2 0 3 2 0 10 \r
+ 2 7 0 3 7 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 2 0 5 2 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 1 0 6 1 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 1 0 7 1 0 10 \r
+ 6 8 0 7 8 0 10 \r
--- /dev/null
+ 4 1 0 4 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 6 2 0 6 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 5 3 0 5 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 5 0 2 5 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 3 2 0 4 2 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 5 2 0 6 2 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
--- /dev/null
+ 1 8 0 1 9 0 10 \r
+ 9 8 0 9 9 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 1 9 0 2 9 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 2 9 0 3 9 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 3 9 0 4 9 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 4 9 0 5 9 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 5 9 0 6 9 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 6 9 0 7 9 0 10 \r
+ 7 8 0 8 8 0 10 \r
+ 7 9 0 8 9 0 10 \r
+ 8 8 0 9 8 0 10 \r
+ 8 9 0 9 9 0 10 \r
--- /dev/null
+ 3 1 0 3 2 0 10 \r
+ 5 1 0 5 2 0 10 \r
+ 3 2 0 3 3 0 10 \r
+ 5 2 0 5 3 0 10 \r
+ 4 3 0 4 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 4 1 0 5 1 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
--- /dev/null
+ 2 3 0 2 4 0 10 \r
+ 6 3 0 6 4 0 10 \r
+ 5 4 0 5 5 0 10 \r
+ 7 4 0 7 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 7 5 0 7 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 5 6 0 5 7 0 10 \r
+ 7 6 0 7 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 8 7 0 8 8 0 10 \r
+ 1 6 0 2 6 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 4 0 3 4 0 10 \r
+ 2 5 0 3 5 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 5 0 4 5 0 10 \r
+ 3 6 0 4 6 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 5 0 5 5 0 10 \r
+ 4 6 0 5 6 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 4 0 7 4 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 7 0 8 7 0 10 \r
+ 7 8 0 8 8 0 10 \r
--- /dev/null
+ 1 1 0 1 2 0 10 \r
+ 4 1 0 4 2 0 10 \r
+ 2 2 0 2 3 0 10 \r
+ 4 2 0 4 3 0 10 \r
+ 2 3 0 2 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 2 4 0 2 5 0 10 \r
+ 4 4 0 4 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 2 5 0 2 6 0 10 \r
+ 4 5 0 4 6 0 10 \r
+ 6 5 0 6 6 0 10 \r
+ 8 5 0 8 6 0 10 \r
+ 2 6 0 2 7 0 10 \r
+ 4 6 0 4 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 1 7 0 1 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 1 0 2 1 0 10 \r
+ 1 2 0 2 2 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 1 8 0 2 8 0 10 \r
+ 2 1 0 3 1 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 1 0 4 1 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+ 2 3 0 2 4 0 10 \r
+ 7 3 0 7 4 0 10 \r
+ 1 4 0 1 5 0 10 \r
+ 3 4 0 3 5 0 10 \r
+ 6 4 0 6 5 0 10 \r
+ 8 4 0 8 5 0 10 \r
+ 1 5 0 1 6 0 10 \r
+ 3 5 0 3 6 0 10 \r
+ 1 6 0 1 7 0 10 \r
+ 3 6 0 3 7 0 10 \r
+ 6 6 0 6 7 0 10 \r
+ 8 6 0 8 7 0 10 \r
+ 2 7 0 2 8 0 10 \r
+ 7 7 0 7 8 0 10 \r
+ 1 4 0 2 4 0 10 \r
+ 1 7 0 2 7 0 10 \r
+ 2 3 0 3 3 0 10 \r
+ 2 8 0 3 8 0 10 \r
+ 3 3 0 4 3 0 10 \r
+ 3 4 0 4 4 0 10 \r
+ 3 7 0 4 7 0 10 \r
+ 3 8 0 4 8 0 10 \r
+ 4 3 0 5 3 0 10 \r
+ 4 4 0 5 4 0 10 \r
+ 4 7 0 5 7 0 10 \r
+ 4 8 0 5 8 0 10 \r
+ 5 3 0 6 3 0 10 \r
+ 5 4 0 6 4 0 10 \r
+ 5 7 0 6 7 0 10 \r
+ 5 8 0 6 8 0 10 \r
+ 6 3 0 7 3 0 10 \r
+ 6 5 0 7 5 0 10 \r
+ 6 6 0 7 6 0 10 \r
+ 6 8 0 7 8 0 10 \r
+ 7 4 0 8 4 0 10 \r
+ 7 5 0 8 5 0 10 \r
+ 7 6 0 8 6 0 10 \r
+ 7 7 0 8 7 0 10 \r
--- /dev/null
+' 3D font table generator\r
+' made by Svjatoslav Agejenko\r
+' last edit 2004.01\r
+' H-Page: svjatoslav.eu\r
+' E-Mail: svjatoslav@svjatoslav.eu\r
+ \r
+DECLARE SUB ln (x1!, y1!, x2!, y2!)\r
+SCREEN 13\r
+\r
+FOR a = 32 TO 255\r
+ LOCATE 2, 2\r
+ PRINT CHR$(a)\r
+ n$ = STR$(a)\r
+ IF LEFT$(n$, 1) = " " THEN n$ = RIGHT$(n$, LEN(n$) - 1)\r
+\r
+ n$ = "ltr" + n$ + ".3d"\r
+\r
+ OPEN n$ FOR OUTPUT AS #1\r
+ FOR y = 0 TO 15\r
+ FOR x = 0 TO 15\r
+ c1 = POINT(x, y)\r
+ c2 = POINT(x + 1, y)\r
+ IF c2 <> c1 THEN ln x + 1, y, x + 1, y + 1\r
+ NEXT x\r
+ NEXT y\r
+\r
+ FOR x = 0 TO 15\r
+ FOR y = 0 TO 15\r
+ c1 = POINT(x, y)\r
+ c2 = POINT(x, y + 1)\r
+ IF c2 <> c1 THEN ln x, y + 1, x + 1, y + 1\r
+ NEXT y\r
+ NEXT x\r
+\r
+ CLOSE #1\r
+NEXT a\r
+SCREEN 0\r
+PRINT "done"\r
+SYSTEM\r
+\r
+SUB ln (x1, y1, x2, y2)\r
+ PRINT #1, x1 - 7; y1 - 7; 0; x2 - 7; y2 - 7; 0; 10\r
+END SUB\r
+\r
--- /dev/null
+qbext\r
+qb /run engine.bas
\ No newline at end of file
--- /dev/null
+:PROPERTIES:
+:ID: 64337011-dc48-4fdd-bd07-489609d1651d
+:END:
+#+TITLE: AGENTS — Operating guide for qbasicapps
+
+* Purpose
+:PROPERTIES:
+:ID: 37c01b99-9f78-43c4-ad26-d43c8691db07
+:END:
+
+Collection of DOS BASIC applications (mostly QBasic, some QuickBasic
+4.5) written around year 2000. The repo doubles as a static web site:
+each category directory holds an ~index.org~ page that exports to an
+~index.html~ via Emacs batch mode. The source programs are ~.bas~
+files; each showcased program usually has a sibling screenshot
+(~.png~) or screencast (~.webm~, ~.mp3~) embedded in the page.
+
+* Layout
+:PROPERTIES:
+:ID: 635fd7db-6abd-4212-a9ce-f908b915ac09
+:END:
+
+#+begin_example
+.
+├── index.org ← site root page, links into every category
+├── 2D GFX/ ← animations, fractals, spirals, textures
+├── 3D GFX/ ← 3D demos, 3D Synthezier, ray casting
+├── Games/ ← checkers, Pomppu Paavo 1/2, Worm
+├── Math/ ← plots, simulations, Game of Life, lottery
+├── Miscellaneous/ ← palette/font/windowing experiments, alarms
+├── Networking/ ← COM/LPT transfer, morse, audio modem
+├── Tutorial/ ← QBasic tutorial groups 1–3
+├── CRT Basic/ ← Java QBasic interpreter project (Maven)
+├── Tools/ ← maintainer helper scripts (see Tooling)
+├── run_dosbox.sh ← mount repo as C: in DOSBox and run programs
+├── QB45/ ← QuickBasic 4.5 compiler (gitignored)
+├── VC.COM, VC.INI ← Volkov Commander (gitignored)
+└── COPYING ← license text
+#+end_example
+
+* Conventions
+:PROPERTIES:
+:ID: ce6f3b18-f106-4786-941e-06fd7c8fdb04
+:END:
+
+** Directory and file names contain spaces
+
+Category directories and most program files use spaces and
+capitalization: ~3D GFX/Space/index.org~, ~Ray casting engine.bas~,
+~Pomppu Paavo 2/~. Always quote paths in shell commands and scripts.
+
+** Site pages
+
+- Every category directory has its own ~index.org~; the root
+ ~index.org~ links down into them.
+- ~index.html~ files are autogenerated by ~Tools/Update web site~ and
+ are gitignored — never edit or commit them.
+- Cross-page links in ~index.org~ use ~[[id:<UUID>][Text]]~ for
+ in-page section targets and ~[[file:...]]~ for other pages. Relative
+ ~file:~ links with spaces appear both percent-encoded
+ ~[[file:2D%20GFX/Animations/index.html][Animations]]~ and literal
+ ~[[file:3D GFX/Space/index.html][...]]~ — match the surrounding
+ page's existing style when editing.
+- Sections that need stable link targets carry a property drawer:
+ : * Fractals
+ : :PROPERTIES:
+ : :ID: 38f8f88a-3f72-4c43-91c6-08d5c7aa54e6
+ : :END:
+ Generate a fresh UUID with ~python3 -c "import uuid; print(uuid.uuid4())"~
+ when adding a new linkable section.
+
+** Showcasing a program
+
+A showcased ~.bas~ program pairs with a screenshot or recording of
+the same base name: ~Stroboscope.bas~ + ~Stroboscope.png~,
+~3D land.bas~ + ~3D land.webm~. New programs added to the site should
+follow this pairing.
+
+** Helper script naming
+
+Executable helper scripts are named as sentences with spaces, not
+kebab-case: ~Tools/Update web site~, ~Tools/Commit and push~,
+~Tools/Open with IntelliJ IDEA~. Invoke with quoting:
+
+: bash "Tools/Update web site"
+
+* Tooling
+:PROPERTIES:
+:ID: 68d4e5b1-e827-4985-8316-7628d411f556
+:END:
+
+| Tool | Purpose |
+|---------------------------------+--------------------------------------------------------|
+| ~run_dosbox.sh~ | Mount the repo as ~C:~ in DOSBox to run .bas files |
+| ~Tools/Update web site~ | Export every ~index.org~ to ~index.html~ (Emacs batch) |
+| ~Tools/Commit and push~ | Open git-cola, then push |
+| ~Tools/Open with IntelliJ IDEA~ | Open repo in IntelliJ (project files present) |
+
+The ~Tools/*~ scripts start with a self-relaunch into ~gnome-terminal~
+when run without the ~T~ argument (they are meant to be double-clicked
+from the file manager); they ~cd~ to the repo root relative to their
+own location.
+
+* Pitfalls
+:PROPERTIES:
+:ID: 1fb7b768-40aa-44d3-bd55-a0d71e2f9c74
+:END:
+
+- *Pitfall: gitignored runtime files.* ~QB45/~, ~VC.COM~, ~VC.INI~,
+ ~.idea/~ and ~qbasicapps.iml~ are intentionally untracked. A fresh
+ clone lacks the QuickBasic compiler and Volkov Commander — DOS
+ programs that need compiling (~BC.EXE~) will not build there.
+- *Pitfall: filenames with spaces everywhere.* Unquoted globs and
+ ~for f in $(ls)~ loops break on ~2D GFX/~, ~Pomppu Paavo 2/~ etc.
+ Use ~find . -name '*.bas' -print0 | xargs -0~ or quoted expansions.
+- *Pitfall: ~index.html~ is a build artifact.* Editing it directly is
+ lost work — edit the ~index.org~ and re-run ~Tools/Update web site~.
+- *Pitfall: case sensitivity.* The collection was written on
+ case-insensitive DOS file systems; ~QB45/~ holds uppercase names
+ (~BC.EXE~, ~DEMO1.BAS~) while the rest of the tree is mixed case.
+ Grep case-insensitively (~grep -i~) when locating program names.
--- /dev/null
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+ LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+ INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+ REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+ PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+ THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+ HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display,
+ communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+ likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+ v. rights protecting the extraction, dissemination, use and reuse of data
+ in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation
+ thereof, including any amended or successor version of such
+ directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+ world based on applicable law or treaty, and any national
+ implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+ warranties of any kind concerning the Work, express, implied,
+ statutory or otherwise, including without limitation warranties of
+ title, merchantability, fitness for a particular purpose, non
+ infringement, or the absence of latent or other defects, accuracy, or
+ the present or absence of errors, whether or not discoverable, all to
+ the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without
+ limitation any person's Copyright and Related Rights in the Work.
+ Further, Affirmer disclaims responsibility for obtaining any necessary
+ consents, permissions or other rights required for any use of the
+ Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to
+ this CC0 or use of the Work.
--- /dev/null
+DECLARE SUB RenderSpriteFromFile (x%, y%, widthMultiplier%, heightMultiplier%, SpriteName$)\r
+DECLARE SUB RenderFlippedSpriteFromFile (x%, y%, widthMultiplier%, heightMultiplier%, Filename$)\r
+' Pomppu Paavo 2\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 1999, Initial version\r
+' 2025, Improved program readability\r
+\r
+DECLARE SUB UpdateLoadingScreen ()\r
+DECLARE SUB HandleEscapeKey ()\r
+DECLARE SUB PlayHurtSound ()\r
+DECLARE SUB GameOverSequence ()\r
+\r
+DECLARE SUB HandlePlayerDeath ()\r
+DEFINT A-Z\r
+DECLARE SUB InitializeAllLevelData ()\r
+DECLARE SUB UpdateHUD (coinIncrementAmount%)\r
+DECLARE SUB LoadCurrentLevel ()\r
+DECLARE SUB ShowIntroScreen ()\r
+DECLARE SUB WaitForUserInput ()\r
+\r
+DIM SHARED userInput$\r
+\r
+' Grid representing solid level elements (m = block, o = breakable, etc.)\r
+DIM SHARED levelGrid(-5 TO 20, -5 TO 20) AS STRING\r
+\r
+' Tracks interactive objects like breakable blocks separately from main grid\r
+DIM SHARED interactiveObjectsGrid(-5 TO 20, -5 TO 20) AS STRING\r
+\r
+' Stores raw text-based level layouts for all worlds\r
+DIM SHARED levelData(1 TO 11, 1 TO 10) AS STRING * 15\r
+\r
+' Background color index for each world's sky\r
+DIM SHARED levelSkyColor(1 TO 10) AS INTEGER\r
+\r
+' Current active level number (1-10)\r
+DIM SHARED currentLevelNumber AS INTEGER\r
+\r
+' Previously played level number (for backtracking after death)\r
+DIM SHARED previousLevelNumber AS INTEGER\r
+\r
+' Temporary storage for current level's row data during loading\r
+DIM SHARED levelRowData(1 TO 15) AS STRING * 15\r
+\r
+' Buffer to store cloud sprite image data\r
+DIM SHARED cloudSpriteBuffer(2100)\r
+\r
+' Buffer for solid block sprite images\r
+DIM SHARED solidBlockSpriteBuffer(202)\r
+\r
+' Buffer for brick/block sprite images\r
+DIM SHARED brickSpriteBuffer(202)\r
+\r
+' Buffer for power-up item sprites (like mushrooms)\r
+DIM SHARED powerUpSpriteBuffer(1000)\r
+\r
+' Buffer for tree sprite images\r
+DIM SHARED treeSpriteBuffer(2000)\r
+\r
+' Buffer for empty space sprite (used when clearing coins/breakables)\r
+DIM SHARED emptySpaceSpriteBuffer(202)\r
+\r
+' Main coin sprite buffer\r
+DIM SHARED coinSpriteBuffer(202)\r
+\r
+' Larger coin variant sprite buffer\r
+DIM SHARED largeCoinSpriteBuffer(400)\r
+\r
+' Smaller coin variant sprite buffer\r
+DIM SHARED smallCoinSpriteBuffer(200)\r
+\r
+' Player character animation frames (base + walking variants)\r
+DIM SHARED playerAnimationFrames(402)\r
+\r
+' Primary player sprite animation frames array\r
+DIM SHARED playerWalkingFrames(202, 1 TO 5)\r
+\r
+' Enemy base sprite buffers (stores background under enemies for erasing)\r
+DIM SHARED enemyBackgroundBuffers(1 TO 230, 1 TO 10)\r
+\r
+' Enemy walking animation frames\r
+DIM SHARED enemyWalkingFrames(1 TO 202, 1 TO 5)\r
+\r
+' X positions of all enemies (max 10 per level)\r
+DIM SHARED enemyXPositions(1 TO 10)\r
+\r
+' Y positions of all enemies\r
+DIM SHARED enemyYPositions(1 TO 10)\r
+\r
+' Vertical movement speeds for enemies (positive = down)\r
+DIM SHARED enemyVerticalSpeeds(1 TO 10)\r
+\r
+' Horizontal movement speeds for enemies (positive = right)\r
+DIM SHARED enemyHorizontalSpeeds(1 TO 10)\r
+\r
+' Array storing individual digits of coin counter (index 1=ones, 2=tens)\r
+DIM SHARED CoinDigits(1 TO 5)\r
+\r
+' Pre-loaded digit images for HUD display (0-9)\r
+DIM SHARED digitImages(100, 0 TO 11)\r
+\r
+' Number of remaining player lives\r
+DIM SHARED lives\r
+\r
+' Total coins collected by player\r
+DIM SHARED coinsCollected\r
+\r
+' Flag: set when a coin needs to be cleared from grid\r
+DIM SHARED shouldClearCoinFlag\r
+\r
+' Grid X position where coin needs clearing\r
+DIM SHARED clearCoinGridX\r
+\r
+' Grid Y position where coin needs clearing\r
+DIM SHARED clearCoinGridY\r
+\r
+' Player's current X coordinate on screen\r
+DIM SHARED playerX\r
+\r
+' Player's current Y coordinate on screen\r
+DIM SHARED playerY\r
+\r
+' Counter tracking loading progress dots\r
+DIM SHARED loadingProgressDotCount\r
+\r
+loadingProgressDotCount = 1\r
+SCREEN 13\r
+currentLevelNumber = 1\r
+previousLevelNumber = 1\r
+InitializeAllLevelData\r
+1\r
+\r
+' Reset entire VGA palette to black (0-254)\r
+FOR colorIndex = 0 TO 254\r
+OUT &H3C8, colorIndex\r
+OUT &H3C9, 0\r
+OUT &H3C9, 0\r
+OUT &H3C9, 0\r
+NEXT colorIndex\r
+\r
+' Set color 255 to bright white (60/63 intensity)\r
+OUT &H3C8, 255\r
+OUT &H3C9, 60\r
+OUT &H3C9, 60\r
+OUT &H3C9, 60\r
+LOCATE 20, 3\r
+COLOR 255\r
+PRINT "LOADING "\r
+\r
+' Load all game assets sequentially with visual feedback\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "pilv"\r
+GET (1, 1)-(109, 35), cloudSpriteBuffer\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "kast"\r
+GET (1, 2)-(20, 21), solidBlockSpriteBuffer\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "tellis"\r
+GET (1, 2)-(20, 21), brickSpriteBuffer\r
+\r
+UpdateLoadingScreen\r
+GET (1, 2)-(20, 21), emptySpaceSpriteBuffer\r
+\r
+RenderSpriteFromFile 0, 0, 1, 1, "paavo1"\r
+GET (1, 2)-(20, 21), playerWalkingFrames(202, 1)\r
+\r
+UpdateLoadingScreen\r
+RenderFlippedSpriteFromFile 0, 0, 1, 1, "paavo1"\r
+GET (3, 2)-(22, 21), playerWalkingFrames(202, 2)\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "paavo2"\r
+GET (1, 2)-(20, 21), playerWalkingFrames(202, 3)\r
+\r
+UpdateLoadingScreen\r
+RenderFlippedSpriteFromFile 0, 0, 1, 1, "paavo2"\r
+GET (3, 2)-(22, 21), playerWalkingFrames(202, 4)\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "poosas"\r
+GET (1, 1)-(60, 21), powerUpSpriteBuffer\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "puu"\r
+GET (1, 1)-(40, 60), treeSpriteBuffer\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "munt"\r
+GET (1, 1)-(10, 11), coinSpriteBuffer\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "munt1"\r
+GET (0, 2)-(20, 11), largeCoinSpriteBuffer\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "munt2"\r
+GET (0, 2)-(20, 11), smallCoinSpriteBuffer\r
+\r
+' Load all numeric digit sprites for HUD display\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "0"\r
+GET (0, 2)-(10, 11), digitImages(100, 0)\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "1"\r
+GET (0, 2)-(10, 11), digitImages(100, 1)\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "2"\r
+GET (0, 2)-(10, 11), digitImages(100, 2)\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "3"\r
+GET (0, 2)-(10, 11), digitImages(100, 3)\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "4"\r
+GET (0, 2)-(10, 11), digitImages(100, 4)\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "5"\r
+GET (0, 2)-(10, 11), digitImages(100, 5)\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "6"\r
+GET (0, 2)-(10, 11), digitImages(100, 6)\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "7"\r
+GET (0, 2)-(10, 11), digitImages(100, 7)\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "8"\r
+GET (0, 2)-(10, 11), digitImages(100, 8)\r
+\r
+UpdateLoadingScreen\r
+GET (0, 2)-(10, 11), digitImages(100, 10)\r
+RenderSpriteFromFile 0, 0, 1, 1, "9"\r
+GET (0, 2)-(10, 11), digitImages(100, 9)\r
+\r
+' Load enemy sprite frames\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "tigu"\r
+GET (1, 2)-(20, 21), enemyWalkingFrames(202, 1)\r
+\r
+UpdateLoadingScreen\r
+RenderSpriteFromFile 0, 0, 1, 1, "tigu1"\r
+GET (3, 2)-(22, 21), enemyWalkingFrames(202, 2)\r
+\r
+UpdateLoadingScreen\r
+RenderFlippedSpriteFromFile 0, 0, 1, 1, "tigu"\r
+GET (1, 2)-(20, 21), enemyWalkingFrames(202, 3)\r
+\r
+UpdateLoadingScreen\r
+RenderFlippedSpriteFromFile 0, 0, 1, 1, "tigu1"\r
+GET (3, 2)-(22, 21), enemyWalkingFrames(202, 4)\r
+\r
+SCREEN 0\r
+SCREEN 13\r
+LoadCurrentLevel\r
+playerX = 50\r
+playerY = 50\r
+horizontalMovementSpeed = 0\r
+currentWalkFrameIndex = 1\r
+leftWalkFrameIndex = 1\r
+rightWalkFrameIndex = 2\r
+coinsCollected = 0\r
+lives = 3\r
+animationFrameCounter = 1\r
+UpdateHUD 0\r
+12\r
+' Save current player position background before drawing character\r
+IF playerY > 0 THEN GET (playerX, playerY)-(playerX + 20, playerY + 20), playerAnimationFrames: PUT (playerX, playerY), playerWalkingFrames(202, currentWalkFrameIndex), OR\r
+\r
+' Process all enemies (max 10)\r
+FOR enemyIndex = 1 TO 10\r
+ ' Only update visible enemies above bottom of screen\r
+ IF enemyYPositions(enemyIndex) < 170 AND animationFrameCounter = 1 THEN\r
+ ' Apply vertical and horizontal movement\r
+ enemyYPositions(enemyIndex) = enemyYPositions(enemyIndex) + enemyVerticalSpeeds(enemyIndex)\r
+ enemyXPositions(enemyIndex) = enemyXPositions(enemyIndex) + enemyHorizontalSpeeds(enemyIndex)\r
+ ' Save background under enemy for later erasing\r
+ GET (enemyXPositions(enemyIndex), enemyYPositions(enemyIndex))-(enemyXPositions(enemyIndex) + 20, enemyYPositions(enemyIndex) + 20), enemyBackgroundBuffers(202, enemyIndex)\r
+\r
+ ' Determine which walking animation frame to show\r
+ IF enemyHorizontalSpeeds(enemyIndex) <= 0 THEN walkAnimationPhase = 1 ELSE walkAnimationPhase = 3\r
+ IF enemyAnimationFrameCounter > 2 THEN walkAnimationPhase = walkAnimationPhase + 1: IF enemyAnimationFrameCounter = 3 THEN enemyVerticalSpeeds(enemyIndex) = enemyVerticalSpeeds(enemyIndex) + 1\r
+\r
+ ' Draw enemy with correct animation frame\r
+ PUT (enemyXPositions(enemyIndex), enemyYPositions(enemyIndex)), enemyWalkingFrames(202, walkAnimationPhase)\r
+ END IF\r
+NEXT enemyIndex\r
+\r
+' Create short delay using silent sound (QBasic lacks proper delay function)\r
+SOUND 0, .5\r
+\r
+' Cycle through animation frames\r
+animationFrameCounter = animationFrameCounter + 1\r
+IF animationFrameCounter > 3 THEN animationFrameCounter = 1\r
+\r
+' Every third frame, process physics and input\r
+IF animationFrameCounter = 1 THEN\r
+ enemyAnimationFrameCounter = enemyAnimationFrameCounter + 1\r
+ IF enemyAnimationFrameCounter > 5 THEN enemyAnimationFrameCounter = 0\r
+\r
+ ' Apply gravity to player (increases downward speed each frame)\r
+ verticalMovementSpeed = verticalMovementSpeed + 1\r
+\r
+ ' Gradually reduce horizontal movement (friction effect)\r
+ IF horizontalMovementSpeed > 0 THEN horizontalMovementSpeed = horizontalMovementSpeed - 1: walkAnimationPhaseCounter = walkAnimationPhaseCounter + 1\r
+ IF horizontalMovementSpeed < 0 THEN horizontalMovementSpeed = horizontalMovementSpeed + 1: walkAnimationPhaseCounter = walkAnimationPhaseCounter + 1\r
+\r
+ ' Alternate between walk animation phases every 2 frames\r
+ IF walkAnimationPhaseCounter > 2 THEN walkAnimationPhaseCounter = 1\r
+ IF walkAnimationPhaseCounter = 2 THEN leftWalkFrameIndex = 1: rightWalkFrameIndex = 2\r
+ IF walkAnimationPhaseCounter = 1 THEN leftWalkFrameIndex = 3: rightWalkFrameIndex = 4\r
+\r
+ ' Process enemy collisions and movements\r
+ FOR enemyIndex = 1 TO 10\r
+ IF enemyYPositions(enemyIndex) < 170 THEN\r
+ ' Reverse vertical direction when hitting ceiling block\r
+ IF levelGrid((enemyXPositions(enemyIndex) + 20) / 20, (enemyYPositions(enemyIndex) + 9) / 20) = "m" THEN enemyVerticalSpeeds(enemyIndex) = -1\r
+\r
+ ' Reverse horizontal direction at screen edges\r
+ IF enemyXPositions(enemyIndex) > 270 THEN enemyHorizontalSpeeds(enemyIndex) = -1\r
+ IF enemyXPositions(enemyIndex) < 2 THEN enemyHorizontalSpeeds(enemyIndex) = 1\r
+\r
+ ' Reverse horizontal direction when hitting wall blocks\r
+ IF levelGrid((enemyXPositions(enemyIndex) + 28) / 20, enemyYPositions(enemyIndex) / 20) = "m" THEN enemyHorizontalSpeeds(enemyIndex) = -1\r
+ IF levelGrid((enemyXPositions(enemyIndex) + 10) / 20, enemyYPositions(enemyIndex) / 20) = "m" THEN enemyHorizontalSpeeds(enemyIndex) = 1\r
+\r
+ ' Check for collision with player (trigger death)\r
+ IF enemyXPositions(enemyIndex) - 20 < playerX AND enemyXPositions(enemyIndex) + 20 > playerX AND enemyYPositions(enemyIndex) - 5 < playerY AND enemyYPositions(enemyIndex) + 20 > playerY THEN PlayHurtSound: HandlePlayerDeath: GOTO 12\r
+ END IF\r
+ NEXT enemyIndex\r
+END IF\r
+\r
+' Check for player collisions with level geometry:\r
+\r
+' Ceiling collision (reverse gravity)\r
+IF levelGrid((playerX + 15) / 20, (playerY + 9) / 20) = "m" THEN verticalMovementSpeed = -1: airTimeCounter = 0\r
+\r
+' Right wall collision\r
+IF levelGrid((playerX + 25) / 20, (playerY + 9) / 20) = "m" THEN verticalMovementSpeed = -1: airTimeCounter = 0\r
+\r
+' Floor collision (stop falling)\r
+IF levelGrid((playerX + 20) / 20, (playerY - 8) / 20) = "m" THEN verticalMovementSpeed = 1: airTimeCounter = 20\r
+\r
+' Right wall collision\r
+IF levelGrid((playerX + 28) / 20, (playerY) / 20) = "m" THEN horizontalMovementSpeed = -1: wallCollisionLock = 1\r
+\r
+' Left wall collision\r
+IF levelGrid((playerX + 10) / 20, (playerY) / 20) = "m" THEN horizontalMovementSpeed = 1: wallCollisionLock = 1\r
+\r
+' Breakable block collision (turn into empty space)\r
+IF interactiveObjectsGrid((playerX + 20) / 20, (playerY - 8) / 20) = "o" THEN verticalMovementSpeed = 1: interactiveObjectsGrid((playerX + 20) / 20, (playerY - 8) / 20) = "": levelGrid((playerX + 20) / 20, (playerY - 8) / 20) = "2": clearCoinGridX _\r
+= ((playerX + 20) / 20) - 1: clearCoinGridY = (playerY - 8) / 20: shouldClearCoinFlag = 1: SOUND 50, .5\r
+\r
+' Coin collection\r
+IF levelGrid((playerX + 20) / 20, (playerY) / 20) = "1" THEN levelGrid((playerX + 20) / 20, (playerY) / 20) = "2": clearCoinGridX = ((playerX + 21) / 20) - 1: clearCoinGridY = (playerY) / 20: shouldClearCoinFlag = 1: coinsCollected = coinsCollected _\r
++ 1: UpdateHUD 1: SOUND 1000, 1: SOUND 2000, 1\r
+\r
+' Track time in air for jump control\r
+airTimeCounter = airTimeCounter + 1\r
+\r
+' Process keyboard input:\r
+userInput$ = INKEY$\r
+' Jump when up arrow pressed (only if not already high in air)\r
+IF userInput$ = CHR$(0) + "H" AND airTimeCounter < 10 THEN verticalMovementSpeed = -6\r
+' Move right with right arrow\r
+IF userInput$ = CHR$(0) + "M" AND wallCollisionLock = 0 THEN horizontalMovementSpeed = horizontalMovementSpeed + 3: currentWalkFrameIndex = leftWalkFrameIndex\r
+' Move left with left arrow\r
+IF userInput$ = CHR$(0) + "K" AND wallCollisionLock = 0 THEN horizontalMovementSpeed = horizontalMovementSpeed - 3: currentWalkFrameIndex = rightWalkFrameIndex\r
+' Escape key handler\r
+IF userInput$ = CHR$(27) THEN HandleEscapeKey\r
+' Level skip (debug only - plus key)\r
+IF userInput$ = "+" AND wallCollisionLock = 0 THEN currentLevelNumber = currentLevelNumber + 1: LoadCurrentLevel: GOTO 12\r
+' Reset wall collision lock each frame\r
+IF wallCollisionLock <> 0 THEN wallCollisionLock = 0\r
+\r
+' Cap movement speeds to prevent excessive speed\r
+IF horizontalMovementSpeed > 5 THEN horizontalMovementSpeed = 3\r
+IF horizontalMovementSpeed < -5 THEN horizontalMovementSpeed = -3\r
+IF verticalMovementSpeed > 3 THEN verticalMovementSpeed = 3\r
+\r
+' Restore background where player was previously drawn\r
+IF playerY > 0 THEN PUT (playerX, playerY), playerAnimationFrames, PSET\r
+\r
+' Redraw enemies on this animation frame\r
+IF animationFrameCounter = 1 THEN\r
+ FOR enemyIndex = 10 TO 1 STEP -1\r
+ IF enemyYPositions(enemyIndex) < 170 THEN PUT (enemyXPositions(enemyIndex), enemyYPositions(enemyIndex)), enemyBackgroundBuffers(202, enemyIndex), PSET\r
+ NEXT enemyIndex\r
+END IF\r
+\r
+' Apply physics to player position\r
+playerY = playerY + verticalMovementSpeed\r
+playerX = playerX + horizontalMovementSpeed\r
+\r
+' Clear collected coin/block from screen\r
+IF shouldClearCoinFlag > 0 THEN shouldClearCoinFlag = 0: PUT (clearCoinGridX * 20, clearCoinGridY * 20), emptySpaceSpriteBuffer, PSET\r
+\r
+' Level transition when reaching screen edges\r
+IF playerX > 280 THEN currentLevelNumber = currentLevelNumber + 1: LoadCurrentLevel: playerX = 3\r
+IF playerX < 2 THEN currentLevelNumber = currentLevelNumber - 1: LoadCurrentLevel: playerX = 279\r
+\r
+' Player death when falling off bottom of screen\r
+IF playerY > 170 THEN FOR tone = 3000 TO 500 STEP -100: SOUND tone, .3: NEXT tone: HandlePlayerDeath\r
+GOTO 12\r
+\r
+SUB GameOverSequence\r
+' Shows game over screen with animated death effect.\r
+' First displays "You are killed!" text, then pixelates the screen,\r
+' adds flying debris animation, waits for keypress, then fades to black.\r
+\r
+DIM deathScreenBuffer(1 TO 2000)\r
+GET (0, 0)-(150, 20), deathScreenBuffer\r
+LOCATE 1, 1\r
+PRINT "You are "\r
+LOCATE 2, 1\r
+PRINT " killed! "\r
+\r
+' Create pixelated death effect by scaling up screen area\r
+FOR x = 0 TO 80\r
+ FOR y = 0 TO 16\r
+ ' Only process non-background pixels\r
+ IF POINT(x, y) > 0 THEN\r
+ ' Draw 5x5 block for each original pixel (magnification effect)\r
+ LINE (x * 5, y * 5 + 50)-(x * 5 + 4, y * 5 + 54), 4, BF\r
+ END IF\r
+ NEXT y\r
+NEXT x\r
+PUT (0, 0), deathScreenBuffer, PSET\r
+\r
+' Add random flying debris particles\r
+FOR particle = 1 TO 100\r
+ x = RND * 290 + 4\r
+ y = RND * 170 + 4\r
+ GET (x, y)-(x + 20, y + 20), deathScreenBuffer\r
+ x = x + RND * 4 - 2\r
+ y = y + RND * 4 - 1\r
+ PUT (x, y), deathScreenBuffer, PSET\r
+NEXT particle\r
+\r
+' Wait briefly before requiring keypress\r
+FOR waitCount = 1 TO 50\r
+ userInput$ = INKEY$\r
+NEXT waitCount\r
+userInput$ = INPUT$(1)\r
+\r
+' Draw closing red lines from top and bottom\r
+FOR lineIndex = 0 TO 10\r
+ SOUND 0, .05\r
+ LINE (0, lineIndex)-(320, lineIndex), 4\r
+ LINE (0, 200 - lineIndex)-(320, 200 - lineIndex), 4\r
+NEXT lineIndex\r
+\r
+' Fade out red color channel to black\r
+FOR fadeStep = 32 TO 0 STEP -1\r
+ SOUND 0, .5\r
+ OUT &H3C8, 4\r
+ OUT &H3C9, fadeStep\r
+ OUT &H3C9, 0\r
+ OUT &H3C9, 0\r
+NEXT fadeStep\r
+END\r
+\r
+END SUB\r
+\r
+SUB HandleEscapeKey\r
+' Handles ESC key press: performs smooth screen fadeout then exits to DOS.\r
+\r
+' Fade screen to black in vertical bands\r
+FOR band = 0 TO 20\r
+ FOR lineIndex = band TO 200 STEP 20\r
+ LINE (0, lineIndex)-(320, lineIndex), 0\r
+ NEXT lineIndex\r
+ SOUND 0, .5\r
+NEXT band\r
+SYSTEM\r
+\r
+END SUB\r
+\r
+SUB HandlePlayerDeath\r
+' Processes player death: moves back one level, resets player position,\r
+' decreases remaining lives, and updates HUD display.\r
+' Does not end game - continues playing from previous level.\r
+\r
+IF currentLevelNumber > 1 THEN currentLevelNumber = currentLevelNumber - 1\r
+\r
+LoadCurrentLevel\r
+playerX = 20\r
+playerY = 100\r
+lives = lives - 1\r
+UpdateHUD 0\r
+END SUB\r
+\r
+SUB InitializeAllLevelData\r
+' Sets up all level layouts as text-based grids.\r
+' Each character represents a game element:\r
+' m = solid block\r
+' o = breakable block\r
+' $ = coin\r
+' . = power-up item\r
+' + = tree/decoration\r
+' numbers 1-9 = enemy spawn points\r
+\r
+levelSkyColor(1) = 1\r
+levelData(1, 1) = "m "\r
+levelData(2, 1) = "m - - "\r
+levelData(3, 1) = "m "\r
+levelData(4, 1) = "m $ $ $ $ "\r
+levelData(5, 1) = "m $ $ $ $ "\r
+levelData(6, 1) = "m + momom "\r
+levelData(7, 1) = "m "\r
+levelData(8, 1) = "m . . "\r
+levelData(9, 1) = "mmmmmmmmmmmmmmm"\r
+\r
+levelSkyColor(2) = 1\r
+levelData(1, 2) = " $2- "\r
+levelData(2, 2) = " o$ "\r
+levelData(3, 2) = " o$ - "\r
+levelData(4, 2) = " o$ 3 "\r
+levelData(5, 2) = " o o1 "\r
+levelData(6, 2) = " + mmom"\r
+levelData(7, 2) = " omom m "\r
+levelData(8, 2) = " $ $ $ $ m "\r
+levelData(9, 2) = "mmmm mm"\r
+\r
+levelSkyColor(3) = 1\r
+levelData(1, 3) = " mmmmm"\r
+levelData(2, 3) = "- $ $ mmmmm"\r
+levelData(3, 3) = " $ $ $ mmmmm"\r
+levelData(4, 3) = " $ $ mmmmm"\r
+levelData(5, 3) = " . mmmmm"\r
+levelData(6, 3) = "mmmm 1 mmmm"\r
+levelData(7, 3) = " mm m"\r
+levelData(8, 3) = " mmm "\r
+levelData(9, 3) = "mmm mmmmm"\r
+\r
+levelSkyColor(4) = 0\r
+levelData(1, 4) = "mmmmmmmmmmmmmmm"\r
+levelData(2, 4) = "m$ $ $ $ $ "\r
+levelData(3, 4) = "mm $m $4$ $ $ "\r
+levelData(4, 4) = "m$m mmmmmommmm"\r
+levelData(5, 4) = "m$ 3 2 m"\r
+levelData(6, 4) = "m1 ooooooomo m"\r
+levelData(7, 4) = "mooo$$$$$$$m m"\r
+levelData(8, 4) = " m"\r
+levelData(9, 4) = "mmmmmmmmmmmmmmm"\r
+\r
+levelSkyColor(5) = 0\r
+levelData(1, 5) = "mmmmmmmmmmmmmmm"\r
+levelData(2, 5) = " m "\r
+levelData(3, 5) = "m m 1 3 mmmm"\r
+levelData(4, 5) = "m m mmm o m"\r
+levelData(5, 5) = "m m4567892o m"\r
+levelData(6, 5) = "m mooooommo m"\r
+levelData(7, 5) = "m mm"\r
+levelData(8, 5) = "m mmm"\r
+levelData(9, 5) = "mmmm mmm mmmm"\r
+\r
+levelSkyColor(6) = 1\r
+levelData(1, 6) = "m "\r
+levelData(2, 6) = " - $ - "\r
+levelData(3, 6) = "m $ $ "\r
+levelData(4, 6) = "m o o $ "\r
+levelData(5, 6) = "m o o "\r
+levelData(6, 6) = "m + "\r
+levelData(7, 6) = "m "\r
+levelData(8, 6) = "mm 1 m 2 m "\r
+levelData(9, 6) = "mmmmmmmmmmmmmmm"\r
+\r
+levelSkyColor(7) = 1\r
+levelData(1, 7) = " - "\r
+levelData(2, 7) = " - "\r
+levelData(3, 7) = " 1m"\r
+levelData(4, 7) = " 2mm"\r
+levelData(5, 7) = " 3mmm"\r
+levelData(6, 7) = " o + 4mmmm"\r
+levelData(7, 7) = " ooo 5mmmmm"\r
+levelData(8, 7) = " 6mmmmmm"\r
+levelData(9, 7) = "mmmmmmmmmmmmmmm"\r
+\r
+levelSkyColor(8) = 1\r
+levelData(1, 8) = " mmmmmmmmmmmmm"\r
+levelData(2, 8) = " m123m456m789 "\r
+levelData(3, 8) = " mm$mmm$mmm$mm"\r
+levelData(4, 8) = " mm$$$$$$$$$$m"\r
+levelData(5, 8) = " mmom$mmm$mmmm"\r
+levelData(6, 8) = " o$$$$$$$$$ o"\r
+levelData(7, 8) = " omooooooo o"\r
+levelData(8, 8) = " - m "\r
+levelData(9, 8) = "mmmmmmmmmmmmmmm"\r
+\r
+levelSkyColor(9) = 0\r
+levelData(1, 9) = " 12345"\r
+levelData(2, 9) = " 6789 "\r
+levelData(3, 9) = " mm"\r
+levelData(4, 9) = " m "\r
+levelData(5, 9) = " m "\r
+levelData(6, 9) = " m "\r
+levelData(7, 9) = " m "\r
+levelData(8, 9) = " m "\r
+levelData(9, 9) = "mm "\r
+\r
+levelSkyColor(10) = 1\r
+levelData(1, 10) = "m "\r
+levelData(2, 10) = " - "\r
+levelData(3, 10) = "m - "\r
+levelData(4, 10) = "m + "\r
+levelData(5, 10) = "m "\r
+levelData(6, 10) = "m + 2 "\r
+levelData(7, 10) = "m mmm "\r
+levelData(8, 10) = "m . 1 "\r
+levelData(9, 10) = "mmmmmmmmmmm mm"\r
+END SUB\r
+\r
+SUB LoadCurrentLevel\r
+' Loads and renders the currently selected level:\r
+' 1. Validates level number (ends game at level 11)\r
+' 2. Copies level data into working arrays\r
+' 3. Resets interactive object grid\r
+' 4. Clears enemy positions\r
+' 5. Renders all level elements based on character codes\r
+\r
+IF currentLevelNumber > 10 THEN\r
+ CLS\r
+ PRINT "Mission complete!"\r
+ PRINT "Game over"\r
+ END\r
+END IF\r
+\r
+' Copy level rows into temporary storage\r
+FOR rowIndex = 1 TO 10\r
+ levelRowData(rowIndex + 1) = levelData(rowIndex, currentLevelNumber)\r
+NEXT rowIndex\r
+\r
+' Clear breakable blocks from previous level\r
+FOR rowIndex = 1 TO 10\r
+ FOR columnIndex = 1 TO 15\r
+ IF levelGrid(columnIndex, rowIndex - 2) = "2" THEN MID$(levelData(rowIndex, previousLevelNumber), columnIndex) = " "\r
+ NEXT columnIndex\r
+NEXT rowIndex\r
+previousLevelNumber = currentLevelNumber\r
+\r
+' Reset entire level grids to empty\r
+FOR x = -3 TO 20\r
+ FOR y = -3 TO 20\r
+ levelGrid(x, y) = ""\r
+ interactiveObjectsGrid(x, y) = ""\r
+ NEXT y\r
+NEXT x\r
+\r
+' Reset all enemies to off-screen positions\r
+FOR enemyIndex = 1 TO 10\r
+ enemyYPositions(enemyIndex) = 1000\r
+ enemyHorizontalSpeeds(enemyIndex) = 1\r
+ enemyVerticalSpeeds(enemyIndex) = 0\r
+NEXT enemyIndex\r
+\r
+' Set background color and clear screen\r
+CLS\r
+PAINT (1, 1), levelSkyColor(currentLevelNumber)\r
+GET (1, 2)-(20, 21), emptySpaceSpriteBuffer\r
+\r
+' Process each character in level data to render elements\r
+FOR rowIndex = 2 TO 10\r
+ FOR columnIndex = 1 TO 15\r
+ ' Extract single character from level data row\r
+ character$ = RIGHT$(LEFT$(levelRowData(rowIndex), columnIndex), 1)\r
+\r
+ ' Render different elements based on character code\r
+ IF character$ = "-" THEN PUT ((columnIndex - 1) * 20, (rowIndex - 2) * 20), cloudSpriteBuffer, OR\r
+ IF character$ = "." THEN PUT ((columnIndex - 1) * 20, (rowIndex - 2) * 20), powerUpSpriteBuffer, OR\r
+ IF character$ = "+" THEN PUT ((columnIndex - 1) * 20, (rowIndex - 2) * 20), treeSpriteBuffer, OR\r
+ IF character$ = "$" THEN PUT ((columnIndex - 1) * 20, (rowIndex - 2) * 20), coinSpriteBuffer, OR: levelGrid(columnIndex, rowIndex - 2) = "1"\r
+ IF character$ = "m" THEN PUT ((columnIndex - 1) * 20, (rowIndex - 2) * 20), solidBlockSpriteBuffer, PSET: levelGrid(columnIndex, rowIndex - 2) = "m"\r
+ IF character$ = "o" THEN PUT ((columnIndex - 1) * 20, (rowIndex - 2) * 20), brickSpriteBuffer, PSET: levelGrid(columnIndex, rowIndex - 2) = "m": interactiveObjectsGrid(columnIndex, rowIndex - 2) = "o"\r
+ IF character$ = " " THEN levelGrid(columnIndex, rowIndex) = " "\r
+\r
+ ' Place enemies based on numeric character codes (1-9,0)\r
+ IF character$ = "1" THEN enemyXPositions(1) = (columnIndex - 1) * 20: enemyYPositions(1) = (rowIndex - 2) * 20: GET (enemyXPositions(1), enemyYPositions(1))-(enemyXPositions(1) + 20, enemyYPositions(1) + 20), enemyBackgroundBuffers(202, 1)\r
+ IF character$ = "2" THEN enemyXPositions(2) = (columnIndex - 1) * 20: enemyYPositions(2) = (rowIndex - 2) * 20: GET (enemyXPositions(2), enemyYPositions(2))-(enemyXPositions(2) + 20, enemyYPositions(2) + 20), enemyBackgroundBuffers(202, 2)\r
+ IF character$ = "3" THEN enemyXPositions(3) = (columnIndex - 1) * 20: enemyYPositions(3) = (rowIndex - 2) * 20: GET (enemyXPositions(3), enemyYPositions(3))-(enemyXPositions(3) + 20, enemyYPositions(3) + 20), enemyBackgroundBuffers(202, 3)\r
+ IF character$ = "4" THEN enemyXPositions(4) = (columnIndex - 1) * 20: enemyYPositions(4) = (rowIndex - 2) * 20: GET (enemyXPositions(4), enemyYPositions(4))-(enemyXPositions(4) + 20, enemyYPositions(4) + 20), enemyBackgroundBuffers(202, 4)\r
+ IF character$ = "5" THEN enemyXPositions(5) = (columnIndex - 1) * 20: enemyYPositions(5) = (rowIndex - 2) * 20: GET (enemyXPositions(5), enemyYPositions(5))-(enemyXPositions(5) + 20, enemyYPositions(5) + 20), enemyBackgroundBuffers(202, 5)\r
+ IF character$ = "6" THEN enemyXPositions(6) = (columnIndex - 1) * 20: enemyYPositions(6) = (rowIndex - 2) * 20: GET (enemyXPositions(6), enemyYPositions(6))-(enemyXPositions(6) + 20, enemyYPositions(6) + 20), enemyBackgroundBuffers(202, 6)\r
+ IF character$ = "7" THEN enemyXPositions(7) = (columnIndex - 1) * 20: enemyYPositions(7) = (rowIndex - 2) * 20: GET (enemyXPositions(7), enemyYPositions(7))-(enemyXPositions(7) + 20, enemyYPositions(7) + 20), enemyBackgroundBuffers(202, 7)\r
+ IF character$ = "8" THEN enemyXPositions(8) = (columnIndex - 1) * 20: enemyYPositions(8) = (rowIndex - 2) * 20: GET (enemyXPositions(8), enemyYPositions(8))-(enemyXPositions(8) + 20, enemyYPositions(8) + 20), enemyBackgroundBuffers(202, 8)\r
+ IF character$ = "9" THEN enemyXPositions(9) = (columnIndex - 1) * 20: enemyYPositions(9) = (rowIndex - 2) * 20: GET (enemyXPositions(9), enemyYPositions(9))-(enemyXPositions(9) + 20, enemyYPositions(9) + 20), enemyBackgroundBuffers(202, 9)\r
+ IF character$ = "0" THEN enemyXPositions(10) = (columnIndex - 1) * 20: enemyYPositions(10) = (rowIndex - 2) * 20: GET (enemyXPositions(10), enemyYPositions(10))-(enemyXPositions(10) + 20, enemyYPositions(10) + 20), enemyBackgroundBuffers(202 _\r
+, 10)\r
+ NEXT columnIndex\r
+NEXT rowIndex\r
+UpdateHUD 0\r
+END SUB\r
+\r
+SUB PlayHurtSound\r
+' Plays distinctive "hurt" sound effect with descending pitch.\r
+' Creates two converging tones that slide downward in frequency.\r
+\r
+startFrequency = 1700\r
+endFrequency = 1900\r
+FOR toneStep = 1 TO 50\r
+ startFrequency = startFrequency + 3\r
+ endFrequency = endFrequency - 5\r
+ SOUND startFrequency, .2\r
+ SOUND endFrequency, .2\r
+NEXT toneStep\r
+END SUB\r
+\r
+SUB RenderFlippedSpriteFromFile (x%, y%, widthMultiplier%, heightMultiplier%, Filename$)\r
+' Renders sprite from text file but flips horizontally during rendering.\r
+' File format: first line = height, subsequent lines contain ASCII art\r
+' where each character's ASCII value determines color (offset by 40).\r
+\r
+x = x * 8\r
+y = y * 8\r
+spriteWidth = widthMultiplier - x\r
+spriteHeight = heightMultiplier - y\r
+OPEN "IMG/" + Filename$ + ".i01" FOR INPUT AS #1\r
+INPUT #1, spriteHeight\r
+FOR row = 1 TO spriteHeight\r
+ LINE INPUT #1, rowText$\r
+ FOR column = LEN(rowText$) TO 1 STEP -1\r
+ ' Calculate screen coordinates and color from ASCII value\r
+ currentColor = ASC(LEFT$(RIGHT$(rowText$, column), 1)) - 40\r
+ ' Draw filled rectangle for each pixel (scaled by multipliers)\r
+ LINE (x + (column * widthMultiplier), (y + (row * heightMultiplier)) + 1)-(x + ((column + 1) * widthMultiplier), y + ((row + 1) * heightMultiplier)), currentColor, BF\r
+ NEXT column\r
+NEXT row\r
+CLOSE\r
+END SUB\r
+\r
+SUB RenderSpriteFromFile (x%, y%, widthMultiplier%, heightMultiplier%, SpriteName$)\r
+' Renders sprite from text file in normal orientation.\r
+' File format and rendering identical to RenderFlippedSpriteFromFile\r
+' but processes characters left-to-right instead of right-to-left.\r
+\r
+spriteWidth = widthMultiplier - x\r
+spriteHeight = heightMultiplier - y\r
+OPEN "IMG/" + SpriteName$ + ".i01" FOR INPUT AS #1\r
+INPUT #1, spriteHeight\r
+FOR row = 1 TO spriteHeight\r
+ LINE INPUT #1, rowText$\r
+ FOR column = 1 TO LEN(rowText$)\r
+ ' Calculate color from ASCII value (offset by 40)\r
+ currentColor = ASC(RIGHT$(LEFT$(rowText$, column), 1)) - 40\r
+ ' Draw scaled pixel block\r
+ LINE (x + (column * widthMultiplier), (y + (row * heightMultiplier)) + 1)-(x + ((column + 1) * widthMultiplier) - 1, y + ((row + 1) * heightMultiplier)), currentColor, BF\r
+ NEXT column\r
+NEXT row\r
+CLOSE\r
+END SUB\r
+\r
+SUB ShowIntroScreen\r
+' Displays introductory splash screen using sprite rendering.\r
+\r
+CLS\r
+RenderSpriteFromFile 2, 2, 10, 1, "win.i01"\r
+END SUB\r
+\r
+SUB UpdateHUD (coinIncrementAmount%)\r
+' Updates Heads-Up Display showing coins and lives:\r
+' - Processes coin counter (with 100-coin bonus life)\r
+' - Draws coin counter digits\r
+' - Shows remaining lives\r
+\r
+' End game if no lives remain\r
+IF lives < 0 THEN GameOverSequence\r
+\r
+' Draw coin icon at left of HUD\r
+PUT (0, 180), largeCoinSpriteBuffer, PSET\r
+\r
+' Add new coins to counter\r
+CoinDigits(1) = CoinDigits(1) + coinIncrementAmount%\r
+\r
+' Handle decimal carry-over for coin counter\r
+FOR digitPosition = 1 TO 3\r
+ ' Carry from ones place to tens place\r
+ IF CoinDigits(1) > 9 THEN\r
+ CoinDigits(1) = CoinDigits(1) - 10\r
+ CoinDigits(2) = CoinDigits(2) + 1\r
+ END IF\r
+\r
+ ' Convert 100 coins to extra life\r
+ IF CoinDigits(2) > 9 THEN\r
+ CoinDigits(1) = 0\r
+ CoinDigits(2) = 0\r
+ lives = lives + 1\r
+ END IF\r
+NEXT digitPosition\r
+\r
+LOCATE 1, 1\r
+digitPosition = 3\r
+' Draw both digits of coin counter\r
+FOR hudElement = 1 TO 2\r
+ digitPosition = digitPosition - 1\r
+ PUT ((hudElement * 11) + 10, 180), digitImages(100, CoinDigits(digitPosition)), PSET\r
+NEXT hudElement\r
+\r
+' Cap maximum lives at 10\r
+IF lives > 10 THEN lives = 10\r
+\r
+' Draw "X" before lives counter\r
+PUT (43, 180), digitImages(100, 10), PSET\r
+' Draw small coin icon next to lives counter\r
+PUT (53, 180), smallCoinSpriteBuffer, PSET\r
+' Draw current lives count\r
+PUT (73, 180), digitImages(100, lives), PSET\r
+END SUB\r
+\r
+SUB UpdateLoadingScreen\r
+' Visual progress indicator during asset loading.\r
+' Draws black screen with incremental dots on bottom row.\r
+\r
+LINE (0, 0)-(319, 150), 0, BF\r
+LOCATE 20, 10 + loadingProgressDotCount\r
+loadingProgressDotCount = loadingProgressDotCount + 1\r
+PRINT "."\r
+END SUB\r
+\r
+SUB WaitForUserInput\r
+' Waits for any keyboard input before continuing.\r
+' Clears userInput$ variable first, then polls INKEY$ until non-empty.\r
+\r
+userInput$ = ""\r
+WHILE userInput$ = ""\r
+ userInput$ = INKEY$\r
+WEND\r
+END SUB\r
+\r
--- /dev/null
+ 10 \r
+((]]]]]]((\r
+(]]]]]]]](\r
+]]]]((]]]]\r
+]]]((((]]]\r
+]]]((((]]]\r
+]]]((((]]]\r
+]]]((((]]]\r
+]]]]((]]]]\r
+(]]]]]]]](\r
+((]]]]]]((\r
--- /dev/null
+ 10 \r
+((((]]](((\r
+(((]]]]]((\r
+(((]]]]]((\r
+(((]]]]]((\r
+(((]]]]]((\r
+(((]]]]]((\r
+(((]]]]]((\r
+(((]]]]]((\r
+(((]]]]]((\r
+((((]]](((\r
--- /dev/null
+ 10 \r
+(]]]]]]]((\r
+]]]]]]]]](\r
+]]]]((]]]]\r
+(]](((]]]]\r
+((((]]]]](\r
+(((]]]]]((\r
+(]]]](((((\r
+]]]](((]](\r
+]]]]]]]]]]\r
+(]]]]]]]](\r
--- /dev/null
+ 10 \r
+(]]]]]]]](\r
+]]]]]]]]]]\r
+(]](((]]]]\r
+(((((((]]]\r
+(((((]]]](\r
+(((((]]]](\r
+(((((((]]]\r
+(]](((]]]]\r
+]]]]]]]]]]\r
+(]]]]]]]](\r
--- /dev/null
+ 10 \r
+(((]](((](\r
+((]]](((]]\r
+((]]]((]]]\r
+(]]](((]]]\r
+(]]]((]]]]\r
+]]]]]]]]]]\r
+(]]]]]]]]]\r
+(((((]]]](\r
+(((((]]]](\r
+((((]]]]((\r
--- /dev/null
+ 10 \r
+((]]]]]]((\r
+(]]]]]](((\r
+(]](((((((\r
+(]](((((((\r
+(]]]]]]]](\r
+((]]]]]]]]\r
+(((((((]]]\r
+]]](((]]]]\r
+]]]]]]]]](\r
+(]]]]]]]((\r
--- /dev/null
+ 10 \r
+((]]]]]]((\r
+]]]]]]]]](\r
+]]](((]]](\r
+]]](((((((\r
+]]]]]]]]](\r
+]]]]]]]]]]\r
+]]]((((]]]\r
+]]](((]]]]\r
+]]]]]]]]](\r
+(]]]]]]]((\r
--- /dev/null
+ 10 \r
+(]]]]]]]](\r
+]]]]]]]]]]\r
+]]]((((]]]\r
+(](((((]]]\r
+((((]]]]]]\r
+((]]]]]]](\r
+((((((]]](\r
+(((((]]]((\r
+((((]]](((\r
+((((]]](((\r
--- /dev/null
+ 10 \r
+((]]]]]]((\r
+(]]]((]]](\r
+(]]((((]](\r
+((]]((]]((\r
+(]]]]]]]](\r
+]]]]((]]]]\r
+]]]((((]]]\r
+]]]]((]]]]\r
+(]]]]]]]](\r
+((]]]]]]((\r
--- /dev/null
+ 10 \r
+(]]]]]]]((\r
+]]]]]]]]](\r
+]]](((]]]]\r
+]](((((]]]\r
+]]](((]]]]\r
+(]]]]]]]]]\r
+((]]]((]]]\r
+((((((]]]]\r
+((]]]]]]](\r
+((]]]]]]((\r
--- /dev/null
+ 20 \r
+(DDDDDDDDDDDDDDDDDD(\r
+D(EEEEEEEEEEEEEEEE(=\r
+DE(EEEEEEEEEEEEEE(>=\r
+DEE@@@@@@@@@@@@@@?>=\r
+DEE@???????????D@?>=\r
+DEE@??CCCCCCCCCD@?>=\r
+DEE@?CCCCCCCCCCD@?>=\r
+DEE@?CCCCCCCCCCD@?>=\r
+DEE@?CCCCCCCCCCD@?>=\r
+DEE@?CCCCCCCCCCD@?>=\r
+DEE@?CCCCCCCCCCD@?>=\r
+DEE@?CCCCCCCCCCD@?>=\r
+DEE@?CCCCCCCCCCD@?>=\r
+DEE@?CCCCCCCCCCD@?>=\r
+DEE@?CCCCCCCCCCD@?>=\r
+DEE@DDDDDDDDDDDD@?>=\r
+DEE@@@@@@@@@@@@@@?>=\r
+DE=??????????????(>=\r
+D(>>>>>>>>>>>>>>>>(=\r
+(==================(\r
--- /dev/null
+ 10 \r
+(((TTTT(((\r
+(TTTSSSSR(\r
+TTSSSSSSSR\r
+TSSS\\SSSR\r
+TSSS\]SSSR\r
+TSSS\]SSSR\r
+TSSS\]SSSR\r
+TSSS\]SSSR\r
+(SRSSSSRR(\r
+(((RRRR(((\r
--- /dev/null
+ 10 \r
+(((TTTT(((((((((((((\r
+(TTTSSSSR((FF((((FC(\r
+TTSSSSSSSR(FCC((FC@(\r
+TSSS\\SSSR((CCCFC@((\r
+TSSS\]SSSR(((CCC@(((\r
+TSSS\]SSSR(((FCC@(((\r
+TSSS\]SSSR((FCC@C@((\r
+TSSS\]SSSR(FC@((@C@(\r
+(SRSSSSRR((C@((((@@(\r
+(((RRRR(((((((((((((\r
--- /dev/null
+ 10 \r
+((QQQQ((((((((((((((\r
+(QQQQQQ((((FF((((FC(\r
+((jjjj(((((FCC((FC@(\r
+((jjjj((((((CCCFC@((\r
+(c(jj(c((((((CCC@(((\r
+c]]]]]]c(((((FCC@(((\r
+((]]]]((((((FCC@C@((\r
+(]]]]]]((((FC@((@C@(\r
+XX]((]XX(((C@((((@@(\r
+XXX((XXX((((((((((((\r
--- /dev/null
+ 20 \r
+(RRRRRQQQQ((((((((((\r
+RRQQQQQQQQQ(RRRR((((\r
+RQQQQQQQQQQRRQQQQ(((\r
+RQQQQQQQQQQQQQQQ((((\r
+QQQQQQQQQQQQQ(((((((\r
+QQQQQQQQQ((\81((((((((\r
+(QQQQQQQ\81\81\81\81\81\81((((((\r
+((\81\81\81\81\81\81\81\81\81\81\81\81\81(((((\r
+((\81\81\81\81\81\81\81\81\81\81\81\81((((((\r
+(((\81\81\81\81\81\81(\81(((((((((\r
+(((((\81\81\81\81\81((((((((((\r
+((((((JJJJJ(((((((((\r
+((((((JJJJJJ((((((((\r
+(((((JJJJJIJ((((((((\r
+(((((JIIIIJJ((((((((\r
+((((IIIIIIIJ((((((((\r
+((((IIIIIIJJJ(((((((\r
+((XXXIII(JJJJXXX((((\r
+(XXXXXXX((JXXXXXXX((\r
+((XXXXX((((XXXXXX(((\r
--- /dev/null
+ 20 \r
+(RRRRQQQQ(((((((((((\r
+RQQQQQQQQQ((((((((((\r
+QQQQQQQQQQRRRRR(((((\r
+QQQQQQQQQQQQQQQQ((((\r
+QQQQQQQQQQQQQQQ(((((\r
+QQQQQQQQ((\81(((((((((\r
+QQQQQQQ\81\81\81\81\81\81(((((((\r
+(\81\81\81\81\81\81\81\81\81\81\81\81\81((((((\r
+(\81\81\81\81\81\81\81\81\81\81\81\81(((((((\r
+((\81\81\81\81\81\81(\81((((((((((\r
+((((\81\81\81\81\81(((((((((((\r
+(((((JJJJJ((((((((((\r
+(((((JJJJJJ(((((((((\r
+((((JJJJJIJ(((((((((\r
+((((JIIIIJJ(((((((((\r
+(((((IIIIIJ(((((((((\r
+(((((IIIII((((((((((\r
+((((XXXXXXXX((((((((\r
+(((XXXXXXXXXX(((((((\r
+((((XXXXXXXX((((((((\r
--- /dev/null
+ 30 \r
+(((((((((((((((((((((((((\\(\((((((((((((((((((((((((](((((((((]((((]((((]](((((((((((((((((((((((((\r
+((((((((((((((((((((((((\((((((((\\(((((((((\(((((((((]]((\(((\(((\((]](]]((((((((((((((((((((((((((\r
+((((((((((((((((\((\((\(\]\\((\(\(((((((]((((((((](((\((\]((((\(]\(\(]]]]]](((((((((((((((((((((((((\r
+(((((((((((((((((((]t\\(]]]\\\](](((\((]((](](((((((]((((\(\]](\((]\(((((\\(](](\]\(((((((((](((((((\r
+((((((((((t((\8fwt\8f\8f\\\t](tt\(]\\((\(](\\t\t((((]\t(](((\((\]\](\(\]](]]((]\(]](((]`\`\(\\](((((((((((\r
+(((((t((((((tttttt\8ft(t\\(\\((\(]]]\t((\\]\]((((\(](\((\\(]\(](`\\`]](\]\\]\(t\\\`\\t(t\]((](((((((((\r
+((((t(tt(t((t\8fttt\8ftt]t\\(](\\(t(t\\ttt\]tt]t\\(]\tt]](\((t]\](\t]((t]\t(]`\t(]]tt\\(tt\\]](]((((((((\r
+((((((\(ttt(tt\8f\8f\8ft\8f\tt]tt\\\\t\]\tt\(\t]((\\\tt\((]](\\t]tt(\\\(tt(t\(`]\`]]\\\\\(\`tt``^```(`((((((\r
+((((tt(tttt\8f\8ftttttt\\t]\tt]ttt(]\\\\\t\\t(\\((\\t\]t\\]]`\\\](\`]\\(\\]\`(t\\\t\\tt\\^(``]\(\]((]`((\r
+(((t\(t\ttt\]\8ft\8ftt\t\8ft]]]\\t]ttt]]t\t\\]ttt\]](tt\(]t\\\]t\t`t\\]\\tt]\^\t]\\\\\tt\\`t\t`^`(\`\]]]((\r
+(((((tt]]t\\twt\\8f\\t\8f\]tt]]t(]\t\tt]\tttt\tt]\((t(\\\t\`]t(\]t\\`\t\\(\\\t\t]^\\t\\\tt\t\\^```(`(]((\r
+((t(](\ttttwttw]t\\tt(^t\(t]\]tt\(\t]t\\t(]]\]ttt\\tttt\]\^]\tt\]``\t`(\tt\`^\\\\\ttt\tt\\`]\\^((\((\r
+]t(]]]]tt]t\t^t\tt\t(\](tt]\tt]\t\\\\\]t\tt`t\\`^]\]t\]]]tt\`(`(]`\tt\\`\t\t]\\tt\ttt^t\\`\`]``(\]((\r
+(]t]t\\t\\t\^t\^t\](\]]\]]t\(ttttt\]t\t\`\t\t\t\\\\`^t`(t(]]t]t`]]t]\\\^tt\]`\t\\t\\``t\\`\``\]t``\(\r
+(]t(tt\\\\\\\\\]^t]]t^t]tt\t^\\]]]]`t\]\t`]\t^```\^^]`\tt^t]`\`]^^\\\\\\\\]^(`\^`\\\\\\^``\```]`\`(]\r
+(](t^^]\\]\\\]t^\]]^]]\^^\]]t\`\^^``]t`^\\`\\`^`]\^\`t]\^^^`^]\\^^^\\\\\]]\`\^````\\]^`\`^`\```]``](\r
+]]]]](t]`t]^\]^]]^]^]^^]^^]`\^\]`]\]`\\\\``]`\`t\\`^]```^`]^^^^^]\^^\t\``]`\\``]\\^\^^^\\\```````]]]\r
+((^((]](`]]`]^^`^^]^`]]\]``\\(\(\`]``\```]`^^^````^````t(]`^t]^^t`\\]^^\^\^`^\^``\]\\````^`\`]```(](\r
+](^]((]\`(``]]]^``^t]^^]]t]``t`]``(`````\``\``\\`\```t`^t^(^^^^^]]t^`(\\^\^`(`^^^`\^```\````\]````](\r
+]((^^]]`]^]^\`]``t^```````\`^`\`\``\^t```````]`````]^`^]]^^t^(^(^]``^```\\\`^]]]^^^^]``^````t]``]``(\r
+(((^((]``^^`^^``^^^^^^]]t`t````^`^`^`^\^`]````````````^`````^^^`]`]^^^^^((]``^^`^]]^^`````]``^^(t`(]\r
+(]^(^(`(`^]]`]`^^^`]^```^^`````t`\^`^`````````^`(`^t^`t^`^^^(```t(`^]]^^^^```^]`]``]^`(```(^(`tttt((\r
+^(^(^(((t](((`]]`^`t``t```^``^``````^````(^`(````^^^``^`(```^]``]^(]`^```]````````(]^``]t]`^`](^(`((\r
+(((tt^(^((((]`^`^```t````^```^^^]``````](`tt``]``^```(^^`]``(``t````t```(``]`^]^t`]^`(`^^^^``tt]`(((\r
+(((((((]^](((``]`(`^`]^^^``]`]]((```(`(^```]((]^`^`````````(`((t``^`````]`^(^^```(`^`](`t]^((^(`((((\r
+(((((((((]((t(^`(`^``((``(^(``^(((((((((``((^``````^(^`t`(`^t``````^]((^^^`](^```((`]((`(]^`((^]((((\r
+(((((((((((t(^``(`(t^(^(`^(^^^((^(`((^(`]((((](((````^(`((((``((``((``(^`]`(]]]]``]``]````(`(``(`(((\r
+(((((((((((((^(^((((((^^(((^(((^(((^^`((`((]`((((^`((`(^``((```^`((((^(((t`(^`((`^(`(]`^`(((`^((((((\r
+((((((((((((((((((((^(((^(((((^(((((((((((((((((^(`^^`^(((^((^((``(((`((((`](((((((^(``(((`(((((((((\r
+(((((((((((((((((((^(((((((^((^(((((((((((((((((((((^(`(^^(`((((((^^(^((`((((](`((((((((((((((((((((\r
--- /dev/null
+ 20 \r
+((((((((((((((((((((((((((((((q((((q(q((((((((((((((((((((((\r
+((((((((((q((q(((q(((qq(((((((qq\8aqqqq(((((((qq((((((((((((((\r
+((((((((((q(q(((q(qq((qq((q((qqq(((q(qq(qq;(qq(q((((((((((((\r
+(((((((((qq(q(\8a(((q(q(q(q((((q2qqq(qqq(q(;((;q(q((((((((((((\r
+(((((qqq(q(q(((222\8aqqq(((\8aq(qqqq\8aq2qqqq2((;\8a((q(((q?q(((((((\r
+((((qq(nq(((q((2(qq2q2q(((nn(\8aq(qqq(nqq2n2;(qnq?(;???(((((((\r
+((((((qqqq2q(qqq2\8a(22\8a(qqq(\8aqq2n(2nqq2qqq(nq?q?\8a2;;;?(((((((\r
+(((((qn(qqqq\8a(\8a(qXn22X\8a(nq\8a\8aq2(22qq22(22(2?Y??2q;?q;22((((((\r
+((((q((qq2qq\8aqqnq2nX\8aX\8aqq2\8a\8aqq\8aqX2q22((qq;(Yq???;;2;;2q(((((\r
+((((((q(22(2q2(((nqqXX\8a(XX2Xq(q2\8a22nq22q?qY((?(?qqqq;???((((\r
+(((q(qq(qqqYYXq((YXXY\8aX2\8a2\8aX2\8aq;?2???2q;;q;X?2???;?;Y;??q(((\r
+(((q(q(q22222YYX2(XX?X2q2?qX2q?YYYn2q;Y;X2???X?;?;;;??;;((((\r
+(((n(qq(\8a2\8a22XYqXY?XY;2;???qq?;?Y;?2Y;2;;Y;?XX9X9;;(9;??;(((\r
+((((qnX\8a?YY22\9f\9f???YYqqX?;qXqqq;;???;@;;;;??X\9d;;?X?q;;;9?;(?(\r
+(nnn\8aX2?2??YX\9f\9fX2q?X;2;;?qq;;;q;?;;;;;;;\9f;X\9d;9;?X;;@;@;;?99(\r
+qqqnq\8aq222\8aX\9f\9f?Y(\9fY??;qq?2;?;q?;?;;?@X;;;?\9f;9999;9@;;;;;9n?9\r
+nqnqqn2??Y??(X?Y\9f\9fX?;?;?X?;Xq;;\9fX;n\9f@;\9f;;;;\9f9;;2;;@;;?;;9((9\r
+nnqqq2(?\9fn?n\9f\9f\9f?\9fY22X;X?q;;;;;qqq;;q;\9f;;;q9X\9d;;99;@;\9d;9;;;??\r
+qnq(qqnqq???\9f\9fX(?n\9fqX(XXqq2;nqq;;;\9f\9fq\9f\9f;\9f\9f;Xq;q;\9d\9d9n;\9d;??n?9\r
+((nn((q\9f(\9fnXn\9f(n\9fXn\9fn(XqqX2\9f\9f;q\9f(qq;(\9f\9fq\9f(9\9d9\9fq\9d\9d\9d?\9d;\9f\9f?????\r
--- /dev/null
+ 60 \r
+(((((((((((((((X(((((X((T(((((((((((((((\r
+(((((((((((((((X((T((X(X((((((((((((((((\r
+((((((((((((X(((((X(X((((((X(X((((((((((\r
+(((((((((((((XX((X(((((((((T((((((((((((\r
+((((((XX((((XX(XTT(X(TXXT(((((X(((((((((\r
+((((((((((((((X((X(TXXT\9f\9f(XXXX((((((((((\r
+((((((X(X((XXX(XXXTTT(XXXTX(X(((((((((((\r
+(((((((XX((X(XX((T((XXXX(T((XXX(X(X(((((\r
+((((X(X((XXXT((XX(XXX(TXXT\9fXX(X\9f(X((((((\r
+((((XXX((((XT(X(XXXTTT(XX\9fX\9f\9f\9f\9fX((X(((((\r
+(((((X((((XT((XX((XT(XTX((XX(\9fX((((\9f\9f(((\r
+(((X((X(((TX((XXXXTXX(TT\9f(((((\9fX\9f((\9fX(((\r
+((((X(XX((X(XX(X(TX(((TTT\9fX\9f(\9fXX\9f(((((((\r
+((((X(XXXXXX((XXTTXX(TXTTT(T(X\9fX(\9f(XX(((\r
+(((((X(XX(TXXTTT(TXXT(X((X((((X\9f(X(XX(((\r
+((((((X((X(XXXXXT(XXX(TT((T(X(((((((X(((\r
+(((XX((XX(((X(TXXX(TX(TTTTXT(\9f(((\9f((\9f(((\r
+(X(((X(((X(T((X(X(XX(T(XXTX(T\9fX((\9f\9fX((((\r
+((XX(X((((((XTX(TTTXTXT(XX((XX(\9f(\9f\9f(((X(\r
+((((((XXXX((X(XXTTXT(XX\9fTT(T(((X\9f((XX(((\r
+(((XXXX(X(((X(T(TTTTXXXXTX(X(XXXX(X(\9f(X(\r
+(((((((((X(XXXXX(XT(X(X((X(XXX(XXX((\9f(((\r
+X(((((X((X(X(X((XTT(((((XX\9f(XXXX\9f(\9f((X\9f(\r
+(((XXX(XXX((X(((XTXX(T(X((\9f(((\9fX(XXXX(X(\r
+(((X(((TTX((TTXTT(XXXT(X\9f\9f(XXX((XX\9f((X(\9f\r
+((X((((XTX(((X(XX(XTT(XXXX((XX(XX\9f(X((\9fX\r
+(((((TX(((X((T(XTTXXXTXX(XX\9fX(X((\9f((((((\r
+((X(X(TXTX(XX((XTTXX(X(X\9fXX\9fT\9fXXXX(\9f(\9f((\r
+((((X(X(X((TXTTT(((X\9f\9fX(XT((XXXXX(\9f(((\9f(\r
+((((X((X((T((X(TXXXXXXX\9f(T\9fX(XX\9f\9f((\9f\9f(((\r
+((((X(((TXTXX(XXX(((XXX(\9fX\9f\9f(X\9f\9f(\9f\9f\9f\9f\9f((\r
+((XX((XXXX((XX(((XX(XXX(T\9f\9f\9fX\9f(XXX\9f\9f((((\r
+((((((X((XTXXTTTXXXXXX\9a\9a\9a\9f(TXT\9f(\9f((((X((\r
+(((X(((XXXTTXTT(T(TX(\9f\9a\9f\9aX\9f\9f\9f(X(\9f\9f(X((((\r
+((X(((((XXT(TTT(X((T(\9aX\9aXXT\9f\9f\9f(\9f\9f\9f((((((\r
+(X(XXXX(X((X((TXTT(TT\9f\9aXX\9f\9f\9fXX(X(\9f(XX(((\r
+((((X(((XXXXTXXX(((T\9f\9a\9fXX\9fX\9fX\9fX\9f(\9fX(((((\r
+(((((((XX(XXX(XXTX((\9f\9a\9a\9aT\9f\9f(\9fTXX(TX(\9f(((\r
+(((((XXXXXXX((X(X(\9f\9f\9f\9a\9a\9a\9fX\9f\9f\9fXT(X((X((((\r
+(((X(((XXXXX(XT(TT(X\9f\9a\9a\9aX\9f\9f\9fTT\9fX\9f((((\9f((\r
+((((((XX(XX((X(XTX\9f\9f\9a\9a\9aX((XXXXTX(((\9f((((\r
+(((((X(XXXXXXXXX\9f(\9f(\9f\9aX\9a(X\9fXTXX((X((((((\r
+(((((((X(X\9fX(XX((T\9f\9f\9fXX\9f\9f(XX\9fXXXX(((((\9f(\r
+((((((XX(XX((XXTX(X(\9a\9a\9a\9fX(XXXX(XXX(X((((\r
+((((((((((XXX\9fX\9a\9a\9f(\9a\9a\9aX\9f(X(TXXX((X((((((\r
+((((((((((X(\9fX(\9a\9f\9aX\9f\9a\9aXX(X(XXX(X((((((((\r
+(((((((((XXX(X\9f\9a\9a\9fX\9f\9aXX\9f\9fX(((X(((((\9f((((\r
+(((((((((((X((X\9a\9a\9f\9f\9f\9f\9aXXX(X(\9fX(\9f\9f(((((((\r
+((((((((((XXX\9f(\9a\9a\9f\9f\9f\9f\9fX\9f\9f(X(((\9f(\9f\9f((((((\r
+(((((((((((((XXX(\9a\9a\9f\9a\9aXX(((((X((((((((((\r
+(((((((((((\9f(X((T\9a\9f\9aXX\9f\9f((((X(\9f(((((((((\r
+((((((((((X(((XX(\9a\9aX\9a\9a\9f\9f((((((((((((((((\r
+((((((((((((((((\9fX\9aXX\9aX(\9f(((((\9f(((((((((\r
+((((((((((((((X(XX\9a\9f\9f\9f((\9f(((((((((((((((\r
+(((((((((((\9f(((XX(\9a\9a\9a\9a(\9f((((((((((((((((\r
+((((((((((((((((((\9a\9a\9a\9aX(((\9f(((((((((((((\r
+((((((((((((((\9f(((\9a\9a\9a\9a((((((((((((((((((\r
+((((((((((((((((((\9a\9a\9a\9a((((((((((((((((((\r
+(((((((((((((((\9f((\9a\9a\9a\9a((((((((((((((((((\r
+((((((((((((((((((\9a\9a\9a(((((((((((((((((((\r
--- /dev/null
+ 20 \r
+00000000000000000000\r
+0@@//@/////////////0\r
+0@//////////@//////0\r
+0//@///////////////0\r
+0@//@//////////////0\r
+00000000000000000000\r
+/////////00@/@/@////\r
+/@///////00@////////\r
+@@///////00//@//////\r
+@////////00/////////\r
+00000000000000000000\r
+0@@////////////////0\r
+0/////@///@////////0\r
+0@///////////@/////0\r
+0//@/////////@@////0\r
+00000000000000000000\r
+/////////00@@///////\r
+/////////00@////////\r
+/////////00/////////\r
+/////////00/////////\r
--- /dev/null
+ 20 \r
+((((((((((((((((((((\r
+((((((((((((((((((((\r
+<(((((((((((((((((((\r
+?((((((((<((((((((((\r
+??((((((??((((((((((\r
+(?(((((??(((((((((((\r
+(??((???((((((((((((\r
+((????((((((((((((((\r
+(((??(((((((((((((((\r
+((<<<(((((((((((((((\r
+<<???<((((((((((((((\r
+<(???<<(((\9b\9b\9b\9b\9b\9b((((\r
+((????((\9b\9b\9b\9b\9b\9b\9b\9b\9b(((\r
+((????(\9b\9b\9b\9b\9b\9b\9b\9b\9b\9b\9b((\r
+((?????\9b\9b\9b\9b\9b\9b\9b\9b\9b\9b\9b((\r
+((?????\9b\9b\9b\9b\9b\9b\9b\9b\9b\9b(((\r
+((??????\9b\9b\9b\9b\9b\9b\9b\9b\9b(((\r
+(((??????\9b\9b\9b\9b\9b\9b\9b((((\r
+((((???????????????(\r
+((((((??????????????\r
--- /dev/null
+ 20 \r
+((((((((((((((((((((\r
+((((((((((((((((((((\r
+((((((((((((((((((((\r
+((((((((((((((((((((\r
+(((((??<((((((((((((\r
+((((??((((((((((((((\r
+(<((?((((?<(((((((((\r
+(<(??????(((((((((((\r
+(<<??(((((((((((((((\r
+((<<<<<<((((((((((((\r
+((???(((((((((((((((\r
+((????((\9b\9b\9b\9b\9b\9b\9b(((((\r
+(?????\9b\9b\9b\9b\9b\9b\9b\9b\9b\9b((((\r
+(????\9b\9b\9b\9b\9b\9b\9b\9b\9b\9b\9b((((\r
+?????\9b\9b\9b\9b\9b\9b\9b\9b\9b\9b\9b((((\r
+?????\9b\9b\9b\9b\9b\9b\9b\9b\9b\9b\9b((((\r
+??????\9b\9b\9b\9b\9b\9b\9b\9b\9b(((((\r
+(??????\9b\9b\9b\9b\9b\9b\9b((((((\r
+((????????????????((\r
+((((????????????????\r
--- /dev/null
+' Pomppu Paavo\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 1998, Initial version\r
+' 2025, Improved program readability\r
+\r
+DECLARE SUB DisplayGameStatistics ()\r
+DECLARE SUB LoadCurrentLevel (levelNumber%)\r
+DECLARE SUB RenderSpriteFromFile (xPosition%, yPosition%, spriteID%, animationFrame%)\r
+\r
+DEFINT A-Z\r
+DIM SHARED AsciiLevelData(1 TO 20) AS STRING * 31\r
+DIM SHARED Companion1VerticalPosition%, Companion1HorizontalPosition%, Companion2VerticalPosition%, Companion2HorizontalPosition%\r
+DIM SHARED LivesRemaining%, CoinsCollected%\r
+DIM SHARED DoorEntryX%, DoorEntryY%\r
+DIM SHARED DoorExitX%, DoorExitY%\r
+DIM SHARED CurrentLevelNumber%\r
+DIM SHARED TerrainGrid(0 TO 34, -10 TO 20) AS STRING * 1\r
+DIM SHARED ObjectGrid(0 TO 34, -10 TO 20) AS STRING * 1\r
+\r
+' Full scale sprites (mostly 20x20 pixels)\r
+DIM SHARED SolidTerrainSprite(51)\r
+DIM SHARED EmptySpaceSprite(51)\r
+DIM SHARED BoxSprite(51)\r
+DIM SHARED PlayerSpriteBuffer(70)\r
+DIM SHARED CloudSprite(209)\r
+DIM SHARED StarSprite(50)\r
+DIM SHARED HedgehogSprite(30)\r
+DIM SHARED HedgehogSprite1(30)\r
+DIM SHARED HedgehogSprite2(30)\r
+DIM SHARED CoinSprite(30)\r
+DIM SHARED BushSprite(100)\r
+DIM SHARED WindowSprite(100)\r
+DIM SHARED TrampolineSprite(50)\r
+DIM SHARED IntroScreen(6000)\r
+DIM SHARED TreeSprite(3000)\r
+DIM SHARED RightArrowSprite(51)\r
+DIM SHARED LeftArrowSprite(51)\r
+DIM SHARED HoleSprite(51)\r
+DIM SHARED PlayerRunRight1Sprite(51)\r
+DIM SHARED PlayerRunRight2Sprite(51)\r
+DIM SHARED PlayerRunLeft1Sprite(51)\r
+DIM SHARED PlayerRunLeft2Sprite(51)\r
+DIM SHARED PlayerJumpingSprite(51)\r
+DIM SHARED DoorSprite(120)\r
+\r
+' Define keyboard control sequences using special arrow key codes\r
+leftArrowKey$ = CHR$(0) + "K"\r
+rightArrowKey$ = CHR$(0) + "M"\r
+upArrowKey$ = CHR$(0) + "H"\r
+downArrowKey$ = CHR$(0) + "P"\r
+\r
+LivesRemaining% = 10\r
+\r
+SCREEN 1\r
+CurrentLevelNumber% = 1\r
+\r
+' Capture sprite images from screen drawing operations.\r
+' This technique uses GET command to save drawn graphics directly into arrays.\r
+GET (1, 1)-(20, 20), EmptySpaceSprite\r
+RenderSpriteFromFile 0, 0, 1, 1\r
+GET (1, 1)-(20, 20), SolidTerrainSprite\r
+RenderSpriteFromFile 0, 0, 4, 1\r
+GET (1, 1)-(20, 20), BoxSprite\r
+PUT (1, 180), SolidTerrainSprite, PSET\r
+PUT (300, 1), SolidTerrainSprite, PSET\r
+PUT (300, 180), SolidTerrainSprite, PSET\r
+RenderSpriteFromFile 30, 50, 2, 1\r
+GET (31, 51)-(91, 76), CloudSprite\r
+PUT (160, 10), CloudSprite, PSET\r
+RenderSpriteFromFile 20, 100, 3, 1\r
+GET (21, 101)-(31, 114), StarSprite\r
+CLS\r
+RenderSpriteFromFile 0, 0, 5, 1\r
+GET (1, 1)-(11, 8), HedgehogSprite\r
+CLS\r
+RenderSpriteFromFile 0, 0, 6, 1\r
+GET (1, 1)-(8, 10), CoinSprite\r
+CLS\r
+RenderSpriteFromFile 0, 0, 7, 1\r
+GET (1, 1)-(31, 11), BushSprite\r
+CLS\r
+RenderSpriteFromFile 0, 0, 8, 1\r
+GET (1, 1)-(26, 21), WindowSprite\r
+CLS\r
+RenderSpriteFromFile 0, 0, 9, 1\r
+GET (1, 1)-(21, 11), TrampolineSprite\r
+CLS\r
+RenderSpriteFromFile 0, 0, 11, 1\r
+GET (1, 1)-(51, 81), TreeSprite\r
+CLS\r
+RenderSpriteFromFile 0, 0, 12, 1\r
+GET (1, 1)-(20, 20), RightArrowSprite\r
+CLS\r
+RenderSpriteFromFile 0, 0, 12, 50\r
+GET (1, 1)-(20, 20), LeftArrowSprite\r
+CLS\r
+RenderSpriteFromFile 0, 0, 13, 1\r
+GET (1, 1)-(20, 20), HoleSprite\r
+CLS\r
+RenderSpriteFromFile 0, 0, 14, 1\r
+GET (1, 1)-(20, 20), PlayerRunRight1Sprite\r
+CLS\r
+RenderSpriteFromFile 0, 0, 15, 1\r
+GET (1, 1)-(20, 20), PlayerRunRight2Sprite\r
+CLS\r
+RenderSpriteFromFile 0, 0, 14, 50\r
+GET (1, 1)-(20, 20), PlayerRunLeft1Sprite\r
+CLS\r
+RenderSpriteFromFile 0, 0, 15, 50\r
+GET (1, 1)-(20, 20), PlayerRunLeft2Sprite\r
+CLS\r
+RenderSpriteFromFile 0, 0, 16, 1\r
+GET (1, 1)-(20, 20), PlayerJumpingSprite\r
+CLS\r
+\r
+' Capture the introductory screen image\r
+RenderSpriteFromFile -1, -1, 10, 4\r
+GET (1, 1)-(318, 124), IntroScreen\r
+\r
+key$ = INPUT$(1)\r
+\r
+LoadCurrentLevel 1\r
+PlayerXPosition% = 50\r
+PlayerYPosition% = 50\r
+Companion1HorizontalSpeed% = 1\r
+Companion2HorizontalSpeed% = 1\r
+MainGameLoop:\r
+keyboardInput$ = INKEY$\r
+IF PlayerYPosition% > 0 THEN GET (PlayerXPosition%, PlayerYPosition%)-(PlayerXPosition% + 20, PlayerYPosition% + 20), PlayerSpriteBuffer\r
+\r
+' Display appropriate player animation frame based on current movement state\r
+IF PlayerYPosition% > 0 THEN IF PlayerAnimationState% = 1 THEN PUT (PlayerXPosition%, PlayerYPosition%), PlayerRunRight1Sprite, OR\r
+IF PlayerYPosition% > 0 THEN IF PlayerAnimationState% = 2 THEN PUT (PlayerXPosition%, PlayerYPosition%), PlayerRunRight2Sprite, OR\r
+IF PlayerYPosition% > 0 THEN IF PlayerAnimationState% = 10 THEN PUT (PlayerXPosition%, PlayerYPosition%), PlayerRunLeft1Sprite, OR\r
+IF PlayerYPosition% > 0 THEN IF PlayerAnimationState% = 20 THEN PUT (PlayerXPosition%, PlayerYPosition%), PlayerRunLeft2Sprite, OR\r
+IF PlayerYPosition% > 0 THEN IF PlayerAnimationState% = 3 THEN PUT (PlayerXPosition%, PlayerYPosition%), PlayerJumpingSprite, OR\r
+\r
+' Draw first companion hedgehog to screen\r
+GET (Companion1HorizontalPosition%, Companion1VerticalPosition%)-(Companion1HorizontalPosition% + 10, Companion1VerticalPosition% + 10), HedgehogSprite1\r
+PUT (Companion1HorizontalPosition%, Companion1VerticalPosition%), HedgehogSprite, OR\r
+\r
+' Draw second companion hedgehog to screen\r
+GET (Companion2HorizontalPosition%, Companion2VerticalPosition%)-(Companion2HorizontalPosition% + 10, Companion2VerticalPosition% + 10), HedgehogSprite2\r
+PUT (Companion2HorizontalPosition%, Companion2VerticalPosition%), HedgehogSprite, OR\r
+\r
+' Create short delay using sound command (workaround for lack of built-in sub-second delay in QBasic)\r
+' SOUND 0,0.8 produces an inaudible tone that takes approximately 0.8 milliseconds to process\r
+SOUND 0, .8\r
+\r
+' Check collisions with solid terrain ("z" character in grid)\r
+' Right side collision detection - checks two points along right edge of player hitbox\r
+' Player hitbox is slightly smaller than sprite (38 instead of full 40 width)\r
+IF TerrainGrid((PlayerXPosition% + 38) \ 20, (PlayerYPosition% + 37) \ 20) = "z" THEN PlayerHorizontalSpeed% = -1: HorizontalAnimationCounter% = 9: GroundContactTime% = 0\r
+IF TerrainGrid((PlayerXPosition% + 38) \ 20, (PlayerYPosition% + 22) \ 20) = "z" THEN PlayerHorizontalSpeed% = -1: HorizontalAnimationCounter% = 9: GroundContactTime% = 0\r
+\r
+' Left side collision detection - checks two points along left edge of player hitbox\r
+IF TerrainGrid((PlayerXPosition% + 21) \ 20, (PlayerYPosition% + 22) \ 20) = "z" THEN PlayerHorizontalSpeed% = 1: HorizontalAnimationCounter% = 9: GroundContactTime% = 0\r
+IF TerrainGrid((PlayerXPosition% + 21) \ 20, (PlayerYPosition% + 37) \ 20) = "z" THEN PlayerHorizontalSpeed% = 1: HorizontalAnimationCounter% = 9: GroundContactTime% = 0\r
+\r
+' Top collision detection - checks if player hits ceiling ("z" block above)\r
+IF TerrainGrid((PlayerXPosition% + 22) \ 20, (PlayerYPosition% + 21) \ 20) = "z" THEN PlayerVerticalSpeed% = 0: CeilingContactCooldown% = 10: GroundContactTime% = 0\r
+IF TerrainGrid((PlayerXPosition% + 37) \ 20, (PlayerYPosition% + 21) \ 20) = "z" THEN PlayerVerticalSpeed% = 0: CeilingContactCooldown% = 10: GroundContactTime% = 0\r
+\r
+' Bottom collision detection (landing on ground) - checks if player lands on solid terrain\r
+' When landing, sets vertical speed to negative (bounce effect), resets jump ability\r
+IF TerrainGrid((PlayerXPosition% + 22) \ 20, (PlayerYPosition% + 38) \ 20) = "z" THEN PlayerVerticalSpeed% = -1: VerticalAnimationCounter% = 2: JumpReadinessCounter% = 1: GroundContactTime% = 0\r
+IF TerrainGrid((PlayerXPosition% + 37) \ 20, (PlayerYPosition% + 38) \ 20) = "z" THEN PlayerVerticalSpeed% = -1: VerticalAnimationCounter% = 2: JumpReadinessCounter% = 1: GroundContactTime% = 0\r
+\r
+HazardExposureTimer% = HazardExposureTimer% + 1: IF ObjectGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 30) \ 20) = "q" AND HazardExposureTimer% > 20 THEN HazardExposureTimer% = 1: LivesRemaining% = LivesRemaining% - 1: _\r
+PlayerHorizontalSpeed% = -10: PlayerVerticalSpeed% = -5: DisplayGameStatistics\r
+IF HazardExposureTimer% > 100 THEN HazardExposureTimer% = 50\r
+\r
+' Coin collection logic - when player overlaps coin position ("1" in grid)\r
+IF TerrainGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 30) \ 20) = "1" THEN CoinsCollected% = CoinsCollected% + 1: CoinCollectedFlag% = 1: DisplayGameStatistics: TerrainGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 30) \ 20) = ""\r
+\r
+' Trampoline effect - when player lands on trampoline ("v" marker), gives strong upward boost\r
+IF TerrainGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 30) \ 20) = "v" THEN PlayerVerticalSpeed% = -8: PlayerAnimationState% = 3\r
+\r
+' Conveyor belt movement - ">" and "<" markers in object grid push player horizontally\r
+IF ObjectGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 38) \ 20) = ">" THEN PlayerHorizontalSpeed% = 3\r
+IF ObjectGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 38) \ 20) = "<" THEN PlayerHorizontalSpeed% = -3\r
+\r
+GroundContactTime% = GroundContactTime% + 1\r
+HorizontalAnimationCounter% = HorizontalAnimationCounter% + 1: IF HorizontalAnimationCounter% > 10 THEN HorizontalAnimationCounter% = 0: IF PlayerHorizontalSpeed% > 0 THEN PlayerHorizontalSpeed% = PlayerHorizontalSpeed% - 1 ELSE IF _\r
+PlayerHorizontalSpeed% < 0 THEN PlayerHorizontalSpeed% = PlayerHorizontalSpeed% + 1\r
+VerticalAnimationCounter% = VerticalAnimationCounter% + 1: IF VerticalAnimationCounter% > 3 THEN VerticalAnimationCounter% = 0: PlayerVerticalSpeed% = PlayerVerticalSpeed% + 1\r
+JumpReadinessCounter% = JumpReadinessCounter% + 1: CeilingContactCooldown% = CeilingContactCooldown% - 1\r
+\r
+' Breakable block interaction - hitting block from below ("o" character) destroys it\r
+IF ObjectGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 21) \ 20) = "o" THEN TerrainGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 21) \ 20) = "": ObjectGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 21) \ 20) = "": _\r
+TopBreakableBlockClearedFlag% = 1\r
+\r
+' Bottom breakable block interaction - similar to above but from top side\r
+IF ObjectGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 38) \ 20) = "a" THEN TerrainGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 38) \ 20) = "": ObjectGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 38) \ 20) = "": _\r
+BottomBreakableBlockClearedFlag% = 1\r
+\r
+' First companion hedgehog terrain collision checks\r
+IF TerrainGrid((Companion1HorizontalPosition% + 25) \ 20, (Companion1VerticalPosition% + 25) \ 20) = "z" THEN Companion1VerticalSpeed% = -1\r
+IF TerrainGrid((Companion1HorizontalPosition% + 30) \ 20, (Companion1VerticalPosition% + 10) \ 20) = "z" THEN Companion1HorizontalSpeed% = -1\r
+IF TerrainGrid((Companion1HorizontalPosition% + 20) \ 20, (Companion1VerticalPosition% + 10) \ 20) = "z" THEN Companion1HorizontalSpeed% = 1\r
+\r
+' Second companion hedgehog terrain collision checks\r
+IF TerrainGrid((Companion2HorizontalPosition% + 25) \ 20, (Companion2VerticalPosition% + 25) \ 20) = "z" THEN Companion2VerticalSpeed% = -1\r
+IF TerrainGrid((Companion2HorizontalPosition% + 30) \ 20, (Companion2VerticalPosition% + 10) \ 20) = "z" THEN Companion2HorizontalSpeed% = -1\r
+IF TerrainGrid((Companion2HorizontalPosition% + 20) \ 20, (Companion2VerticalPosition% + 10) \ 20) = "z" THEN Companion2HorizontalSpeed% = 1\r
+\r
+' Screen boundary checks for companions to keep them within play area\r
+IF Companion1HorizontalPosition% > 300 THEN Companion1HorizontalSpeed% = -1\r
+IF Companion1HorizontalPosition% < 3 THEN Companion1HorizontalSpeed% = 1\r
+IF Companion2HorizontalPosition% > 300 THEN Companion2HorizontalSpeed% = -1\r
+IF Companion2HorizontalPosition% < 3 THEN Companion2HorizontalSpeed% = 1\r
+\r
+' Restore previous companion positions before moving them (erases old sprite)\r
+PUT (Companion2HorizontalPosition%, Companion2VerticalPosition%), HedgehogSprite2, PSET\r
+PUT (Companion1HorizontalPosition%, Companion1VerticalPosition%), HedgehogSprite1, PSET\r
+\r
+' Restore previous player position (erases old sprite)\r
+IF PlayerYPosition% > 0 THEN PUT (PlayerXPosition%, PlayerYPosition%), PlayerSpriteBuffer, PSET\r
+\r
+' Handle sprite clearing after collecting coins or breaking blocks\r
+IF TopBreakableBlockClearedFlag% = 1 THEN TopBreakableBlockClearedFlag% = 0: PUT (((PlayerXPosition% + 10) \ 20) * 20, (PlayerYPosition% \ 20) * 20), EmptySpaceSprite, PSET\r
+IF CoinCollectedFlag% = 1 THEN CoinCollectedFlag% = 0: PUT (((PlayerXPosition% + 10) \ 20) * 20, ((PlayerYPosition% + 10) \ 20) * 20), EmptySpaceSprite, PSET\r
+IF BottomBreakableBlockClearedFlag% = 1 THEN BottomBreakableBlockClearedFlag% = 0: PUT (((PlayerXPosition% + 10) \ 20) * 20, ((PlayerYPosition% + 28) \ 20) * 20), EmptySpaceSprite, PSET\r
+\r
+IF PullBackwardFlag% = 1 THEN PullBackwardFlag% = 0: PlayerXPosition% = PlayerXPosition% - 20\r
+\r
+ObjectGrid((Companion2HorizontalPosition% + 25) \ 20, (Companion2VerticalPosition% + 8) \ 20) = "": ObjectGrid((Companion1HorizontalPosition% + 25) \ 20, (Companion1VerticalPosition% + 8) \ 20) = ""\r
+\r
+' Update companion positions based on their current velocities\r
+Companion1HorizontalPosition% = Companion1HorizontalPosition% + Companion1HorizontalSpeed%\r
+Companion1VerticalPosition% = Companion1VerticalPosition% + Companion1VerticalSpeed%\r
+Companion2HorizontalPosition% = Companion2HorizontalPosition% + Companion2HorizontalSpeed%\r
+Companion2VerticalPosition% = Companion2VerticalPosition% + Companion2VerticalSpeed%\r
+\r
+' Mark new companion positions in object grid for collision detection\r
+ObjectGrid((Companion2HorizontalPosition% + 25) \ 20, (Companion2VerticalPosition% + 8) \ 20) = "q": ObjectGrid((Companion1HorizontalPosition% + 25) \ 20, (Companion1VerticalPosition% + 8) \ 20) = "q"\r
+\r
+' Apply gravity to companions (max downward speed capped at 2 pixels/frame)\r
+Companion1VerticalSpeed% = Companion1VerticalSpeed% + 1: IF Companion1VerticalSpeed% > 2 THEN Companion1VerticalSpeed% = 2\r
+Companion2VerticalSpeed% = Companion2VerticalSpeed% + 1: IF Companion2VerticalSpeed% > 2 THEN Companion2VerticalSpeed% = 2\r
+\r
+' Update player position based on calculated velocities\r
+PlayerXPosition% = PlayerXPosition% + PlayerHorizontalSpeed%\r
+PlayerYPosition% = PlayerYPosition% + PlayerVerticalSpeed%\r
+\r
+' Level transition when reaching right edge of screen\r
+IF PlayerXPosition% > 297 THEN PlayerXPosition% = 2: CurrentLevelNumber% = CurrentLevelNumber% + 1: LoadCurrentLevel CurrentLevelNumber%: Companion1HorizontalSpeed% = 1: Companion2HorizontalSpeed% = 1\r
+\r
+' Level transition when reaching left edge of screen\r
+IF PlayerXPosition% < 1 THEN PlayerXPosition% = 296: IF CurrentLevelNumber% = 1 THEN LoadCurrentLevel CurrentLevelNumber% ELSE CurrentLevelNumber% = CurrentLevelNumber% - 1: LoadCurrentLevel CurrentLevelNumber%: IF GraphicsDisplayMode% = 2 THEN _\r
+PlayerXPosition% = 594\r
+\r
+' Player falls off bottom of screen - lose life and restart level\r
+IF PlayerYPosition% > 179 THEN LivesRemaining% = LivesRemaining% - 1: DisplayGameStatistics: CurrentLevelNumber% = CurrentLevelNumber% - 1: LoadCurrentLevel CurrentLevelNumber%: PlayerYPosition% = 100: PlayerXPosition% = 2: DisplayGameStatistics\r
+\r
+' Teleportation triggers ("u" and "U" markers in level data create door pairs)\r
+IF TerrainGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 30) \ 20) = "u" THEN PlayerXPosition% = DoorExitX% + 10: PlayerYPosition% = DoorExitY%: PlayerHorizontalSpeed% = 0\r
+IF TerrainGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 30) \ 20) = "U" THEN PlayerXPosition% = DoorEntryX% + 10: PlayerYPosition% = DoorEntryY%: PlayerHorizontalSpeed% = 0\r
+\r
+' Handle keyboard input for movement controls\r
+IF keyboardInput$ = rightArrowKey$ THEN PlayerHorizontalSpeed% = PlayerHorizontalSpeed% + 1: IF PlayerHorizontalSpeed% > 3 THEN PlayerHorizontalSpeed% = 3: HorizontalAnimationCounter% = 0 ELSE IF GroundContactTime% > 10 THEN PlayerHorizontalSpeed% = 5\r
+IF keyboardInput$ = rightArrowKey$ THEN IF RunningAnimationStage% = 1 THEN PlayerAnimationState% = 1 ELSE PlayerAnimationState% = 2\r
+IF keyboardInput$ = leftArrowKey$ THEN IF RunningAnimationStage% = 1 THEN PlayerAnimationState% = 10 ELSE PlayerAnimationState% = 20\r
+IF keyboardInput$ = leftArrowKey$ THEN PlayerHorizontalSpeed% = PlayerHorizontalSpeed% - 1: IF PlayerHorizontalSpeed% < -3 THEN PlayerHorizontalSpeed% = -3: HorizontalAnimationCounter% = 0 ELSE IF GroundContactTime% > 10 THEN PlayerHorizontalSpeed% = -5\r
+IF keyboardInput$ = upArrowKey$ AND JumpReadinessCounter% < 10 THEN PlayerVerticalSpeed% = PlayerVerticalSpeed% - 5: JumpReadinessCounter% = 20: VerticalAnimationCounter% = 0: PlayerAnimationState% = 3\r
+IF keyboardInput$ = downArrowKey$ THEN PlayerVerticalSpeed% = PlayerVerticalSpeed% + 1\r
+IF keyboardInput$ = "/" THEN PlayerXPosition% = 2: PlayerYPosition% = 50: CurrentLevelNumber% = CurrentLevelNumber% + 1: LoadCurrentLevel CurrentLevelNumber%: Companion1HorizontalSpeed% = 1: Companion2HorizontalSpeed% = 1\r
+IF keyboardInput$ = "+" THEN PlayerXPosition% = 2: PlayerYPosition% = 50: CurrentLevelNumber% = CurrentLevelNumber% + 5: LoadCurrentLevel CurrentLevelNumber%: Companion1HorizontalSpeed% = 1: Companion2HorizontalSpeed% = 1\r
+IF keyboardInput$ = "q" THEN END\r
+\r
+' Cycle through running animation frames (alternates between two states)\r
+RunningAnimationStage% = RunningAnimationStage% + 1\r
+IF RunningAnimationStage% = 3 THEN RunningAnimationStage% = 1\r
+GOTO MainGameLoop\r
+\r
+SUB DisplayGameStatistics\r
+'\r
+' Updates and displays the game's status information on screen (coins collected, remaining lives)\r
+' Handles game over condition when player runs out of lives.\r
+'\r
+' This subroutine is triggered whenever:\r
+' - A coin is collected (incrementing coins counter)\r
+' - The player loses a life due to hazards or falling off-screen\r
+' - Periodically during gameplay for live status updates\r
+\r
+LOCATE 1, 1\r
+IF GraphicsDisplayMode% = 2 THEN GOTO SkipTextDisplay\r
+\r
+' Clear previous statistics display to prevent overlapping text\r
+PRINT " "\r
+\r
+' Award extra life every 10 coins collected as bonus\r
+IF CoinsCollected% > 9 THEN\r
+ CoinsCollected% = 0\r
+ LivesRemaining% = LivesRemaining% + 1\r
+END IF\r
+\r
+' Display current game statistics in top-left corner of screen\r
+LOCATE 1, 1\r
+PRINT "Coins: "; CoinsCollected%; " Lives: "; LivesRemaining%\r
+\r
+SkipTextDisplay:\r
+' Check if player has completely run out of lives (game over condition)\r
+IF LivesRemaining% < 0 THEN END\r
+END SUB\r
+\r
+SUB LoadCurrentLevel (levelNumber%)\r
+125\r
+Companion1HorizontalPosition% = 0\r
+Companion1VerticalPosition% = 0\r
+Companion2HorizontalPosition = 0\r
+Companion2VerticalPosition% = 0\r
+\r
+' Clear terrain and object grids before loading new level data\r
+FOR xIndex% = 1 TO 32\r
+ FOR yIndex% = 1 TO 20\r
+ TerrainGrid(xIndex%, yIndex%) = ""\r
+ ObjectGrid(xIndex%, yIndex%) = ""\r
+ NEXT yIndex%\r
+NEXT xIndex%\r
+\r
+' Initialize ASCII level data array\r
+FOR lineCounter% = 1 TO 20\r
+ AsciiLevelData(lineCounter%) = ""\r
+NEXT lineCounter%\r
+\r
+CLS\r
+LOCATE 3, 10\r
+\r
+' Determine which level file to load based on requested level number\r
+IF levelNumber% >= 1 AND levelNumber% <= 18 THEN\r
+ fileName$ = "lvl/" + LTRIM$(STR$(levelNumber%)) + ".lvl"\r
+ OPEN fileName$ FOR INPUT AS #1\r
+ INPUT #1, LevelNumberAdjustment%\r
+ rowIndex% = 1\r
+ WHILE NOT EOF(1)\r
+ LINE INPUT #1, AsciiLevelData(rowIndex%)\r
+ rowIndex% = rowIndex% + 1\r
+ WEND\r
+ CLOSE #1\r
+ CurrentLevelNumber% = CurrentLevelNumber% + LevelNumberAdjustment%\r
+ELSE\r
+ ' Special handling for non-standard levels (intro screen, test levels)\r
+ SELECT CASE levelNumber%\r
+ CASE 19\r
+ CLS\r
+ RenderSpriteFromFile 1, 1, 10, 3\r
+ LOCATE 20, 1\r
+ PRINT "end"\r
+ ' Wait for 50 frames before continuing (creates brief pause)\r
+ FOR frameCounter% = 1 TO 50\r
+ inputBuffer$ = INKEY$\r
+ NEXT frameCounter%\r
+ inputBuffer$ = INPUT$(1)\r
+ CLS\r
+ SCREEN 2\r
+ END\r
+ CASE 100\r
+ ' Create empty level with 10 blank lines\r
+ FOR lineIndex% = 1 TO 10\r
+ AsciiLevelData(lineIndex%) = " "\r
+ NEXT lineIndex%\r
+ CASE 101\r
+ ' Create larger empty level with 19 blank lines\r
+ FOR lineIndex% = 1 TO 19\r
+ AsciiLevelData(lineIndex%) = " "\r
+ NEXT lineIndex%\r
+ GraphicsDisplayMode% = 2\r
+ END SELECT\r
+END IF\r
+\r
+' Parse ASCII level representation into game world\r
+FOR rowIndex% = 0 TO 9\r
+ FOR columnIndex% = 0 TO 15\r
+ ' Extract single character from level data at current position\r
+ currentCharacter$ = RIGHT$(LEFT$(AsciiLevelData(rowIndex% + 1), columnIndex% + 1), 1)\r
+\r
+ ' Interpret character codes to build terrain and place objects:\r
+ ' "m" = solid block (terrain)\r
+ IF currentCharacter$ = "m" THEN PUT (columnIndex% * 20, rowIndex% * 20), SolidTerrainSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "z"\r
+\r
+ ' "o" = breakable box (both terrain and object properties)\r
+ IF currentCharacter$ = "o" THEN PUT (columnIndex% * 20, rowIndex% * 20), BoxSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "z": ObjectGrid(columnIndex% + 1, rowIndex% + 1) = "o"\r
+\r
+ ' "." = star decoration (cosmetic only)\r
+ IF currentCharacter$ = "." THEN PUT (columnIndex% * 20, rowIndex% * 20), StarSprite, PSET\r
+\r
+ ' "-" = cloud decoration (cosmetic only)\r
+ IF currentCharacter$ = "-" THEN PUT (columnIndex% * 20, rowIndex% * 20), CloudSprite, PSET\r
+\r
+ ' "x" = starting position for first companion hedgehog\r
+ IF currentCharacter$ = "x" THEN Companion1HorizontalPosition% = columnIndex% * 20: Companion1VerticalPosition% = (rowIndex% + 1) * 20\r
+\r
+ ' "y" = starting position for second companion hedgehog\r
+ IF currentCharacter$ = "y" THEN Companion2HorizontalPosition% = columnIndex% * 20: Companion2VerticalPosition% = (rowIndex% + 1) * 20\r
+\r
+ ' "1" = collectible coin\r
+ IF currentCharacter$ = "1" THEN PUT (columnIndex% * 20, rowIndex% * 20), CoinSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "1"\r
+\r
+ ' "p" = decorative bush (rendered slightly lower)\r
+ IF currentCharacter$ = "p" THEN PUT (columnIndex% * 20, (rowIndex% * 20) + 10), BushSprite, PSET\r
+\r
+ ' "h" = window decoration\r
+ IF currentCharacter$ = "h" THEN PUT (columnIndex% * 20, rowIndex% * 20), WindowSprite, PSET\r
+\r
+ ' "v" = trampoline that boosts player upward when landed on\r
+ IF currentCharacter$ = "v" THEN PUT (columnIndex% * 20, (rowIndex% * 20) + 10), TrampolineSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "v"\r
+\r
+ ' "t" = tree decoration\r
+ IF currentCharacter$ = "t" THEN PUT (columnIndex% * 20, rowIndex% * 20), TreeSprite, PSET\r
+\r
+ ' ">" = right-moving conveyor belt (overrides normal movement)\r
+ IF currentCharacter$ = ">" THEN PUT (columnIndex% * 20, rowIndex% * 20), RightArrowSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "z": ObjectGrid(columnIndex% + 1, rowIndex% + 1) = ">"\r
+\r
+ ' "<" = left-moving conveyor belt (overrides normal movement)\r
+ IF currentCharacter$ = "<" THEN PUT (columnIndex% * 20, rowIndex% * 20), LeftArrowSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "z": ObjectGrid(columnIndex% + 1, rowIndex% + 1) = "<"\r
+\r
+ ' "a" = bottom breakable block (similar to "o" but different behavior)\r
+ IF currentCharacter$ = "a" THEN PUT (columnIndex% * 20, rowIndex% * 20), HoleSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "z": ObjectGrid(columnIndex% + 1, rowIndex% + 1) = "a"\r
+\r
+ ' "u" = entry door for teleportation system\r
+ IF currentCharacter$ = "u" THEN PUT (columnIndex% * 20, rowIndex% * 20), DoorSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "u": DoorEntryX% = columnIndex% * 20: DoorEntryY% = rowIndex% * 20\r
+\r
+ ' "U" = exit door for teleportation system (pairs with "u")\r
+ IF currentCharacter$ = "U" THEN PUT (columnIndex% * 20, rowIndex% * 20), DoorSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "U": DoorExitX% = columnIndex% * 20: DoorExitY% = rowIndex% * 20\r
+ NEXT columnIndex%\r
+NEXT rowIndex%\r
+END SUB\r
+\r
+SUB RenderSpriteFromFile (x%, y%, spriteID%, animationFrame%)\r
+' Renders a sprite on screen by loading pixel data directly from external file\r
+' File format explanation:\r
+' - First line contains height (number of pixel rows in sprite)\r
+' - Subsequent lines contain strings of digit characters where:\r
+' '0' = transparent/background (no drawing)\r
+' '1'-'3' = color values (mapped to current palette)\r
+' Example file for simple 3x2 sprite:\r
+' 2\r
+' 123\r
+' 010\r
+'\r
+' Parameters:\r
+' xPosition%, yPosition% = Top-left drawing coordinates on screen\r
+' spriteID% = Which sprite file to load (references img/<id>.i01)\r
+' animationFrame% = Special rendering mode selector:\r
+' 1 = normal rendering\r
+' 50 = horizontally flipped version\r
+' Other values = scaled rendering (value indicates scale factor)\r
+\r
+DIM rowText AS STRING\r
+fileName$ = "img/" + LTRIM$(STR$(spriteID%)) + ".i01"\r
+OPEN fileName$ FOR INPUT AS #1\r
+INPUT #1, spriteHeight%\r
+DIM spritePixelRows(1 TO 100) AS STRING\r
+FOR rowIndex% = 1 TO spriteHeight%\r
+ LINE INPUT #1, spritePixelRows(rowIndex%)\r
+NEXT rowIndex%\r
+CLOSE #1\r
+\r
+' Handle special rendering modes based on animation frame parameter\r
+IF animationFrame% = 50 THEN GOTO DrawFlippedSprite\r
+\r
+' Normal rendering - draw pixels from top to bottom, left to right\r
+FOR rowIndex% = 1 TO 100\r
+ IF spritePixelRows(rowIndex%) = "" THEN GOTO FinishDrawing\r
+ FOR pixelColumn% = 1 TO LEN(spritePixelRows(rowIndex%))\r
+ ' Convert character digit to numeric color value\r
+ ' ASCII '0'=48, so subtracting 48 gives 0-9 numeric value\r
+ pixelColor% = ASC(RIGHT$(LEFT$(spritePixelRows(rowIndex%), pixelColumn%), 1)) - 48\r
+\r
+ ' Only draw non-zero pixels (0 is treated as transparent)\r
+ IF pixelColor% > 0 THEN PSET ((xPosition% + pixelColumn%), (yPosition% + rowIndex%)), pixelColor%\r
+ NEXT pixelColumn%\r
+NEXT rowIndex%\r
+GOTO FinishDrawing\r
+\r
+DrawFlippedSprite:\r
+' Horizontally flipped rendering - mirror image for left-facing sprites\r
+FOR rowIndex% = 1 TO 100\r
+ IF spritePixelRows(rowIndex%) = "" THEN GOTO FinishDrawing\r
+ FOR columnIndex% = 1 TO LEN(spritePixelRows(rowIndex%))\r
+ ' Note: X position is mirrored (right-to-left)\r
+ PSET ((x% + (LEN(spritePixelRows(rowIndex%)) - columnIndex% + 1)), (y% + rowIndex%)), ASC(RIGHT$(LEFT$(spritePixelRows(rowIndex%), columnIndex%), 1)) - 48\r
+ NEXT columnIndex%\r
+NEXT rowIndex%\r
+\r
+FinishDrawing:\r
+ERASE spritePixelRows\r
+END SUB\r
+\r
--- /dev/null
+20\r
+00000000000000000000\r
+00111111111111111100\r
+01222222222222222210\r
+01233333333333333210\r
+01232222222222223210\r
+01232111111111123210\r
+01232111111111123210\r
+01232111111111123210\r
+01232111111111123210\r
+01232111111111123210\r
+01232111111111123210\r
+01232111111111123210\r
+01232111111111123210\r
+01232111111111123210\r
+01232111111111123210\r
+01232222222222223210\r
+01233333333333333210\r
+01222222222222222210\r
+00111111111111111100\r
+00000000000000000000
\ No newline at end of file
--- /dev/null
+30\r
+33333333333333333333333333333333333333333333333333333333333333333333333333333333\r
+30000000000000000000000000000000000000000000000000000000000000000000000000000003\r
+30000110000111001110011111100011111110011111100000000000000000000000000000000003\r
+30001111100111001110011111110011111110011111110000000000000000002222000000000003\r
+30011001100011001100011100110011100110011100111000000000000000222222220000000003\r
+30011000000011001100011111110011100000011100111000000000000000222222222222000003\r
+30011000000011001100011111100011100110011111110000000000000000330330330002200003\r
+30011111000011001100011100000011111110011111100000000000000000333333330000000003\r
+30001111100011001100011100000011111110011100100000000000000000332222330000000003\r
+30000001100011001100011100000011100000011100110000000000000000033333300000000003\r
+30110001100011001100011100000011100110011100111000000000000030000111000000000003\r
+30111011100011111100011100000011111110011100111000000000000331111111111000000003\r
+30111111000001111000011100000011111110011100111000000000000331111111111100000003\r
+30000000000000000000000000000000000000000000000000000000000000001111101100000003\r
+30000000000000000000000000000000000000000000000000000000000000001111101100000003\r
+30000000000000000000000000000000000000000000000000000000000000001101100000000003\r
+30000000000000000000000000000000000000000000000000000000000000011101110000000003\r
+30000000000000000000000000000000000000000000000000000000000000011101110000000003\r
+30000000000000000000000000000000000000000000000000000000000000333303330000000003\r
+30000000000000000000000000000000000000000000000000000000000000000000000000000003\r
+30000000000000000000000000000000000000000000000000000000000000000000000000000003\r
+30000000000000000000000000000000000000000000000000000000000000000000000000000003\r
+30000000000000000000000000000000000000000000000000000000000000000000000000000003\r
+30000000000000000000000000000000000000000000000000000000000000000000000000000003\r
+30000000000000000000000000000000000000000000000000000000000000000000000000000003\r
+30000000000000000000000000000000000000000000000000000000000000000000000000000003\r
+30000000000000000000000000000000000000000000000000000000000000000000000000000003\r
+30000000000000000000000000000000000000000000000000000000000000000000000000000003\r
+30000000000000000000000000000000000000000000000000000000000000000000000000000003\r
+33333333333333333333333333333333333333333333333333333333333333333333333333333333\r
--- /dev/null
+80\r
+00000000000111111110000000000000000000000000000000\r
+00000000011111111111000001100000000000000000000000\r
+00000000111111111111110011110000000000000000000000\r
+00000001101111111111111111111000000000000000000000\r
+00000011111111111111111111111111000000000000000000\r
+00000111111111111111111111111111000000000000000000\r
+00000111111111111111111111111111001100000000000000\r
+00000111111111111111111111111111111111100000000000\r
+00000111111111111111111111111111111111100000000000\r
+00000111111111111111111111111111111111110000000000\r
+00000111111111111111111111111111111111111000000000\r
+00000111111111111111111111111111111111111100000000\r
+00000111111111111111111111111111111111111100000000\r
+00000111111111111111111111111111111111111100000000\r
+00000111111111111111111111111111111111111100000000\r
+00000111111111111111111111111111111111111100000000\r
+00011111111111111111111111111111111111111100000000\r
+00011111111111111111111111111111111111111100000000\r
+00111111110111111111111111111111111111111100000000\r
+01110111111111111111111111111111111111111100000000\r
+11111111111111111111111111111111111111111111100000\r
+11111111111111111111111111111111111111111111100000\r
+11111111111111111111111111111111111111111111100000\r
+11111111111111111111111111111111111111111111100000\r
+11111111111111111111111111111111111111111111111110\r
+11111111111111111111111111111111111111111111110111\r
+11111111111111111111111111111111111111111111111111\r
+11011111111111111111111111111111111111111111111101\r
+11111111111111111111111111111111111111111111111111\r
+11111111111111111111111111111111111111111111111111\r
+11111111111111111111111111111111111111111111111011\r
+11111111111111111111111111111111111111111111111100\r
+11111111111111111111111111111111111111111111111000\r
+01111111111111111111111111111111111111111111110000\r
+11111111111111111111111111111111111111111110110000\r
+11111111111111111111111111111111111111111110110000\r
+11111111111111111111111111111111111111111111110000\r
+01111111111111111111111111111111111111111111110000\r
+01111111111111111111111111111111111111111111110000\r
+00011111111111111111111111111111111111111111100000\r
+00111111111111111111111111111111111111111111100000\r
+00011111111111111111111111111111111111111111110000\r
+00001111111111111111111111111111111111111111110000\r
+00001111111111111111111111111111111111111111111000\r
+0000110111111111111111111111111111111111111111100\r
+0000110011111111111111111111011111111111111100000\r
+0000111101101111111111111111111111111110111000000\r
+0000000000001111111111111111111111111111110000000\r
+0000000000000001111111111111111111110111110000000\r
+0000000000000000000011111111111111100111110000000\r
+0000000000000000000001111020111000000000000000000\r
+0000000000000000000001111222200000000000000000000\r
+0000000000000000000000222222220000000000000000000\r
+0000000000000000000000222222020000000000000000000\r
+0000000000000000000000202222220000000000000000000\r
+0000000000000000000000222222220000000000000000000\r
+0000000000000000000000220202220000000000000000000\r
+0000000000000000000000222222220000000000000000000\r
+0000000000000000000000202222220000000000000000000\r
+0000000000000000000000222222220000000000000000000\r
+000000000000000000000022022220000000000\r
+0000000000000000000000222222220000000000000000000\r
+0000000000000000000000220222200000000000000000000\r
+0000000000000000000000222220200000000000000000000\r
+0000000000000000000000220222200000000000000000000\r
+0000000000000000000000222222200000000000000000000\r
+0000000000000000000000222222200000000000000000000\r
+0000000000000000000000202222000000000000000000000\r
+0000000000000000002000222222220000000000000000000\r
+0000000000000000002200222222000000000000000000000\r
+0000000000000000000222222222000000000000000000000\r
+0000000000000000000222222222000000000000000000000\r
+0000000000000000000022222222000000000000000000000\r
+0000000000000000000022222222000000000000000000000\r
+0000000000000000000020222222000000000000000000000\r
+0000000000000000000222222202000000000000000000000\r
+000000000000000000022022222200000000000\r
+0000000000000000022222222222200000000000000000000\r
+0000000000000000220222222222220000\r
+000000000000000022222222222222\r
--- /dev/null
+20\r
+11111111111111111111\r
+11111111111111111111\r
+11111111112111111111\r
+11111111112211111111\r
+11111111112221111111\r
+11111111112222111111\r
+11111111112222211111\r
+11122222222222221111\r
+11122222222222222111\r
+11122222222222222211\r
+11122222222222222211\r
+11122222222222222111\r
+11122222222222221111\r
+11111111112222211111\r
+11111111112222111111\r
+11111111112221111111\r
+11111111112211111111\r
+11111111112111111111\r
+11111111111111111111\r
+11111111111111111111\r
--- /dev/null
+20\r
+03333333333333333330\r
+33333333222233333333\r
+33333332222223333333\r
+33333332222223333333\r
+33333332222223333333\r
+33333332222223333333\r
+33333332222223333333\r
+33333332222223333333\r
+33333332222223333333\r
+33333332222223333333\r
+33333333222233333333\r
+33333333333333333333\r
+33333333333333333333\r
+33333333222233333333\r
+33333332222223333333\r
+33333332222223333333\r
+33333332222223333333\r
+33333333222233333333\r
+33333333333333333333\r
+03333333333333333330\r
--- /dev/null
+20\r
+00000000022220000000\r
+00000000022220000000\r
+00000000022222000000\r
+00000000033333000000\r
+00000000033333300000\r
+00000000033333300000\r
+00000000003333000000\r
+00000000011100000000\r
+00000003111130000000\r
+00000003111130000000\r
+00000003111130000000\r
+00000003111133000000\r
+00000003111130000000\r
+00000003111130000000\r
+00000000333300000000\r
+00000000333300000000\r
+00000003303300000000\r
+00000003303300000000\r
+00000033302220000000\r
+00000022200000000000\r
--- /dev/null
+20\r
+00000000022220000000\r
+00000000022220000000\r
+00000000022222000000\r
+00000000033333000000\r
+00000000033333300000\r
+00000000033333300000\r
+00000000003333000000\r
+00000000011100000000\r
+00000003111130000000\r
+00000003111130000000\r
+00000003111130000000\r
+00000033111130000000\r
+00000003111130000000\r
+00000003111130000000\r
+00000000333300000000\r
+00000000333300000000\r
+00000000330330000000\r
+00000000330330000000\r
+00000002220333000000\r
+00000000000222000000\r
--- /dev/null
+20\r
+00000000022220000000\r
+00000000022220000000\r
+00000000022222000000\r
+00000000033333000000\r
+00000000033333300000\r
+00000000033333300000\r
+00000000103330100000\r
+00000001111111000000\r
+00000000311130000000\r
+00000000311130000000\r
+00000000311130000000\r
+00000000311130000000\r
+00000000311130000000\r
+00000000311130000000\r
+00000000333300000000\r
+00000000333300000000\r
+00000000330330000000\r
+00000000330330000000\r
+00000000330330000000\r
+00000000222222000000\r
--- /dev/null
+30\r
+00000022222222000000\r
+00002222222222220000\r
+00022220000000222000\r
+00020002222222002000\r
+00202222222222222200\r
+00202222222222220200\r
+00202222222222220200\r
+02202222222222220220\r
+02022222222222220220\r
+02022323232323322020\r
+02022323232323222020\r
+02022323233223332020\r
+22022323232322232022\r
+20222323232322232202\r
+20222232232323332202\r
+20222222222222222202\r
+20222222222222112202\r
+20222222222222112202\r
+20222222222222112202\r
+20222222222222222202\r
+20222222222222222202\r
+20222222222222222202\r
+20222222222222222202\r
+20222222222222222202\r
+20222222222222222202\r
+20222222222222222202\r
+20222222222222222202\r
+20222222222222222202\r
+20000000000000000002\r
+22222222222222222222\r
--- /dev/null
+25\r
+000000022200000222220000002222222200000000000222222000000000\r
+000000022222002222222000222222222222000000222222222220000000\r
+000000222222222222222202222222222222222222222222222222200000\r
+000000222222222222222222222333333222220222222222222221110000\r
+000000222222233333322222223333333322222222222222222221111000\r
+000000022333333333333222233333333333222233322222222221111000\r
+000002222333333333333322233333333333333333333222222221111100\r
+000222222333333333333333333333333333333333333322222221111100\r
+002222223333333333333333333333333333333333333333222221111100\r
+022223333333333333333333333333333333333333333333222221111110\r
+022233333333333333333333333333333333333333333333322222111110\r
+222333333333333333333333333333333333333333333333322222111110\r
+222333333333333333333333323333333323131113333333221221111110\r
+223333333333333333333331112233331121111133333322112211111110\r
+213333333333333333333331111133111111111111111112222111111110\r
+111333313333333333333111111122111111111111111111221111111110\r
+111333311111111333111111111111111111111111111111111111111100\r
+011111111111111111111111111111111111111111111111111111111100\r
+011111111111111111111111111111111111111111111111111111111100\r
+011111111111111111111111111111111111111111111111111111111000\r
+001111111111111111111111111111111111111111111111110111100000\r
+001111111111111100111111111111111111111111111111100000000000\r
+000111111111110000011111111111100011111111111111000000000000\r
+000011111111100000000111111111000000011111111100000000000000\r
+000001111110000000000001111110000000000000000000000000000000\r
--- /dev/null
+13\r
+0000010000\r
+0000010000\r
+0000121000\r
+0000131000\r
+1111232111\r
+0123333210\r
+0123333210\r
+0012332100\r
+0001221000\r
+0012112100\r
+0121001210\r
+0110000110\r
+1100000011\r
--- /dev/null
+20\r
+01111111110111111111\r
+01222222210122222221\r
+01233333210123333321\r
+01233333210123333321\r
+01233333210123333321\r
+01233333210123333321\r
+01233333210123333321\r
+01222222210122222221\r
+01111111110111111111\r
+00000000000000000000\r
+01111111110111111111\r
+01222222210122222221\r
+01233333210123333321\r
+01233333210123333321\r
+01233333210123333321\r
+01233333210123333321\r
+01233333210123333321\r
+01222222210122222221\r
+01111111110111111111\r
+00000000000000000000\r
--- /dev/null
+7\r
+0000333000\r
+0033333300\r
+0332222220\r
+3322222222\r
+3222111112\r
+3111111111\r
+1111111111\r
--- /dev/null
+10\r
+00111100\r
+01222210\r
+12233221\r
+12233221\r
+12233221\r
+12233221\r
+12233221\r
+12233221\r
+01222210\r
+00111100\r
--- /dev/null
+10\r
+000000000000000033333300000000\r
+000000000000000333333333000000\r
+000000333300003332222222300000\r
+000003333330333322232222220000\r
+000033322333333222222222222000\r
+003332222223332222322212222200\r
+033222232222222222111211122200\r
+033222222232111111111111112220\r
+332223222111121121111111111222\r
+322222111111111111121111111111\r
--- /dev/null
+20\r
+0000000002222222000000000\r
+0000000222111112220000000\r
+0000002211131311122000000\r
+0000022113331133112200000\r
+0000022133331333312200000\r
+0000221133331333311220000\r
+0000221333331333331220000\r
+0000221333331333331220000\r
+0000221111111111111220000\r
+0000221333331333331220000\r
+0002211333331333331122000\r
+0002213333331333333122000\r
+0002213333331333333122000\r
+0002213333331333333122000\r
+0002213333331333333122000\r
+0002213333331333333122000\r
+0002213333331333333122000\r
+0002211111111111111122000\r
+2222222222222222222222222\r
+0222222222222222222222220\r
--- /dev/null
+10\r
+00000001112220000000\r
+00001112222111120000\r
+00112222111122221100\r
+02222111122221111110\r
+01111122221111122220\r
+11122221111122221111\r
+22221111122221111111\r
+21111122221111112222\r
+11222221111112222111\r
+22221111112222111111\r
--- /dev/null
+0\r
+ mmm\r
+ - m mm\r
+ . - mmm\r
+o . . mymm\r
+o -mmm\r
+o t mxmm\r
+o mmm\r
+o 1 1\r
+o p p 1 1 1\r
+mmmmmmmmmmmmmmmm\r
--- /dev/null
+0\r
+m. - m\r
+m . m\r
+m 111 - m\r
+mmmmm>>> ammm\r
+a a m\r
+mmm t a m\r
+ ma m\r
+>>> a m\r
+ m yx m m\r
+>>>mmmmmmmmmmm m\r
--- /dev/null
+2\r
+>>>>>>>>>>>>>>><\r
+> <x <\r
+> < >> <\r
+> <y>>>>>>> <\r
+> < < <<<\r
+> <<<<a<< << < >\r
+> < < <\r
+> <m >m>>m < >\r
+> <\r
+>>>>m<<<<<<<<mm<\r
--- /dev/null
+0\r
+m aaaaaaaaam\r
+m - xmm\r
+m t. ym 1\r
+m . moom\r
+m am 1\r
+m mamomm\r
+m - mmam 1\r
+m mmmamomm\r
+m p p mm 1\r
+mmmmmmmmmammmm<<\r
--- /dev/null
+0\r
+mmmmmmmmmmmmmmmm\r
+m m m\r
+ ma 1a1a1a m\r
+mmma aaaaaaaam m\r
+11maaaaaaaaaam m\r
+mmmaaaaaaaaaam m\r
+11x ym m\r
+mmmmmmmmmmmmmm m\r
+ m\r
+mmmmmmmmmmmmmmmm\r
--- /dev/null
+0\r
+mmmmmmmmm-\r
+mm mmmmmmm -\r
+mm m\r
+mm >>>>> m -\r
+mmv m m .\r
+>><< m <<m -\r
+11 m m m .\r
+>> m m m xy\r
+mm vm v\r
+mm>><m>>>>>mmmmm\r
--- /dev/null
+0\r
+ m m\r
+mm ymmmmmmmmmaaa\r
+<<oo 1111maaa\r
+ <<111maaa\r
+<<m< m11maaa\r
+ t oomm aaa\r
+ vo mm1m\r
+ mm<<<mm1m\r
+ m x <<mmmmm11\r
+mmmmmmmmmmmmmmmm\r
--- /dev/null
+0\r
+mmmmmmmmmmmmmmmm\r
+mm h h\r
+mmx m mmmymmm\r
+mmommmmmm mom m\r
+mo 1 1 1 o1m1m\r
+momm m m m m111m\r
+m h mmmmoom\r
+ mm h m\r
+ v mmm mm\r
+mmmmmmmmmmmmmmmm\r
--- /dev/null
+0\r
+mmmmmmmmmmmmmmmm\r
+ h h h h h ym11\r
+mm mmmmmmmmmmm1m\r
+m h m xm\r
+mm m m mmmmmmmmm\r
+mmmm m1m\r
+m h m1moo m\r
+m mmmmmm m1moomm\r
+m 11111m h h\r
+mmmmmmmmmmmmmmmm\r
--- /dev/null
+0\r
+mmmmmmmmmmmmmmmm\r
+ h1 h1 m\r
+mmm 1 11 1 o1m\r
+ m 1 oo 1o1m\r
+m moo oo1m\r
+ m h o\r
+mmm h o\r
+m o\r
+ x oy\r
+mmmmmmmmmmmmmmmm\r
--- /dev/null
+0\r
+m . y -\r
+m m moo\r
+m. mxm mmo\r
+m - m mmmmmm\r
+m . m mm\r
+mt o o m\r
+m o om o ooo\r
+m ooooooooooo\r
+ v o\r
+oooooooooooooooo\r
--- /dev/null
+0\r
+ -\r
+ .\r
+ oo- oo\r
+ - 11 11 .\r
+ oo oo\r
+ m ym11 11\r
+ m m\r
+ ooom <> <>\r
+ xmmm mmm\r
+mmmmmmmmmmm mmm\r
--- /dev/null
+0\r
+ oooo\r
+ o111 .\r
+ oooo> >>>>>>\r
+ . x v m\r
+ mym m\r
+ m m\r
+ 111m\r
+ 111m\r
+ v p\r
+oooaaaaaaaaaoooo\r
--- /dev/null
+1\r
+ . o\r
+ . mm o\r
+. ommm t o\r
+ mom mm o\r
+ pmmoyxmmm o\r
+ mmmomammmm m\r
+p mmmmv mmmm\r
+mmmmmmmmm mmmmmm\r
+\r
+>>>>>>>>>>>>>>>>\r
--- /dev/null
+2\r
+mammmmmmmmmmmmm\r
+m1m y xmo\r
+mamooo>>>a>am om\r
+m1m m1mamo m\r
+mamm m1mam om\r
+m1m mm1mamo m\r
+mammm m1ma om\r
+m1m mmm1ma o m\r
+m amam om\r
+mmmmmmmm<mmammmm\r
--- /dev/null
+/###################################\r
+/#mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm#\r
+/###################################\r
--- /dev/null
+/###################### ##########\r
+/###################### ##########\r
+/#m m ##\r
+/#m m ##\r
+/#m m ##\r
+/#m mmmmmmmmmmmmm m ##\r
+/#m m m ##\r
+/#m m m ##\r
+/#m m m ##\r
+/#mmmmmmmmmm m m ##\r
+/#m m m ##\r
+/#m m m ##\r
+/#m m m ##\r
+/#m mmmmmmmmmmmmm m ##\r
+/#m m ##\r
+/#m m ##\r
+/#m m ##\r
+/#m m m m#\r
+/#mmmmmmmmmmmmmmmmm m ##\r
+/ m m \r
+/ m m \r
+/ m m \r
+/#m m mmmmmmmmmmmmmmmmm#\r
+/#m m m m#\r
+/#m m m m#\r
+/#m m m m#\r
+/ m \r
+/ m \r
+/ m \r
+/#mmmmmmmmmmmmmmmmmmmmmmmmmmmmm m#\r
+/ m \r
+/ m \r
+/ m \r
+/#mmmmmmmmmmmmmmmmmmmmm mmmmmmmmm#\r
+/###################### ##########\r
--- /dev/null
+/###################################\r
+/#mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm#\r
+/#m m#\r
+/#m m#\r
+/#m m m m m m#\r
+/#m mm m m mm m#\r
+/#m mmm m m mmm m#\r
+/#m m m m m m m m#\r
+/#m m m m m m m m#\r
+/#m m m m m m m#\r
+/#m m m m m m#\r
+/#m m m m m m#\r
+/#m m m m m m#\r
+/#m m m m m m#\r
+/#m m m m m m#\r
+/#m m m m m m#\r
+/#m m m m m m#\r
+/#m m m m m m#\r
+/#m m m m m m#\r
+/#m m m m m m#\r
+/#m m m m m m#\r
+/#m m m m m m#\r
+/#m m m m m m m m#\r
+/#m m mm m mm m m#\r
+/#m m mmm mmm m m#\r
+/#m m m m m m m m#\r
+/#m m m m m m m m#\r
+/#m m m m m m m m#\r
+/#m m m m m m m m#\r
+/#m m m m m m m m#\r
+/#m m m m m m m#\r
+/#m m#\r
+/#m m#\r
+/#mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm#\r
+/###################################\r
--- /dev/null
+/###################################\r
+/#mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm#\r
+/#m mm\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm#\r
+/###################################\r
--- /dev/null
+/########### ### ###########\r
+/#mmmmmmmmmm mmm mmmmmmmmmm#\r
+/#mmmmmmmm mmmmmmmm#\r
+/#mmmmmm mmmmmm#\r
+/#mmmmm mmmmm#\r
+/#mmmm mmm mmmm#\r
+/#mmm mmmmm mmm#\r
+/mmm mmmmm mm#\r
+/#mm mmm mm#\r
+/#m m m#\r
+/#m m m#\r
+/ m \r
+/ m \r
+/ m \r
+/ mmm \r
+/ mm mmm mm \r
+/#m mmmm mmmmmmm mmmm m#\r
+/#m mmmmmmmmmmmmmmmmmmmmmmmmm m#\r
+/#m mmmm mmmmmmm mmmm m#\r
+/ mm mmm mm \r
+/ mmm \r
+/ m \r
+/ m \r
+/ m \r
+/#m m m#\r
+/#m m m#\r
+/#mm mmm mm#\r
+/#mm mmmmm mm#\r
+/#mmm mmmmm mmm#\r
+/#mmmm mmm mmmm#\r
+/#mmmmm mmmmm#\r
+/#mmmmmm mmmmmm#\r
+/#mmmmmmmm mmmmmmmm#\r
+/#mmmmmmmmmm mmm mmmmmmmmmm#\r
+/########### ### ###########\r
--- /dev/null
+/ \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ mm mm \r
+/ m m \r
+/ \r
+/ m m \r
+/ mm mm \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ mmmmmmmmmmmmmmmmm \r
+/ m \r
+/ m \r
+/ m m \r
+/ m m \r
+/ m m \r
+/ mmmmmmmmmmmmmm \r
+/ m m \r
+/ m m \r
+/ m m \r
+/ m \r
+/ m m \r
+/ mmmmmmmmmmmmm m \r
+/ m \r
+/ \r
+/ m \r
+/ m \r
+/ m \r
+/ \r
+/ \r
--- /dev/null
+/################ ################\r
+/#mmmmmmmmmmmmmmm mmmmmmmmmmmmmmm#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m ##### ##### ###### m#\r
+/#m # # m#\r
+/#m # # m#\r
+/#m # # m#\r
+/#m # # m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m # ##### # m#\r
+/ # ##### # \r
+/ # ##### # \r
+/ # ##### # \r
+/#m # ##### # mm\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m # # m#\r
+/#m # # m#\r
+/#m # # m#\r
+/#m # # m#\r
+/#m ##### ##### ##### m#\r
+/#m mm\r
+/#m m#\r
+/#m m#\r
+/#mmmmmmmmmmmmmmm mmmmmmmmmmmmmmm#\r
+/################ ################\r
--- /dev/null
+/###### ################### ######\r
+/#mmmmm mmmmmmmmmmmmmmmmmmm #mmmm#\r
+/#m # m#\r
+/#m # m#\r
+/#m # m#\r
+/#m ######################### m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/###### mm\r
+/ # # \r
+/ # # \r
+/#m # # m#\r
+/#m # # m#\r
+/#m # # # m#\r
+/#m # # # m#\r
+/#m # # # m#\r
+/#m # ####### # m#\r
+/#m # # # m#\r
+/#m # m # m#\r
+/#m # m # m#\r
+/#m # # m#\r
+/#m # # m#\r
+/ # # \r
+/ # # \r
+/mm ######\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m ######################### m#\r
+/#m # m#\r
+/#m # m#\r
+/#m # m#\r
+/mmmmm# mmmmmmmmmmmmmmmmmmm mmmmm#\r
+/###### ################### ######\r
--- /dev/null
+/ ############################# \r
+/ mmmmmmmmmmmmmmmmmmmmmmmmmmmmm \r
+/ m \r
+/#m m m#\r
+/#m m m#\r
+/#m ######################### m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m # m#\r
+/#m # # m#\r
+/#m # # m#\r
+/#m # mmmmm mmmmm # m#\r
+/#m # m m # m#\r
+/#m # m m # m#\r
+/#m # m m # m#\r
+/#m # m m # m#\r
+/#mmmm# m #mmmm#\r
+/#m # m m # m#\r
+/#m # m m # m#\r
+/#m # m m # m#\r
+/#m # m m # m#\r
+/#m # mmmmm mmmmm # m#\r
+/#m # # m#\r
+/#m # # m#\r
+/#m # # m#\r
+/#m m#\r
+/#m m#\r
+/#m m#\r
+/#m ######################### m#\r
+/#m m m#\r
+/#m m m#\r
+/ m \r
+/ mmmmmmmmmmmmmmmmmmmmmmmmmmmmm \r
+/ ############################# \r
--- /dev/null
+/###################################\r
+/#mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm#\r
+/#m m#\r
+/#m mmmmm mmmmm m#\r
+/#m mm mm m#\r
+/#m m m m#\r
+/#m m m m#\r
+/#m m m m#\r
+/#m m m m#\r
+/ \r
+/ \r
+/#m m#\r
+/#m m#\r
+/#m m mmmm m m#\r
+/#m m m m m m#\r
+/#m m m m m m#\r
+/#m m m m m m#\r
+/#m m mmmmmmmmm m m#\r
+/#m m m m m m#\r
+/#m m m m m m#\r
+/#m m m m m m#\r
+/#m m mmmm m m#\r
+/#m m#\r
+/#m m#\r
+/ \r
+/ \r
+/#m m m m#\r
+/#m m m m#\r
+/#m m m m#\r
+/#m m m m#\r
+/#m mm mm m#\r
+/#m mmmmm mmmmm m#\r
+/#m m#\r
+/#mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm#\r
+/###################################\r
--- /dev/null
+/#mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm#\r
+/#mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm#\r
+/ \r
+/ \r
+/ m \r
+/ mmm \r
+/ mmmmm \r
+/ m \r
+/ m \r
+/ mmmmmmmmmm \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ mmmmm mmmmm mmmmm mmmmm \r
+/ mmmmm mmmmm mmmmm mmmmm \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ \r
+/ \r
+/#mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm#\r
+/###################################\r
--- /dev/null
+' Game of worms.\r
+'\r
+' Game supports up to 5 players. Any amount of those players can be AI controlled.\r
+'\r
+' Goal for each player is to eat as many fruits as possible while avoiding collisions\r
+' with walls and other worms.\r
+'\r
+' Game has multiple levels. After worms have eaten certain amount of fruits, game\r
+' advances to the next level.\r
+'\r
+' Each worm has limited amount of lives. When worm runs into the wall or\r
+' another worm, it loses one life.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2002, Initial version\r
+' 2024-2005, Improved program readability\r
+\r
+DECLARE FUNCTION cnum$ (a%)\r
+DECLARE SUB putworm (a%)\r
+DECLARE SUB level (a%)\r
+DECLARE SUB showb ()\r
+DECLARE SUB sc2 (x%, y%)\r
+DECLARE SUB ai (a%)\r
+DECLARE SUB autop (a%)\r
+DECLARE SUB prc (a%)\r
+DECLARE SUB dead (a%)\r
+DECLARE SUB add (a%)\r
+DECLARE SUB tkt ()\r
+DECLARE SUB subt (b%)\r
+DECLARE SUB show ()\r
+DECLARE SUB sc (x%, y%)\r
+DEFINT A-Z\r
+\r
+' Shared arrays for the game grid and worms\r
+DIM SHARED buf(0 TO 36, 0 TO 36)\r
+DIM SHARED buf2(0 TO 36, 0 TO 36)\r
+DIM SHARED ussx(1 TO 2000, 1 TO 5)\r
+DIM SHARED ussy(1 TO 2000, 1 TO 5)\r
+DIM SHARED ussp(1 TO 5)\r
+DIM SHARED ussl(1 TO 5)\r
+DIM SHARED usss(1 TO 5)\r
+DIM SHARED ussk(1 TO 2000, 1 TO 5)\r
+DIM SHARED usskp(1 TO 5)\r
+\r
+' Variables for worm positions and game state\r
+DIM SHARED ux(1 TO 5), uy(1 TO 5), uxp(1 TO 5), uyp(1 TO 5)\r
+DIM SHARED mtm\r
+DIM SHARED playerCount\r
+DIM SHARED lives(1 TO 5)\r
+DIM SHARED isAI(1 TO 5)\r
+DIM SHARED ail\r
+DIM SHARED lvl\r
+DIM SHARED elum\r
+DIM SHARED spd\r
+\r
+playerCount = 1\r
+ail = 10\r
+lvl = 1\r
+\r
+' Array defines if player is human (0) or computer (1).\r
+isAI(1) = 0\r
+isAI(2) = 0\r
+isAI(3) = 0\r
+isAI(4) = 0\r
+isAI(5) = 0\r
+\r
+CLS\r
+\r
+INPUT "How many players (1 - 5):", playerCount\r
+INPUT "How many of them are computers:", a\r
+FOR b = playerCount TO playerCount - a + 1 STEP -1\r
+ isAI(b) = 1\r
+NEXT b\r
+\r
+INPUT "How many lives:", elum\r
+INPUT "Speed: (1-slow, 3-ok, 10-very fast)", spd\r
+\r
+start\r
+\r
+level lvl\r
+1\r
+tkt\r
+delay .5 / spd\r
+' spd\r
+IF mtm >= 15 THEN\r
+ mtm = 1\r
+ lvl = lvl + 1\r
+ level lvl\r
+END IF\r
+GOTO 1\r
+\r
+SUB ai (a%)\r
+ ' This subroutine handles the AI logic for computer-controlled worms.\r
+ FOR y = 0 TO 36\r
+ FOR x = 0 TO 36\r
+ buf2(x, y) = 32000\r
+ IF buf(x, y) = 2 THEN buf2(x, y) = 0\r
+ IF buf(x, y) > 9 OR buf(x, y) = 1 THEN buf2(x, y) = -1\r
+ NEXT x\r
+ NEXT y\r
+\r
+ ' Set the target position to the center of the grid.\r
+ IF buf2(16, 16) = 32000 THEN buf2(16, 16) = 15000\r
+\r
+6\r
+ b = 0\r
+ FOR y = 1 TO 35\r
+ FOR x = 1 TO 34\r
+ IF (buf2(x + 1, y) > buf2(x, y) + 1) AND (buf2(x, y) >= 0) THEN\r
+ buf2(x + 1, y) = buf2(x, y) + 1\r
+ b = 1\r
+ END IF\r
+ NEXT x\r
+\r
+ ' Check if moving left is the shortest path.\r
+ FOR x = 35 TO 2 STEP -1\r
+ IF (buf2(x - 1, y) > buf2(x, y) + 1) AND (buf2(x, y) >= 0) THEN\r
+ buf2(x - 1, y) = buf2(x, y) + 1\r
+ b = 1\r
+ END IF\r
+ NEXT x\r
+\r
+ IF (buf2(1, y) > buf2(35, y) + 1) AND (buf2(35, y) >= 0) THEN\r
+ buf2(1, y) = buf2(35, y) + 1\r
+ b = 1\r
+ END IF\r
+\r
+ IF (buf2(35, y) > buf2(1, y) + 1) AND (buf2(1, y) >= 0) THEN\r
+ buf2(35, y) = buf2(1, y) + 1\r
+ b = 1\r
+ END IF\r
+ NEXT y\r
+\r
+ FOR x = 1 TO 35\r
+ FOR y = 1 TO 34\r
+ IF (buf2(x, y + 1) > buf2(x, y) + 1) AND (buf2(x, y) >= 0) THEN\r
+ buf2(x, y + 1) = buf2(x, y) + 1\r
+ b = 1\r
+ END IF\r
+ NEXT y\r
+\r
+ ' Check if moving up is the shortest path.\r
+ FOR y = 35 TO 2 STEP -1\r
+ IF (buf2(x, y - 1) > buf2(x, y) + 1) AND (buf2(x, y) >= 0) THEN\r
+ buf2(x, y - 1) = buf2(x, y) + 1\r
+ b = 1\r
+ END IF\r
+ NEXT y\r
+\r
+ IF (buf2(x, 1) > buf2(x, 35) + 1) AND (buf2(x, 35) >= 0) THEN\r
+ buf2(x, 1) = buf2(x, 35) + 1\r
+ b = 1\r
+ END IF\r
+\r
+ IF (buf2(x, 35) > buf2(x, 1) + 1) AND (buf2(x, 1) >= 0) THEN\r
+ buf2(x, 35) = buf2(x, 1) + 1\r
+ b = 1\r
+ END IF\r
+ NEXT x\r
+\r
+ ' If no shorter path is found, exit the loop.\r
+ IF b = 1 THEN GOTO 6\r
+\r
+ tx = ux(a)\r
+ ty = uy(a)\r
+\r
+ d = 0\r
+7\r
+ b = 32001\r
+ tmpxp = 0\r
+ tmpyp = 0\r
+\r
+ ' Check if moving right is the shortest path.\r
+ IF (buf2(tx - 1, ty) < b) AND (buf2(tx - 1, ty) >= 0) THEN\r
+ b = buf2(tx - 1, ty)\r
+ tmpxp = -1\r
+ tmpyp = 0\r
+ c = 1\r
+ END IF\r
+\r
+ ' Check if moving down is the shortest path.\r
+ IF (buf2(tx, ty - 1) < b) AND (buf2(tx, ty - 1) >= 0) THEN\r
+ b = buf2(tx, ty - 1)\r
+ tmpxp = 0\r
+ tmpyp = -1\r
+ c = 2\r
+ END IF\r
+\r
+ ' Check if moving left is the shortest path.\r
+ IF (buf2(tx + 1, ty) < b) AND (buf2(tx + 1, ty) >= 0) THEN\r
+ b = buf2(tx + 1, ty)\r
+ tmpxp = 1\r
+ tmpyp = 0\r
+ c = 3\r
+ END IF\r
+\r
+ ' Check if moving up is the shortest path.\r
+ IF (buf2(tx, ty + 1) < b) AND (buf2(tx, ty + 1) >= 0) THEN\r
+ b = buf2(tx, ty + 1)\r
+ tmpxp = 0\r
+ tmpyp = 1\r
+ c = 4\r
+ END IF\r
+\r
+ ' If no shorter path is found, set the direction to random.\r
+ IF b = 32001 THEN\r
+ tmpxp = -1\r
+ tmpyp = 0\r
+ c = 1\r
+ b = -1\r
+ END IF\r
+\r
+ buf2(tx, ty) = -1\r
+ d = d + 1\r
+ ussk(d, a) = c\r
+ tx = tx + tmpxp\r
+ ty = ty + tmpyp\r
+\r
+ ' Wrap around the edges of the grid.\r
+ IF tx = 1 THEN tx = 34\r
+ IF ty = 1 THEN ty = 34\r
+ IF tx = 35 THEN tx = 2\r
+ IF ty = 35 THEN ty = 2\r
+\r
+ e = buf2(tx, ty)\r
+ buf2(tx, ty) = -1\r
+\r
+ sc2 tx, ty\r
+\r
+ ' If the worm hits a wall or another worm, stop moving.\r
+ IF d > ail THEN GOTO 8\r
+\r
+ ' If the worm finds food, continue moving.\r
+ IF (e > 0) AND (b > -1) THEN GOTO 7\r
+\r
+8\r
+ d = d + 1\r
+ ussk(d, a) = 5\r
+ usskp(a) = 1\r
+\r
+ showb\r
+END SUB\r
+\r
+SUB autop (a%)\r
+ ' This subroutine handles the movement of computer-controlled worms.\r
+ c = 0\r
+\r
+5\r
+ ' If the worm is not at the end of its path, continue moving.\r
+ IF usskp(a) > 0 THEN\r
+ b = ussk(usskp(a), a)\r
+\r
+ IF b = 1 THEN\r
+ uxp(a) = -1\r
+ uyp(a) = 0\r
+ ELSEIF b = 2 THEN\r
+ uxp(a) = 0\r
+ uyp(a) = -1\r
+ ELSEIF b = 3 THEN\r
+ uxp(a) = 1\r
+ uyp(a) = 0\r
+ ELSEIF b = 4 THEN\r
+ uxp(a) = 0\r
+ uyp(a) = 1\r
+ ELSEIF b = 5 THEN\r
+ ai a\r
+ GOTO 5\r
+ END IF\r
+\r
+ usskp(a) = usskp(a) + 1\r
+ END IF\r
+\r
+ ' Calculate the new position of the worm.\r
+ nx = ux(a) + uxp(a)\r
+ ny = uy(a) + uyp(a)\r
+\r
+ ' Check if the worm hits a wall or another worm.\r
+ b = buf(INT(nx), INT(ny))\r
+\r
+ ' If the worm hits a wall or another worm, recalculate the AI.\r
+ IF (b = 1 OR b > 9) AND (c = 0) THEN\r
+ ai a\r
+ c = 1\r
+ GOTO 5\r
+ END IF\r
+END SUB\r
+\r
+SUB clearTail (playerNumber)\r
+ ' This subroutine takes care of clearing out worm tail.\r
+ ' As worm head advances forward in each frame, this procedure\r
+ ' is responsible for clearing out squares where worm tail moved out\r
+ ' of. Such squares are marked as empty (no longer occupied by worm)\r
+ ' and also correspondingly are erased from the screen.\r
+ a = ussp(playerNumber) - ussl(playerNumber)\r
+\r
+ IF a < 1 THEN\r
+ a = a + 2000\r
+ END IF\r
+\r
+ IF ussx(a, playerNumber) > 0 THEN\r
+ buf(ussx(a, playerNumber), ussy(a, playerNumber)) = 0\r
+\r
+ drawGridCell ussx(a, playerNumber), ussy(a, playerNumber)\r
+\r
+ ussx(a, playerNumber) = 0\r
+ END IF\r
+END SUB\r
+\r
+FUNCTION cnum$ (a%)\r
+ ' This function converts an integer to a string.\r
+ b$ = STR$(a%)\r
+\r
+ ' Remove leading spaces from the string.\r
+ IF LEFT$(b$, 1) = " " THEN\r
+ b$ = RIGHT$(b$, LEN(b$) - 1)\r
+ END IF\r
+\r
+ cnum$ = b$\r
+END FUNCTION\r
+\r
+SUB dead (a%)\r
+ ' This subroutine handles the death of a worm.\r
+ lives(a) = lives(a) - 1\r
+ putworm a\r
+END SUB\r
+\r
+SUB delay (delayInSeconds AS SINGLE)\r
+ ' Since QBasic does not have precise timer suitable for delaying animations,\r
+ ' workaround here is to use SOUND function. Inaudible sound with frequency\r
+ ' of 0 Hz is produced. Second argument for SOUND function is sound duration\r
+ ' that is approximately 1/18'th of the second.\r
+ SOUND 0, delayInSeconds * 18\r
+END SUB\r
+\r
+SUB drawGridCell (x%, y%)\r
+' This subroutine updates one cell on the screen as denoted by its\r
+' X and Y coordinates.\r
+'\r
+' Cell content is red from global 'buf' array and corresponding\r
+' sprite is drawn on the screen.\r
+'\r
+' This procedure is handy because it allows redrawing only parts of the\r
+' screen that were changed and thereby we avoid redrawing entire screen\r
+' for every frame.\r
+\r
+ x1 = x% * 5\r
+\r
+ y1 = y% * 5\r
+\r
+ LINE (x1, y1)-(x1 + 3, y1 + 3), 0, BF\r
+\r
+ SELECT CASE buf(x%, y%)\r
+ CASE 0\r
+ ' Draw an empty space on the grid.\r
+ LINE (x1, y1)-(x1 + 3, y1 + 3), 1, BF\r
+\r
+ CASE 1\r
+ ' Draw a wall on the grid.\r
+ LINE (x1, y1)-(x1 + 3, y1 + 3), 7, BF\r
+\r
+ LINE (x1, y1)-(x1 + 3, y1 + 3), 8, B\r
+\r
+ CASE 2\r
+ ' Draw food on the grid.\r
+ LINE (x1, y1)-(x1 + 3, y1 + 3), 14, BF\r
+\r
+ CASE 10\r
+ ' Draw the head of a worm.\r
+ LINE (x1, y1)-(x1 + 3, y1 + 3), 10, BF\r
+\r
+ PSET (x1, y1), 0\r
+\r
+ PSET (x1 + 3, y1), 0\r
+\r
+ PSET (x1, y1 + 3), 0\r
+\r
+ PSET (x1 + 3, y1 + 3), 0\r
+\r
+ CASE 11\r
+ ' Draw the body of a worm.\r
+ LINE (x1, y1)-(x1 + 3, y1 + 3), 12, BF\r
+\r
+ PSET (x1, y1), 0\r
+\r
+ PSET (x1 + 3, y1), 0\r
+\r
+ PSET (x1, y1 + 3), 0\r
+\r
+ PSET (x1 + 3, y1 + 3), 0\r
+\r
+ CASE 12\r
+ ' Draw the body of a worm.\r
+ LINE (x1, y1)-(x1 + 3, y1 + 3), 13, BF\r
+\r
+ PSET (x1, y1), 0\r
+\r
+ PSET (x1 + 3, y1), 0\r
+\r
+ PSET (x1, y1 + 3), 0\r
+\r
+ PSET (x1 + 3, y1 + 3), 0\r
+\r
+ CASE 13\r
+ ' Draw the body of a worm.\r
+ LINE (x1, y1)-(x1 + 3, y1 + 3), 15, BF\r
+\r
+ PSET (x1, y1), 0\r
+\r
+ PSET (x1 + 3, y1), 0\r
+\r
+ PSET (x1, y1 + 3), 0\r
+\r
+ PSET (x1 + 3, y1 + 3), 0\r
+\r
+ CASE 14\r
+ ' Draw the body of a worm.\r
+ LINE (x1, y1)-(x1 + 3, y1 + 3), 9, BF\r
+\r
+ PSET (x1, y1), 0\r
+\r
+ PSET (x1 + 3, y1), 0\r
+\r
+ PSET (x1, y1 + 3), 0\r
+\r
+ PSET (x1 + 3, y1 + 3), 0\r
+ END SELECT\r
+END SUB\r
+\r
+SUB init\r
+ ' Initialize the game by setting up the first level.\r
+ level 1\r
+END SUB\r
+\r
+SUB level (a%)\r
+ ' This subroutine sets up a new level of the game.\r
+ LOCATE 5, 5\r
+ PRINT "G E T R E A D Y"\r
+\r
+ LOCATE 7, 5\r
+ PRINT "L E V E L :"; a%\r
+\r
+ ' Display a countdown before starting the level.\r
+ delay 2\r
+\r
+ CLS\r
+\r
+ ' Clear the game grid.\r
+ FOR y = 0 TO 36\r
+ FOR x = 0 TO 36\r
+ buf(x, y) = 0\r
+ NEXT x\r
+ NEXT y\r
+\r
+ ' Set up the walls of the grid.\r
+ FOR x = 0 TO 36\r
+ buf(x, 0) = 1\r
+ buf(x, 36) = 1\r
+ buf(0, x) = 1\r
+ buf(36, x) = 1\r
+ NEXT x\r
+\r
+ ' Load the level from a file.\r
+ b$ = cnum(a%) + ".lvl"\r
+\r
+ OPEN b$ FOR INPUT AS #1\r
+\r
+10\r
+ ' Read the level data line by line.\r
+ IF EOF(1) <> 0 THEN GOTO 11\r
+\r
+ LINE INPUT #1, c$\r
+\r
+ ' If the line starts with a slash, it contains grid data.\r
+ IF LEFT$(c$, 1) = "/" THEN\r
+ d = d + 1\r
+\r
+ IF d > 35 THEN\r
+ GOTO 12\r
+ END IF\r
+\r
+ g = LEN(c$)\r
+ IF g > 36 THEN\r
+ g = 36\r
+ END IF\r
+\r
+ ' Parse the grid data and set up the game grid.\r
+ FOR e = 2 TO g\r
+ f$ = RIGHT$(LEFT$(c$, e), 1)\r
+\r
+ IF f$ = "#" OR f$ = "m" THEN\r
+ buf(e - 1, d) = 1\r
+ ELSE\r
+ buf(e - 1, d) = 0\r
+ END IF\r
+ NEXT e\r
+ END IF\r
+\r
+12\r
+ GOTO 10\r
+\r
+11\r
+ CLOSE #1\r
+\r
+ ' Place food randomly on the grid.\r
+ stuff\r
+\r
+ ' Initialize the worms for each player.\r
+ show\r
+\r
+ FOR b = 1 TO playerCount\r
+ ussl(b) = 0\r
+ putworm b\r
+ NEXT b\r
+\r
+ stat\r
+END SUB\r
+\r
+SUB prc (playerNumber)\r
+' This subroutine handles the main game loop for each player.\r
+ \r
+ clearTail playerNumber\r
+\r
+ ussp(playerNumber) = ussp(playerNumber) + 1\r
+\r
+ ' If the current player has no lives left, no further processing is needed\r
+ IF lives(playerNumber) = 0 THEN\r
+ GOTO 4\r
+ END IF\r
+\r
+ ' If the worm is controlled by AI, recalculate its path.\r
+ IF isAI(playerNumber) = 1 THEN\r
+ autop playerNumber\r
+ END IF\r
+\r
+ ' Move the worm based on user input or AI direction.\r
+ ux(playerNumber) = ux(playerNumber) + uxp(playerNumber)\r
+ uy(playerNumber) = uy(playerNumber) + uyp(playerNumber)\r
+\r
+ ' Wrap around the edges of the grid.\r
+ IF ux(playerNumber) = 35 THEN\r
+ ux(playerNumber) = 2\r
+ END IF\r
+\r
+ IF uy(playerNumber) = 35 THEN\r
+ uy(playerNumber) = 2\r
+ END IF\r
+\r
+ IF ux(playerNumber) = 1 THEN\r
+ ux(playerNumber) = 34\r
+ END IF\r
+\r
+ IF uy(playerNumber) = 1 THEN\r
+ uy(playerNumber) = 34\r
+ END IF\r
+\r
+ x = ux(playerNumber)\r
+ y = uy(playerNumber)\r
+\r
+3\r
+ IF buf(x, y) = 2 THEN\r
+ buf(x, y) = 0\r
+\r
+ drawGridCell x, y\r
+\r
+ stuff\r
+\r
+ ussl(playerNumber) = ussl(playerNumber) + mtm\r
+\r
+ usss(playerNumber) = usss(playerNumber) + mtm\r
+\r
+ FOR b = 1 TO playerCount\r
+ IF (lives(b) > 0) AND (isAI(b) = 1) THEN\r
+ ai b\r
+ END IF\r
+ NEXT b\r
+\r
+ stat\r
+\r
+ GOTO 3\r
+ END IF\r
+\r
+ IF buf(x, y) > 0 THEN\r
+ dead playerNumber\r
+\r
+ GOTO 4\r
+ END IF\r
+\r
+ IF playerNumber = 1 THEN\r
+ buf(x, y) = 10\r
+ ELSEIF playerNumber = 2 THEN\r
+ buf(x, y) = 11\r
+ ELSEIF playerNumber = 3 THEN\r
+ buf(x, y) = 12\r
+ ELSEIF playerNumber = 4 THEN\r
+ buf(x, y) = 13\r
+ ELSEIF playerNumber = 5 THEN\r
+ buf(x, y) = 14\r
+ END IF\r
+\r
+ drawGridCell x, y\r
+\r
+ IF ussp(playerNumber) > 2000 THEN\r
+ ussp(playerNumber) = ussp(playerNumber) - 2000\r
+ END IF\r
+\r
+ ussx(ussp(playerNumber), playerNumber) = x\r
+\r
+ ussy(ussp(playerNumber), playerNumber) = y\r
+\r
+4\r
+END SUB\r
+\r
+SUB putworm (a%)\r
+ ' This subroutine initializes a new worm for a player.\r
+ b = ussl(a%)\r
+\r
+ ' Move the worm back to its starting position.\r
+ FOR c = b TO 1 STEP -1\r
+ ussl(a%) = c\r
+\r
+ clearTail a%\r
+ NEXT c\r
+\r
+9\r
+ uy(a%) = INT(RND * 30 + 2)\r
+\r
+ ux(a%) = INT(RND * 10 + 5)\r
+\r
+ ' Ensure that the worm starts in an empty space.\r
+ FOR b = ux(a%) TO ux(a%) + 10\r
+ IF buf(b, uy(a%)) <> 0 THEN\r
+ GOTO 9\r
+ END IF\r
+ NEXT b\r
+\r
+ ' Set the initial direction of the worm.\r
+ uxp(a%) = 1\r
+\r
+ uyp(a%) = 0\r
+\r
+ ussl(a%) = 3\r
+\r
+ stat\r
+END SUB\r
+\r
+SUB sc2 (x%, y%)\r
+ ' This subroutine draws a worm on the game grid for AI pathfinding.\r
+ ' LOCATE 1, 1\r
+ ' PRINT x%, y%\r
+\r
+ ' x1 = x% * 5 + 2\r
+\r
+ ' y1 = y% * 5 + 2\r
+\r
+ ' PSET (x1, y1), 15\r
+\r
+ ' a$ = INPUT$(1)\r
+END SUB\r
+\r
+SUB show\r
+ ' This subroutine draws the entire game grid.\r
+ FOR y = 1 TO 35\r
+ FOR x = 1 TO 35\r
+ drawGridCell x, y\r
+ NEXT x\r
+ NEXT y\r
+END SUB\r
+\r
+SUB showb\r
+GOTO 15\r
+FOR x = 1 TO 35\r
+FOR y = 1 TO 35\r
+\r
+LINE (x * 2 + 200, y * 2 + 100)-(x * 2 + 201, y * 2 + 101), buf2(x, y) MOD 255, BF\r
+NEXT y\r
+NEXT x\r
+15\r
+'a$ = INPUT$(1)\r
+END SUB\r
+\r
+SUB start\r
+ ' Initialize the game screen and settings.\r
+ SCREEN 13\r
+\r
+ RANDOMIZE TIMER\r
+\r
+ uy(1) = 5\r
+\r
+ uy(2) = 10\r
+\r
+ uy(3) = 15\r
+\r
+ uy(4) = 20\r
+\r
+ uy(5) = 25\r
+\r
+ FOR a = 1 TO playerCount\r
+ ux(a) = 15\r
+\r
+ uxp(a) = 1\r
+\r
+ uyp(a) = 0\r
+\r
+ ussp(a) = 0\r
+\r
+ ussl(a) = 3\r
+\r
+ lives(a) = elum\r
+\r
+ usss(a) = 0\r
+\r
+ usskp(a) = 1\r
+\r
+ ussk(1, a) = 5\r
+ NEXT a\r
+\r
+ mtm = 0\r
+END SUB\r
+\r
+SUB stat\r
+ ' This subroutine displays the current game statistics.\r
+ LOCATE 1, 25\r
+\r
+ PRINT mtm\r
+\r
+ FOR a = 1 TO 5\r
+ COLOR 15\r
+\r
+ LOCATE 2 + a, 24\r
+\r
+ PRINT RIGHT$(STR$(a), 1)\r
+\r
+ COLOR 10\r
+\r
+ LOCATE 2 + a, 26\r
+\r
+ IF isAI(a) = 1 THEN\r
+ PRINT "*"\r
+ ELSE\r
+ PRINT "-"\r
+ END IF\r
+\r
+ COLOR 12\r
+\r
+ LOCATE 2 + a, 27\r
+\r
+ b$ = STR$(usss(a))\r
+\r
+ PRINT RIGHT$(b$, LEN(b$) - 1)\r
+\r
+ COLOR 13\r
+\r
+ LOCATE 2 + a, 30\r
+\r
+ b$ = STR$(lives(a))\r
+\r
+ PRINT RIGHT$(b$, LEN(b$) - 1)\r
+ NEXT a\r
+\r
+ COLOR 10\r
+\r
+ LOCATE 8, 26\r
+\r
+ PRINT "AI"\r
+\r
+ COLOR 12\r
+\r
+ LOCATE 2, 27\r
+\r
+ PRINT "Score"\r
+\r
+ COLOR 13\r
+\r
+ LOCATE 8, 30\r
+\r
+ PRINT "Lives"\r
+\r
+ LOCATE 1, 30\r
+\r
+ PRINT "Level:"; lvl\r
+END SUB\r
+\r
+SUB stuff\r
+ ' This subroutine places food randomly on the game grid.\r
+2\r
+ x = INT(RND * 33 + 2)\r
+\r
+ y = INT(RND * 33 + 2)\r
+\r
+ IF buf(x, y) = 0 THEN\r
+ buf(x, y) = 2\r
+\r
+ drawGridCell x, y\r
+ ELSE\r
+ GOTO 2\r
+ END IF\r
+\r
+ mtm = mtm + 1\r
+\r
+ stat\r
+END SUB\r
+\r
+SUB tkt\r
+ ' This subroutine handles user input and AI recalculation.\r
+ a$ = INKEY$\r
+\r
+ IF a$ = CHR$(27) THEN\r
+ SYSTEM\r
+ END IF\r
+\r
+ IF (a$ = CHR$(0) + "M") AND (uxp(1) <> -1) THEN\r
+ uxp(1) = 1\r
+\r
+ uyp(1) = 0\r
+ END IF\r
+\r
+ IF (a$ = CHR$(0) + "K") AND (uxp(1) <> 1) THEN\r
+ uxp(1) = -1\r
+\r
+ uyp(1) = 0\r
+ END IF\r
+\r
+ IF (a$ = CHR$(0) + "P") AND (uyp(1) <> -1) THEN\r
+ uxp(1) = 0\r
+\r
+ uyp(1) = 1\r
+ END IF\r
+\r
+ IF (a$ = CHR$(0) + "H") AND (uyp(1) <> 1) THEN\r
+ uxp(1) = 0\r
+\r
+ uyp(1) = -1\r
+ END IF\r
+\r
+ IF (a$ = "d") AND (uxp(2) <> -1) THEN\r
+ uxp(2) = 1\r
+\r
+ uyp(2) = 0\r
+ END IF\r
+\r
+ IF (a$ = "a") AND (uxp(2) <> 1) THEN\r
+ uxp(2) = -1\r
+\r
+ uyp(2) = 0\r
+ END IF\r
+\r
+ IF (a$ = "s") AND (uyp(2) <> -1) THEN\r
+ uxp(2) = 0\r
+\r
+ uyp(2) = 1\r
+ END IF\r
+\r
+ IF (a$ = "w") AND (uyp(2) <> 1) THEN\r
+ uxp(2) = 0\r
+\r
+ uyp(2) = -1\r
+ END IF\r
+\r
+ b = VAL(a$)\r
+\r
+ IF b > 0 THEN\r
+ IF isAI(b) = 1 THEN\r
+ isAI(b) = 0\r
+ ELSE\r
+ isAI(b) = 1\r
+ END IF\r
+\r
+ stat\r
+ END IF\r
+\r
+ FOR a = 1 TO playerCount\r
+ prc a\r
+ NEXT a\r
+END SUB\r
--- /dev/null
+' Game of checkers.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 1998, Initial version\r
+' 2025, Improved program readability\r
+'\r
+' Usage:\r
+' arrow keys - move around\r
+' ENTER key - pick piece on the desk and place it to new location\r
+' q - quit game\r
+\r
+DECLARE SUB CheckPossibleMoves ()\r
+DECLARE SUB HandleMovement ()\r
+DECLARE SUB GameLoop ()\r
+DECLARE SUB HandleInput ()\r
+DECLARE SUB UpdateDisplay ()\r
+DEFINT A-Z\r
+\r
+DIM SHARED boardState(-100 TO 300) AS INTEGER\r
+' 0 - black piece\r
+' 1 - white piece\r
+' 3 - Empty square that piece is allowed to move to\r
+' 4 - Empty square that is not reachable according to the game rules\r
+'\r
+' Cell address calculation (row 1--10, col 1--10):\r
+' cell address = ((row - 1) * 20) + col\r
+\r
+\r
+DIM SHARED moveMade AS INTEGER\r
+DIM SHARED hasMove AS INTEGER\r
+DIM SHARED cursorImage(1000)\r
+DIM SHARED cursorX, cursorY\r
+SCREEN 2\r
+\r
+\r
+CLS\r
+' Draw cursor image and store it into array for quick drawing on the screen\r
+LINE (1, 1)-(10, 1)\r
+LINE (1, 1)-(1, 5)\r
+LINE (10, 1)-(6, 2)\r
+LINE (6, 2)-(10, 4)\r
+LINE (10, 4)-(8, 5)\r
+LINE (8, 5)-(4, 3)\r
+LINE (4, 3)-(1, 5)\r
+PAINT (2, 2), 1\r
+GET (1, 1)-(10, 5), cursorImage\r
+\r
+CLS\r
+' Draw the checkerboard grid\r
+FOR col = 0 TO 10\r
+ LINE ((col * 40) + 20, 10)-((col * 40) + 20, 189), 1\r
+NEXT col\r
+\r
+FOR row = 0 TO 20\r
+ LINE (20, (row * 18) + 9)-(420, (row * 18) + 9), 1\r
+NEXT row\r
+\r
+' Initialize the board state to empty squares\r
+FOR cell = 1 TO 200\r
+ boardState(cell) = 4\r
+NEXT cell\r
+\r
+' Draw the initial checkerboard pattern.\r
+' (alternating squares to create the checkerboard)\r
+\r
+FOR row = 2 TO 10 STEP 2\r
+ FOR col = 1 TO 10 STEP 2\r
+ PAINT ((col * 40) + 5, (row * 18) + 5)\r
+ NEXT col\r
+NEXT row\r
+\r
+FOR row = 1 TO 10 STEP 2\r
+ FOR col = 2 TO 10 STEP 2\r
+ PAINT ((col * 40) + 5, (row * 18) + 5)\r
+ NEXT col\r
+NEXT row\r
+\r
+' Place the white pieces on the board\r
+FOR row = 2 TO 4 STEP 2\r
+ FOR col = 1 TO 10 STEP 2\r
+ boardState(((row - 1) * 20) + col) = 1\r
+ NEXT col\r
+NEXT row\r
+\r
+FOR row = 1 TO 4 STEP 2\r
+ FOR col = 2 TO 10 STEP 2\r
+ boardState(((row - 1) * 20) + col) = 1\r
+ NEXT col\r
+NEXT row\r
+\r
+' Place the black pieces on the board\r
+FOR row = 8 TO 10 STEP 2\r
+ FOR col = 1 TO 10 STEP 2\r
+ boardState(((row - 1) * 20) + col) = 0\r
+ NEXT col\r
+NEXT row\r
+\r
+FOR row = 7 TO 10 STEP 2\r
+ FOR col = 2 TO 10 STEP 2\r
+ boardState(((row - 1) * 20) + col) = 0\r
+ NEXT col\r
+NEXT row\r
+\r
+FOR col = 2 TO 10 STEP 2\r
+ boardState(80 + col) = 3\r
+NEXT col\r
+\r
+FOR col = 1 TO 10 STEP 2\r
+ boardState(100 + col) = 3\r
+NEXT col\r
+\r
+UpdateDisplay\r
+moveMade = 1\r
+GameLoop\r
+\r
+SUB CheckPossibleMoves\r
+ ' Checks if there are any possible moves on the board\r
+ hasMove = 0\r
+ FOR cell = 1 TO 200\r
+ ' Check for possible jumps in all directions\r
+ IF boardState(cell) = 0 AND boardState(cell - 21) = 1 AND boardState(cell - 42) = 3 THEN hasMove = 1\r
+ IF boardState(cell) = 0 AND boardState(cell - 19) = 1 AND boardState(cell - 38) = 3 THEN hasMove = 1\r
+ IF boardState(cell) = 0 AND boardState(cell + 21) = 1 AND boardState(cell + 42) = 3 THEN hasMove = 1\r
+ IF boardState(cell) = 0 AND boardState(cell + 19) = 1 AND boardState(cell + 38) = 3 THEN hasMove = 1\r
+ NEXT cell\r
+END SUB\r
+\r
+SUB GameLoop\r
+4\r
+ HandleInput\r
+ HandleMovement\r
+ CheckPossibleMoves\r
+ IF hasMove = 1 THEN SOUND 1234, 2\r
+ GOTO 4\r
+END SUB\r
+\r
+SUB HandleInput\r
+ DIM tempImage(1000)\r
+\r
+ inputPhase = 1\r
+\r
+5\r
+ cursorX = ax1\r
+ cursorY = ax2\r
+\r
+7\r
+ IF inputPhase = 1 THEN\r
+ LOCATE 1, 60\r
+ PRINT "From where ?"\r
+ END IF\r
+ IF inputPhase = 2 THEN\r
+ LOCATE 1, 60\r
+ PRINT "To where ? "\r
+ END IF\r
+\r
+\r
+ selectedCell = (((cursorY \ 18) - 1) * 20) + (cursorX \ 40)\r
+ 'LOCATE 2, 60\r
+ 'PRINT selectedCell\r
+\r
+ GET (cursorX, cursorY)-(cursorX + 10, cursorY + 10), tempImage\r
+ PUT (cursorX, cursorY), cursorImage, PSET\r
+\r
+getKey:\r
+ key$ = INKEY$\r
+IF key$ = "" THEN GOTO getKey\r
+\r
+ PUT (cursorX, cursorY), tempImage, PSET\r
+\r
+ IF inputPhase = 2 AND key$ = CHR$(13) THEN\r
+ destinationCell = selectedCell\r
+ cursorX = ax1\r
+ cursorY = ax2\r
+ GOTO 8\r
+ END IF\r
+ IF inputPhase = 1 AND key$ = CHR$(13) THEN\r
+ sourceCell = selectedCell\r
+ inputPhase = 2\r
+ END IF\r
+\r
+ IF key$ = "q" THEN\r
+ END\r
+ END IF\r
+ IF key$ = CHR$(0) + "M" THEN ' Right arrow\r
+ cursorX = cursorX + 40\r
+ END IF\r
+ IF key$ = CHR$(0) + "K" THEN ' Left arrow\r
+ cursorX = cursorX - 40\r
+ END IF\r
+ IF key$ = CHR$(0) + "H" THEN ' Up arrow\r
+ cursorY = cursorY - 18\r
+ END IF\r
+ IF key$ = CHR$(0) + "P" THEN ' Down arrow\r
+ cursorY = cursorY + 18\r
+ END IF\r
+\r
+ IF cursorX < 1 THEN\r
+ cursorX = 1\r
+ END IF\r
+\r
+ IF cursorY < 1 THEN\r
+ cursorY = 1\r
+ END IF\r
+\r
+ GOTO 7\r
+\r
+8\r
+ moveMade = 1\r
+\r
+ 'LOCATE 3, 60\r
+ 'PRINT sourceCell; "-"; destinationCell\r
+\r
+10\r
+\r
+ ' This section controls the movement of pieces on the board\r
+ IF sourceCell = destinationCell + 19 AND boardState(sourceCell) = 0 AND boardState(destinationCell) = 3 THEN\r
+ BEEP\r
+ SWAP boardState(sourceCell), boardState(destinationCell)\r
+ END IF\r
+ IF sourceCell = destinationCell + 21 AND boardState(sourceCell) = 0 AND boardState(destinationCell) = 3 THEN\r
+ BEEP\r
+ SWAP boardState(sourceCell), boardState(destinationCell)\r
+ END IF\r
+\r
+ captureMade = 0\r
+\r
+ IF sourceCell = destinationCell + 42 AND boardState(sourceCell) = 0 AND boardState(destinationCell) = 3 AND boardState(destinationCell + 21) = 1 THEN\r
+ BEEP\r
+ SWAP boardState(sourceCell), boardState(destinationCell)\r
+ boardState(destinationCell + 21) = 3\r
+ captureMade = 1\r
+ END IF\r
+ IF sourceCell = destinationCell + 38 AND boardState(sourceCell) = 0 AND boardState(destinationCell) = 3 AND boardState(destinationCell + 19) = 1 THEN\r
+ BEEP\r
+ SWAP boardState(sourceCell), boardState(destinationCell)\r
+ boardState(destinationCell + 19) = 3\r
+ captureMade = 1\r
+ END IF\r
+ IF sourceCell = destinationCell - 42 AND boardState(sourceCell) = 0 AND boardState(destinationCell) = 3 AND boardState(destinationCell - 21) = 1 THEN\r
+ BEEP\r
+ SWAP boardState(sourceCell), boardState(destinationCell)\r
+ boardState(destinationCell - 21) = 3\r
+ captureMade = 1\r
+ END IF\r
+ IF sourceCell = destinationCell - 38 AND boardState(sourceCell) = 0 AND boardState(destinationCell) = 3 AND boardState(destinationCell - 19) = 1 THEN\r
+ BEEP\r
+ SWAP boardState(sourceCell), boardState(destinationCell)\r
+ boardState(destinationCell - 19) = 3\r
+ captureMade = 1\r
+ END IF\r
+\r
+ UpdateDisplay\r
+\r
+ IF captureMade = 1 THEN\r
+ CheckPossibleMoves\r
+ IF hasMove = 1 THEN\r
+ SOUND 1234, 1\r
+ inputPhase = 2\r
+ sourceCell = destinationCell\r
+ GOTO 5\r
+ END IF\r
+ END IF\r
+\r
+6\r
+END SUB\r
+\r
+SUB HandleMovement\r
+3\r
+' Check for possible jumps where a AI can eat 2 pieces at once\r
+FOR cell = 1 TO 200\r
+ IF boardState(cell) = 1 AND boardState(cell + 21) = 0 AND boardState(cell + 42) = 3 AND boardState(cell + 61) = 0 AND boardState(cell + 80) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 21) = 3: boardState(cell + 42) = 1\r
+ moveMade = 1\r
+ UpdateDisplay\r
+ GOTO 3\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell + 21) = 0 AND boardState(cell + 42) = 3 AND boardState(cell + 23) = 0 AND boardState(cell + 4) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 21) = 3: boardState(cell + 42) = 1\r
+ moveMade = 1\r
+ UpdateDisplay\r
+ GOTO 3\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell + 19) = 0 AND boardState(cell + 38) = 3 AND boardState(cell + 59) = 0 AND boardState(cell + 80) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 19) = 3: boardState(cell + 38) = 1\r
+\r
+ moveMade = 1\r
+ UpdateDisplay\r
+ GOTO 3\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell + 19) = 0 AND boardState(cell + 38) = 3 AND boardState(cell + 17) = 0 AND boardState(cell - 4) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 19) = 3: boardState(cell + 38) = 1\r
+\r
+ moveMade = 1\r
+ UpdateDisplay\r
+ GOTO 3\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell + 21) = 0 AND boardState(cell + 42) = 3 AND boardState(cell + 63) = 0 AND boardState(cell + 84) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 21) = 3: boardState(cell + 42) = 1\r
+\r
+ moveMade = 1\r
+ UpdateDisplay\r
+ GOTO 3\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell + 19) = 0 AND boardState(cell + 38) = 3 AND boardState(cell + 57) = 0 AND boardState(cell + 76) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 19) = 3: boardState(cell + 38) = 1\r
+\r
+ moveMade = 1\r
+ UpdateDisplay\r
+ GOTO 3\r
+ END IF\r
+\r
+ IF boardState(cell) = 1 AND boardState(cell - 21) = 0 AND boardState(cell - 42) = 3 AND boardState(cell - 61) = 0 AND boardState(cell - 80) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell - 21) = 3: boardState(cell - 42) = 1\r
+\r
+ moveMade = 1\r
+ UpdateDisplay\r
+ GOTO 3\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell - 21) = 0 AND boardState(cell - 42) = 3 AND boardState(cell - 23) = 0 AND boardState(cell - 4) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell - 21) = 3: boardState(cell - 42) = 1\r
+\r
+ moveMade = 1\r
+ UpdateDisplay\r
+ GOTO 3\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell - 19) = 0 AND boardState(cell - 38) = 3 AND boardState(cell - 59) = 0 AND boardState(cell - 80) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell - 19) = 3: boardState(cell - 38) = 1\r
+\r
+ moveMade = 1\r
+ UpdateDisplay\r
+ GOTO 3\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell - 19) = 0 AND boardState(cell - 38) = 3 AND boardState(cell - 17) = 0 AND boardState(cell + 4) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell - 19) = 3: boardState(cell - 38) = 1\r
+\r
+ moveMade = 1\r
+ UpdateDisplay\r
+ GOTO 3\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell - 21) = 0 AND boardState(cell - 42) = 3 AND boardState(cell - 63) = 0 AND boardState(cell - 84) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell - 21) = 3: boardState(cell - 42) = 1\r
+\r
+ moveMade = 1\r
+ UpdateDisplay\r
+ GOTO 3\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell - 19) = 0 AND boardState(cell - 38) = 3 AND boardState(cell - 57) = 0 AND boardState(cell - 76) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell - 19) = 3: boardState(cell - 38) = 1\r
+\r
+ moveMade = 1\r
+ UpdateDisplay\r
+ GOTO 3\r
+ END IF\r
+NEXT cell\r
+\r
+' Check for possible single moves (single eating)\r
+FOR cell = 1 TO 200\r
+ IF boardState(cell) = 1 AND boardState(cell + 21) = 0 AND boardState(cell + 42) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 21) = 3: boardState(cell + 42) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell + 19) = 0 AND boardState(cell + 38) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 19) = 3: boardState(cell + 38) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell - 21) = 0 AND boardState(cell - 42) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell - 21) = 3: boardState(cell - 42) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell - 19) = 0 AND boardState(cell - 38) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell - 19) = 3: boardState(cell - 38) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+NEXT cell\r
+\r
+' Check for possible defensive moves (to protect own pieces)\r
+FOR cell = 1 TO 200\r
+ IF boardState(cell) = 1 AND boardState(cell + 19) = 3 AND boardState(cell + 21) = 3 AND boardState(cell + 40) = 1 AND boardState(cell + 38) = 3 AND boardState(cell + 61) = 0 THEN\r
+ boardState(cell) = 3: boardState(cell + 19) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell + 19) = 3 AND boardState(cell + 21) = 0 AND boardState(cell + 40) = 1 AND boardState(cell + 38) = 3 AND boardState(cell + 61) = 0 THEN\r
+ boardState(cell) = 3: boardState(cell + 19) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell + 19) = 3 AND boardState(cell + 21) = 3 AND boardState(cell + 40) = 1 AND boardState(cell + 38) = 1 AND boardState(cell + 61) = 0 THEN\r
+ boardState(cell) = 3: boardState(cell + 19) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell + 19) = 3 AND boardState(cell + 21) = 0 AND boardState(cell + 40) = 1 AND boardState(cell + 38) = 1 AND boardState(cell + 61) = 0 THEN\r
+ boardState(cell) = 3: boardState(cell + 19) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+\r
+ IF boardState(cell - 2) = 1 AND boardState(cell + 19) = 3 AND boardState(cell) = 3 AND boardState(cell + 40) = 1 AND boardState(cell + 38) = 3 AND boardState(cell + 61) = 0 THEN\r
+ boardState(cell - 2) = 3: boardState(cell + 19) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+ IF boardState(cell - 2) = 1 AND boardState(cell + 19) = 3 AND boardState(cell) = 1 AND boardState(cell + 40) = 1 AND boardState(cell + 38) = 3 AND boardState(cell + 61) = 0 THEN\r
+ boardState(cell - 2) = 3: boardState(cell + 19) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+ IF boardState(cell - 2) = 1 AND boardState(cell + 19) = 3 AND boardState(cell) = 3 AND boardState(cell + 40) = 1 AND boardState(cell + 38) = 1 AND boardState(cell + 61) = 0 THEN\r
+ boardState(cell - 2) = 3: boardState(cell + 19) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+ IF boardState(cell - 2) = 1 AND boardState(cell + 19) = 3 AND boardState(cell) = 1 AND boardState(cell + 40) = 1 AND boardState(cell + 38) = 1 AND boardState(cell + 61) = 0 THEN\r
+ boardState(cell - 2) = 3: boardState(cell + 19) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+NEXT cell\r
+\r
+' Check for possible moves to the board edges (to protect own pieces)\r
+FOR cell = 1 TO 200\r
+ IF boardState(cell) = 1 AND boardState(cell + 2) = 4 AND boardState(cell + 21) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 21) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell - 2) = 4 AND boardState(cell + 19) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 19) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+NEXT cell\r
+\r
+' Check for possible moves to the corner (safe moves)\r
+FOR cell = 1 TO 200\r
+ IF boardState(cell) = 1 AND boardState(cell + 19) = 3 AND boardState(cell + 38) = 3 AND boardState(cell + 40) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 19) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell + 21) = 3 AND boardState(cell + 42) = 3 AND boardState(cell + 40) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 21) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+\r
+ IF boardState(cell) = 1 AND boardState(cell + 19) = 3 AND boardState(cell + 38) = 1 AND boardState(cell + 40) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 19) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell + 21) = 3 AND boardState(cell + 42) = 1 AND boardState(cell + 40) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 21) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+\r
+ IF boardState(cell) = 1 AND boardState(cell + 19) = 3 AND boardState(cell + 38) = 3 AND boardState(cell + 40) = 1 THEN\r
+ boardState(cell) = 3: boardState(cell + 19) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell + 21) = 3 AND boardState(cell + 42) = 3 AND boardState(cell + 40) = 1 THEN\r
+ boardState(cell) = 3: boardState(cell + 21) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+\r
+ IF boardState(cell) = 1 AND boardState(cell + 19) = 3 AND boardState(cell + 38) = 1 AND boardState(cell + 40) = 1 THEN\r
+ boardState(cell) = 3: boardState(cell + 19) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell + 21) = 3 AND boardState(cell + 42) = 1 AND boardState(cell + 40) = 1 THEN\r
+ boardState(cell) = 3: boardState(cell + 21) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+NEXT cell\r
+\r
+' Check for any remaining moves that can be made\r
+FOR cell = 1 TO 200\r
+ IF boardState(cell) = 1 AND boardState(cell + 21) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 21) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+ IF boardState(cell) = 1 AND boardState(cell + 19) = 3 THEN\r
+ boardState(cell) = 3: boardState(cell + 19) = 1\r
+\r
+ GOTO 2\r
+ END IF\r
+NEXT cell\r
+LOCATE 4, 5\r
+PRINT " Y O U W O N !"\r
+END\r
+GOTO 3\r
+2\r
+UpdateDisplay\r
+9\r
+END SUB\r
+\r
+SUB UpdateDisplay\r
+ ' Draw the pieces on the board\r
+ FOR row = 1 TO 10\r
+ FOR col = 1 TO 10\r
+ pieceType = boardState(((row - 1) * 20) + col)\r
+ SELECT CASE pieceType\r
+ CASE 1\r
+ CIRCLE (col * 40, row * 18), 17, 1\r
+ PAINT (col * 40, row * 18), 1\r
+ CIRCLE (col * 40, row * 18), 17, 0\r
+ CIRCLE (col * 40, row * 18), 16, 0\r
+ LINE ((col * 40) - 16, row * 18)-((col * 40) + 16, row * 18), 0\r
+ CASE 0\r
+ CIRCLE (col * 40, row * 18), 17, 0\r
+ PAINT (col * 40, row * 18), 0\r
+ CIRCLE (col * 40, row * 18), 17, 1\r
+ CIRCLE (col * 40, row * 18), 15, 1\r
+ CIRCLE (col * 40, row * 18), 3, 1\r
+ CIRCLE (col * 40, row * 18), 7, 1\r
+ LINE ((col * 40) - 16, row * 18)-((col * 40) + 16, row * 18), 0\r
+ CASE 3\r
+ PAINT (col * 40, row * 18), 1\r
+ END SELECT\r
+ NEXT col\r
+ NEXT row\r
+END SUB\r
+\r
--- /dev/null
+' Game of checkers. Supports basic moves. Incomplete.
+'
+' This program is free software: released under Creative Commons Zero (CC0) license
+' by Svjatoslav Agejenko.
+' Email: svjatoslav@svjatoslav.eu
+' Homepage: http://www.svjatoslav.eu
+'
+' Changelog:
+' 2001, Initial version
+' 2024, Improved program readability
+
+DECLARE SUB compki (m%, h%, x1%, y1%)
+DECLARE SUB compgo2 (h%)
+DECLARE SUB compgo (h%)
+DECLARE SUB humngo (h%)
+DefInt A-Z
+
+DECLARE SUB thinkc ()
+DECLARE SUB thinkh ()
+DECLARE SUB cmd (a$)
+DECLARE SUB freet ()
+DECLARE SUB prn (x%, y%, c%, a$)
+DECLARE SUB msg (a$, c)
+DECLARE SUB getfnt ()
+DECLARE SUB playg ()
+DECLARE SUB geth ()
+DECLARE SUB start ()
+DECLARE SUB mklau ()
+DECLARE SUB showr (x, y)
+DECLARE SUB show ()
+Dim Shared font(0 To 7, 0 To 7, 0 To 255)
+Dim Shared siz, fi, ri, rs
+Dim Shared stri$
+Dim Shared humx1, humy1, humx2, humy2
+Dim Shared sug, smax
+Dim Shared npos As Long
+Dim Shared cx1, cy1, cx2, cy2
+
+siz = 6 ' Board size
+fi = 0
+ri = 2
+smax = 3 ' thinking depth
+
+Dim Shared lau(-1 To siz + 2, -1 To siz + 2)
+
+start
+mklau
+show
+playg
+
+Sub cmd (a$)
+ mitus = 0
+ Dim sona$(1 To 10)
+ For b = 1 To 10
+ sona$(b) = ""
+ Next b
+
+ d = 1
+ e = 1
+ For b = 1 To Len(a$)
+ c$ = Right$(Left$(a$, b), 1)
+ If c$ = " " Then
+ If e = 0 Then d = d + 1: e = 1
+ GoTo 4
+ End If
+ e = 0
+ sona$(d) = sona$(d) + c$
+ 4
+ Next b
+ If e = 1 Then d = d - 1
+ mitus = d
+
+ Select Case sona$(1)
+ Case "m"
+ If humx1 > 0 Then msg "Move replaced.", 14
+
+ humx1 = Asc(Left$(sona$(2), 1)) - 64
+ If humx1 > 32 Then humx1 = humx1 - 32
+ humy1 = Val(Right$(sona$(2), Len(sona$(2)) - 1))
+ humx2 = Asc(Left$(sona$(3), 1)) - 64
+ If humx2 > 32 Then humx2 = humx2 - 32
+ humy2 = Val(Right$(sona$(3), Len(sona$(2)) - 1))
+
+ Case "h"
+ msg "h - display help screen", 14
+ msg "q - to quit", 14
+ msg "m <from> <to> - make move", 14
+ msg "n - no. positions processed", 14
+
+ Case "q"
+ System
+
+ Case "n"
+ b$ = "positions processed:" + Str$(npos)
+ msg b$, 14
+
+ End Select
+
+End Sub
+
+Sub compgo (h)
+ If sug > smax Then h = 0: GoTo 6
+ sug = sug + 1
+ npos = npos + 1
+ freet
+ If sug = 1 Then h1 = -2000 Else h1 = -1000
+
+ 'cx1 = x: cy1 = y: cx2 = x - 1: cy2 = y + 1
+ b = 0
+ c = 0
+ m = 0
+ For y = 1 To siz ' check for eating
+ For x = 1 To siz
+ If lau(x, y) = 1 Then
+ 8
+ If (lau(x - 1, y + 1) = 2) And (lau(x - 2, y + 2) = 0) Then
+ Swap lau(x, y), lau(x - 2, y + 2)
+ lau(x - 1, y + 1) = 0
+ compki m1, h2, x - 2, y + 2
+ lau(x - 1, y + 1) = 2
+ Swap lau(x, y), lau(x - 2, y + 2)
+ m1 = m1 + 1
+ If m1 > m Then m = m1: h1 = -1000
+ If m1 = m Then
+ If h2 + 1 > h1 Then
+ h1 = h2 + 1
+ If npos = 1 Then cx1 = x: cy1 = y: cx2 = x - 2: cy2 = y + 2
+ End If
+ End If
+ b = 1
+ End If
+
+ If (lau(x + 1, y + 1) = 2) And (lau(x + 2, y + 2) = 0) Then
+ Swap lau(x, y), lau(x + 2, y + 2)
+ lau(x + 1, y + 1) = 0
+ compki m1, h2, x + 2, y + 2
+ lau(x + 1, y + 1) = 2
+ Swap lau(x, y), lau(x + 2, y + 2)
+ m1 = m1 + 1
+ If m1 > m Then m = m1: h1 = -1000
+ If m1 = m Then
+ If h2 + 1 > h1 Then
+ h1 = h2 + 1
+ If npos = 1 Then cx1 = x: cy1 = y: cx2 = x + 2: cy2 = y + 2
+ End If
+ End If
+ b = 1
+ End If
+
+ If (lau(x - 1, y - 1) = 2) And (lau(x - 2, y - 2) = 0) Then
+ Swap lau(x, y), lau(x - 2, y - 2)
+ lau(x - 1, y - 1) = 0
+ compki m1, h2, x - 2, y - 2
+ lau(x - 1, y - 1) = 2
+ Swap lau(x, y), lau(x - 2, y - 2)
+ m1 = m1 + 1
+ If m1 > m Then m = m1: h1 = -1000
+ If m1 = m Then
+ If h2 + 1 > h1 Then
+ h1 = h2 + 1
+ If npos = 1 Then cx1 = x: cy1 = y: cx2 = x - 2: cy2 = y - 2
+ End If
+ End If
+ b = 1
+ End If
+
+ If (lau(x + 1, y - 1) = 2) And (lau(x + 2, y - 2) = 0) Then
+ Swap lau(x, y), lau(x + 2, y - 2)
+ lau(x + 1, y - 1) = 0
+ compki m1, h2, x + 2, y - 2
+ lau(x + 1, y - 1) = 2
+ Swap lau(x, y), lau(x + 2, y - 2)
+ m1 = m1 + 1
+ If m1 > m Then m = m1: h1 = -1000
+ If m1 = m Then
+ If h2 + 1 > h1 Then
+ h1 = h2 + 1
+ If npos = 1 Then cx1 = x: cy1 = y: cx2 = x + 2: cy2 = y - 2
+ End If
+ End If
+ b = 1
+ End If
+
+ If c = 1 Then GoTo 9
+ End If
+ Next x
+ Next y
+
+ 9
+ If (b = 1) And (npos = 1) Then
+ cx3 = (cx1 + cx2) / 2
+ cy3 = (cy1 + cy2) / 2
+ lau(cx3, cy3) = 0
+ showr cx3, cy3
+
+ Swap lau(cx1, cy1), lau(cx2, cy2)
+ showr cx1, cy1
+ showr cx2, cy2
+ msg "NJAM!", 10
+ x = cx2
+ y = cy2
+ c = 1
+ b = 0
+ GoTo 8
+ End If
+ If c = 1 Then
+ cx1 = 1: cy1 = 1: cx2 = 1: cy2 = 1
+ GoTo 10
+ End If
+
+ If sug = 1 Then
+ msg "Cannot eat.", 4
+ msg Str$(h1), 4
+ End If
+
+ For y = 1 To siz ' unuseful move
+ For x = 1 To siz
+ If lau(x, y) = 1 Then
+ If lau(x - 1, y + 1) = 0 Then
+ Swap lau(x, y), lau(x - 1, y + 1)
+ humngo h2
+ Swap lau(x, y), lau(x - 1, y + 1)
+ If h2 > h1 Then
+ h1 = h2
+ If sug = 1 Then cx1 = x: cy1 = y: cx2 = x - 1: cy2 = y + 1
+ End If
+ End If
+
+ If lau(x + 1, y + 1) = 0 Then
+ Swap lau(x, y), lau(x + 1, y + 1)
+ humngo h2
+ Swap lau(x, y), lau(x + 1, y + 1)
+ If h2 > h1 Then
+ h1 = h2
+ If sug = 1 Then cx1 = x: cy1 = y: cx2 = x + 1: cy2 = y + 1
+ End If
+ End If
+
+ End If
+ Next x
+ Next y
+ h = h1
+ 10
+ sug = sug - 1
+ 6
+End Sub
+
+Sub compki (m, h, x1, y1)
+ h1 = 0
+
+ For y = 1 To siz
+ For x = 1 To siz
+ Next x
+ Next y
+ h = h1
+
+End Sub
+
+Sub freet
+ a$ = InKey$
+ If a$ = "" Then
+ Else
+ If a$ = Chr$(8) Then
+ If Len(stri$) > 0 Then
+ stri$ = Left$(stri$, Len(stri$) - 1): GoTo 3
+ End If
+ End If
+ If a$ = Chr$(13) Then
+ If Len(stri$) > 0 Then
+ msg stri$, 7
+ cmd stri$
+ stri$ = ""
+ End If
+ GoTo 3
+ End If
+ stri$ = stri$ + a$
+ 3
+ Line (400, 468)-(639, 479), 1, BF
+ prn 405, 469, 14, stri$
+ End If
+End Sub
+
+Sub getfnt
+ Screen 13
+ For a = 0 To 255
+ If (a > 5) And (a < 17) Then GoTo 2
+ Locate 1, 1
+ Print Chr$(a)
+ 2
+ For y = 0 To 7
+ For x = 0 To 7
+ font(x, y, a) = Point(x, y)
+ Next x
+ Next y
+ Next a
+
+End Sub
+
+Sub humngo (h)
+ npos = npos + 1
+ h1 = 1000
+
+ For y = siz To 1 Step -1
+ For x = siz To 1 Step -1
+ If lau(x, y) = 2 Then
+ If lau(x - 1, y - 1) = 0 Then
+ Swap lau(x, y), lau(x - 1, y - 1)
+ compgo h2
+ Swap lau(x, y), lau(x - 1, y - 1)
+ If h2 < h1 Then h1 = h2
+ End If
+
+ If lau(x + 1, y - 1) = 0 Then
+ Swap lau(x, y), lau(x + 1, y - 1)
+ compgo h2
+ Swap lau(x, y), lau(x + 1, y - 1)
+ If h2 < h1 Then h1 = h2
+ End If
+
+ If (lau(x - 1, y - 1) = 1) And (lau(x - 2, y - 2) = 0) Then
+ Swap lau(x, y), lau(x - 2, y - 2)
+ lau(x - 1, y - 1) = 0
+ humngo h2
+ lau(x - 1, y - 1) = 1
+ Swap lau(x, y), lau(x - 2, y - 2)
+ If h2 - 1 < h1 Then h1 = h2 - 1
+ End If
+
+ If (lau(x + 1, y - 1) = 1) And (lau(x + 2, y - 2) = 0) Then
+ Swap lau(x, y), lau(x + 2, y - 2)
+ lau(x + 1, y - 1) = 0
+ humngo h2
+ lau(x + 1, y - 1) = 1
+ Swap lau(x, y), lau(x + 2, y - 2)
+ If h2 - 1 < h1 Then h1 = h2 - 1
+ End If
+
+ End If
+ Next x
+ Next y
+ h = h1
+End Sub
+
+Sub mklau
+ For y = -1 To siz + 2
+ For x = -1 To siz + 2
+ lau(x, y) = -1
+ Next x
+ Next y
+
+ For y = 1 To siz
+ For x = 1 To siz
+ lau(x, y) = 0
+ Next x
+ Next y
+
+ For y = 1 To ri
+ For x = 1 To siz
+ If (x + y + fi) / 2 = Int((x + y + fi) / 2) Then
+ lau(x, y) = 1
+ End If
+ Next x
+ Next y
+
+ For y = siz - ri + 1 To siz
+ For x = 1 To siz
+ If (x + y + fi) / 2 = Int((x + y + fi) / 2) Then
+ lau(x, y) = 2
+ End If
+ Next x
+ Next y
+
+End Sub
+
+Sub msg (a$, c)
+ Dim buf(1 To 10000)
+ For x = 400 To 630 Step 40
+ Get (x, 8)-(x + 39, 467), buf(1)
+ Put (x, 0), buf(1), PSet
+ Next x
+ Line (400, 460)-(639, 467), 0, BF
+ prn 405, 460, c, a$
+End Sub
+
+Sub playg
+ 'GOTO 7
+ 1
+ thinkc
+ show
+ 7
+ thinkh
+ show
+ GoTo 1
+
+End Sub
+
+Sub prn (x, y, c, a$)
+ x1 = x
+ y1 = y
+ For a = 1 To Len(a$)
+ b = Asc(Right$(Left$(a$, a), 1))
+ For y2 = 0 To 7
+ For x2 = 0 To 7
+ If font(x2, y2, b) > 0 Then PSet (x2 + x1, y2 + y1), c
+ Next x2
+ Next y2
+ x1 = x1 + 8
+ Next a
+End Sub
+
+Sub show
+ For y = 1 To siz
+ For x = 1 To siz
+ showr x, y
+ Next x
+ Next y
+
+ sp = rs / 2
+ For x = 1 To siz
+ prn ((x - 1) * rs + 12 + sp), 2, 10, Chr$(64 + x)
+ prn ((x - 1) * rs + 12 + sp), siz * rs + 11, 10, Chr$(64 + x)
+ Next x
+
+ For y = 1 To siz
+ a$ = Str$(y)
+ a$ = Right$(a$, Len(a$) - 1)
+ prn 15 - (Len(a$) * 8), (y - 1) * rs + sp + 7, 10, a$
+ prn (siz * rs + 16), (y - 1) * rs + sp + 7, 10, a$
+ Next y
+
+End Sub
+
+Sub showr (x, y)
+ If (x + y + fi) / 2 = Int((x + y + fi) / 2) Then c = 8 Else c = 7
+ x1 = (x - 1) * rs + 15
+ y1 = (y - 1) * rs + 10
+ Line (x1, y1)-(x1 + rs - 1, y1 + rs - 1), c, BF
+
+ If lau(x, y) > 0 Then
+ sp = rs / 2
+ If lau(x, y) = 1 Then c1 = 15 Else c1 = 14
+ Circle (x1 + sp, y1 + sp), sp - 1, c1
+ Paint (x1 + sp, y1 + sp), c1
+ End If
+End Sub
+
+Sub start
+ getfnt
+ Screen 12
+ Line (399, 0)-(399, 479), 13
+ msg "Type 'h' for help.", 14
+
+ rs = Int(370 / siz)
+
+End Sub
+
+Sub thinkc
+ msg "Computer turn.", 14
+ sug = 0
+ npos = 0
+ cx1 = -1
+
+ compgo h
+ cmd "n"
+ If cx1 = -1 Then msg "You won!", 10: msg "--------", 10: System
+
+ If h <= -2 Then msg "Oh no...", 10
+ If h = -1 Then msg "Oops!", 10
+ If h = 1 Then msg "Yess! I will eat soon!", 10
+ If h >= 2 Then msg "HA HA HA YOU ARE IN TROUBLE!", 10
+
+ If Abs(cx1 - cx2) = 2 Then
+ cx3 = (cx1 + cx2) / 2
+ cy3 = (cy1 + cy2) / 2
+ lau(cx3, cy3) = 0
+ showr cx3, cy3
+ End If
+
+ Swap lau(cx1, cy1), lau(cx2, cy2)
+ showr cx1, cy1
+ showr cx2, cy2
+
+End Sub
+
+Sub thinkh
+ msg "Your turn.", 14
+ 5
+ freet
+ If humx1 = 0 Then GoTo 5
+ Swap lau(humx2, humy2), lau(humx1, humy1)
+ showr humx1, humy1
+ showr humx2, humy2
+ If Abs(humx1 - humx2) = 2 Then
+ cx3 = (humx1 + humx2) / 2
+ cy3 = (humy1 + humy2) / 2
+ lau(cx3, cy3) = 0
+ showr cx3, cy3
+ End If
+
+ humx1 = 0
+End Sub
--- /dev/null
+.....#.#.....\r
+...##...##...\r
+..#.......#..\r
+.#..##.##..#.\r
+.#.#.....#.#.\r
+#..#.###.#..#\r
+.....#.#.....\r
+#..#.###.#..#\r
+.#.#.....#.#.\r
+.#..##.##..#.\r
+..#.......#..\r
+...##...##...\r
+.....#.#.....\r
--- /dev/null
+' Program renders rotating 3D animation from cubes.
+' Cubes appear and disappear according to Conway's Game of Life rules.
+'
+' This program is free software: released under Creative Commons Zero (CC0) license
+' by Svjatoslav Agejenko.
+' Email: svjatoslav@svjatoslav.eu
+' Homepage: http://www.svjatoslav.eu
+'
+' Changelog:
+' ~2000, Initial version
+' 2024 - 2025, Improved program readability
+
+DECLARE SUB PlaceCube (xCoordinate!, yCoordinate!, zCoordinate!)
+DECLARE SUB DrawScene ()
+DECLARE SUB Generate3DScene ()
+DECLARE SUB UpdateCollisionData ()
+DECLARE SUB InitializeGame ()
+
+DIM SHARED totalPoints, totalLines, currentPointCount, currentLineCount
+DIM SHARED pointXCoordinates(1 TO 3000), pointYCoordinates(1 TO 3000), pointZCoordinates(1 TO 3000)
+DIM SHARED renderedPointXCoordinates(1 TO 7000), renderedPointYCoordinates(1 TO 7000)
+DIM SHARED previousRenderedPointXCoordinates(0 TO 9000), previousRenderedPointYCoordinates(0 TO 9000)
+DIM SHARED previousPointCount, previousLineCount
+DIM SHARED lineVertex1Indices(1 TO 3800), lineVertex2Indices(1 TO 3800), lineColorValues(1 TO 3800)
+DIM SHARED previousLineVertex1Indices(1 TO 3800), previousLineVertex2Indices(1 TO 3800)
+DIM SHARED cameraPositionX, cameraPositionY, cameraPositionZ
+DIM SHARED previousCameraPositionX, previousCameraPositionY, previousCameraPositionZ
+DIM SHARED rotationAngle1, rotationAngle2
+DIM SHARED rotationAngle1String, rotationAngle2String
+DIM SHARED currentFrameCount
+DIM SHARED currentGameOfLifeGrid(1 TO 50, 1 TO 50)
+DIM SHARED nextGameOfLifeGrid(1 TO 50, 1 TO 50)
+
+' Main program
+InitializeGame
+rotationAngle1 = 1.5
+
+10
+currentFrameCount = currentFrameCount + 1
+Generate3DScene
+DrawScene
+
+cameraPositionX = SIN(currentFrameCount / 20) * 12
+cameraPositionY = SIN(currentFrameCount / 50) * 10 + 15
+cameraPositionZ = COS(currentFrameCount / 20) * 12
+rotationAngle1 = rotationAngle1 - .05
+rotationAngle2 = 2.2 + SIN(currentFrameCount / 50) / 2
+
+inputKey$ = INKEY$
+IF inputKey$ <> "" THEN SYSTEM
+GOTO 10
+
+SUB Generate3DScene
+ ' This subroutine generates 3D scene of cubes based on the current state of the Game of Life grid.
+ ' It iterates over the grid and places cubes where the grid cells are alive.
+ ' It also updates the grid based on Conway's Game of Life rules every 10 frames.
+
+ currentPointCount = totalPoints
+ currentLineCount = totalLines
+
+ FOR y = 1 TO 50
+ FOR x = 1 TO 50
+ IF currentGameOfLifeGrid(x, y) = 1 THEN
+ value = ABS(x - 26) + ABS(y - 26) + currentFrameCount
+ PlaceCube x - 25, SIN(value / 5) * 5, y - 25
+ END IF
+ NEXT x
+ NEXT y
+
+ IF currentFrameCount \ 10 = currentFrameCount / 10 THEN ' activate every 10-th frame to update grid
+ FOR y = 2 TO 49
+ FOR x = 2 TO 49
+ neighborCount = currentGameOfLifeGrid(x - 1, y - 1)
+ neighborCount = neighborCount + currentGameOfLifeGrid(x, y - 1)
+ neighborCount = neighborCount + currentGameOfLifeGrid(x + 1, y - 1)
+ neighborCount = neighborCount + currentGameOfLifeGrid(x - 1, y)
+ neighborCount = neighborCount + currentGameOfLifeGrid(x + 1, y)
+ neighborCount = neighborCount + currentGameOfLifeGrid(x - 1, y + 1)
+ neighborCount = neighborCount + currentGameOfLifeGrid(x, y + 1)
+ neighborCount = neighborCount + currentGameOfLifeGrid(x + 1, y + 1)
+
+ IF currentGameOfLifeGrid(x, y) = 1 THEN
+ IF (neighborCount > 3) OR (neighborCount < 2) THEN
+ nextGameOfLifeGrid(x, y) = 0
+ ELSE
+ nextGameOfLifeGrid(x, y) = 1
+ END IF
+ ELSE
+ IF neighborCount = 3 THEN
+ nextGameOfLifeGrid(x, y) = 1
+ ELSE
+ nextGameOfLifeGrid(x, y) = 0
+ END IF
+ END IF
+ NEXT x
+ NEXT y
+
+ FOR y = 1 TO 50
+ FOR x = 1 TO 50
+ currentGameOfLifeGrid(x, y) = nextGameOfLifeGrid(x, y)
+ NEXT x
+ NEXT y
+ END IF
+END SUB
+
+SUB InitializeEnvironment
+ ' This subroutine initializes the environment by creating a grid of points and lines.
+ ' It sets up the initial state of the points and lines arrays.
+
+ FOR z = -5 TO 5
+ FOR x = -5 TO 5
+ currentPointCount = currentPointCount + 1
+ pointXCoordinates(currentPointCount) = x
+ pointYCoordinates(currentPointCount) = 0
+ pointZCoordinates(currentPointCount) = z
+
+ IF x > -5 THEN
+ currentLineCount = currentLineCount + 1
+ lineVertex1Indices(currentLineCount) = currentPointCount
+ lineVertex2Indices(currentLineCount) = currentPointCount - 1
+ lineColorValues(currentLineCount) = 1
+ END IF
+
+ IF z > -5 THEN
+ currentLineCount = currentLineCount + 1
+ lineVertex1Indices(currentLineCount) = currentPointCount
+ lineVertex2Indices(currentLineCount) = currentPointCount - 10
+ lineColorValues(currentLineCount) = 1
+ END IF
+ NEXT x
+ NEXT z
+
+ totalPoints = currentPointCount
+ totalLines = currentLineCount
+END SUB
+
+SUB PlaceCube (xCoordinate, yCoordinate, zCoordinate)
+ ' This subroutine places a cube at the specified coordinates (xCoordinate, yCoordinate, zCoordinate).
+ ' It defines the vertices and edges of the cube and stores them in the respective arrays.
+
+ colorValue = 3
+
+ ' Define the edges of the cube
+ currentLineCount = currentLineCount + 1
+ lineVertex1Indices(currentLineCount) = currentPointCount + 1
+ lineVertex2Indices(currentLineCount) = currentPointCount + 2
+ lineColorValues(currentLineCount) = colorValue
+
+ currentLineCount = currentLineCount + 1
+ lineVertex1Indices(currentLineCount) = currentPointCount + 2
+ lineVertex2Indices(currentLineCount) = currentPointCount + 3
+ lineColorValues(currentLineCount) = colorValue
+
+ currentLineCount = currentLineCount + 1
+ lineVertex1Indices(currentLineCount) = currentPointCount + 3
+ lineVertex2Indices(currentLineCount) = currentPointCount + 4
+ lineColorValues(currentLineCount) = colorValue
+
+ currentLineCount = currentLineCount + 1
+ lineVertex1Indices(currentLineCount) = currentPointCount + 4
+ lineVertex2Indices(currentLineCount) = currentPointCount + 1
+ lineColorValues(currentLineCount) = colorValue
+
+ currentLineCount = currentLineCount + 1
+ lineVertex1Indices(currentLineCount) = currentPointCount + 5
+ lineVertex2Indices(currentLineCount) = currentPointCount + 6
+ lineColorValues(currentLineCount) = colorValue
+
+ currentLineCount = currentLineCount + 1
+ lineVertex1Indices(currentLineCount) = currentPointCount + 6
+ lineVertex2Indices(currentLineCount) = currentPointCount + 7
+ lineColorValues(currentLineCount) = colorValue
+
+ currentLineCount = currentLineCount + 1
+ lineVertex1Indices(currentLineCount) = currentPointCount + 7
+ lineVertex2Indices(currentLineCount) = currentPointCount + 8
+ lineColorValues(currentLineCount) = colorValue
+
+ currentLineCount = currentLineCount + 1
+ lineVertex1Indices(currentLineCount) = currentPointCount + 8
+ lineVertex2Indices(currentLineCount) = currentPointCount + 5
+ lineColorValues(currentLineCount) = colorValue
+
+ currentLineCount = currentLineCount + 1
+ lineVertex1Indices(currentLineCount) = currentPointCount + 1
+ lineVertex2Indices(currentLineCount) = currentPointCount + 5
+ lineColorValues(currentLineCount) = colorValue
+
+ currentLineCount = currentLineCount + 1
+ lineVertex1Indices(currentLineCount) = currentPointCount + 2
+ lineVertex2Indices(currentLineCount) = currentPointCount + 6
+ lineColorValues(currentLineCount) = colorValue
+
+ currentLineCount = currentLineCount + 1
+ lineVertex1Indices(currentLineCount) = currentPointCount + 3
+ lineVertex2Indices(currentLineCount) = currentPointCount + 7
+ lineColorValues(currentLineCount) = colorValue
+
+ currentLineCount = currentLineCount + 1
+ lineVertex1Indices(currentLineCount) = currentPointCount + 4
+ lineVertex2Indices(currentLineCount) = currentPointCount + 8
+ lineColorValues(currentLineCount) = colorValue
+
+ ' Define the vertices of the cube
+ currentPointCount = currentPointCount + 1
+ pointXCoordinates(currentPointCount) = xCoordinate - .5
+ pointYCoordinates(currentPointCount) = yCoordinate
+ pointZCoordinates(currentPointCount) = zCoordinate - .5
+
+ currentPointCount = currentPointCount + 1
+ pointXCoordinates(currentPointCount) = xCoordinate + .5
+ pointYCoordinates(currentPointCount) = yCoordinate
+ pointZCoordinates(currentPointCount) = zCoordinate - .5
+
+ currentPointCount = currentPointCount + 1
+ pointXCoordinates(currentPointCount) = xCoordinate + .5
+ pointYCoordinates(currentPointCount) = yCoordinate
+ pointZCoordinates(currentPointCount) = zCoordinate + .5
+
+ currentPointCount = currentPointCount + 1
+ pointXCoordinates(currentPointCount) = xCoordinate - .5
+ pointYCoordinates(currentPointCount) = yCoordinate
+ pointZCoordinates(currentPointCount) = zCoordinate + .5
+
+ currentPointCount = currentPointCount + 1
+ pointXCoordinates(currentPointCount) = xCoordinate - .5
+ pointYCoordinates(currentPointCount) = yCoordinate + 1
+ pointZCoordinates(currentPointCount) = zCoordinate - .5
+
+ currentPointCount = currentPointCount + 1
+ pointXCoordinates(currentPointCount) = xCoordinate + .5
+ pointYCoordinates(currentPointCount) = yCoordinate + 1
+ pointZCoordinates(currentPointCount) = zCoordinate - .5
+
+ currentPointCount = currentPointCount + 1
+ pointXCoordinates(currentPointCount) = xCoordinate + .5
+ pointYCoordinates(currentPointCount) = yCoordinate + 1
+ pointZCoordinates(currentPointCount) = zCoordinate + .5
+
+ currentPointCount = currentPointCount + 1
+ pointXCoordinates(currentPointCount) = xCoordinate - .5
+ pointYCoordinates(currentPointCount) = yCoordinate + 1
+ pointZCoordinates(currentPointCount) = zCoordinate + .5
+END SUB
+
+SUB DrawScene
+ ' This subroutine renders the scene by transforming the 3D coordinates of the points to 2D screen coordinates
+ ' and drawing the lines between the points. It uses trigonometric functions to rotate and project the 3D points onto the 2D screen.
+
+ sineAngle1 = SIN(rotationAngle1)
+ cosineAngle1 = COS(rotationAngle1)
+ sineAngle2 = SIN(rotationAngle2)
+ cosineAngle2 = COS(rotationAngle2)
+
+ FOR index = 1 TO currentPointCount
+ x = pointXCoordinates(index) + cameraPositionX
+ y = pointYCoordinates(index) - cameraPositionY
+ z = pointZCoordinates(index) + cameraPositionZ
+
+ transformedX = x * sineAngle1 - z * cosineAngle1
+ transformedZ = x * cosineAngle1 + z * sineAngle1
+ transformedY = y * sineAngle2 - transformedZ * cosineAngle2
+ transformedZ2 = y * cosineAngle2 + transformedZ * sineAngle2
+
+ IF transformedZ2 < .5 THEN
+ renderedPointXCoordinates(index) = -1
+ ELSE
+ renderedPointXCoordinates(index) = 320 + (transformedX / transformedZ2 * 400)
+ renderedPointYCoordinates(index) = 240 - (transformedY / transformedZ2 * 400)
+ END IF
+ NEXT index
+
+ FOR index = 1 TO currentLineCount
+ vertex1 = previousLineVertex1Indices(index)
+ vertex2 = previousLineVertex2Indices(index)
+
+ IF previousRenderedPointXCoordinates(vertex1) = -1 OR previousRenderedPointXCoordinates(vertex2) = -1 THEN
+ ELSE
+ LINE (previousRenderedPointXCoordinates(vertex1), previousRenderedPointYCoordinates(vertex1))-(previousRenderedPointXCoordinates(vertex2), previousRenderedPointYCoordinates(vertex2)), 0
+ END IF
+
+ vertex1 = lineVertex1Indices(index)
+ vertex2 = lineVertex2Indices(index)
+
+ IF renderedPointXCoordinates(vertex1) = -1 OR renderedPointXCoordinates(vertex2) = -1 THEN
+ ELSE
+ LINE (renderedPointXCoordinates(vertex1), renderedPointYCoordinates(vertex1))-(renderedPointXCoordinates(vertex2), renderedPointYCoordinates(vertex2)), lineColorValues(index)
+ END IF
+ NEXT index
+
+ IF currentLineCount < previousLineCount THEN
+ FOR index = currentLineCount + 1 TO previousLineCount
+ vertex1 = previousLineVertex1Indices(index)
+ vertex2 = previousLineVertex2Indices(index)
+
+ IF previousRenderedPointXCoordinates(vertex1) = -1 OR previousRenderedPointXCoordinates(vertex2) = -1 THEN
+ ELSE
+ LINE (previousRenderedPointXCoordinates(vertex1), previousRenderedPointYCoordinates(vertex1))-(previousRenderedPointXCoordinates(vertex2), previousRenderedPointYCoordinates(vertex2)), 0
+ END IF
+ NEXT index
+ END IF
+
+ FOR index = 1 TO currentPointCount
+ previousRenderedPointXCoordinates(index) = renderedPointXCoordinates(index)
+ previousRenderedPointYCoordinates(index) = renderedPointYCoordinates(index)
+ NEXT index
+
+ previousPointCount = currentPointCount
+
+ FOR index = 1 TO currentLineCount
+ previousLineVertex1Indices(index) = lineVertex1Indices(index)
+ previousLineVertex2Indices(index) = lineVertex2Indices(index)
+ NEXT index
+
+ previousLineCount = currentLineCount
+END SUB
+
+SUB InitializeGame
+ ' This subroutine initializes the game by setting up the screen, initializing the points and lines arrays,
+ ' and loading the initial state of the Game of Life grid from a file.
+
+ SCREEN 12
+ totalPoints = 0
+ totalLines = 0
+ currentPointCount = totalPoints
+ currentLineCount = totalLines
+ gridSize = 50
+
+ cameraPositionX = 4
+ cameraPositionY = 15
+ cameraPositionZ = 17
+ rotationAngle1 = ATN(1) / 2 - .29
+ rotationAngle2 = rotationAngle1 + 1
+
+ FOR index = 1 TO 1000
+ lineColorValues(index) = 4
+ NEXT index
+
+ FOR index = 1 TO 1000
+ previousLineVertex1Indices(index) = 1
+ previousLineVertex2Indices(index) = 1
+ NEXT index
+
+ OPEN "3dlife.dat" FOR INPUT AS #1
+ y = 20
+
+20
+ IF EOF(1) <> 0 THEN GOTO 30
+ x = 20
+ LINE INPUT #1, inputLine$
+
+ FOR characterIndex = 1 TO LEN(inputLine$)
+ currentChar$ = RIGHT$(LEFT$(inputLine$, characterIndex), 1)
+ IF currentChar$ = "#" THEN currentGameOfLifeGrid(x, y) = 1
+ x = x + 1
+ NEXT characterIndex
+
+ y = y + 1
+ GOTO 20
+
+30
+ CLOSE #1
+END SUB
--- /dev/null
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+........####......................................\r
+.......#....#.....................................\r
+........####......................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+................................#######...........\r
+...............................#.......#..........\r
+................................#######...........\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+........#####.....................................\r
+.......#.....#....................................\r
+........#####.....................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+................................######............\r
+...............................#......#...........\r
+................................######............\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
--- /dev/null
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+........................###.......................\r
+.....................#.......#....................\r
+....................#.........#...................\r
+........................###.......................\r
+.......................#...#......................\r
+...................#..#.....#..#..................\r
+...................#..#.....#..#..................\r
+...................#..#.....#..#..................\r
+.......................#...#......................\r
+........................###.......................\r
+....................#.........#...................\r
+.....................#.......#....................\r
+........................###.......................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
--- /dev/null
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+........................###.......................\r
+.....................#...#...#....................\r
+....................##...#...##...................\r
+......................#.###.#.....................\r
+.......................#...#......................\r
+...................#..#.....#..#..................\r
+...................####.....####..................\r
+...................#..#.....#..#..................\r
+.......................#...#......................\r
+......................#.###.#.....................\r
+....................##...#...##...................\r
+.....................#...#...#....................\r
+........................###.......................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
--- /dev/null
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+...............##.................................\r
+...............#..................................\r
+.................#................................\r
+.............#####................................\r
+.............#....................................\r
+...........##...##................................\r
+.......##.#....##.#.##............................\r
+........#.#....##.#.#.............................\r
+.......#..##....#.#..#............................\r
+........##..#.#....##.............................\r
+..........#.#######...............................\r
+..........#.......#...............................\r
+...........#######................................\r
+..................................................\r
+.............###..................................\r
+............#..#..................................\r
+............##..................##................\r
+...............................#..#.##............\r
+...............................#.##.#.#...........\r
+..............................##..#.#.#...........\r
+.............................#..#.#...#.##........\r
+.............................##.#.#...#..#........\r
+................................#.#.#..##.........\r
+................................#.#.##.#..........\r
+.................................##.#..#..........\r
+.....................................##...........\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
--- /dev/null
+..................................................\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+..................................................\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+..................................................\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+..................................................\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+..................................................\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+..................................................\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+..................................................\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+..................................................\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+..................................................\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+..................................................\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+..................................................\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+..................................................\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+..................................................\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##.##..\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+.##.##.##.##.##.##.##.##.##.##.##.##..............\r
+.##.##.##.##.##.##.##.##.##.##.##.##..............\r
+...........................................###....\r
+.##.##.##.##.##.##.##.##.##.##.##.##.......#......\r
+.##.##.##.##.##.##.##.##.##.##.##.##........#.....\r
+..................................................\r
+..................................................\r
--- /dev/null
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+........................#.........................\r
+.......................###........................\r
+.......................#.#........................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
--- /dev/null
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..............................#...................\r
+.............................###..................\r
+...............................#..................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
--- /dev/null
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+......###.....#...#...#...#...#...#...#...#.......\r
+......#.#.....#...#...#...#...#...#...#...#.......\r
+......###.....#...#...#...#...#...#...#...#.......\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+.............#..#..#..#..#..#..#..#..#............\r
+.............#..#..#..#..#..#..#..#..#............\r
+.............#..#..#..#..#..#..#..#..#............\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
--- /dev/null
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+.......###........................................\r
+.........#........................................\r
+........#.........................................\r
+..................................................\r
+........................................###.......\r
+........................................#.........\r
+.........................................#........\r
+..................................................\r
+..................................................\r
+..................................................\r
--- /dev/null
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................#.#.#.#.#.#.....................\r
+.................#.#.#.#.#.#.#....................\r
+..................#.#.#.#.#.#.....................\r
+.................#.#.#.#.#.#.#....................\r
+..................#.#.#.#.#.#.....................\r
+.................#.#.#.#.#.#.#....................\r
+..................#.#.#.#.#.#.....................\r
+.................#.#.#.#.#.#.#....................\r
+..................#.#.#.#.#.#.....................\r
+.................#.#.#.#.#.#.#....................\r
+..................#.#.#.#.#.#.....................\r
+.................#.#.#.#.#.#.#....................\r
+..................#.#.#.#.#.#.....................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
--- /dev/null
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+....................................##............\r
+..................................##..#...........\r
+............#####.................#..##...........\r
+..........#.......#................##.............\r
+.........#.........#..............................\r
+.............###..................................\r
+........#...#...#...#.............................\r
+........#..#.....#..#.............................\r
+........#..#.....#..#.............................\r
+........#..#.....#..#.............................\r
+........#...#...#...#.............................\r
+.............###..................................\r
+.........#.........#..............................\r
+..........#.......#...............................\r
+............#####.................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+...................................#####..........\r
+.................................##.....##........\r
+................................#.........#.......\r
+................................#...###...#.......\r
+...............................#...#...#...#......\r
+...............................#..#.....#..#......\r
+...............................#..#.....#..#......\r
+........#......................#..#.....#..#......\r
+........##.##..................#...#...#...#......\r
+............#...................#...###...#.......\r
+................................#.........#.......\r
+.................................##.....##........\r
+...................................#####..........\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
--- /dev/null
+' Conway's Game of Life.\r
+' It has world editor, and can save/load worlds.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2001, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+' Usage:\r
+'\r
+' Observation Mode\r
+' ----------------\r
+'\r
+' Purpose: Observation mode is the primary mode of the program where\r
+' you can observe the simulation of Conway's Game of Life. In this\r
+' mode, the grid evolves according to the rules of the Game of Life,\r
+' and you can control the simulation's progression, speed, and other\r
+' aspects.\r
+\r
+' Available Keys:\r
+'\r
+' x: Run the simulation for 10,000 cycles. This allows you to\r
+' observe the long-term behavior of the grid without manually\r
+' advancing each step.\r
+'\r
+' s: Run the simulation for a specified number of cycles. You will\r
+' be prompted to enter the number of cycles you want to advance.\r
+'\r
+' n: Run the simulation for 1 cycle. This allows you to step\r
+' through the simulation one generation at a time.\r
+'\r
+' z: Stop running the simulation. This halts the automatic\r
+' advancement of cycles, allowing you to observe the current state\r
+' of the grid.\r
+'\r
+' c: Clear all cells in the grid. This resets the grid to a blank\r
+' state, with all cells set to dead.\r
+'\r
+' w: Write the current state of the grid to a file. You will be\r
+' prompted to enter a filename. The grid state will be saved in a\r
+' format that can be loaded later.\r
+'\r
+' l: Load a grid state from a file. You will be prompted to enter\r
+' the filename of the saved grid state. The grid will be loaded\r
+' and displayed.\r
+'\r
+' e: Switch to edit mode. This allows you to manually edit the\r
+' grid, toggle cells on/off, and perform other editing functions.\r
+'\r
+' q: Quit the program. This exits the simulation and returns you\r
+' to the operating system.\r
+'\r
+'\r
+' Edit Mode\r
+' ---------\r
+'\r
+' Purpose: Edit mode allows you to manually edit the grid. You can\r
+' toggle individual cells on or off, move around the grid, and perform\r
+' other editing functions. This mode is useful for setting up initial\r
+' conditions, creating specific patterns, or making adjustments to the\r
+' grid.\r
+'\r
+'Available Keys:\r
+'\r
+' Cursor Keys (Arrow Keys): Move the cursor around the grid. The\r
+' cursor highlights the current cell, allowing you to toggle it on\r
+' or off.\r
+'\r
+' 4, 8, 6, 2: Move the cursor around the grid in large jumps. These\r
+' keys allow you to quickly navigate to different areas of the\r
+' grid.\r
+'\r
+' s: Switch to select mode. This allows you to select a region of\r
+' the grid for copying or cutting.\r
+'\r
+' v: Paste the contents of the copy buffer to the current cursor\r
+' position. This is useful for duplicating patterns or restoring\r
+' cut regions.\r
+'\r
+' SPACE: Toggle the current cell on or off. If the cell is alive,\r
+' it will be set to dead, and vice versa.\r
+'\r
+' ESC: Return to observing mode. This exits edit mode and returns\r
+' you to the primary observation mode, where you can observe the\r
+' simulation.\r
+'\r
+'\r
+' Select Mode\r
+' -----------\r
+'\r
+' Purpose: Select mode is a sub-mode of edit mode that allows you to\r
+' select a region of the grid. You can copy or cut the selected\r
+' region, which can then be pasted elsewhere in the grid.\r
+'\r
+' Available Keys:\r
+'\r
+' Cursor Keys (Arrow Keys): Adjust the selection rectangle. You\r
+' can resize the selection by moving the cursor.\r
+'\r
+' 4, 8, 6, 2: Adjust the selection rectangle in large jumps. These\r
+' keys allow you to quickly resize the selection.\r
+'\r
+' c: Copy the selected region to the copy buffer. The selected\r
+' region remains intact on the grid.\r
+'\r
+' x: Cut the selected region to the copy buffer. The selected\r
+' region is cleared from the grid and copied to the buffer.\r
+'\r
+' ESC: Return to edit mode. This exits select mode and returns you\r
+' to edit mode, where you can continue editing the grid.\r
+'\r
+\r
+DECLARE SUB LoadGridFromFile ()\r
+DECLARE SUB SaveGridToFile ()\r
+DECLARE SUB DisplayCopyBuffer ()\r
+DEFINT A-Z\r
+DECLARE SUB EnterSelectMode (gridX, gridY)\r
+DECLARE SUB ClearGridBuffers ()\r
+DECLARE SUB EnterEditMode ()\r
+DECLARE SUB DisplayGridState ()\r
+DECLARE SUB ClearScreenLine ()\r
+DECLARE SUB ProcessLifeGeneration ()\r
+DECLARE SUB InitializeSimulation ()\r
+\r
+DIM SHARED gridBufferA(1 TO 50, 1 TO 50)\r
+DIM SHARED gridBufferB(1 TO 50, 1 TO 50)\r
+DIM SHARED currentBuffer\r
+DIM SHARED generationCount\r
+DIM SHARED autoAdvanceCount\r
+DIM SHARED copyBuffer(0 TO 50, 0 TO 50)\r
+DIM SHARED copyBufferWidth, copyBufferHeight\r
+\r
+InitializeSimulation\r
+\r
+1\r
+ProcessLifeGeneration\r
+generationCount = generationCount + 1\r
+\r
+2\r
+LOCATE 1, 27\r
+PRINT "frame:" + STR$(generationCount) + " "\r
+LOCATE 2, 27\r
+PRINT "skip:" + STR$(autoAdvanceCount) + " "\r
+userInput$ = INKEY$\r
+\r
+IF userInput$ = "s" THEN\r
+ LOCATE 5, 27\r
+ INPUT "skip ", autoAdvanceCount\r
+ ClearScreenLine\r
+END IF\r
+\r
+IF userInput$ = "q" THEN\r
+ SYSTEM\r
+END IF\r
+\r
+IF userInput$ = "n" THEN GOTO 1\r
+IF userInput$ = "c" THEN ClearGridBuffers\r
+IF userInput$ = "e" THEN EnterEditMode\r
+IF userInput$ = "z" THEN autoAdvanceCount = 0\r
+IF userInput$ = "x" THEN autoAdvanceCount = 10000\r
+IF userInput$ = "w" THEN SaveGridToFile\r
+IF userInput$ = "l" THEN LoadGridFromFile\r
+\r
+IF autoAdvanceCount > 0 THEN\r
+ autoAdvanceCount = autoAdvanceCount - 1\r
+ GOTO 1\r
+END IF\r
+\r
+GOTO 2\r
+\r
+SUB ClearGridBuffers\r
+' Clears the grid buffers and resets the simulation counters.\r
+FOR gridY = 1 TO 50\r
+ FOR gridX = 1 TO 50\r
+ gridBufferA(gridX, gridY) = 0\r
+ gridBufferB(gridX, gridY) = 0\r
+ NEXT gridX\r
+NEXT gridY\r
+currentBuffer = 0\r
+generationCount = 0\r
+autoAdvanceCount = 0\r
+DisplayGridState\r
+END SUB\r
+\r
+SUB ClearScreenLine\r
+' Clears a specific line on the screen.\r
+LOCATE 5, 27\r
+PRINT " "\r
+END SUB\r
+\r
+SUB DisplayGridState\r
+' Displays the current state of the grid.\r
+FOR gridY = 1 TO 50\r
+ FOR gridX = 1 TO 50\r
+ IF currentBuffer = 0 THEN cellState = gridBufferA(gridX, gridY) ELSE cellState = gridBufferB(gridX, gridY)\r
+ IF cellState = 0 THEN cellState = 1 ELSE cellState = 10\r
+ LINE (gridX * 4, gridY * 4)-(gridX * 4 + 2, gridY * 4 + 2), cellState, BF\r
+ NEXT gridX\r
+NEXT gridY\r
+END SUB\r
+\r
+SUB EnterEditMode\r
+' Allows the user to edit the grid manually.\r
+cursorX = 25\r
+cursorY = 25\r
+\r
+3\r
+IF cursorX < 1 THEN cursorX = 1\r
+IF cursorY < 1 THEN cursorY = 1\r
+IF cursorX > 50 THEN cursorX = 50\r
+IF cursorY > 49 THEN cursorY = 49\r
+\r
+IF currentBuffer = 0 THEN cellState = gridBufferA(cursorX, cursorY) ELSE cellState = gridBufferB(cursorX, cursorY)\r
+IF cellState = 0 THEN cellState = 1 ELSE cellState = 10\r
+LINE (cursorX * 4, cursorY * 4)-(cursorX * 4 + 2, cursorY * 4 + 2), cellState, BF\r
+LINE (cursorX * 4 - 1, cursorY * 4 - 1)-(cursorX * 4 + 3, cursorY * 4 + 3), 14, B\r
+\r
+4\r
+userInput$ = INKEY$\r
+IF userInput$ = "" THEN GOTO 4\r
+LINE (cursorX * 4 - 1, cursorY * 4 - 1)-(cursorX * 4 + 3, cursorY * 4 + 3), 0, B\r
+\r
+' Handle cursor movement\r
+IF userInput$ = CHR$(0) + "M" THEN cursorX = cursorX + 1 ' Right arrow\r
+IF userInput$ = CHR$(0) + "K" THEN cursorX = cursorX - 1 ' Left arrow\r
+IF userInput$ = CHR$(0) + "P" THEN cursorY = cursorY + 1 ' Down arrow\r
+IF userInput$ = CHR$(0) + "H" THEN cursorY = cursorY - 1 ' Up arrow\r
+\r
+' Handle large jumps\r
+IF userInput$ = "6" THEN cursorX = cursorX + 8\r
+IF userInput$ = "4" THEN cursorX = cursorX - 8\r
+IF userInput$ = "2" THEN cursorY = cursorY + 8\r
+IF userInput$ = "8" THEN cursorY = cursorY - 8\r
+\r
+IF userInput$ = CHR$(27) THEN GOTO 5 ' ESC key to exit edit mode\r
+IF userInput$ = "s" THEN EnterSelectMode cursorX, cursorY\r
+\r
+' Paste from copy buffer\r
+IF userInput$ = "v" THEN\r
+ FOR pasteY = 0 TO copyBufferHeight\r
+ FOR pasteX = 0 TO copyBufferWidth\r
+ cellState = copyBuffer(pasteX, pasteY)\r
+ gridX = pasteX + cursorX\r
+ gridY = pasteY + cursorY\r
+ IF (gridX < 50) AND (gridY < 50) THEN\r
+ IF currentBuffer = 0 THEN gridBufferA(gridX, gridY) = cellState ELSE gridBufferB(gridX, gridY) = cellState\r
+ END IF\r
+ NEXT pasteX\r
+ NEXT pasteY\r
+ DisplayGridState\r
+END IF\r
+\r
+' Toggle cell on/off\r
+IF userInput$ = " " THEN\r
+ IF currentBuffer = 0 THEN cellState = gridBufferA(cursorX, cursorY) ELSE cellState = gridBufferB(cursorX, cursorY)\r
+ IF cellState = 1 THEN cellState = 0 ELSE cellState = 1\r
+ IF currentBuffer = 0 THEN gridBufferA(cursorX, cursorY) = cellState ELSE gridBufferB(cursorX, cursorY) = cellState\r
+END IF\r
+\r
+GOTO 3\r
+\r
+5\r
+END SUB\r
+\r
+SUB InitializeSimulation\r
+' Initializes the screen and buffers.\r
+SCREEN 13\r
+RANDOMIZE TIMER\r
+copyBufferWidth = 0\r
+copyBufferHeight = 0\r
+ClearGridBuffers\r
+END SUB\r
+\r
+SUB LoadGridFromFile\r
+' Loads a grid state from a file.\r
+ClearGridBuffers\r
+LOCATE 5, 27\r
+INPUT "file ", fileName$\r
+ClearScreenLine\r
+gridY = 1\r
+OPEN fileName$ FOR INPUT AS #1\r
+\r
+9\r
+IF EOF(1) <> 0 THEN GOTO 10\r
+LINE INPUT #1, fileLine$\r
+FOR gridX = 1 TO LEN(fileLine$)\r
+ fileChar$ = RIGHT$(LEFT$(fileLine$, gridX), 1)\r
+ IF fileChar$ = "#" THEN cellState = 1 ELSE cellState = 0\r
+ IF currentBuffer = 0 THEN gridBufferA(gridX, gridY) = cellState ELSE gridBufferB(gridX, gridY) = cellState\r
+NEXT gridX\r
+gridY = gridY + 1\r
+GOTO 9\r
+\r
+10\r
+CLOSE #1\r
+DisplayGridState\r
+END SUB\r
+\r
+SUB ProcessLifeGeneration\r
+' Processes one generation of Conway's Game of Life.\r
+IF currentBuffer = 0 THEN\r
+ FOR gridY = 2 TO 48\r
+ FOR gridX = 2 TO 49\r
+ IF gridBufferA(gridX - 1, gridY - 1) = 1 THEN neighborCount = 1 ELSE neighborCount = 0\r
+ IF gridBufferA(gridX, gridY - 1) = 1 THEN neighborCount = neighborCount + 1\r
+ IF gridBufferA(gridX + 1, gridY - 1) = 1 THEN neighborCount = neighborCount + 1\r
+ IF gridBufferA(gridX - 1, gridY) = 1 THEN neighborCount = neighborCount + 1\r
+ IF gridBufferA(gridX + 1, gridY) = 1 THEN neighborCount = neighborCount + 1\r
+ IF gridBufferA(gridX - 1, gridY + 1) = 1 THEN neighborCount = neighborCount + 1\r
+ IF gridBufferA(gridX, gridY + 1) = 1 THEN neighborCount = neighborCount + 1\r
+ IF gridBufferA(gridX + 1, gridY + 1) = 1 THEN neighborCount = neighborCount + 1\r
+\r
+ ' Apply Game of Life rules\r
+ IF gridBufferA(gridX, gridY) = 1 THEN\r
+ IF neighborCount = 2 OR neighborCount = 3 THEN gridBufferB(gridX, gridY) = 1 ELSE gridBufferB(gridX, gridY) = 0\r
+ ELSE\r
+ IF neighborCount = 3 THEN gridBufferB(gridX, gridY) = 1 ELSE gridBufferB(gridX, gridY) = 0\r
+ END IF\r
+ NEXT gridX\r
+ NEXT gridY\r
+ currentBuffer = 1\r
+ DisplayGridState\r
+ELSE ' Process second half of the grid\r
+ FOR gridY = 2 TO 48\r
+ FOR gridX = 2 TO 49\r
+ IF gridBufferB(gridX - 1, gridY - 1) = 1 THEN neighborCount = 1 ELSE neighborCount = 0\r
+ IF gridBufferB(gridX, gridY - 1) = 1 THEN neighborCount = neighborCount + 1\r
+ IF gridBufferB(gridX + 1, gridY - 1) = 1 THEN neighborCount = neighborCount + 1\r
+ IF gridBufferB(gridX - 1, gridY) = 1 THEN neighborCount = neighborCount + 1\r
+ IF gridBufferB(gridX + 1, gridY) = 1 THEN neighborCount = neighborCount + 1\r
+ IF gridBufferB(gridX - 1, gridY + 1) = 1 THEN neighborCount = neighborCount + 1\r
+ IF gridBufferB(gridX, gridY + 1) = 1 THEN neighborCount = neighborCount + 1\r
+ IF gridBufferB(gridX + 1, gridY + 1) = 1 THEN neighborCount = neighborCount + 1\r
+\r
+ ' Apply Game of Life rules\r
+ IF gridBufferB(gridX, gridY) = 1 THEN\r
+ IF neighborCount = 2 OR neighborCount = 3 THEN gridBufferA(gridX, gridY) = 1 ELSE gridBufferA(gridX, gridY) = 0\r
+ ELSE\r
+ IF neighborCount = 3 THEN gridBufferA(gridX, gridY) = 1 ELSE gridBufferA(gridX, gridY) = 0\r
+ END IF\r
+ NEXT gridX\r
+ NEXT gridY\r
+ currentBuffer = 0\r
+ DisplayGridState\r
+END IF\r
+END SUB\r
+\r
+SUB EnterSelectMode (gridX, gridY)\r
+' Allows the user to select a region of the grid.\r
+cursorX = gridX * 4 - 1 ' Calculate initial x position for selection rectangle\r
+cursorY = gridY * 4 - 1 ' Calculate initial y position for selection rectangle\r
+selectionEndX = gridX + 2 ' Initialize end x position for selection rectangle\r
+selectionEndY = gridY + 2 ' Initialize end y position for selection rectangle\r
+\r
+6\r
+selectionRightEdge = selectionEndX * 4 + 3 ' Calculate right edge of selection rectangle\r
+selectionBottomEdge = selectionEndY * 4 + 3 ' Calculate bottom edge of selection rectangle\r
+\r
+' Draw selection rectangle\r
+LINE (cursorX, cursorY)-(selectionRightEdge, selectionBottomEdge), 14, B\r
+\r
+8\r
+userInput$ = INKEY$\r
+IF userInput$ = "" THEN GOTO 8\r
+\r
+' Erase selection rectangle\r
+LINE (cursorX, cursorY)-(selectionRightEdge, selectionBottomEdge), 0, B\r
+\r
+' Handle cursor movement\r
+IF userInput$ = CHR$(0) + "M" THEN selectionEndX = selectionEndX + 1 ' Right arrow\r
+IF userInput$ = CHR$(0) + "K" THEN selectionEndX = selectionEndX - 1 ' Left arrow\r
+IF userInput$ = CHR$(0) + "P" THEN selectionEndY = selectionEndY + 1 ' Down arrow\r
+IF userInput$ = CHR$(0) + "H" THEN selectionEndY = selectionEndY - 1 ' Up arrow\r
+\r
+' Handle large jumps\r
+IF userInput$ = "6" THEN selectionEndX = selectionEndX + 8\r
+IF userInput$ = "4" THEN selectionEndX = selectionEndX - 8\r
+IF userInput$ = "2" THEN selectionEndY = selectionEndY + 8\r
+IF userInput$ = "8" THEN selectionEndY = selectionEndY - 8\r
+\r
+IF userInput$ = CHR$(27) THEN GOTO 7 ' ESC key to exit select mode\r
+\r
+IF userInput$ = "c" THEN\r
+ copyBufferWidth = selectionEndX - gridX ' Calculate size of selection rectangle\r
+ copyBufferHeight = selectionEndY - gridY\r
+ FOR sourceY = gridY TO selectionEndY\r
+ FOR sourceX = gridX TO selectionEndX\r
+ IF currentBuffer = 0 THEN cellState = gridBufferA(sourceX, sourceY) ELSE cellState = gridBufferB(sourceX, sourceY)\r
+ copyBuffer(sourceX - gridX, sourceY - gridY) = cellState ' Copy selection to buffer\r
+ NEXT sourceX\r
+ NEXT sourceY\r
+ DisplayCopyBuffer ' Display copied selection\r
+END IF\r
+\r
+IF userInput$ = "x" THEN\r
+ copyBufferWidth = selectionEndX - gridX ' Calculate size of selection rectangle\r
+ copyBufferHeight = selectionEndY - gridY\r
+ FOR sourceY = gridY TO selectionEndY\r
+ FOR sourceX = gridX TO selectionEndX\r
+ IF currentBuffer = 0 THEN cellState = gridBufferA(sourceX, sourceY): gridBufferA(sourceX, sourceY) = 0 ELSE cellState = gridBufferB(sourceX, sourceY): gridBufferB(sourceX, sourceY) = 0 ' Clear selection\r
+ copyBuffer(sourceX - gridX, sourceY - gridY) = cellState ' Copy cleared selection to buffer\r
+ NEXT sourceX\r
+ NEXT sourceY\r
+ DisplayCopyBuffer ' Display cut selection\r
+ DisplayGridState ' Update grid\r
+END IF\r
+\r
+GOTO 6\r
+\r
+7\r
+END SUB\r
+\r
+SUB DisplayCopyBuffer\r
+' Displays the contents of the copy buffer.\r
+cursorX = copyBufferWidth ' Calculate width of copied selection\r
+IF cursorX > 15 THEN cursorX = 15\r
+cursorY = copyBufferHeight ' Calculate height of copied selection\r
+IF cursorY > 15 THEN cursorY = 15\r
+\r
+' Draw copy buffer rectangle\r
+LINE (204, 99)-(319, 199), 0, BF\r
+LINE (204, 99)-(208 + 4 * cursorX, 103 + 4 * cursorY), 14, B\r
+\r
+FOR bufferY = 0 TO cursorY ' Iterate over copied selection\r
+ FOR bufferX = 0 TO cursorX\r
+ cellState = copyBuffer(bufferX, bufferY) ' Get color of cell in copy buffer\r
+ IF cellState = 0 THEN cellState = 1 ELSE cellState = 10 ' Convert to display color\r
+ LINE (bufferX * 4 + 205, bufferY * 4 + 100)-(bufferX * 4 + 2 + 205, bufferY * 4 + 2 + 100), cellState, BF ' Draw cell in copy buffer\r
+ NEXT bufferX\r
+NEXT bufferY\r
+END SUB\r
+\r
+SUB SaveGridToFile\r
+' Saves the current grid state to a file.\r
+LOCATE 5, 27\r
+INPUT "file ", fileName$\r
+ClearScreenLine\r
+OPEN fileName$ FOR OUTPUT AS #1\r
+\r
+FOR gridY = 1 TO 50\r
+ fileLine$ = "" ' Initialize line string\r
+ FOR gridX = 1 TO 50\r
+ IF currentBuffer = 0 THEN cellState = gridBufferA(gridX, gridY) ELSE cellState = gridBufferB(gridX, gridY)\r
+ IF cellState = 0 THEN fileLine$ = fileLine$ + "." ELSE fileLine$ = fileLine$ + "#" ' Convert to file format\r
+ NEXT gridX\r
+ PRINT #1, fileLine$ ' Write line to file\r
+NEXT gridY\r
+\r
+CLOSE #1\r
+END SUB\r
--- /dev/null
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+.................####.............####............\r
+.....................#...........#................\r
+...................####.........#.................\r
+.......................#...#...#..................\r
+........................#.#.#.#...................\r
+.................#########...#########............\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
+..................................................\r
--- /dev/null
+DECLARE SUB loadData ()\r
+DECLARE SUB predictNextDraw ()\r
+DECLARE SUB parseDrawNumbers (drawString$)\r
+DECLARE SUB displayDotGraph ()\r
+DECLARE SUB waitForUserInput ()\r
+DECLARE SUB displayLineGraph ()\r
+DECLARE SUB displayCombinatoricsGraph ()\r
+DECLARE SUB displayMenu ()\r
+DECLARE SUB startProgram ()\r
+' Program to analyze lottery winning numbers.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+'\r
+'\r
+' This program is designed to analyze lottery winning numbers. It\r
+' provides various graphical representations and statistical insights\r
+' based on historical lottery data. The program offers a simple\r
+' menu-driven interface to visualize and analyze the data.\r
+'\r
+' Features:\r
+'\r
+' Data Loading: The program loads historical lottery data from a\r
+' text file named "loto.txt". Each line in the file represents a\r
+' single draw, with numbers separated by spaces.\r
+'\r
+' Graphical Representations:\r
+'\r
+' Dot Graph: Displays the lottery numbers as dots on a graph,\r
+' with vertical lines representing each draw.\r
+'\r
+' Line Graph: Shows a dynamic line graph connecting\r
+' consecutive lottery numbers, providing a visual\r
+' representation of number trends over time.\r
+'\r
+' Combinatorics Graph: Graph is fitted to every possible\r
+' resolution. If there are patterns in data, they would likely\r
+' be visible it some resolutions.\r
+'\r
+' Statistical Analysis: Analyzes the last 10 draws to predict the\r
+' most frequent numbers and identifies numbers that have appeared\r
+' least recently.\r
+'\r
+'\r
+' Input File Format: The input file loto.txt should be formatted as\r
+' follows:\r
+'\r
+' Each line represents a single lottery draw.\r
+'\r
+' The first number on each line is the draw sequence number.\r
+'\r
+' The subsequent numbers are the lottery numbers drawn, separated\r
+' by spaces. 6 numbers per draw.\r
+'\r
+' Example:\r
+'\r
+' 1 7 15 16 23 34 38\r
+' 2 2 15 17 25 37 40\r
+' 3 9 16 18 23 25 45\r
+' ...\r
+' 500 4 15 16 24 30 46\r
+'\r
+'\r
+'\r
+' Changelog:\r
+' 2001, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+\r
+DEFINT A-Y\r
+\r
+DIM SHARED totalDraws, drawNumbers$(1 TO 50)\r
+DIM SHARED lotteryNumbers(1 TO 500, 1 TO 7)\r
+DIM SHARED currentDraw\r
+\r
+startProgram\r
+loadData\r
+\r
+displayMenu\r
+\r
+SUB displayCombinatoricsGraph\r
+ CLS\r
+ PAINT (1, 1), 3\r
+ DIM buffer(1 TO 48)\r
+ DIM buffer2(1 TO 20000)\r
+\r
+ totalNumbers = 0\r
+\r
+ ' Prepare data for drawing\r
+ FOR drawIndex = 1 TO currentDraw\r
+ FOR number = 1 TO 48\r
+ buffer(number) = 0\r
+ NEXT number\r
+\r
+ FOR numberPosition = 2 TO 7\r
+ buffer(lotteryNumbers(drawIndex, numberPosition)) = 10\r
+ NEXT numberPosition\r
+\r
+ FOR number = 1 TO 48\r
+ totalNumbers = totalNumbers + 1\r
+ buffer2(totalNumbers) = buffer(number)\r
+ NEXT number\r
+ NEXT drawIndex\r
+\r
+ ' Draw the graph\r
+ FOR yAxisValue = 2 TO 400\r
+ xAxisValue = 0\r
+ FOR xPosition = 1 TO 639\r
+ FOR yPosition = 1 TO yAxisValue\r
+ xAxisValue = xAxisValue + 1\r
+ IF xAxisValue > totalNumbers THEN GOTO skipDrawing\r
+ PSET (xPosition, yPosition), buffer2(xAxisValue)\r
+ NEXT yPosition\r
+ NEXT xPosition\r
+skipDrawing:\r
+\r
+ LINE (xPosition + 1, 1)-(xPosition + 1, yAxisValue), 14\r
+ LINE (xPosition + 1, yPosition)-(xPosition + 4, yPosition), 12\r
+\r
+ IF INKEY$ <> "" THEN GOTO 1\r
+ NEXT yAxisValue\r
+\r
+waitForUserInput\r
+1\r
+END SUB\r
+\r
+SUB displayDotGraph\r
+ CLS\r
+ LINE (0, 0)-(600, 0), 1\r
+ LINE (0, 49)-(600, 49), 1\r
+ LINE (0, 50)-(600, 50), 1\r
+ LINE (0, 48 * 6 + 51)-(600, 48 * 6 + 51), 1\r
+\r
+ ' Draw vertical lines for each draw and plot numbers\r
+ FOR drawIndex = 1 TO currentDraw\r
+ totalNumbers = 0\r
+ FOR numberPosition = 2 TO 7\r
+ totalNumbers = totalNumbers + lotteryNumbers(drawIndex, numberPosition)\r
+ PSET (drawIndex, lotteryNumbers(drawIndex, numberPosition)), 15\r
+ NEXT numberPosition\r
+ LINE (drawIndex, totalNumbers + 50)-(drawIndex, 24 * 6 + 50), 10\r
+ NEXT drawIndex\r
+\r
+ waitForUserInput\r
+END SUB\r
+\r
+SUB displayLineGraph\r
+ CLS\r
+ DIM buffer(1 TO 20000)\r
+\r
+ ' Draw lines connecting consecutive lottery numbers\r
+ FOR x = 1 TO currentDraw - 1\r
+ FOR numberPosition = 2 TO 7\r
+ LINE (600, lotteryNumbers(x, numberPosition))-(610, lotteryNumbers(x + 1, numberPosition)), 3\r
+ NEXT numberPosition\r
+ LINE (600, 1)-(600, 48), 1\r
+ SOUND 0, 2\r
+\r
+ ' Scroll the screen to the left\r
+ GET (10, 1)-(610, 50), buffer(1)\r
+ PUT (1, 1), buffer(1), PSET\r
+ LINE (601, 1)-(610, 50), 0, BF\r
+\r
+ IF INKEY$ <> "" GOTO 5\r
+ NEXT x\r
+\r
+ waitForUserInput\r
+5\r
+END SUB\r
+\r
+SUB displayMenu\r
+menuLoop:\r
+ CLS\r
+\r
+7\r
+ LOCATE 1, 1\r
+\r
+ PRINT " Lottery statistics analysis"\r
+\r
+ PRINT "1 - Dot graph"\r
+ PRINT "2 - Line graph"\r
+ PRINT "3 - Combinatorics"\r
+ PRINT "4 - Statistics"\r
+ PRINT "5 - Exit program"\r
+\r
+ userInput$ = INPUT$(1)\r
+\r
+ IF userInput$ = "1" THEN displayDotGraph\r
+ IF userInput$ = "2" THEN displayLineGraph\r
+ IF userInput$ = "3" THEN displayCombinatoricsGraph\r
+ IF userInput$ = "4" THEN predictNextDraw: GOTO 7\r
+ IF userInput$ = "5" THEN SYSTEM\r
+\r
+ GOTO menuLoop\r
+\r
+END SUB\r
+\r
+SUB loadData\r
+ PRINT "One moment..."\r
+\r
+ currentDraw = 0\r
+ OPEN "loto.txt" FOR INPUT AS #1\r
+\r
+loadNextLine:\r
+ IF EOF(1) <> 0 THEN GOTO endOfFile\r
+\r
+ LINE INPUT #1, drawString$\r
+ parseDrawNumbers drawString$\r
+\r
+ currentDraw = currentDraw + 1\r
+\r
+ ' Parse and store lottery numbers\r
+ FOR numberPosition = 1 TO 7\r
+ lotteryNumbers(currentDraw, numberPosition) = VAL(drawNumbers$(numberPosition))\r
+ NEXT numberPosition\r
+\r
+ GOTO loadNextLine\r
+\r
+endOfFile:\r
+ CLOSE #1\r
+\r
+ CLS\r
+END SUB\r
+\r
+SUB parseDrawNumbers (drawString$)\r
+ totalDraws = 0\r
+\r
+ numberIndex = 1\r
+ FOR charPosition = 1 TO LEN(drawString$)\r
+ currentChar$ = RIGHT$(LEFT$(drawString$, charPosition), 1)\r
+ IF currentChar$ = " " THEN\r
+ numberIndex = 1\r
+ ELSE\r
+ IF numberIndex = 1 THEN\r
+ totalDraws = totalDraws + 1\r
+ drawNumbers$(totalDraws) = ""\r
+ numberIndex = 0\r
+ END IF\r
+ drawNumbers$(totalDraws) = drawNumbers$(totalDraws) + currentChar$\r
+ END IF\r
+ NEXT charPosition\r
+\r
+END SUB\r
+\r
+SUB predictNextDraw\r
+ DIM buffer(1 TO 48)\r
+ PRINT "During the last 10 draws:"\r
+\r
+ ' Count occurrences of each number in the last 10 draws\r
+ FOR drawIndex = currentDraw - 10 TO currentDraw\r
+ FOR numberPosition = 2 TO 7\r
+ buffer(lotteryNumbers(drawIndex, numberPosition)) = buffer(lotteryNumbers(drawIndex, numberPosition)) + 1\r
+ NEXT numberPosition\r
+ NEXT drawIndex\r
+\r
+ ' Print the most frequent numbers\r
+ FOR position = 1 TO 6\r
+ maxCount = 0\r
+ FOR number = 1 TO 48\r
+ IF buffer(number) > maxCount THEN\r
+ maxCount = buffer(number)\r
+ mostFrequentNumber = number\r
+ END IF\r
+ NEXT number\r
+ PRINT mostFrequentNumber; " appeared: "; maxCount; " times"\r
+ buffer(mostFrequentNumber) = 0\r
+ NEXT position\r
+\r
+ PRINT "--------------------------------------"\r
+\r
+ ' Find when each number last appeared\r
+ FOR drawIndex = 1 TO currentDraw\r
+ FOR numberPosition = 2 TO 7\r
+ buffer(lotteryNumbers(drawIndex, numberPosition)) = drawIndex\r
+ NEXT numberPosition\r
+ NEXT drawIndex\r
+\r
+ FOR position = 1 TO 6\r
+ minAppearances = 30000\r
+ FOR number = 1 TO 48\r
+ IF buffer(number) < minAppearances THEN\r
+ minAppearances = buffer(number)\r
+ leastRecentNumber = number\r
+ END IF\r
+ NEXT number\r
+ PRINT leastRecentNumber; " appeared last time: "; currentDraw - minAppearances; " draws ago"\r
+ buffer(leastRecentNumber) = 30000\r
+ NEXT position\r
+\r
+END SUB\r
+\r
+SUB startProgram\r
+ SCREEN 12\r
+\r
+END SUB\r
+\r
+SUB waitForUserInput\r
+ userInput$ = INPUT$(1)\r
+\r
+END SUB\r
--- /dev/null
+1 2 10 13 25 32 48\r
+2 1 3 15 27 33 40\r
+3 9 16 18 23 25 45\r
+4 2 3 15 21 27 45\r
+5 3 5 8 13 29 39\r
+6 5 11 20 22 27 41\r
+7 6 9 12 13 39 45\r
+8 3 18 21 28 37 38\r
+9 5 13 16 36 37 39\r
+10 4 15 16 24 30 46\r
+11 1 7 10 25 32 38\r
+12 2 15 17 25 37 40\r
+13 9 16 18 23 25 45\r
+14 2 3 15 21 27 45\r
+15 3 5 8 13 29 39\r
+16 5 11 20 22 27 41\r
+17 6 9 12 13 39 45\r
+18 3 18 21 28 37 38\r
+19 5 13 16 36 37 39\r
+20 4 15 16 24 30 46\r
+21 1 7 10 25 32 38\r
+22 2 15 17 25 37 40\r
+23 9 16 18 23 25 45\r
+24 2 3 15 21 27 45\r
+25 3 5 8 13 29 39\r
+26 5 11 20 22 27 41\r
+27 6 9 12 13 39 45\r
+28 3 18 21 28 37 38\r
+29 5 13 16 36 37 39\r
+30 4 15 16 24 30 46\r
+31 1 7 10 25 32 38\r
+32 2 15 17 25 37 40\r
+33 9 16 18 23 25 45\r
+34 2 3 15 21 27 45\r
+35 3 5 8 13 29 39\r
+36 5 11 20 22 27 41\r
+37 6 9 12 13 39 45\r
+38 3 18 21 28 37 38\r
+39 5 13 16 36 37 39\r
+40 4 15 16 24 30 46\r
+41 1 7 10 25 32 38\r
+42 2 15 17 25 37 40\r
+43 9 16 18 23 25 45\r
+44 2 3 15 21 27 45\r
+45 3 5 8 13 29 39\r
+46 5 11 20 22 27 41\r
+47 6 9 12 13 39 45\r
+48 3 18 21 28 37 38\r
+49 5 13 16 36 37 39\r
+50 4 15 16 24 30 46\r
+51 1 7 10 25 32 38\r
+52 2 15 17 25 37 40\r
+53 9 16 18 23 25 45\r
+54 2 3 15 21 27 45\r
+55 3 5 8 13 29 39\r
+56 5 11 20 22 27 41\r
+57 6 9 12 13 39 45\r
+58 3 18 21 28 37 38\r
+59 5 13 16 36 37 39\r
+60 4 15 16 24 30 46\r
+61 1 7 10 25 32 38\r
+62 2 15 17 25 37 40\r
+63 9 16 18 23 25 45\r
+64 2 3 15 21 27 45\r
+65 3 5 8 13 29 39\r
+66 5 11 20 22 27 41\r
+67 6 9 12 13 39 45\r
+68 3 18 21 28 37 38\r
+69 5 13 16 36 37 39\r
+70 4 15 16 24 30 46\r
+71 1 7 10 25 32 38\r
+72 2 15 17 25 37 40\r
+73 9 16 18 23 25 45\r
+74 2 3 15 21 27 45\r
+75 3 5 8 13 29 39\r
+76 5 11 20 22 27 41\r
+77 6 9 12 13 39 45\r
+78 3 18 21 28 37 38\r
+79 5 13 16 36 37 39\r
+80 4 15 16 24 30 46\r
+81 1 7 10 25 32 38\r
+82 2 15 17 25 37 40\r
+83 9 16 18 23 25 45\r
+84 2 3 15 21 27 45\r
+85 3 5 8 13 29 39\r
+86 5 11 20 22 27 41\r
+87 6 9 12 13 39 45\r
+88 3 18 21 28 37 38\r
+89 5 13 16 36 37 39\r
+90 4 15 16 24 30 46\r
+91 1 7 10 25 32 38\r
+92 2 15 17 25 37 40\r
+93 9 16 18 23 25 45\r
+94 2 3 15 21 27 45\r
+95 3 5 8 13 29 39\r
+96 5 11 20 22 27 41\r
+97 6 9 12 13 39 45\r
+98 3 18 21 28 37 38\r
+99 5 13 16 36 37 39\r
+100 4 15 16 24 30 46\r
+101 1 7 10 25 32 38\r
+102 2 15 17 25 37 40\r
+103 9 16 18 23 25 45\r
+104 2 3 15 21 27 45\r
+105 3 5 8 13 29 39\r
+106 5 11 20 22 27 41\r
+107 6 9 12 13 39 45\r
+108 3 18 21 28 37 38\r
+109 5 13 16 36 37 39\r
+110 4 15 16 24 30 46\r
+111 1 7 10 25 32 38\r
+112 2 15 17 25 37 40\r
+113 9 16 18 23 25 45\r
+114 2 3 15 21 27 45\r
+115 3 5 8 13 29 39\r
+116 5 11 20 22 27 41\r
+117 6 9 12 13 39 45\r
+118 3 18 21 28 37 38\r
+119 5 13 16 36 37 39\r
+120 4 15 16 24 30 46\r
+121 1 7 10 25 32 38\r
+122 2 15 17 25 37 40\r
+123 9 16 18 23 25 45\r
+124 2 3 15 21 27 45\r
+125 3 5 8 13 29 39\r
+126 5 11 20 22 27 41\r
+127 6 9 12 13 39 45\r
+128 3 18 21 28 37 38\r
+129 5 13 16 36 37 39\r
+130 4 15 16 24 30 46\r
+131 1 7 10 25 32 38\r
+132 2 15 17 25 37 40\r
+133 9 16 18 23 25 45\r
+134 2 3 15 21 27 45\r
+135 3 5 8 13 29 39\r
+136 5 11 20 22 27 41\r
+137 6 9 12 13 39 45\r
+138 3 18 21 28 37 38\r
+139 5 13 16 36 37 39\r
+140 4 15 16 24 30 46\r
+141 1 7 10 25 32 38\r
+142 2 15 17 25 37 40\r
+143 9 16 18 23 25 45\r
+144 2 3 15 21 27 45\r
+145 3 5 8 13 29 39\r
+146 5 11 20 22 27 41\r
+147 6 9 12 13 39 45\r
+148 3 18 21 28 37 38\r
+149 5 13 16 36 37 39\r
+150 4 15 16 24 30 46\r
+151 1 7 10 25 32 38\r
+152 2 15 17 25 37 40\r
+153 9 16 18 23 25 45\r
+154 2 3 15 21 27 45\r
+155 3 5 8 13 29 39\r
+156 5 11 20 22 27 41\r
+157 6 9 12 13 39 45\r
+158 3 18 21 28 37 38\r
+159 5 13 16 36 37 39\r
+160 4 15 16 24 30 46\r
+161 1 7 10 25 32 38\r
+162 2 15 17 25 37 40\r
+163 9 16 18 23 25 45\r
+164 2 3 15 21 27 45\r
+165 3 5 8 13 29 39\r
+166 5 11 20 22 27 41\r
+167 6 9 12 13 39 45\r
+168 3 18 21 28 37 38\r
+169 5 13 16 36 37 39\r
+170 4 15 16 24 30 46\r
+171 1 7 10 25 32 38\r
+172 2 15 17 25 37 40\r
+173 9 16 18 23 25 45\r
+174 2 3 15 21 27 45\r
+175 3 5 8 13 29 39\r
+176 5 11 20 22 27 41\r
+177 6 9 12 13 39 45\r
+178 3 18 21 28 37 38\r
+179 5 13 16 36 37 39\r
+180 4 15 16 24 30 46\r
+181 1 7 10 25 32 38\r
+182 2 15 17 25 37 40\r
+183 9 16 18 23 25 45\r
+184 2 3 15 21 27 45\r
+185 3 5 8 13 29 39\r
+186 5 11 20 22 27 41\r
+187 6 9 12 13 39 45\r
+188 3 18 21 28 37 38\r
+189 5 13 16 36 37 39\r
+190 4 15 16 24 30 46\r
+191 1 7 10 25 32 38\r
+192 2 15 17 25 37 40\r
+193 9 16 18 23 25 45\r
+194 2 3 15 21 27 45\r
+195 3 5 8 13 29 39\r
+196 5 11 20 22 27 41\r
+197 6 9 12 13 39 45\r
+198 3 18 21 28 37 38\r
+199 5 13 16 36 37 39\r
+200 4 15 16 24 30 46\r
+201 1 7 10 25 32 38\r
+202 2 15 17 25 37 40\r
+203 9 16 18 23 25 45\r
+204 2 3 15 21 27 45\r
+205 3 5 8 13 29 39\r
+206 5 11 20 22 27 41\r
+207 6 9 12 13 39 45\r
+208 3 18 21 28 37 38\r
+209 5 13 16 36 37 39\r
+210 4 15 16 24 30 46\r
+211 1 7 10 25 32 38\r
+212 2 15 17 25 37 40\r
+213 9 16 18 23 25 45\r
+214 2 3 15 21 27 45\r
+215 3 5 8 13 29 39\r
+216 5 11 20 22 27 41\r
+217 6 9 12 13 39 45\r
+218 3 18 21 28 37 38\r
+219 5 13 16 36 37 39\r
+220 4 15 16 24 30 46\r
+221 1 7 10 25 32 38\r
+222 2 15 17 25 37 40\r
+223 9 16 18 23 25 45\r
+224 2 3 15 21 27 45\r
+225 3 5 8 13 29 39\r
+226 5 11 20 22 27 41\r
+227 6 9 12 13 39 45\r
+228 3 18 21 28 37 38\r
+229 5 13 16 36 37 39\r
+230 4 15 16 24 30 46\r
+231 1 7 10 25 32 38\r
+232 2 15 17 25 37 40\r
+233 9 16 18 23 25 45\r
+234 2 3 15 21 27 45\r
+235 3 5 8 13 29 39\r
+236 5 11 20 22 27 41\r
+237 6 9 12 13 39 45\r
+238 3 18 21 28 37 38\r
+239 5 13 16 36 37 39\r
+240 4 15 16 24 30 46\r
+241 1 7 10 25 32 38\r
+242 2 15 17 25 37 40\r
+243 9 16 18 23 25 45\r
+244 2 3 15 21 27 45\r
+245 3 5 8 13 29 39\r
+246 5 11 20 22 27 41\r
+247 6 9 12 13 39 45\r
+248 3 18 21 28 37 38\r
+249 5 13 16 36 37 39\r
+250 4 15 16 24 30 46\r
+251 1 7 10 25 32 38\r
+252 2 15 17 25 37 40\r
+253 9 16 18 23 25 45\r
+254 2 3 15 21 27 45\r
+255 3 5 8 13 29 39\r
+256 5 11 20 22 27 41\r
+257 6 9 12 13 39 45\r
+258 3 18 21 28 37 38\r
+259 5 13 16 36 37 39\r
+260 4 15 16 24 30 46\r
+261 1 7 10 25 32 38\r
+262 2 15 17 25 37 40\r
+263 9 16 18 23 25 45\r
+264 2 3 15 21 27 45\r
+265 3 5 8 13 29 39\r
+266 5 11 20 22 27 41\r
+267 6 9 12 13 39 45\r
+268 3 18 21 28 37 38\r
+269 5 13 16 36 37 39\r
+270 4 15 16 24 30 46\r
+271 1 7 10 25 32 38\r
+272 2 15 17 25 37 40\r
+273 9 16 18 23 25 45\r
+274 2 3 15 21 27 45\r
+275 3 5 8 13 29 39\r
+276 5 11 20 22 27 41\r
+277 6 9 12 13 39 45\r
+278 3 18 21 28 37 38\r
+279 5 13 16 36 37 39\r
+280 4 15 16 24 30 46\r
+281 1 7 10 25 32 38\r
--- /dev/null
+' Program to teach and test multiplication.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+\r
+' Changelog:\r
+' 2000, Initial version\r
+' 2024, Improved program readability\r
+\r
+DECLARE SUB showGreetingAndSetup ()\r
+DEFINT A-Y\r
+DECLARE SUB getUserInputAndDisplayQuestions ()\r
+DIM SHARED userName$\r
+DIM SHARED numberOfQuestions\r
+\r
+showGreetingAndSetup\r
+getUserInputAndDisplayQuestions\r
+\r
+SUB getUserInputAndDisplayQuestions\r
+RANDOMIZE TIMER\r
+\r
+numberOfAttempts = 0\r
+incorrectAnswers = 0\r
+correctAnswers = 0\r
+PRINT "How much is:"\r
+4\r
+numberOfAttempts = numberOfAttempts + 1\r
+IF numberOfAttempts > numberOfQuestions THEN GOTO 6\r
+\r
+' Generate random numbers for multiplication\r
+multiplier1 = RND * 9\r
+multiplier2 = RND * 9\r
+question$ = STR$(multiplier1) + " X" + STR$(multiplier2)\r
+PRINT " "\r
+PRINT question$\r
+\r
+5\r
+INPUT userAnswer$\r
+\r
+' Handle invalid inputs\r
+IF LEFT$(userAnswer$, 6) = "don't know" THEN\r
+ PRINT "Try at least !"\r
+ GOTO 5\r
+END IF\r
+\r
+' Convert input to number\r
+IF userAnswer$ = "0" THEN\r
+ userAnswer = 0\r
+ GOTO 10\r
+ELSE\r
+ userAnswer = VAL(userAnswer$)\r
+ IF userAnswer = 0 THEN userAnswer = -1\r
+END IF\r
+\r
+10\r
+\r
+' Check if the answer is correct\r
+IF multiplier1 * multiplier2 = userAnswer THEN\r
+ correctAnswers = correctAnswers + 1\r
+ PRINT "Correct !"\r
+ELSE\r
+ PRINT "Wrong !"\r
+ PRINT "Correct answer is ", multiplier1 * multiplier2\r
+ incorrectAnswers = incorrectAnswers + 1\r
+END IF\r
+\r
+GOTO 4\r
+\r
+6\r
+PRINT "-------------------------"\r
+COLOR 2\r
+PRINT "Incorrect answers: ", incorrectAnswers\r
+\r
+' Calculate the score\r
+scorePercentage = correctAnswers / numberOfQuestions * 100\r
+\r
+grade = 1\r
+\r
+' Determine the grade\r
+IF scorePercentage >= 25 THEN grade = 2\r
+IF scorePercentage >= 50 THEN grade = 3\r
+IF scorePercentage >= 70 THEN grade = 4\r
+IF scorePercentage >= 90 THEN grade = 5\r
+\r
+COLOR 14\r
+PRINT "Your grade is: "; grade\r
+END SUB\r
+\r
+DEFINT Z\r
+SUB showGreetingAndSetup\r
+\r
+' Clear the screen and set up graphics mode\r
+CLS\r
+SCREEN 13\r
+LOCATE 2, 1\r
+PRINT " Math teaching program"\r
+\r
+' Draw a simple background pattern\r
+FOR y = 3 TO 20\r
+ FOR x = 0 TO 320\r
+ IF POINT(x, y) > 0 THEN\r
+ colorIndex = y + 56\r
+ ELSE\r
+ colorIndex = 31 - y / 2\r
+ END IF\r
+ PSET (x, y), colorIndex\r
+ NEXT x\r
+NEXT y\r
+\r
+' Get user input for their name\r
+LOCATE 5, 1\r
+COLOR 7\r
+INPUT "Enter your name ", userName$\r
+LOCATE 5, 1\r
+COLOR 8\r
+PRINT "Enter your name " + userName$\r
+\r
+' Greet the user\r
+LOCATE 6, 1\r
+COLOR 7\r
+PRINT "Hello " + userName$ + "!"\r
+\r
+8\r
+LOCATE 7, 1\r
+COLOR 8\r
+PRINT SPACE$(35)\r
+COLOR 7\r
+LOCATE 7, 1\r
+INPUT "How many questions would you like ? ", numberOfQuestions\r
+LOCATE 7, 1\r
+COLOR 8\r
+PRINT SPACE$(35)\r
+LOCATE 7, 1\r
+COLOR 8\r
+PRINT "How many questions would you like? " + STR$(numberOfQuestions)\r
+\r
+' Validate the number of questions\r
+IF numberOfQuestions < 5 THEN\r
+ PRINT "That would be too easy !"\r
+ GOTO 8\r
+END IF\r
+\r
+IF numberOfQuestions > 30 THEN\r
+ PRINT "That would be too hard !"\r
+ GOTO 8\r
+END IF\r
+\r
+PRINT "I will ask you some math questions."\r
+PRINT "Press any button when you are ready..."\r
+\r
+' Initialize color palette\r
+FOR a = 200 TO 230\r
+ OUT &H3C8, a\r
+ OUT &H3C9, a - 200\r
+ OUT &H3C9, 0\r
+ OUT &H3C9, 0\r
+NEXT\r
+\r
+' Initialize color array\r
+DIM colorArray(1 TO 32)\r
+\r
+currentColorIndex = 4\r
+colorChangeDirection = 1\r
+\r
+2\r
+FOR a = 0 TO 31\r
+ ' Draw vertical lines with decreasing brightness\r
+ LINE (a * 10, 170)-(a * 10 + 10, 190), 200 + colorArray(a + 1), BF\r
+ colorArray(a + 1) = colorArray(a + 1) - 1\r
+ IF colorArray(a + 1) < 0 THEN colorArray(a + 1) = 0\r
+NEXT a\r
+\r
+' Change the color index\r
+currentColorIndex = currentColorIndex + colorChangeDirection\r
+IF currentColorIndex > 30 OR currentColorIndex < 3 THEN colorChangeDirection = -colorChangeDirection\r
+colorArray(currentColorIndex) = 30\r
+SOUND 0, 1\r
+\r
+' Check if user is ready\r
+IF INKEY$ <> "" THEN GOTO 3\r
+GOTO 2\r
+\r
+3\r
+CLS\r
+END SUB\r
+\r
--- /dev/null
+' 2D Graph Plotter.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Created initial version\r
+' 2024.08, Updated for better readability and maintainability\r
+\r
+\r
+DECLARE SUB InitializeGraphicsEnvironment ()\r
+DECLARE SUB PlotPoint (x1 AS SINGLE, y1 AS SINGLE, x2 AS SINGLE, y2 AS SINGLE, colorCode AS INTEGER)\r
+\r
+' Scaling factor for the graph\r
+DIM SHARED scaleFactor AS INTEGER\r
+scaleFactor = 100\r
+\r
+' Initialize the graphics environment\r
+InitializeGraphicsEnvironment\r
+\r
+' Set the origin of the graph\r
+DIM originX AS SINGLE\r
+DIM originY AS SINGLE\r
+originX = -320 / scaleFactor\r
+originY = 0\r
+\r
+' Loop to plot each point on the graph based on the formula\r
+DIM currentX AS SINGLE\r
+DIM currentY AS SINGLE\r
+FOR currentX = -320 / scaleFactor TO 320 / scaleFactor STEP 1 / scaleFactor\r
+ ' Function to calculate y-value based on x-value\r
+ currentY = 1 - (COS(currentX * 2)) + (SIN(currentX * 2)) ' User-defined formula\r
+\r
+ ' Plot the point and update the origin for the next segment\r
+ PlotPoint currentX, currentY, originX, originY, 14\r
+ originX = currentX\r
+ originY = currentY\r
+NEXT currentX\r
+\r
+' Subroutine to initialize the graphics window and grid\r
+SUB InitializeGraphicsEnvironment\r
+ SCREEN 12\r
+\r
+ ' Draw horizontal grid lines\r
+ DIM horizontalGridStep AS SINGLE\r
+ FOR horizontalGridStep = -320 TO 320\r
+ IF horizontalGridStep / scaleFactor = horizontalGridStep \ scaleFactor THEN\r
+ LINE (horizontalGridStep + 320, 0)-(horizontalGridStep + 320, 479), 1\r
+ END IF\r
+ NEXT horizontalGridStep\r
+\r
+ ' Draw vertical grid lines\r
+ DIM verticalGridStep AS SINGLE\r
+ FOR verticalGridStep = -240 TO 240\r
+ IF verticalGridStep / scaleFactor = verticalGridStep \ scaleFactor THEN\r
+ LINE (0, verticalGridStep + 240)-(639, verticalGridStep + 240), 1\r
+ END IF\r
+ NEXT verticalGridStep\r
+\r
+ ' Draw the central axis lines\r
+ LINE (0, 240)-(639, 240), 3\r
+ LINE (320, 0)-(320, 479), 3\r
+END SUB\r
+\r
+' Subroutine to plot a point on the graph\r
+SUB PlotPoint (x AS SINGLE, y AS SINGLE, x1 AS SINGLE, y1 AS SINGLE, colorCode AS INTEGER)\r
+ ' Convert graph coordinates to screen pixel coordinates\r
+ DIM screenX1 AS INTEGER\r
+ DIM screenY1 AS INTEGER\r
+ DIM screenX2 AS INTEGER\r
+ DIM screenY2 AS INTEGER\r
+\r
+ screenX1 = (x * scaleFactor) + 320\r
+ screenY1 = 240 - (y * scaleFactor)\r
+ screenX2 = (x1 * scaleFactor) + 320\r
+ screenY2 = 240 - (y1 * scaleFactor)\r
+\r
+ ' Check if the point is within the screen boundaries before plotting\r
+ IF screenX1 >= 0 AND screenY1 >= 0 AND screenX1 <= 639 AND screenY1 <= 479 AND screenX2 >= 0 AND screenY2 >= 0 AND screenX2 <= 639 AND screenY2 <= 479 THEN\r
+ LINE (screenX1, screenY1)-(screenX2, screenY2), colorCode\r
+ END IF\r
+END SUB\r
+\r
--- /dev/null
+DECLARE SUB formula (x!, y!, z!)\r
+DECLARE SUB graaf ()\r
+DECLARE SUB mkgr3 (x1!, y1!, z1!)\r
+DECLARE SUB mkgr2 (x1!, y1!, z1!)\r
+DECLARE SUB mkgr (x1!, y1!, z1!)\r
+DECLARE SUB start ()\r
+DECLARE SUB getcor ()\r
+DECLARE SUB nait3d ()\r
+' 3D heightmap explorer. Allows to visualize heightmap for arbitrary function.\r
+' Inspect and edit function "formula" to visualize alternative mathematical functions.\r
+\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+\r
+' Changelog:\r
+' 2002, Initial version\r
+' 2024.09, Improved program readability\r
+\r
+' Keyboard controls:\r
+' Cursor keys - move around\r
+' - - fly up\r
+' + - fly down\r
+' ESC - exit program\r
+\r
+' Type your formula to sub module "formula".\r
+' X & Y are surface coordinates. Z must be formula\r
+' result, indicating height. "tm" variable counts\r
+' frames. Use it in your formula to make graph moving in time.\r
+\r
+DIM SHARED vertexX(4000), vertexY(4000), vertexZ(4000)\r
+DIM SHARED x(4000), y(4000), z(4000)\r
+\r
+DIM SHARED xo(4000), yo(4000), zo(4000)\r
+DIM SHARED linePoint1(4000), linePoint2(4000)\r
+DIM SHARED lineColor(4000)\r
+DIM SHARED vertexCount, lineCount\r
+DIM SHARED tmvertexCount, tmlineCount, tm\r
+DIM SHARED myx, myy, myz, mye, myk\r
+\r
+myx = 520\r
+myy = -250\r
+myz = -1000\r
+tm = 0\r
+\r
+ON ERROR GOTO 3\r
+start\r
+\r
+nait3d\r
+\r
+3\r
+PRINT "Kuskil programmis l�ks mingi arv �le lubatud piiride!!!"\r
+RESUME\r
+\r
+' This subroutine initializes the coordinate system and sets up the grid.\r
+SUB getcor\r
+ c = 12\r
+\r
+ ' Create background 2D grids along every axis in 3D space\r
+ ' to help viewer perceive scale.\r
+ mkgr -500, 0, 0\r
+ mkgr2 0, 0, 500\r
+ mkgr3 0, -500, 0\r
+\r
+ ' Place center-crossing pink lines across every axis (3D cross).\r
+ ' This is to help viewer to see where zero point on the graph is.\r
+\r
+ ' Add vertices for the 3D cross.\r
+ vertexX(vertexCount + 1) = 0\r
+ vertexY(vertexCount + 1) = -500\r
+ vertexZ(vertexCount + 1) = 0\r
+\r
+ vertexX(vertexCount + 2) = 0\r
+ vertexY(vertexCount + 2) = 500\r
+ vertexZ(vertexCount + 2) = 0\r
+\r
+ vertexX(vertexCount + 3) = -500\r
+ vertexY(vertexCount + 3) = 0\r
+ vertexZ(vertexCount + 3) = 0\r
+\r
+ vertexX(vertexCount + 4) = 500\r
+ vertexY(vertexCount + 4) = 0\r
+ vertexZ(vertexCount + 4) = 0\r
+\r
+ vertexX(vertexCount + 5) = 0\r
+ vertexY(vertexCount + 5) = 0\r
+ vertexZ(vertexCount + 5) = -500\r
+\r
+ vertexX(vertexCount + 6) = 0\r
+ vertexY(vertexCount + 6) = 0\r
+ vertexZ(vertexCount + 6) = 500\r
+\r
+ ' Add lines for the 3D cross.\r
+ linePoint1(lineCount + 1) = vertexCount + 1\r
+ linePoint2(lineCount + 1) = vertexCount + 2\r
+ lineColor(lineCount + 1) = c\r
+\r
+ linePoint1(lineCount + 2) = vertexCount + 3\r
+ linePoint2(lineCount + 2) = vertexCount + 4\r
+ lineColor(lineCount + 2) = c\r
+\r
+ linePoint1(lineCount + 3) = vertexCount + 5\r
+ linePoint2(lineCount + 3) = vertexCount + 6\r
+ lineColor(lineCount + 3) = c\r
+\r
+ ' Update the vertex and line counts\r
+ vertexCount = vertexCount + 6\r
+ lineCount = lineCount + 3\r
+ tmvertexCount = vertexCount\r
+ tmlineCount = lineCount\r
+END SUB\r
+\r
+' This subroutine generates a grid of points based on the formula\r
+SUB graaf\r
+ c = 14\r
+\r
+ d = 0\r
+ e = 0\r
+ FOR x = -500 TO 500 STEP 50\r
+ FOR z = -500 TO 500 STEP 50\r
+\r
+ ' Increment the vertex count and add a new vertex\r
+ d = d + 1\r
+ vertexX(vertexCount + d) = x\r
+ formula x / 50, z / 50, y ' evaluate formula that we want to visualize\r
+ vertexY(vertexCount + d) = y * 50\r
+ vertexZ(vertexCount + d) = z\r
+\r
+ ' Connect current point on the grid with neighbors\r
+ IF z > -500 THEN\r
+ e = e + 1\r
+ linePoint1(lineCount + e) = vertexCount + d\r
+ linePoint2(lineCount + e) = vertexCount + d - 1\r
+ lineColor(lineCount + e) = c\r
+ END IF\r
+\r
+ IF x > -500 THEN\r
+ e = e + 1\r
+ linePoint1(lineCount + e) = vertexCount + d\r
+ linePoint2(lineCount + e) = vertexCount + d - 21\r
+ lineColor(lineCount + e) = c\r
+ END IF\r
+\r
+ NEXT z\r
+ NEXT x\r
+\r
+ ' Update the vertex and line counts\r
+ vertexCount = vertexCount + d\r
+ lineCount = lineCount + e\r
+END SUB\r
+\r
+' This subroutine generates a measuring grid in the ZY plane.\r
+SUB mkgr (x1, y1, z1)\r
+ c = 3\r
+\r
+ d = 0\r
+ e = 0\r
+ FOR z = -500 TO 500 STEP 100\r
+ FOR y = -500 TO 500 STEP 100\r
+\r
+ ' Increment the vertex count and add a new vertex\r
+ d = d + 1\r
+ vertexX(vertexCount + d) = x1\r
+ vertexY(vertexCount + d) = y1 + y\r
+ vertexZ(vertexCount + d) = z1 + z\r
+\r
+ ' Add lines to the line array if necessary\r
+ IF y > -500 THEN\r
+ e = e + 1\r
+ linePoint1(lineCount + e) = vertexCount + d\r
+ linePoint2(lineCount + e) = vertexCount + d - 1\r
+ lineColor(lineCount + e) = c\r
+ END IF\r
+\r
+ IF z > -500 THEN\r
+ e = e + 1\r
+ linePoint1(lineCount + e) = vertexCount + d\r
+ linePoint2(lineCount + e) = vertexCount + d - 11\r
+ lineColor(lineCount + e) = c\r
+ END IF\r
+\r
+ NEXT y\r
+ NEXT z\r
+\r
+ ' Update the vertex and line counts\r
+ vertexCount = vertexCount + d\r
+ lineCount = lineCount + e\r
+END SUB\r
+\r
+' This subroutine generates a measuring grid XY plane.\r
+SUB mkgr2 (x1, y1, z1)\r
+ c = 3\r
+\r
+ d = 0\r
+ e = 0\r
+ FOR x = -500 TO 500 STEP 100\r
+ FOR y = -500 TO 500 STEP 100\r
+\r
+ ' Increment the vertex count and add a new vertex\r
+ d = d + 1\r
+ vertexX(vertexCount + d) = x1 + x\r
+ vertexY(vertexCount + d) = y1 + y\r
+ vertexZ(vertexCount + d) = z1\r
+\r
+ ' Add lines to the line array if necessary\r
+ IF y > -500 THEN\r
+ e = e + 1\r
+ linePoint1(lineCount + e) = vertexCount + d\r
+ linePoint2(lineCount + e) = vertexCount + d - 1\r
+ lineColor(lineCount + e) = c\r
+ END IF\r
+\r
+ IF x > -500 THEN\r
+ e = e + 1\r
+ linePoint1(lineCount + e) = vertexCount + d\r
+ linePoint2(lineCount + e) = vertexCount + d - 11\r
+ lineColor(lineCount + e) = c\r
+ END IF\r
+\r
+ NEXT y\r
+ NEXT x\r
+\r
+ ' Update the vertex and line counts\r
+ vertexCount = vertexCount + d\r
+ lineCount = lineCount + e\r
+END SUB\r
+\r
+' This subroutine generates a measuring grid in the XZ plane.\r
+SUB mkgr3 (x1, y1, z1)\r
+ c = 3\r
+\r
+ d = 0\r
+ e = 0\r
+ FOR x = -500 TO 500 STEP 100\r
+ FOR z = -500 TO 500 STEP 100\r
+\r
+ ' Increment the vertex count and add a new vertex\r
+ d = d + 1\r
+ vertexX(vertexCount + d) = x1 + x\r
+ vertexY(vertexCount + d) = y1\r
+ vertexZ(vertexCount + d) = z\r
+\r
+ ' Add lines to the line array if necessary\r
+ IF z > -500 THEN\r
+ e = e + 1\r
+ linePoint1(lineCount + e) = vertexCount + d\r
+ linePoint2(lineCount + e) = vertexCount + d - 1\r
+ lineColor(lineCount + e) = c\r
+ END IF\r
+\r
+ IF x > -500 THEN\r
+ e = e + 1\r
+ linePoint1(lineCount + e) = vertexCount + d\r
+ linePoint2(lineCount + e) = vertexCount + d - 11\r
+ lineColor(lineCount + e) = c\r
+ END IF\r
+\r
+ NEXT z\r
+ NEXT x\r
+\r
+ ' Update the vertex and line counts\r
+ vertexCount = vertexCount + d\r
+ lineCount = lineCount + e\r
+END SUB\r
+\r
+' This subroutine renders the 3D scene.\r
+SUB nait3d\r
+\r
+1\r
+vertexCount = tmvertexCount\r
+lineCount = tmlineCount\r
+tm = tm + 1\r
+graaf\r
+\r
+myx = myx + SIN(deg1) * mye\r
+myz = myz + COS(deg1) * mye\r
+\r
+myx = myx + COS(deg1) * myk\r
+myz = myz - SIN(deg1) * myk\r
+\r
+myy = myy + myyp\r
+\r
+deg1 = deg1 + d1\r
+Deg2 = Deg2 + d2\r
+\r
+C1 = COS(deg1): S1 = SIN(deg1)\r
+C2 = COS(Deg2): S2 = SIN(Deg2)\r
+\r
+' Transform the vertices to 3D space\r
+FOR a = 1 TO vertexCount\r
+\r
+ xo = vertexX(a) - myx\r
+ yo = -vertexY(a) - myy\r
+ zo = vertexZ(a) - myz\r
+\r
+ ' Apply rotation transformations\r
+ x1 = (xo * C1 - zo * S1)\r
+ z1 = (xo * S1 + zo * C1)\r
+\r
+ y1 = (yo * C2 - z1 * S2)\r
+ z2 = (yo * S2 + z1 * C2)\r
+\r
+ ' Project the vertices onto the 2D screen\r
+ xo(a) = x(a)\r
+ yo(a) = y(a)\r
+\r
+ IF z2 < 20 THEN\r
+ x(a) = -1\r
+ ELSE\r
+ x(a) = 320 + (x1 / z2 * 500)\r
+ y(a) = 240 + (y1 / z2 * 500)\r
+ END IF\r
+NEXT\r
+\r
+' Draw the lines on the screen\r
+FOR a = 1 TO lineCount\r
+ p1 = linePoint1(a)\r
+ p2 = linePoint2(a)\r
+\r
+ ' Skip drawing if either point is off-screen\r
+ IF xo(p1) = -1 OR xo(p2) = -1 THEN\r
+ ' Do nothing\r
+ ELSE\r
+ ' erase line at previous position\r
+ LINE (xo(p1), yo(p1))-(xo(p2), yo(p2)), 0\r
+ ' draw line at new position\r
+ LINE (x(p1), y(p1))-(x(p2), y(p2)), lineColor(a)\r
+ END IF\r
+\r
+NEXT\r
+\r
+' Handle keyboard input\r
+K$ = INKEY$\r
+IF K$ <> "" THEN\r
+\r
+ SELECT CASE K$\r
+\r
+ CASE CHR$(0) + "P"\r
+ mye = mye - 3\r
+\r
+ CASE CHR$(0) + "H"\r
+ mye = mye + 3\r
+\r
+ CASE CHR$(0) + "M"\r
+ myk = myk + 3\r
+\r
+ CASE CHR$(0) + "K"\r
+ myk = myk - 3\r
+\r
+ CASE "+"\r
+ myyp = myyp + 5\r
+\r
+ CASE "-"\r
+ myyp = myyp - 5\r
+\r
+ CASE "6"\r
+ d1 = d1 + .01\r
+\r
+ CASE "4"\r
+ d1 = d1 - .01\r
+\r
+ CASE "8"\r
+ d2 = d2 - .01\r
+\r
+ CASE "2"\r
+ d2 = d2 + .01\r
+\r
+ CASE " "\r
+ d1 = d1 / 2\r
+ d2 = d2 / 2\r
+ d3 = d3 / 2\r
+ mye = mye / 2\r
+ myk = myk / 2\r
+ myyp = myyp / 2\r
+\r
+ CASE "q"\r
+ SYSTEM\r
+\r
+ CASE CHR$(27)\r
+ SYSTEM\r
+\r
+ END SELECT\r
+END IF\r
+\r
+GOTO 1\r
+END SUB\r
+\r
+' This subroutine initializes the graphics and sets up the program.\r
+SUB start\r
+SCREEN 12\r
+CLS\r
+\r
+FOR a = 1 TO 4000\r
+ lineColor(a) = 15\r
+NEXT a\r
+\r
+vertexCount = 0\r
+lineCount = 0\r
+\r
+getcor\r
+\r
+END SUB\r
+\r
+' This subroutine calculates the height of a point based on the formula\r
+SUB formula (x, y, z)\r
+z = 0\r
+v = SQR(x * x + y * y) ' v = distance from center, some formulas need it.\r
+\r
+' Apply the formula to calculate the height\r
+z = z + SIN(x + y) * SIN(tm / 10) ' diagonal lines\r
+z = z + (SQR((15 + v) * (15 - v)) - 10) ' top of the ball\r
+\r
+' As you see, multiple formulas can be enabled simultaneously.\r
+' Few more example formulas that you can uncomment and enable.\r
+' z = z + RND * 1 ' noise\r
+' z = z + SIN((y + tm) / 2) ' forward moving wave\r
+' z = z + SIN(v / 2) * 2 ' circular waves\r
+' z = z - SQR(v * 6) ' sharp peak\r
+' z = z + SIN(y / 1.5) / 1.5 + COS(x / 1.5) / 1.5' custom 1\r
+' z = z + SIN(y / 1.5) * COS(x / 1.5) / 1.5 ' custom 2\r
+' z = z + INT(SIN(1.5 * x * SIN(tm / 10))) * 3 ' custom 3\r
+' z = z - INT(v / 5) * 3 + 3 ' custom 4\r
+' z = z + 3 * ((-INT((x - .3) / 20) * INT((23 + x - ABS(y * 1.2)) / 15)) + -INT(-y / 20) * -INT(-x / 20) * INT(-((x - 2) * (x - 2) + (y * 1.2 - 4) * (y * 1.2 - 4)) / 2000 + 1.01) + -INT(y / 20) * -INT(-x / 20) * INT(-((x - 2) * (x - 2) + (y * 1.2 + 4) * (y * 1.2 + 4)) / 2000 + 1.01)) ' heart\r
+\r
+END SUB\r
+\r
--- /dev/null
+' Program that computes and plots arbitrary mathematical function on a 2D graph.\r
+' Also it computes and plots the derivative of the function.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 200?, Initial version\r
+' 2024.09, Improved program readability\r
+\r
+\r
+DECLARE SUB Initialize ()\r
+DECLARE SUB PlotPoint (x, y, x1, y1, c!)\r
+DIM SHARED scaleFactor\r
+\r
+scaleFactor = 50 ' Scale factor for the graph\r
+Initialize\r
+\r
+oldX = -320 / scaleFactor\r
+oldY = 0\r
+\r
+FOR x = -320 / scaleFactor TO 320 / scaleFactor STEP 1 / scaleFactor\r
+\r
+ ' Calculate the function value (replace with your desired formula)\r
+ t = x ^ 3 - (3 * x)\r
+\r
+ PlotPoint x, t, oldX, prevY, 10\r
+ y = (t - prevY) * scaleFactor\r
+ prevY = t\r
+\r
+ PlotPoint x, y, oldX, oldY, 14\r
+ oldX = x\r
+ oldY = y\r
+NEXT x\r
+\r
+SUB Initialize\r
+ SCREEN 12\r
+\r
+ ' Draw vertical grid lines\r
+ FOR x = -320 TO 320\r
+ IF x / scaleFactor = x \ scaleFactor THEN LINE (x + 320, 0)-(x + 320, 479), 1\r
+ NEXT x\r
+\r
+ ' Draw horizontal grid lines\r
+ FOR y = -240 TO 240\r
+ IF y / scaleFactor = y \ scaleFactor THEN LINE (0, y + 240)-(639, y + 240), 1\r
+ NEXT y\r
+\r
+ ' Draw thicker vertical grid lines for every 5th unit\r
+ FOR x = -320 TO 320\r
+ IF x / (scaleFactor * 5) = x \ (scaleFactor * 5) THEN LINE (x + 320, 0)-(x + 320, 479), 4\r
+ NEXT x\r
+\r
+ ' Draw thicker horizontal grid lines for every 5th unit\r
+ FOR y = -240 TO 240\r
+ IF y / (scaleFactor * 5) = y \ (scaleFactor * 5) THEN LINE (0, y + 240)-(639, y + 240), 4\r
+ NEXT y\r
+\r
+ ' Draw x-axis and y-axis\r
+ LINE (0, 240)-(639, 240), 3\r
+ LINE (320, 0)-(320, 479), 3\r
+END SUB\r
+\r
+SUB PlotPoint (x, y, x1, y1, c)\r
+\r
+ x2 = (x * scaleFactor) + 320\r
+ y2 = 240 - (y * scaleFactor)\r
+ x3 = (x1 * scaleFactor) + 320\r
+ y3 = 240 - (y1 * scaleFactor)\r
+\r
+ ' Check if the points are within the screen boundaries\r
+ IF x2 < 0 THEN GOTO Skip\r
+ IF y2 < 0 THEN GOTO Skip\r
+ IF x2 > 639 THEN GOTO Skip\r
+ IF y2 > 479 THEN GOTO Skip\r
+ IF x3 < 0 THEN GOTO Skip\r
+ IF y3 < 0 THEN GOTO Skip\r
+ IF x3 > 639 THEN GOTO Skip\r
+ IF y3 > 479 THEN GOTO Skip\r
+\r
+ ' Draw a line between the two points with the specified color\r
+ LINE (x2, y2)-(x3, y3), c\r
+\r
+Skip:\r
+END SUB\r
--- /dev/null
+' SIN & COS table generator\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version.\r
+' 2024.08, Updated code readability.\r
+\r
+\r
+' Screen dimensions and video mode settings\r
+screenWidth = 640\r
+screenHeight = 480\r
+videoMode = 12 ' Video mode switch (0 for text mode, non-zero for graphics mode)\r
+stringSize = 0 ' String size for text mode\r
+\r
+' Adjust screen dimensions for a more accurate representation\r
+screenWidth = screenWidth / 11.3\r
+screenHeight = screenHeight / 11.7\r
+\r
+' Determine string size based on video mode\r
+IF stringSize = 0 THEN\r
+ SELECT CASE videoMode\r
+ CASE 12, 11\r
+ stringSize = 16\r
+\r
+ CASE 9, 10\r
+ stringSize = 14\r
+\r
+ CASE 1, 13, 2, 7, 8\r
+ stringSize = 8\r
+ END SELECT\r
+ELSE\r
+ GOTO InitializeScreen\r
+END IF\r
+\r
+InitializeScreen:\r
+SCREEN videoMode\r
+\r
+' Draw grid and label axes\r
+FOR gridLine = 1 TO 10\r
+ ' Draw horizontal grid lines\r
+ LINE (0, gridLine * screenHeight)-(screenWidth * 10, gridLine * screenHeight), 8\r
+\r
+ ' Draw vertical grid lines\r
+ LINE (gridLine * screenWidth, 0)-(gridLine * screenWidth, screenHeight * 10), 8\r
+\r
+ ' Label horizontal axis with numbers\r
+ textRow = 10 * screenHeight / stringSize + 2\r
+ textCol = gridLine * screenWidth / 8 + 1\r
+ LOCATE textRow, textCol\r
+ PRINT CHR$(gridLine + 48);\r
+NEXT gridLine\r
+\r
+' Label the end of the horizontal axis\r
+LOCATE 10 * screenHeight / stringSize + 2, screenWidth * 10 / 8\r
+PRINT "10";\r
+\r
+' Label special points on the vertical axis\r
+LOCATE 1 * screenHeight / stringSize + 1, screenWidth * 10 / 8 + 3\r
+PRINT "-1";\r
+LOCATE 5 * screenHeight / stringSize + 1, screenWidth * 10 / 8 + 3\r
+PRINT "0";\r
+LOCATE 10 * screenHeight / stringSize, screenWidth * 10 / 8 + 3\r
+PRINT "1";\r
+\r
+' Draw central horizontal and vertical lines\r
+LINE (0, screenHeight * 5 + 1)-(screenWidth * 10, screenHeight * 5 + 1), 14\r
+LINE (5 * screenWidth + 1, 0)-(5 * screenWidth + 1, 10 * screenHeight), 14\r
+\r
+' Plot SIN function\r
+FOR angle = 0 TO 10 STEP .05\r
+ xPosition = angle * screenWidth\r
+ yPosition = SIN(angle) * screenHeight * 5 + screenHeight * 5\r
+ IF angle > 0 THEN LINE (xPositionPrev, yPositionPrev)-(xPosition, yPosition), 15\r
+ xPositionPrev = xPosition\r
+ yPositionPrev = yPosition\r
+NEXT angle\r
+\r
+' Label the SIN curve\r
+textRow = yPosition / stringSize + 1\r
+textCol = screenWidth * 10 / 8\r
+LOCATE textRow, textCol\r
+PRINT "sin";\r
+\r
+' Plot COS function\r
+FOR angle = 0 TO 10 STEP .05\r
+ xPosition = angle * screenWidth\r
+ yPosition = COS(angle) * screenHeight * 5 + screenHeight * 5\r
+ IF angle > 0 THEN LINE (xPositionPrev, yPositionPrev)-(xPosition, yPosition), 12\r
+ xPositionPrev = xPosition\r
+ yPositionPrev = yPosition\r
+NEXT angle\r
+\r
+' Label the COS curve\r
+textRow = yPosition / stringSize + 1\r
+textCol = screenWidth * 10 / 8\r
+LOCATE textRow, textCol\r
+PRINT "cos";\r
+\r
+' Wait for user input before exiting\r
+a$ = INPUT$(1)\r
+SYSTEM\r
+\r
--- /dev/null
+#+TITLE: Plotting
+#+LANGUAGE: en
+#+LATEX_HEADER: \usepackage[margin=1.0in]{geometry}
+#+LATEX_HEADER: \usepackage{parskip}
+#+LATEX_HEADER: \usepackage[none]{hyphenat}
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+ .flex-center {
+ display: flex; /* activate flexbox */
+ justify-content: center; /* horizontally center anything inside */
+ }
+
+ .flex-center video {
+ width: min(90%, 1000px); /* whichever is smaller wins */
+ height: auto; /* preserve aspect ratio */
+ }
+
+ .responsive-img {
+ width: min(100%, 1000px);
+ height: auto;
+ }
+</style>
+#+end_export
+
+* 2D graph
+
+The 2D Graph Plotter is a simple yet effective program written in
+QBasic that allows users to plot mathematical functions on a
+two-dimensional grid. This program is particularly useful for
+visualizing mathematical functions and understanding their graphical
+representations.
+
+The main loop of the program calculates the y-value for each x-value
+based on a user-defined mathematical function.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:2D%20graph%20plot.bas][file:2D%20graph%20plot.png]]
+
+[[file:2D%20graph%20plot.bas][Source code]]
+
+* 3D graph
+
+The 3D Heightmap Explorer is a QBasic program designed to visualize
+mathematical functions in three dimensions. It allows users to explore
+various heightmaps by defining custom formulas and observing their
+graphical representations. This program is particularly useful for
+educational purposes, helping users understand complex mathematical
+surfaces.
+
+Users can navigate through the 3D space using keyboard controls to
+move around and inspect the heightmap from different angles.
+
+The core of the program is the formula subroutine, where users can
+define their mathematical functions. Multiple example formulas are
+provided, which can be enabled or disabled to create different visual
+effects.
+
+The program includes a grid system that helps users perceive the scale
+and orientation of the 3D space. This includes background grids and a
+central 3D cross to indicate the zero point.
+
+The formula subroutine evaluates the user-defined mathematical
+function to determine the height (Z-coordinate) of each point on the
+grid.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:3D%20graph.bas][file:3D%20graph.png]]
+
+[[file:3D%20graph.bas][Source code]]
+
+* Deriviative calculator
+
+This QBasic program is designed to compute and plot an arbitrary
+mathematical function on a 2D graph. Additionally, it calculates and
+plots the derivative of the function, providing a visual
+representation of both the function and its rate of change. The
+program is a great educational tool for those interested in
+understanding how mathematical functions and their derivatives can be
+visualized.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Deriviative%20calculator.bas][file:Deriviative%20calculator.png]]
+
+[[file:Deriviative%20calculator.bas][Source code]]
+
+* Sine and cosine table
+
+The SIN & COS Table Generator is a QBasic program designed to visually
+plot the sine and cosine functions on a graphical screen. This program
+is particularly useful for educational purposes, providing a clear
+visual representation of these fundamental trigonometric functions.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Sine%20and%20cosine%20table.bas][file:Sine%20and%20cosine%20table.png]]
+
+[[file:Sine%20and%20cosine%20table.bas][Source code]]
--- /dev/null
+' Program to simulate shock waves propagation in gas.\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+DECLARE SUB SetLocalPressure(xCoord!, yCoord!, pressureValue!)\r
+DECLARE SUB DrawBoundaryLine(startX!, startY!, endX!, endY!)\r
+DIM SHARED wallBoundary\r
+wallBoundary = 9980 ' Special value indicating solid wall boundaries\r
+\r
+' Shared arrays for fluid simulation:\r
+DIM SHARED pressureGrid(1 TO 100, 1 TO 100) ' Stores pressure values at each grid point\r
+DIM SHARED horizontalVelocity(1 TO 100, 1 TO 100) ' Stores horizontal velocity components\r
+DIM SHARED verticalVelocity(1 TO 100, 1 TO 100) ' Stores vertical velocity components\r
+DIM SHARED horizontalPressureChange(1 TO 100, 1 TO 100) ' Stores x-direction pressure change at each grid point\r
+DIM SHARED verticalPressureChange(1 TO 100, 1 TO 100) ' Stores y-direction pressure change at each grid point\r
+\r
+SCREEN 13\r
+PAINT (1, 1), 1\r
+SetupInitialConditions\r
+\r
+1 ' Main simulation loop\r
+\r
+ ' Check if any key is pressed; if so, exit the program\r
+ IF INKEY$ <> "" THEN SYSTEM\r
+\r
+ ' Display pressure values in a grid at the bottom of the screen.\r
+ FOR gridY = 2 TO 99\r
+ FOR gridX = 2 TO 99\r
+ IF pressureGrid(gridX, gridY) = wallBoundary THEN\r
+ ' Set velocities to zero for wall boundaries\r
+ horizontalVelocity(gridX - 1, gridY) = 0\r
+ verticalVelocity(gridX, gridY - 1) = 0\r
+ horizontalVelocity(gridX, gridY) = 0\r
+ verticalVelocity(gridX, gridY) = 0\r
+ GOTO 3 ' Skip further calculations for this grid point if it's a wall\r
+ END IF\r
+\r
+ ' Apply gravitation by subtracting pressure from vertical speed\r
+ verticalVelocity(gridX, gridY) = verticalVelocity(gridX, gridY) - (pressureGrid(gridX, gridY) / 500)\r
+\r
+ IF pressureGrid(gridX + 1, gridY) = wallBoundary THEN\r
+ horizontalVelocity(gridX, gridY) = 0 ' Set horizontal speed to zero if there's a wall to the right\r
+ GOTO 2 ' Skip further calculations for this grid point if there's a wall to the right\r
+ END IF\r
+\r
+ ' Calculate x-direction speed based on pressure difference and previous speed\r
+ horizontalVelocity(gridX, gridY) = (pressureGrid(gridX + 1, gridY) - pressureGrid(gridX, gridY)) / 20 + horizontalVelocity(gridX, gridY)\r
+\r
+2 ' Label for skipping further calculations if there's a wall to the right\r
+ IF pressureGrid(gridX, gridY + 1) = wallBoundary THEN\r
+ verticalVelocity(gridX, gridY) = 0 ' Set vertical speed to zero if there's a wall below\r
+ GOTO 3 ' Skip further calculations for this grid point if there's a wall below\r
+ END IF\r
+\r
+ ' Calculate y-direction speed based on pressure difference and previous speed\r
+ verticalVelocity(gridX, gridY) = (pressureGrid(gridX, gridY + 1) - pressureGrid(gridX, gridY)) / 20 + verticalVelocity(gridX, gridY)\r
+\r
+3 ' Label for skipping further calculations if there's a wall below or above\r
+ NEXT gridX\r
+ NEXT gridY\r
+\r
+4 ' Negative pressure correction loop\r
+ negativePressureFlag = 0 ' Initialize negative pressure flag to zero\r
+ FOR gridY = 2 TO 99\r
+ FOR gridX = 2 TO 99\r
+ pressureDifference = pressureGrid(gridX, gridY) + horizontalVelocity(gridX, gridY) + verticalVelocity(gridX, gridY) - horizontalVelocity(gridX - 1, gridY) - verticalVelocity(gridX, gridY - 1)\r
+\r
+ IF pressureDifference = 0 OR ((pressureDifference < 0) AND (pressureDifference > -.0001)) THEN\r
+ ' If difference in pressure is zero or slightly negative, set speeds to zero\r
+ IF horizontalVelocity(gridX, gridY) < 0 THEN\r
+ horizontalVelocity(gridX, gridY) = 0\r
+ END IF\r
+ IF verticalVelocity(gridX, gridY) < 0 THEN\r
+ verticalVelocity(gridX, gridY) = 0\r
+ END IF\r
+ IF horizontalVelocity(gridX - 1, gridY) > 0 THEN\r
+ horizontalVelocity(gridX - 1, gridY) = 0\r
+ END IF\r
+ IF verticalVelocity(gridX, gridY - 1) > 0 THEN\r
+ verticalVelocity(gridX, gridY - 1) = 0\r
+ END IF\r
+ END IF\r
+\r
+ ' If pressure difference is negative\r
+ IF pressureDifference < 0 THEN\r
+ IF horizontalVelocity(gridX, gridY) < 0 THEN\r
+ horizontalVelocity(gridX, gridY) = horizontalVelocity(gridX, gridY) / 1.5 ' Divide horizontal speed by 1.5 if negative\r
+ END IF\r
+ IF verticalVelocity(gridX, gridY) < 0 THEN\r
+ verticalVelocity(gridX, gridY) = verticalVelocity(gridX, gridY) / 1.5 ' Divide vertical speed by 1.5 if negative\r
+ END IF\r
+ IF horizontalVelocity(gridX - 1, gridY) > 0 THEN\r
+ horizontalVelocity(gridX - 1, gridY) = horizontalVelocity(gridX - 1, gridY) / 1.5 ' Divide horizontal speed by 1.5 if positive\r
+ END IF\r
+ IF verticalVelocity(gridX, gridY - 1) > 0 THEN\r
+ verticalVelocity(gridX, gridY - 1) = verticalVelocity(gridX, gridY - 1) / 1.5 ' Divide vertical speed by 1.5 if positive\r
+ END IF\r
+ negativePressureFlag = 1 ' Set negative pressure flag to one\r
+ ' Display negative pressure value at the bottom of the screen\r
+ LOCATE 20, 1\r
+ PRINT pressureDifference\r
+ END IF\r
+ NEXT gridX\r
+ NEXT gridY\r
+\r
+ IF negativePressureFlag = 1 THEN GOTO 4 ' If negative pressure was detected, repeat this loop to correct speeds\r
+\r
+' Update pressure based on velocity\r
+FOR gridY = 2 TO 99\r
+ FOR gridX = 2 TO 99\r
+ ' Update pressure based on speed in the x-direction\r
+ IF horizontalVelocity(gridX, gridY) > 0 THEN\r
+ horizontalPressureChange(gridX - 1, gridY) = ((pressureGrid(gridX, gridY) * horizontalVelocity(gridX - 1, gridY)) + (horizontalVelocity(gridX, gridY) * horizontalVelocity(gridX, gridY))) / (pressureGrid(gridX, gridY) + horizontalVelocity(gridX, gridY)) - horizontalVelocity(gridX - 1, gridY)\r
+ END IF\r
+\r
+ ' Update pressure based on speed in the y-direction\r
+ IF verticalVelocity(gridX, gridY) > 0 THEN\r
+ verticalPressureChange(gridX, gridY - 1) = ((pressureGrid(gridX, gridY) * verticalVelocity(gridX, gridY - 1)) + (verticalVelocity(gridX, gridY) * verticalVelocity(gridX, gridY))) / (pressureGrid(gridX, gridY) + verticalVelocity(gridX, gridY)) - verticalVelocity(gridX, gridY - 1)\r
+ END IF\r
+\r
+ ' Handle negative speeds in the x-direction\r
+ IF horizontalVelocity(gridX - 1, gridY) < 0 THEN\r
+ horizontalPressureChange(gridX, gridY) = ((pressureGrid(gridX, gridY) * horizontalVelocity(gridX, gridY)) - (horizontalVelocity(gridX - 1, gridY) * horizontalVelocity(gridX - 1, gridY))) / (pressureGrid(gridX, gridY) - horizontalVelocity(gridX - 1, gridY)) - horizontalVelocity(gridX, gridY)\r
+ END IF\r
+\r
+ ' Handle negative speeds in the y-direction\r
+ IF verticalVelocity(gridX, gridY - 1) < 0 THEN\r
+ verticalPressureChange(gridX, gridY) = ((pressureGrid(gridX, gridY) * verticalVelocity(gridX, gridY)) - (verticalVelocity(gridX, gridY - 1) * verticalVelocity(gridX, gridY - 1))) / (pressureGrid(gridX, gridY) - verticalVelocity(gridX, gridY - 1)) - verticalVelocity(gridX, gridY)\r
+ END IF\r
+ NEXT gridX\r
+NEXT gridY\r
+\r
+' Update pressure grid based on velocities\r
+FOR gridY = 2 TO 99\r
+ FOR gridX = 2 TO 99\r
+ ' Update pressure based on speed in the x-direction\r
+ pressureGrid(gridX + 1, gridY) = pressureGrid(gridX + 1, gridY) - horizontalVelocity(gridX, gridY)\r
+\r
+ ' Update pressure based on speed in the y-direction\r
+ pressureGrid(gridX, gridY + 1) = pressureGrid(gridX, gridY + 1) - verticalVelocity(gridX, gridY)\r
+\r
+ ' Add x and y speeds to pressure\r
+ pressureGrid(gridX, gridY) = pressureGrid(gridX, gridY) + horizontalVelocity(gridX, gridY)\r
+ pressureGrid(gridX, gridY) = pressureGrid(gridX, gridY) + verticalVelocity(gridX, gridY)\r
+ NEXT gridX\r
+NEXT gridY\r
+\r
+' Update velocities based on pressure changes\r
+FOR gridY = 2 TO 99\r
+ FOR gridX = 2 TO 99\r
+ ' Update speed based on previous speed in the x-direction\r
+ horizontalVelocity(gridX, gridY) = horizontalVelocity(gridX, gridY) + horizontalPressureChange(gridX, gridY)\r
+\r
+ ' Reset pressure change to zero for next iteration\r
+ horizontalPressureChange(gridX, gridY) = 0\r
+\r
+ ' Update speed based on previous speed in the y-direction\r
+ verticalVelocity(gridX, gridY) = verticalVelocity(gridX, gridY) + verticalPressureChange(gridX, gridY)\r
+\r
+ ' Reset pressure change to zero for next iteration\r
+ verticalPressureChange(gridX, gridY) = 0\r
+ NEXT gridX\r
+NEXT gridY\r
+\r
+' Draw the grid based on pressure values\r
+FOR gridY = 1 TO 100\r
+ FOR gridX = 1 TO 100\r
+ ' Draw pixel based on pressure value\r
+ PSET (gridX, gridY), pressureGrid(gridX, gridY) + 16\r
+ NEXT gridX\r
+NEXT gridY\r
+\r
+GOTO 1 ' Repeat the main simulation loop\r
+\r
+SUB DrawBoundaryLine (startX!, startY!, endX!, endY!)\r
+ ' Draws a straight line between two points in the pressure grid\r
+ ' All points along the line are set to wallBoundary value\r
+ ' Uses linear interpolation for smooth line drawing\r
+ maxSteps = ABS(startX - endX)\r
+ IF ABS(startY - endY) > maxSteps THEN maxSteps = ABS(startY - endY)\r
+ deltaX = endX - startX\r
+ deltaY = endY - startY\r
+ FOR stepCount = 0 TO maxSteps\r
+ ' Calculate interpolated coordinates\r
+ interpX = deltaX * stepCount / maxSteps + startX\r
+ interpY = deltaY * stepCount / maxSteps + startY\r
+ ' Mark this point as a wall boundary\r
+ pressureGrid(interpX, interpY) = wallBoundary\r
+ NEXT stepCount\r
+END SUB\r
+\r
+SUB SetLocalPressure (xCoord!, yCoord!, pressureValue!)\r
+ ' Sets a 2x2 block of cells to specified pressure value\r
+ ' Creates localized pressure disturbances in simulation\r
+ pressureGrid(xCoord, yCoord) = pressureValue\r
+ pressureGrid(xCoord + 1, yCoord) = pressureValue\r
+ pressureGrid(xCoord, yCoord + 1) = pressureValue\r
+ pressureGrid(xCoord + 1, yCoord + 1) = pressureValue\r
+END SUB\r
+\r
+SUB SetupInitialConditions\r
+ ' Sets up initial conditions for the simulation:\r
+ ' - Initializes all pressure and velocity arrays\r
+ ' - Places initial pressure disturbances\r
+ ' - Creates boundary walls\r
+ FOR yIndex = 1 TO 100\r
+ FOR xIndex = 1 TO 100\r
+ ' Initialize pressure and velocity variables\r
+ pressureGrid(xIndex, yIndex) = 3\r
+ horizontalVelocity(xIndex, yIndex) = 0\r
+ verticalVelocity(xIndex, yIndex) = 0\r
+ horizontalPressureChange(xIndex, yIndex) = 0\r
+ verticalPressureChange(xIndex, yIndex) = 0\r
+ NEXT xIndex\r
+ NEXT yIndex\r
+\r
+ ' Create initial pressure spots\r
+ FOR yIndex = 30 TO 60\r
+ FOR xIndex = 10 TO 50\r
+ SetLocalPressure xIndex, yIndex, 30\r
+ NEXT xIndex\r
+ NEXT yIndex\r
+\r
+ ' Draw boundary lines\r
+ DrawBoundaryLine 2, 2, 2, 99\r
+ DrawBoundaryLine 99, 2, 99, 99\r
+ DrawBoundaryLine 2, 99, 99, 99\r
+ DrawBoundaryLine 2, 2, 99, 2\r
+\r
+ ' Draw additional lines for testing\r
+ FOR xIndex = 5 TO 40 STEP 5\r
+ DrawBoundaryLine xIndex, 80, xIndex + 50, 80 - xIndex\r
+ NEXT xIndex\r
+END SUB\r
--- /dev/null
+' Gravitation Simulation\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' This program simulates the gravitational pull of a central mass\r
+' on a small object in two-dimensional space. The simulation is\r
+' visualized on the screen with the central mass as a large circle\r
+' and the orbiting object as a smaller circle.\r
+'\r
+' Changelog:\r
+' 2001, Initial version\r
+' 2024 - 2025, Improved code readability\r
+\r
+DEFDBL A-Z ' Declare all variables as double precision for accuracy\r
+SCREEN 12 ' Set the graphics mode to 640x480 resolution, 16 colors\r
+\r
+' Initialize position and velocity of the orbiting object\r
+objX = -200 ' X-coordinate of the object\r
+objY = 0 ' Y-coordinate of the object\r
+objVelX = -1 ' X-velocity (speed) of the object\r
+objVelY = 3 ' Y-velocity (speed) of the object\r
+\r
+' Draw the central mass as a large circle\r
+CIRCLE (320, 240), 100, 3\r
+\r
+' Main simulation loop\r
+DO\r
+\r
+ ' Check for user input and exit if any key is pressed\r
+ IF INKEY$ <> "" THEN SYSTEM\r
+\r
+ ' Draw a small circle to represent the orbiting object\r
+ CIRCLE (objX + 320, objY + 240), 2, 14\r
+\r
+ ' Update the position of the orbiting object\r
+ objX = objX + objVelX\r
+ objY = objY + objVelY\r
+\r
+ ' Calculate the distance from the central mass\r
+ dist = SQR(objX * objX + objY * objY)\r
+\r
+ ' Calculate the gravitational acceleration towards the center\r
+ gravAccel = 20 / dist ' Gravitational constant for this simulation\r
+\r
+ ' Adjust velocities based on gravitational pull and distance\r
+ objVelX = objVelX + (gravAccel * (-objX) / dist)\r
+ objVelY = objVelY + (gravAccel * (-objY) / dist)\r
+\r
+ ' Draw a line to show the object's trajectory\r
+ LINE (objX + 320, objY + 240)-(320, 240), 1\r
+ \r
+ \r
+ SOUND 0, .1\r
+\r
+LOOP\r
+\r
--- /dev/null
+' Program to simulate gravitational forces between atoms.\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+DECLARE SUB Gravitate ()\r
+DECLARE SUB AddAtom (x AS SINGLE, y AS SINGLE, z AS SINGLE, size AS SINGLE)\r
+DECLARE SUB DisplaySystem ()\r
+\r
+DIM SHARED atomX(1 TO 100)\r
+DIM SHARED atomY(1 TO 100)\r
+DIM SHARED atomZ(1 TO 100)\r
+DIM SHARED atomXSpeed(1 TO 100)\r
+DIM SHARED atomYSpeed(1 TO 100)\r
+DIM SHARED atomZSpeed(1 TO 100)\r
+DIM SHARED atomSize(1 TO 100)\r
+DIM SHARED countOfAtoms\r
+DIM SHARED myX, myY, myZ\r
+DIM SHARED oldAtomX(1 TO 100)\r
+DIM SHARED oldAtomY(1 TO 100)\r
+DIM SHARED oldAtomSize(1 TO 100)\r
+\r
+myX = 0\r
+myY = 0\r
+myZ = -5\r
+countOfAtoms = 0\r
+\r
+SCREEN 13\r
+\r
+' Initialize the system with a random distribution of atoms\r
+FOR a = 1 TO 30\r
+ AddAtom RND * 6 - 3, RND * 6 - 3, RND * 4, 50\r
+NEXT a\r
+\r
+' Main loop to display and update the system\r
+1\r
+ DisplaySystem\r
+ Gravitate\r
+ IF INKEY$ <> "" THEN SYSTEM ' Exit on any key press\r
+ \r
+ ' Delay animation\r
+ SOUND 0, 1\r
+GOTO 1\r
+\r
+SUB AddAtom (x, y, z, size)\r
+ ' Increment the atom count\r
+ countOfAtoms = countOfAtoms + 1\r
+\r
+ ' Store the new atom's position and size\r
+ atomX(countOfAtoms) = x\r
+ atomY(countOfAtoms) = y\r
+ atomZ(countOfAtoms) = z\r
+ atomSize(countOfAtoms) = size\r
+\r
+ ' Initialize the speed of the new atom to zero\r
+ atomXSpeed(countOfAtoms) = 0\r
+ atomYSpeed(countOfAtoms) = 0\r
+ atomZSpeed(countOfAtoms) = 0\r
+END SUB\r
+\r
+SUB DisplaySystem\r
+ FOR a = 1 TO countOfAtoms\r
+ ' Calculate the relative position of each atom\r
+ x = atomX(a) - myX\r
+ y = atomY(a) - myY\r
+ z = atomZ(a) - myZ\r
+\r
+ ' Project the 3D positions onto a 2D screen\r
+ x1 = x / z * 100 + 160\r
+ y1 = y / z * 100 + 100\r
+\r
+ ' Erase the old atom position and draw the new one\r
+ CIRCLE (oldAtomX(a), oldAtomY(a)), oldAtomSize(a), 0\r
+ CIRCLE (x1, y1), atomSize(a) / z, 15\r
+\r
+ ' Update the old positions for the next frame\r
+ oldAtomX(a) = x1\r
+ oldAtomY(a) = y1\r
+ oldAtomSize(a) = atomSize(a) / z\r
+ NEXT a\r
+END SUB\r
+\r
+SUB Gravitate\r
+ DIM pxs, pys, pzs\r
+\r
+ FOR a = 1 TO countOfAtoms\r
+ ' Get the current atom's position\r
+ x = atomX(a)\r
+ y = atomY(a)\r
+ z = atomZ(a)\r
+\r
+ ' Initialize gravitational forces to zero\r
+ pxs = 0\r
+ pys = 0\r
+ pzs = 0\r
+\r
+ FOR b = 1 TO countOfAtoms\r
+ IF b = a THEN GOTO 2 ' Skip self-gravitation\r
+\r
+ ' Calculate the distance between atoms\r
+ v = SQR((atomX(b) - x) ^ 2 + (atomY(b) - y) ^ 2 + (atomZ(b) - z) ^ 2)\r
+ v2 = 1 / (v - 1)\r
+\r
+ ' Accumulate gravitational forces from other atoms\r
+ pxs = pxs + (atomX(b) - x) / v2 / 10000\r
+ pys = pys + (atomY(b) - y) / v2 / 10000\r
+ pzs = pzs + (atomZ(b) - z) / v2 / 10000\r
+\r
+2 NEXT b\r
+\r
+ ' Update the atom's velocity with the accumulated forces\r
+ atomXSpeed(a) = atomXSpeed(a) / 1.01 + pxs\r
+ atomYSpeed(a) = atomYSpeed(a) / 1.01 + pys\r
+ atomZSpeed(a) = atomZSpeed(a) / 1.01 + pzs\r
+ NEXT a\r
+\r
+ ' Update the positions of all atoms based on their velocities\r
+ FOR a = 1 TO countOfAtoms\r
+ atomX(a) = atomX(a) + atomXSpeed(a)\r
+ atomY(a) = atomY(a) + atomYSpeed(a)\r
+ atomZ(a) = atomZ(a) + atomZSpeed(a)\r
+ NEXT a\r
+END SUB\r
+\r
--- /dev/null
+' Program simulates interference between two slightly different frequencies
+'
+' This program is free software: released under Creative Commons Zero (CC0) license
+' by Svjatoslav Agejenko.
+' Email: svjatoslav@svjatoslav.eu
+' Homepage: http://www.svjatoslav.eu
+'
+' Changelog:
+' ?, Initial version
+' 2024-2025, Improved program readability
+
+DECLARE SUB GetFrequency ()
+DECLARE SUB Start ()
+DECLARE FUNCTION GetY! (t!)
+
+SCREEN 12
+1
+
+SOUND 0, 1.5
+
+' Check for user input and exit if any key is pressed
+IF INKEY$ <> "" THEN SYSTEM
+
+frame = frame + 1
+FOR x = 0 TO 639
+
+ oldY1 = y1
+ oldY2 = y2
+ oldY3 = y3
+
+ ' Calculate new Y values for the waves
+ ' First wave: simple sine wave
+ y1 = SIN(frame + x / 4) * 20 + 150
+
+ ' Second wave: same but with additional phase shift that increases with x
+ ' This creates a slight frequency difference
+ y2 = SIN(frame + x / 4 + (x / 50)) * 20 + 150
+
+ ' Third line: sum of both waves to show interference pattern
+ y3 = y1 + y2
+
+ ' Clear the previous frame by drawing black vertical line
+ LINE (x, 0)-(x, 479), 0
+
+ ' Draw new lines for each wave
+ LINE (x - 1, oldY1)-(x, y1), 1 ' Blue wave
+ LINE (x - 1, oldY2)-(x, y2), 2 ' Green wave
+ LINE (x - 1, oldY3)-(x, y3), 15 ' White combined wave
+
+NEXT x
+GOTO 1
+
+
--- /dev/null
+' Program simulates lot of frequencies interfering with itself.\r
+' As a result, interferogram is produced.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' ?, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+' Set graphics mode (640x480 with 16 colors)\r
+SCREEN 12\r
+\r
+' Start drawing from the leftmost pixel\r
+PSET (0, 0)\r
+\r
+' Loop through all horizontal positions on screen\r
+FOR currentXPosition = 0 TO 639\r
+\r
+ ' Calculate frequency scaling factor based on position\r
+ ' This creates a gradient effect in the interference pattern\r
+ frequencyScalingFactor = (currentXPosition - 320) / 5000 + 1\r
+\r
+ ' Initialize accumulated signal value\r
+ totalSignalValue = 0\r
+\r
+ ' Sample the signal at multiple time steps to calculate interference\r
+ FOR currentTimeStep = 1 TO 5000 STEP 5\r
+ ' Generate two sine waves:\r
+ ' y1 - base frequency wave\r
+ ' y2 - frequency scaled wave (based on horizontal position)\r
+ baseWave = SIN(currentTimeStep)\r
+ scaledWave = SIN(currentTimeStep * frequencyScalingFactor)\r
+\r
+ ' Calculate interference by summing the waves and taking absolute value\r
+ totalSignalValue = totalSignalValue + ABS(baseWave + scaledWave)\r
+ NEXT currentTimeStep\r
+\r
+ ' Normalize the signal value\r
+ normalizedSignalValue = totalSignalValue / 5\r
+\r
+ ' Limit the value to screen boundaries\r
+ IF normalizedSignalValue > 470 THEN normalizedSignalValue = 470\r
+ IF normalizedSignalValue < 0 THEN normalizedSignalValue = 0\r
+\r
+ ' Draw a line from previous position to current position\r
+ LINE -(currentXPosition, 479 - normalizedSignalValue), 15\r
+\r
+NEXT currentXPosition\r
+\r
--- /dev/null
+' Program simulates water spill and subsequent surface tension effects\r
+' that try to round out sharp edges through cellular automata rules.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+DEFINT A-Z\r
+WIDTH 80, 50\r
+VIEW PRINT 1 TO 50\r
+RANDOMIZE TIMER\r
+CLS\r
+\r
+' Create two grids for double buffering technique\r
+' This prevents visual artifacts during updates\r
+DIM SHARED currentGrid(1 TO 80, 1 TO 50)\r
+DIM SHARED nextGrid(1 TO 80, 1 TO 50)\r
+\r
+' Initialize grid with random water (1) and empty space (0)\r
+FOR row = 1 TO 50\r
+ FOR column = 1 TO 80\r
+ currentGrid(column, row) = INT(RND * 2)\r
+ NEXT column\r
+NEXT row\r
+\r
+'================================================================================\r
+' MAIN SIMULATION LOOP\r
+' Continuously calculates next state based on surface tension rules\r
+' Uses cellular automata approach with Moore neighborhood (8 neighbors)\r
+'================================================================================\r
+1\r
+\r
+' Check for user input and exit if any key is pressed\r
+IF INKEY$ <> "" THEN SYSTEM\r
+\r
+FOR row = 2 TO 49\r
+ FOR column = 2 TO 79\r
+ ' Count live cells around current position (Moore neighborhood)\r
+ ' This includes all 8 surrounding cells forming a square around it\r
+ neighborTotal = currentGrid(column - 1, row - 1)\r
+ neighborTotal = neighborTotal + currentGrid(column, row - 1)\r
+ neighborTotal = neighborTotal + currentGrid(column + 1, row - 1)\r
+ neighborTotal = neighborTotal + currentGrid(column - 1, row)\r
+ neighborTotal = neighborTotal + currentGrid(column + 1, row)\r
+ neighborTotal = neighborTotal + currentGrid(column - 1, row + 1)\r
+ neighborTotal = neighborTotal + currentGrid(column, row + 1)\r
+ neighborTotal = neighborTotal + currentGrid(column + 1, row + 1)\r
+\r
+ ' Apply surface tension rules:\r
+ ' 1. Water cell (value 1) survives only if surrounded by moderate density\r
+ ' 2. Empty space (value 0) becomes water if surrounded by high density\r
+ IF currentGrid(column, row) = 1 THEN\r
+ IF neighborTotal > 3 THEN\r
+ nextGrid(column, row) = 1\r
+ ELSE\r
+ nextGrid(column, row) = 0\r
+ END IF\r
+ ELSE\r
+ IF neighborTotal > 4 THEN\r
+ nextGrid(column, row) = 1\r
+ ELSE\r
+ nextGrid(column, row) = 0\r
+ END IF\r
+ END IF\r
+ NEXT column\r
+NEXT row\r
+\r
+' UPDATE DISPLAY AND SWAP BUFFERS\r
+' Renders the simulation state to screen using ASCII characters and prepares\r
+' for next iteration by swapping active/inactive grids\r
+FOR row = 1 TO 50\r
+ FOR column = 1 TO 80\r
+ ' Transfer calculated state from working buffer to display buffer\r
+ cellState = nextGrid(column, row)\r
+ currentGrid(column, row) = cellState\r
+\r
+ ' Visual representation: # for water, . for empty space\r
+ LOCATE row, column\r
+ IF cellState = 0 THEN\r
+ PRINT ".";\r
+ ELSE\r
+ PRINT "#"\r
+ END IF\r
+ NEXT column\r
+NEXT row\r
+\r
+'================================================================================\r
+' FRAME RATE CONTROL\r
+' Creates approximately 60 frames per second using inaudible sound workaround\r
+' Actual frequency value of 0 creates short delay without producing sound\r
+'================================================================================\r
+SOUND 0, 3\r
+\r
+' Return to start of simulation loop\r
+GOTO 1\r
+\r
--- /dev/null
+' Program simulate wave propagation across surface.\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+SCREEN 13\r
+\r
+DIM SHARED yHigh(1 TO 300) ' surface height\r
+DIM SHARED yVelocity(1 TO 300) ' surface movement direction and velocity\r
+\r
+' Initialize the arrays\r
+FOR x = 1 TO 300\r
+ yVelocity(x) = 0\r
+ yHigh(x) = 100\r
+NEXT x\r
+\r
+' Create an initial wave shape\r
+FOR x = 140 TO 160\r
+ yHigh(x) = 150\r
+NEXT x\r
+\r
+' Main simulation loop\r
+1 :\r
+ ' Draw the wave\r
+ FOR x = 1 TO 300\r
+ LINE (x, 0)-(x, 200 - yHigh(x)), 0\r
+ LINE (x, 200 - yHigh(x))-(x, 200), 15\r
+ NEXT x\r
+\r
+ ' Calculate the average height of neighboring points\r
+ FOR x = 10 TO 290\r
+ avgHeight = (yHigh(x - 1) + yHigh(x + 1) + yHigh(x + 2) + yHigh(x - 2)) / 4\r
+ ' Update the smooth wave height\r
+ yVelocity(x) = yVelocity(x) + (avgHeight - yHigh(x)) / 5\r
+ ' Apply a damping factor\r
+ yVelocity(x) = yVelocity(x) / 1.01\r
+ NEXT x\r
+\r
+ ' Update the wave height based on the smooth values\r
+ FOR x = 10 TO 290\r
+ yHigh(x) = yHigh(x) + yVelocity(x)\r
+ ' Apply smoothing to neighboring points\r
+ yHigh(x - 1) = yHigh(x - 1) + yVelocity(x) / 2\r
+ yHigh(x + 1) = yHigh(x + 1) + yVelocity(x) / 2\r
+ NEXT x\r
+\r
+ ' Play a sound\r
+ SOUND 0, .5\r
+\r
+ ' Check for user input to exit\r
+ IF INKEY$ <> "" THEN SYSTEM\r
+\r
+' Loop back to the start of the simulation loop\r
+GOTO 1\r
+\r
--- /dev/null
+' Program renders 2D surface of a water. Water surface is disturbed by random rain droplets.\r
+' Program simulates and visualizes propagating waves on the water surface.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+SCREEN 13\r
+\r
+DIM SHARED surfaceHeight(1 TO 300)\r
+DIM SHARED verticalMovementSpeed(1 TO 300)\r
+\r
+FOR x = 1 TO 300\r
+ verticalMovementSpeed(x) = 0\r
+ surfaceHeight(x) = 50\r
+NEXT x\r
+\r
+' Main loop\r
+1\r
+\r
+CLS\r
+FOR x = 1 TO 300\r
+ ' Draw the current wave height at each point\r
+ PSET (x, 200 - surfaceHeight(x)), 31\r
+NEXT x\r
+\r
+' Calculate new wave heights based on neighboring points\r
+FOR x = 10 TO 290\r
+ averageNeighborHeights = (surfaceHeight(x - 1) + surfaceHeight(x + 1) + surfaceHeight(x + 2) + surfaceHeight(x - 2)) / 4\r
+ verticalMovementSpeed(x) = verticalMovementSpeed(x) + (averageNeighborHeights - surfaceHeight(x)) / 5\r
+ ' Smooth the new wave heights\r
+ verticalMovementSpeed(x) = verticalMovementSpeed(x) / 1.01\r
+NEXT x\r
+\r
+' Update the current wave heights with the newly calculated values\r
+FOR x = 10 TO 290\r
+ surfaceHeight(x) = surfaceHeight(x) + verticalMovementSpeed(x)\r
+NEXT x\r
+\r
+' Randomly generate a new wave at the start point\r
+IF RND * 100 < 2 THEN\r
+ newWaveIndex = RND * 200\r
+ waveAmplitude = RND * 10 + 2\r
+ FOR x = 0 TO 3.14 STEP 3.14 / waveAmplitude\r
+ surfaceHeight(newWaveIndex) = surfaceHeight(newWaveIndex) + SIN(x) * waveAmplitude * 3\r
+ newWaveIndex = newWaveIndex + 1\r
+ NEXT x\r
+END IF\r
+\r
+' Check for user input to exit the program\r
+IF INKEY$ <> "" THEN SYSTEM\r
+\r
+SOUND 0, .5\r
+\r
+' Go back to the main loop\r
+GOTO 1\r
--- /dev/null
+#+TITLE: Simulation
+#+LANGUAGE: en
+#+LATEX_HEADER: \usepackage[margin=1.0in]{geometry}
+#+LATEX_HEADER: \usepackage{parskip}
+#+LATEX_HEADER: \usepackage[none]{hyphenat}
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+ .flex-center {
+ display: flex; /* activate flexbox */
+ justify-content: center; /* horizontally center anything inside */
+ }
+
+ .flex-center video {
+ width: min(90%, 1000px); /* whichever is smaller wins */
+ height: auto; /* preserve aspect ratio */
+ }
+
+ .responsive-img {
+ width: min(100%, 1000px);
+ height: auto;
+ }
+</style>
+#+end_export
+
+* Explosion simulator
+
+This QBasic program simulates the propagation of shock waves in a gas
+within a confined space. It models the behavior of pressure and
+velocity in a two-dimensional grid, providing a visual representation
+of how shock waves interact with boundaries and each other.
+
+The program initializes a 100x100 grid to represent pressure and
+velocity values. It sets up initial conditions, including placing
+pressure disturbances and defining boundary walls.
+
+The core of the program is a loop that continuously updates the
+pressure and velocity values. The velocities in the horizontal and
+vertical directions are updated based on pressure differences between
+adjacent grid points. The program checks for and corrects negative
+pressure values to ensure physical realism. The pressure grid is
+updated based on the current velocities. The program handles boundary
+conditions by setting velocities to zero at wall boundaries.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Explosion%20simulator.bas][file:Explosion%20simulator.png]]
+
+[[file:Explosion%20simulator.bas][Source code]]
+
+* Gravity in 2D
+
+The Gravitation Simulation program is a simple yet insightful QBasic
+application that simulates the gravitational interaction between a
+central mass and an orbiting object in a two-dimensional space. This
+program provides a visual representation of how gravitational forces
+influence the motion of celestial bodies, making it an excellent
+educational tool for understanding basic orbital mechanics.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Gravity%20in%202D.bas][file:Gravity%20in%202D.png]]
+
+[[file:Gravity%20in%202D.bas][Source code]]
+
+* Gravity in 3D
+
+This QBasic program simulates the gravitational interactions between
+spheres in a three-dimensional space. It provides a visual
+representation of how spheres might move under the influence of
+gravitational forces, offering an educational insight into basic
+physics principles.
+
+When spheres are far apart, gravity is dominating force. When Distance
+between spheres crosses critical threshold, much stronger repulsive
+force emerges and becomes dominant.
+
+There is also friction. This ensures that after some bouncing, spheres
+will reach stable configuration.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="Gravity%20in%203D.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:Gravity%20in%203D.bas][Source code]]
+
+* Interference
+
+This QBasic program simulates the interference pattern created by two
+sine waves with slightly different frequencies. It visually
+demonstrates how wave interference works, which is a fundamental
+concept in physics and engineering, particularly in the study of
+sound, light, and other wave phenomena.
+
+Program combines two waves to create an interference pattern, which is
+displayed as a third waveform.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="Interference.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:Interference.bas][Source code]]
+
+* Interferogram
+
+This QBasic program simulates the interference pattern created by
+multiple frequencies interacting with each other. The result is a
+visual representation known as an interferogram, which is commonly
+used in physics and engineering to analyze wave interactions.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Interferogram.bas][file:Interferogram.png]]
+
+[[file:Interferogram.bas][Source code]]
+
+* Surface tension
+
+This QBasic program simulates the behavior of water spills and the
+subsequent effects of surface tension using cellular automata
+rules. The simulation models how water spreads and how surface tension
+affects the shape of the water body, particularly smoothing out sharp
+edges over time.
+
+The main loop continuously calculates the next state of each cell
+based on the surface tension rules. It uses the Moore neighborhood,
+which includes all eight surrounding cells, to determine the state of
+each cell in the next iteration.
+
+The rules dictate that a water cell survives only if surrounded by a
+moderate density of other water cells, while an empty space becomes a
+water cell if surrounded by a high density of water cells.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Surface%20tension.bas][file:Surface%20tension.png]]
+
+[[file:Surface%20tension.bas][Source code]]
+
+* Wave 1
+
+This QBasic program simulates the propagation of waves across a
+surface. It provides a visual representation of wave dynamics, which
+can be both educational and a source of inspiration for those
+interested in physics simulations or algorithmic art.
+
+The program updates the velocity and height of each point based on the
+calculated averages, applying a damping factor to simulate energy
+loss.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Wave%201.bas][file:Wave%201.png]]
+
+[[file:Wave%201.bas][Source code]]
+
+* Wave 2
+
+This QBasic program simulates and visualizes the behavior of water
+waves on a 2D surface. It creates a dynamic animation of water
+disturbed by random rain droplets, demonstrating how waves propagate
+and interact with each other. The program is an example of a simple
+physics simulation and can serve as an educational tool for
+understanding wave mechanics.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Wave%202.bas][file:Wave%202.png]]
+
+[[file:Wave%202.bas][Source code]]
--- /dev/null
+' Sine calculator without relying on built-in trigonometry functions.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+' 2024 - 2025, Improved program readability.\r
+'\r
+' This program calculates the sine of an angle without using the\r
+' built-in SIN function. Then it plots the calculated sine wave\r
+' alongside the built-in sine wave for comparison. There is\r
+' intentional vertical 1 pixel offset between the two waves so that we\r
+' can see them simultaneously.\r
+\r
+SCREEN 12\r
+\r
+' Draw a horizontal baseline\r
+LINE (0, 240)-(640, 240), 15\r
+\r
+' Initialize variables for the sine wave calculation\r
+' r represents the current value of the sine approximation\r
+' r1 represents the rate of change of the sine approximation\r
+LET radius = 0\r
+LET rateOfChange = 1\r
+\r
+' Iterate over each horizontal pixel to calculate and plot the sine values\r
+FOR angleDegrees = 1 TO 639\r
+ ' Calculate the actual sine value using the built-in SIN function\r
+ ' for comparison.\r
+ ' Scale and translate the sine wave to fit within the screen coordinates.\r
+ LET trueSineY = SIN(angleDegrees / 100) * 100 + 240\r
+ PSET (angleDegrees, trueSineY), 15\r
+\r
+ ' Update the rate of change and the radius (sine approximation)\r
+ ' This is a simple implementation of the differential equation\r
+ ' that defines the sine function, effectively integrating over time\r
+ LET rateOfChange = rateOfChange + ((0 - radius) / 10000)\r
+ LET radius = radius + rateOfChange\r
+\r
+ ' Calculate the approximate sine value using our own method\r
+ ' Offset the plot by 241 pixels to display below the true sine wave\r
+ LET approxSineY = radius\r
+ PSET (angleDegrees, approxSineY + 241), 12\r
+NEXT angleDegrees\r
+\r
+' Wait for a key press before ending the program\r
+PRINT "Press any key to exit."\r
+DO UNTIL INKEY$ <> ""\r
+LOOP\r
--- /dev/null
+#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
+#+TITLE: Truth table calculator
+#+LANGUAGE: en
+#+LATEX_HEADER: \usepackage[margin=1.0in]{geometry}
+#+LATEX_HEADER: \usepackage{parskip}
+#+LATEX_HEADER: \usepackage[none]{hyphenat}
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+- See also: https://en.wikipedia.org/wiki/Truth_table
+
+A truth table is a mathematical table used to determine the output of a logic function
+based on all possible combinations of inputs. Each row represents a possible state of
+the input variables, with the corresponding output value. Truth tables are crucial in
+designing and understanding digital circuits, Boolean algebra, and logical expressions.
+
+* Implemented logical operations
+** Equivalent ( ⇔ , 1 )
+
+The equivalent operation, also known as logical biconditional, is true if and only if
+both inputs are the same. In other words, it asserts that both propositions are
+either both true or both false. It is often represented by the symbol *⇔*.
+
+Truth Table:
+
+| A | B | A ⇔ B |
+|---+---+-------|
+| T | T | T |
+| T | F | F |
+| F | T | F |
+| F | F | T |
+
+** Implies ( ⇒ , 2 )
+
+An implication asserts that if the first proposition is true, the
+second must be true as well. If the first is false, the implication
+holds regardless of the second proposition's value.
+
+Truth table:
+
+| A | B | A ⇒ B |
+|---+---+-------|
+| T | T | T |
+| T | F | F |
+| F | T | T |
+| F | F | T |
+
+** OR ( ∨ , 3 )
+
+The OR operation, also known as logical disjunction, is true if at
+least one of the inputs is true. It asserts that if either proposition
+is true, the entire expression is true.
+
+Truth table:
+
+| A | B | A ∨ B |
+|---+---+-------|
+| T | T | T |
+| T | F | T |
+| F | T | T |
+| F | F | F |
+
+** AND ( ∧ , 4 )
+
+The AND operation, also known as logical conjunction, is true if and
+only if both inputs are true.
+
+Truth table:
+
+| A | B | A ∧ B |
+|---+---+-------|
+| T | T | T |
+| T | F | F |
+| F | T | F |
+| F | F | F |
+
+** NOT ( ¬ , 5 )
+
+The NOT operation, also known as logical negation, inverts the value
+of the input. If the input is true, the output is false, and vice
+versa.
+
+Truth Table:
+
+| A | ¬A |
+|---+----|
+| T | F |
+| F | T |
+* Examples
+
+** Example: (A ∧ B) ∨ ¬C
+
+| A | B | C | (A ∧ B) ∨ ¬C |
+|---+---+---+--------------|
+| T | T | T | T |
+| T | T | F | T |
+| T | F | T | F |
+| T | F | F | T |
+| F | T | T | F |
+| F | T | F | T |
+| F | F | T | F |
+| F | F | F | T |
+
+** Example: A ⇒ (B ∨ ¬C)
+
+| A | B | C | A ⇒ (B ∨ ¬C) |
+|---+---+---+--------------|
+| T | T | T | T |
+| T | T | F | T |
+| T | F | T | F |
+| T | F | F | T |
+| F | T | T | T |
+| F | T | F | T |
+| F | F | T | T |
+| F | F | F | T |
+
+** Example: (A ⇔ B) ∧ C
+
+Truth Table:
+
+| A | B | C | (A ⇔ B) ∧ C |
+|---+---+---+-------------|
+| T | T | T | T |
+| T | T | F | F |
+| T | F | T | F |
+| T | F | F | F |
+| F | T | T | F |
+| F | T | F | F |
+| F | F | T | T |
+| F | F | F | F |
--- /dev/null
+' TRUTH TABLE CALCULATOR\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2002, Initial version\r
+' 2024 - 2025, Improved program readability\r
+'\r
+'\r
+' A truth table is a mathematical table used to determine the output of a\r
+' logic function based on all possible combinations of inputs. Each row\r
+' represents a possible state of the input variables, with the\r
+' corresponding output value. Truth tables are crucial in designing and\r
+' understanding digital circuits, Boolean algebra, and logical\r
+' expressions.\r
+'\r
+' Implemented operations:\r
+' Equivalent ( Keyboard shortcut: 1 )\r
+' Implies ( Keyboard shortcut: 2 )\r
+' OR ( Keyboard shortcut: 3 )\r
+' AND ( Keyboard shortcut: 4 )\r
+' NOT ( Keyboard shortcut: 5 )\r
+\r
+DECLARE SUB removeRedundancies (startIndex!, endIndex!, removalCount!)\r
+DECLARE SUB getOperatorPriority (a!, b!)\r
+DECLARE SUB movM (x1!, n!)\r
+DECLARE SUB clearScreenBuffer ()\r
+DECLARE SUB lendm (x1!, m!)\r
+DECLARE SUB mov (x1!, n!)\r
+DECLARE SUB lendp (x1!, m!)\r
+DECLARE SUB teeslg (x1!, x2!, l!)\r
+DECLARE SUB prepare ()\r
+DECLARE SUB tee (x1!, x2!)\r
+DECLARE SUB lahend (x1, x2)\r
+DECLARE SUB printText (x!, y!, c!, c1!, a$)\r
+DECLARE SUB sist ()\r
+DECLARE SUB start ()\r
+DIM SHARED font(0 TO 7, 0 TO 7, 0 TO 122)\r
+\r
+' Logical expression storage and processing arrays\r
+DIM SHARED logicalExpression(0 TO 79) ' Stores ASCII values of logical expression\r
+DIM SHARED variableValues(1 TO 8, 1 TO 100) ' Stores variable values for each combination\r
+DIM SHARED variableNames(1 TO 8) ' Stores ASCII values of variable names\r
+DIM SHARED resultValues(1 TO 100) ' Stores computed result values\r
+DIM SHARED expressionPosition(0 TO 79) ' Stores screen positions of expression characters\r
+DIM SHARED xlahn\r
+DIM SHARED tehl\r
+DIM SHARED nm\r
+DIM SHARED prnp\r
+\r
+start\r
+\r
+13\r
+sist\r
+prepare\r
+GOTO 13\r
+\r
+SUB clearScreenBuffer\r
+' Waits for user input to clear the screen buffer\r
+FOR a = 1 TO 50\r
+ a$ = INKEY$\r
+NEXT a\r
+END SUB\r
+\r
+SUB getOperatorPriority (operator, priority)\r
+' Determines the priority of logical operators\r
+SELECT CASE operator\r
+ CASE 5 ' NOT\r
+ priority = 1\r
+ CASE 3, 4 ' OR, AND\r
+ priority = 2\r
+ CASE 2 ' Implies\r
+ priority = 3\r
+ CASE 1 ' Equivalent\r
+ priority = 4\r
+ CASE 40, 41 ' Parentheses\r
+ priority = 100\r
+END SELECT\r
+END SUB\r
+\r
+\r
+SUB lahend (x1, x2)\r
+' Analyzes and prepares the logical equation for solving\r
+DIM muu(65 TO 122)\r
+FOR a = 65 TO 122\r
+ muu(a) = 0\r
+NEXT a\r
+\r
+muu(116) = 1 ' t\r
+muu(118) = 1 ' v\r
+\r
+nm = 0\r
+FOR a = x1 TO x2\r
+ b = logicalExpression(a)\r
+ IF ((b >= 65) AND (b <= 90)) OR ((b >= 97) AND (b <= 122)) THEN\r
+ IF muu(b) = 0 THEN\r
+ nm = nm + 1\r
+ variableNames(nm) = b\r
+ muu(b) = 1\r
+ END IF\r
+ END IF\r
+NEXT a\r
+\r
+variableNames(nm + 1) = 116 ' t\r
+variableNames(nm + 2) = 118 ' v\r
+\r
+f = 2 ^ nm\r
+tehl = f\r
+FOR a = 1 TO nm\r
+ d = 1\r
+ e = 1\r
+ f = f / 2\r
+ FOR b = 1 TO 2 ^ nm\r
+ IF e > f THEN d = -d: e = 1\r
+ IF d = 1 THEN c = ASC("t") ELSE c = ASC("v")\r
+ variableValues(a, b) = c\r
+ e = e + 1\r
+ NEXT b\r
+NEXT a\r
+\r
+FOR a = 1 TO tehl\r
+ variableValues(nm + 1, a) = 116 ' t\r
+ variableValues(nm + 2, a) = 118 ' v\r
+NEXT a\r
+\r
+nm = nm + 2\r
+\r
+DIM bck(0 TO 79)\r
+FOR a = 0 TO 79\r
+ bck(a) = logicalExpression(a)\r
+ expressionPosition(a) = a\r
+NEXT a\r
+\r
+LOCATE 5, 1\r
+teeslg x1, x2, a\r
+\r
+tee x1, x2 + a\r
+\r
+FOR a = 0 TO 79\r
+ logicalExpression(a) = bck(a)\r
+NEXT a\r
+\r
+FOR a = 1 TO tehl\r
+ printText x2 + 1, a, 14, 0, CHR$(resultValues(a))\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB lendm (x1, m)\r
+' Measures the length of a logical expression enclosed in parentheses\r
+IF logicalExpression(x1) <> 41 THEN m = 1: GOTO 19\r
+c = x1\r
+d = 1\r
+20\r
+c = c - 1\r
+IF logicalExpression(c) = 40 THEN d = d - 1\r
+IF logicalExpression(c) = 41 THEN d = d + 1\r
+IF d > 0 THEN GOTO 20\r
+m = x1 - c\r
+19\r
+END SUB\r
+\r
+SUB lendp (x1, m)\r
+' Measures the length of a logical expression enclosed in parentheses\r
+IF logicalExpression(x1) <> 40 THEN m = 1: GOTO 17\r
+c = x1\r
+d = 1\r
+18\r
+c = c + 1\r
+IF logicalExpression(c) = 40 THEN d = d + 1\r
+IF logicalExpression(c) = 41 THEN d = d - 1\r
+IF d > 0 THEN GOTO 18\r
+m = c - x1 + 1\r
+17\r
+END SUB\r
+\r
+SUB mov (x1, n)\r
+' Moves a portion of the logical expression to the right\r
+FOR a = 79 - n TO x1 STEP -1\r
+ logicalExpression(a + n) = logicalExpression(a)\r
+ expressionPosition(a + n) = expressionPosition(a)\r
+NEXT a\r
+END SUB\r
+\r
+SUB movM (x1, n)\r
+' Moves a portion of the logical expression to the left\r
+FOR a = x1 TO 79 - n\r
+ logicalExpression(a) = logicalExpression(a + n)\r
+ expressionPosition(a) = expressionPosition(a + n)\r
+NEXT a\r
+END SUB\r
+\r
+SUB prepare\r
+' Prepares the logical equation for processing\r
+CLS\r
+\r
+ln = 79\r
+FOR a = 0 TO 79\r
+5\r
+ IF logicalExpression(a) = 32 OR logicalExpression(a) = 0 THEN\r
+ FOR b = a TO 78\r
+ logicalExpression(b) = logicalExpression(b + 1)\r
+ NEXT b\r
+ ln = ln - 1\r
+ IF ln <= a - 1 THEN GOTO 6\r
+ GOTO 5\r
+ END IF\r
+NEXT a\r
+6\r
+\r
+CLS\r
+\r
+FOR a = 0 TO ln\r
+ printText a, 0, 13, 1, CHR$(logicalExpression(a))\r
+NEXT a\r
+\r
+printText 0, 1, 7, 0, SPACE$(79)\r
+\r
+lahend 0, ln\r
+\r
+a$ = INPUT$(1)\r
+\r
+END SUB\r
+\r
+SUB printText (x, y, c, c1, a$)\r
+ ' Prints characters to the screen at location (x,y) with color c, background c1\r
+ x1 = x * 8\r
+ y1 = (y + prnp) * 8\r
+\r
+ FOR b = 1 TO LEN(a$)\r
+ LINE (x1, y1)-(x1 + 7, y1 + 7), c1, BF\r
+ d = ASC(RIGHT$(LEFT$(a$, b), 1))\r
+ IF d > 122 THEN GOTO 22\r
+ FOR y2 = 0 TO 7\r
+ FOR x2 = 0 TO 7\r
+ c2 = font(x2, y2, d)\r
+ IF c2 > 0 THEN PSET (x1 + x2, y1 + y2), c\r
+ NEXT x2\r
+ NEXT y2\r
+22 x1 = x1 + 8\r
+ NEXT b\r
+\r
+END SUB\r
+\r
+SUB removeRedundancies (startIndex, endIndex, removalCount)\r
+ ' This procedure scans for parentheses that can be safely removed\r
+ ' without changing the logic of the expression, then removes them.\r
+\r
+ DIM currentEnd, parenthesesCount\r
+ currentEnd = endIndex\r
+ parenthesesCount = 0\r
+\r
+ a = startIndex\r
+26 IF logicalExpression(a) = 40 THEN\r
+ ' We found an opening parenthesis. Now let's see if it can be removed.\r
+ IF a = startIndex THEN p1 = 100 ELSE getOperatorPriority logicalExpression(a - 1), p1\r
+\r
+ c = a\r
+ d = 1\r
+ p2 = 0\r
+\r
+25 c = c + 1\r
+ IF logicalExpression(c) = 40 THEN d = d + 1\r
+ IF logicalExpression(c) = 41 THEN d = d - 1\r
+\r
+ ' Once d returns to 1, we are back to one level of parentheses,\r
+ ' meaning we can check operator priority inside.\r
+ IF d = 1 THEN\r
+ IF (logicalExpression(c) > 0) AND (logicalExpression(c) <= 5) THEN\r
+ getOperatorPriority logicalExpression(c), b\r
+ IF b > p2 THEN p2 = b\r
+ END IF\r
+ END IF\r
+\r
+ IF d > 0 THEN GOTO 25\r
+\r
+ IF c + 1 > currentEnd THEN p3 = 100 ELSE getOperatorPriority logicalExpression(c + 1), p3\r
+\r
+ ' If the operator outside is higher priority than what's inside,\r
+ ' we can safely remove the parentheses.\r
+ IF (p1 > p2) AND (p3 >= p2) THEN\r
+ movM c, 1\r
+ movM a, 1\r
+ parenthesesCount = parenthesesCount + 2\r
+ currentEnd = currentEnd - 2\r
+ a = a - 1\r
+ END IF\r
+ END IF\r
+\r
+ a = a + 1\r
+ IF a <= currentEnd THEN GOTO 26\r
+\r
+ removalCount = parenthesesCount\r
+END SUB\r
+\r
+SUB sist\r
+' Interacts with the user to input a logical equation\r
+CLS\r
+printText 0, 0, 3, 0, "Enter equation (ESC to quit) keys: 1 - " + CHR$(1) + " 2 - " + CHR$(2) + " 3 - " + CHR$(3) + " 4 - " + CHR$(4) + " 5 - " + CHR$(5)\r
+printText 0, 1, 3, 0, "Example: a" + CHR$(1) + "b" + CHR$(2) + "(g" + CHR$(3) + "b)"\r
+\r
+FOR a = 0 TO 79\r
+ logicalExpression(a) = 0\r
+NEXT a\r
+\r
+x = 0\r
+1\r
+FOR a = 0 TO 79\r
+ IF a = x THEN printText a, 2, 14, 1, CHR$(logicalExpression(a)) ELSE printText a, 2, 3, 0, CHR$(logicalExpression(a))\r
+NEXT a\r
+2\r
+a$ = INKEY$\r
+IF a$ = "" THEN GOTO 2\r
+\r
+IF a$ = CHR$(27) THEN SYSTEM\r
+IF a$ = CHR$(0) + "M" THEN x = x + 1\r
+IF a$ = CHR$(0) + "K" THEN x = x - 1\r
+IF x < 0 THEN x = 0\r
+IF x > 79 THEN x = 79\r
+\r
+IF LEN(a$) = 1 THEN\r
+ SELECT CASE ASC(a$)\r
+ CASE 32, 40, 41, 65 TO 90, 97 TO 122\r
+3\r
+ FOR a = 78 TO x STEP -1\r
+ logicalExpression(a + 1) = logicalExpression(a)\r
+ NEXT a\r
+ logicalExpression(x) = ASC(a$)\r
+ x = x + 1\r
+ CASE 8\r
+ IF x > 0 THEN\r
+ FOR a = x - 1 TO 78\r
+ logicalExpression(a) = logicalExpression(a + 1)\r
+ NEXT a\r
+ x = x - 1\r
+ END IF\r
+ CASE 49 TO 53\r
+ a$ = CHR$(ASC(a$) - 48)\r
+ GOTO 3\r
+ CASE 13\r
+ GOTO 4\r
+ END SELECT\r
+END IF\r
+\r
+GOTO 1\r
+4\r
+\r
+END SUB\r
+\r
+SUB start\r
+' Initializes the screen and font\r
+prnp = 0\r
+\r
+SCREEN 7\r
+\r
+FOR a = 0 TO 122\r
+ LOCATE 1, 1\r
+ SELECT CASE a\r
+ CASE 7\r
+ CASE 1\r
+ LINE (0, 0)-(7, 7), 0, BF\r
+ LINE (2, 1)-(0, 3), 15\r
+ LINE (1, 4)-(2, 5), 15\r
+ LINE (5, 1)-(7, 3), 15\r
+ LINE (6, 4)-(5, 5), 15\r
+ LINE (1, 2)-(5, 2), 15\r
+ LINE (1, 4)-(5, 4), 15\r
+\r
+ CASE 2\r
+ LINE (0, 0)-(7, 7), 0, BF\r
+ LINE (5, 1)-(7, 3), 15\r
+ LINE (6, 4)-(5, 5), 15\r
+ LINE (1, 2)-(5, 2), 15\r
+ LINE (1, 4)-(5, 4), 15\r
+\r
+ CASE 3\r
+ LINE (0, 0)-(7, 7), 0, BF\r
+ LINE (0, 0)-(3, 7), 15\r
+ LINE (6, 0)-(3, 7), 15\r
+\r
+ CASE 4\r
+ LINE (0, 0)-(7, 7), 0, BF\r
+ LINE (0, 7)-(3, 0), 15\r
+ LINE (6, 7)-(3, 0), 15\r
+\r
+ CASE 5\r
+ LINE (0, 0)-(7, 7), 0, BF\r
+ LINE (0, 0)-(4, 0), 15\r
+ LINE (4, 1)-(4, 7), 15\r
+\r
+ CASE ELSE\r
+ PRINT CHR$(a)\r
+ END SELECT\r
+\r
+ FOR y = 0 TO 7\r
+ FOR x = 0 TO 7\r
+ font(x, y, a) = POINT(x, y)\r
+ NEXT x\r
+ NEXT y\r
+NEXT a\r
+\r
+SCREEN 12\r
+\r
+END SUB\r
+\r
+SUB tee (x1, x2)\r
+' Processes the logical equation and applies logical operations\r
+DIM opr(1 TO 2, 1 TO tehl)\r
+ng = 0\r
+ngx = 0\r
+oprm = 1\r
+oe = 0\r
+oex = 0\r
+\r
+FOR a = x1 TO x2\r
+ b = logicalExpression(a)\r
+ SELECT CASE b\r
+ CASE 40\r
+ c = a\r
+ d = 1\r
+10\r
+ c = c + 1\r
+ IF logicalExpression(c) = ASC("(") THEN d = d + 1\r
+ IF logicalExpression(c) = ASC(")") THEN d = d - 1\r
+ IF d = 0 THEN GOTO 11\r
+ GOTO 10\r
+11\r
+ tee a + 1, c - 1\r
+ a = c\r
+ FOR c = 1 TO tehl\r
+ opr(oprm, c) = resultValues(c)\r
+ NEXT c\r
+ GOTO 12\r
+ CASE 5\r
+ ng = 1\r
+ ngx = a\r
+ CASE 1 TO 4\r
+ oe = b\r
+ oex = a\r
+ CASE 65 TO 90, 97 TO 122\r
+ FOR c = 1 TO nm\r
+ IF variableNames(c) = b THEN d = c: GOTO 8\r
+ NEXT c\r
+8\r
+ FOR c = 1 TO tehl\r
+ opr(oprm, c) = variableValues(d, c)\r
+ printText expressionPosition(a), c, 3, 0, CHR$(variableValues(d, c))\r
+ NEXT c\r
+12\r
+ IF ng = 1 THEN GOSUB mkneg\r
+ IF oprm = 2 THEN\r
+ SELECT CASE oe\r
+ CASE 1\r
+ FOR c = 1 TO tehl\r
+ d = opr(1, c)\r
+ e = opr(2, c)\r
+ IF d = e THEN f = ASC("t") ELSE f = ASC("v")\r
+ opr(1, c) = f\r
+ printText expressionPosition(oex), c, 12, 0, CHR$(f)\r
+ NEXT c\r
+ CASE 2\r
+ FOR c = 1 TO tehl\r
+ d = opr(1, c)\r
+ e = opr(2, c)\r
+ f = ASC("t")\r
+ IF (d = ASC("t")) AND (e = ASC("v")) THEN f = ASC("v")\r
+ opr(1, c) = f\r
+ printText expressionPosition(oex), c, 12, 0, CHR$(f)\r
+ NEXT c\r
+ CASE 3\r
+ FOR c = 1 TO tehl\r
+ d = opr(1, c)\r
+ e = opr(2, c)\r
+ f = ASC("t")\r
+ IF (d = ASC("v")) AND (e = ASC("v")) THEN f = ASC("v")\r
+ opr(1, c) = f\r
+ printText expressionPosition(oex), c, 12, 0, CHR$(f)\r
+ NEXT c\r
+ CASE 4\r
+ FOR c = 1 TO tehl\r
+ d = opr(1, c)\r
+ e = opr(2, c)\r
+ f = ASC("v")\r
+ IF (d = ASC("t")) AND (e = ASC("t")) THEN f = ASC("t")\r
+ opr(1, c) = f\r
+ printText expressionPosition(oex), c, 12, 0, CHR$(f)\r
+ NEXT c\r
+ END SELECT\r
+ ELSE\r
+ oprm = oprm + 1\r
+ END IF\r
+ END SELECT\r
+NEXT a\r
+\r
+GOTO 9\r
+\r
+mkneg:\r
+ ' NOT operation (negation) is applied to the current operand\r
+ FOR c = 1 TO tehl\r
+ d = opr(oprm, c)\r
+ IF d = ASC("t") THEN d = ASC("v") ELSE d = ASC("t")\r
+ printText expressionPosition(ngx), c, 4, 0, CHR$(d)\r
+ opr(oprm, c) = d\r
+ NEXT c\r
+ ng = 0\r
+RETURN\r
+9\r
+\r
+FOR c = 1 TO tehl\r
+ resultValues(c) = opr(1, c)\r
+NEXT c\r
+END SUB\r
+\r
+SUB teeslg (x1, x4, l)\r
+' Prepares the logical equation for solving by simplifying expressions within parentheses\r
+x2 = x4\r
+h = 0\r
+FOR e = 1 TO 4\r
+ g = 1\r
+ a = x1\r
+21\r
+ b = logicalExpression(a)\r
+ IF b = 40 THEN\r
+ c = a\r
+ d = 1\r
+14\r
+ c = c + 1\r
+ IF logicalExpression(c) = ASC("(") THEN d = d + 1\r
+ IF logicalExpression(c) = ASC(")") THEN d = d - 1\r
+ IF d = 0 THEN GOTO 15\r
+ GOTO 14\r
+15\r
+ IF e = 1 THEN teeslg a + 1, c - 1, l ELSE l = 0\r
+ a = c + l\r
+ x2 = x2 + l\r
+ h = h + l\r
+ GOTO 16\r
+ END IF\r
+\r
+ IF (b = 5) AND (e = 1) AND (g > 1) THEN\r
+ mov a, 1\r
+ logicalExpression(a) = 40\r
+ lendp a + 2, f\r
+ mov a + 2 + f, 1\r
+ logicalExpression(a + 2 + f) = 41\r
+ h = h + 2\r
+ x2 = x2 + 2\r
+ a = a + 2 + f\r
+ GOTO 16\r
+ END IF\r
+\r
+ IF (b = 3 OR b = 4) AND (e = 2) AND (g > 2) THEN\r
+ lendm a - 1, f\r
+ mov a - f, 1\r
+ logicalExpression(a - f) = 40\r
+ lendp a + 2, f\r
+ mov a + 2 + f, 1\r
+ logicalExpression(a + 2 + f) = 41\r
+ h = h + 2\r
+ x2 = x2 + 2\r
+ a = a + 2 + f\r
+ GOTO 16\r
+ END IF\r
+\r
+ IF (b = 2) AND (e = 3) AND (g > 3) THEN\r
+ lendm a - 1, f\r
+ mov a - f, 1\r
+ logicalExpression(a - f) = 40\r
+ lendp a + 2, f\r
+ mov a + 2 + f, 1\r
+ logicalExpression(a + 2 + f) = 41\r
+ h = h + 2\r
+ x2 = x2 + 2\r
+ a = a + 2 + f\r
+ GOTO 16\r
+ END IF\r
+\r
+ SELECT CASE b\r
+ CASE 5\r
+ g = 1\r
+ CASE 3, 4\r
+ g = 2\r
+ CASE 2\r
+ g = 3\r
+ CASE 1\r
+ g = 4\r
+ END SELECT\r
+16\r
+ a = a + 1\r
+ IF a <= x2 THEN GOTO 21\r
+NEXT e\r
+l = h\r
+END SUB\r
+\r
--- /dev/null
+' 4D engine. It renders a 5-cell (aka. pentachoron) as a series\r
+' of 3D tetrahedrons with varying brightness. Brightness is used\r
+' to indicate shift in the fourth dimension.\r
+'\r
+' In essence, you can look at a 3D object as a series of 2D\r
+' cross-sections along the third dimension. Here we look at\r
+' a 4D object as a series of 3D cross-sections with varying\r
+' brightness (to distinguish between them).\r
+'\r
+' 4 dimensions also make it possible to rotate the object along\r
+' 6 different axes. Interestingly, the shape of the object changes\r
+' in 3D space when it is rotated along any of the axes that\r
+' involve the fourth dimension.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.08, Initial version\r
+' 2024 - 2025, Improved program readability\r
+\r
+' Declare subroutines and functions that will be used in the program\r
+DECLARE SUB CalculateInterpolatedLine (originalX1!, originalY1!, originalZ1!, originalQ1!, originalX2!, originalY2!, originalZ2!, originalQ2!)\r
+DECLARE SUB RotatePoint (x1!, y1!, z1!, q1!, x4!, y4!, z4!, q4!)\r
+DECLARE SUB SetupPalette ()\r
+DECLARE SUB GetPointAtDistance (x1!, y1!, z1!, q1!, x2!, y2!, z2!, q2!, distanceFactor!, rx!, ry!, rz!, rq!)\r
+DECLARE SUB RenderPentachoron (ox1!, oy1!, oz1!, oq1!, ox2!, oy2!, oz2!, oq2!, ox3!, oy3!, oz3!, oq3!, ox4!, oy4!, oz4!, oq4!, ox5!, oy5!, oz5!, oq5!)\r
+DECLARE FUNCTION CalculateDistance (x1!, y1!, z1!, q1!, x2!, y2!, z2!, q2!)\r
+\r
+' Shared variables that can be accessed from any subroutine\r
+DIM SHARED screenSize\r
+DIM SHARED angleXZ, angleYZ, angleXY, angleQX, angleQY, angleQZ\r
+DIM SHARED cameraX, cameraY, cameraZ, cameraQ\r
+DIM SHARED pi\r
+DIM SHARED sineXZ, sineYZ, sineXY, sineQX, sineQY, sineQZ\r
+DIM SHARED cosineXZ, cosineYZ, cosineXY, cosineQX, cosineQY, cosineQZ\r
+\r
+' Arrays to store projected points and other drawing information\r
+DIM SHARED projectedX(1 TO 10)\r
+DIM SHARED projectedY(1 TO 10)\r
+DIM SHARED pointCount\r
+DIM SHARED frame\r
+\r
+' Display control instructions to the user\r
+PRINT ""\r
+PRINT " Use keys:"\r
+PRINT " Rotate:"\r
+PRINT " qw - XZ"\r
+PRINT " as - YZ"\r
+PRINT " zx - XY"\r
+PRINT " er - QX"\r
+PRINT " df - QY"\r
+PRINT " cv - QZ"\r
+PRINT " Move:"\r
+PRINT " 46 - x"\r
+PRINT " 82 - y"\r
+PRINT " 71 - z"\r
+PRINT " -+ - q"\r
+PRINT\r
+PRINT " ESC - to quit program"\r
+PRINT\r
+PRINT " Press any key to continue..."\r
+in$ = INPUT$(1)\r
+\r
+' Initialize pi value for rotation calculations\r
+pi = 3.1415\r
+\r
+' Initialize rotation angles for each axis\r
+angleXZ = pi * .5\r
+angleYZ = angleXZ\r
+angleXY = angleXZ\r
+angleQX = angleXZ\r
+angleQY = angleXZ\r
+angleQZ = angleXZ\r
+\r
+' Set initial camera position in 4D space\r
+cameraX = 0\r
+cameraY = 0\r
+cameraZ = 0\r
+cameraQ = .5\r
+\r
+' Set graphics mode to 640x480 with 16 colors\r
+SCREEN 12\r
+' Setup the color palette for rendering\r
+SetupPalette\r
+\r
+MainLoop:\r
+' Clear screen for new frame\r
+CLS\r
+\r
+' Calculate sine and cosine values for each rotation angle\r
+sineXZ = SIN(angleXZ): cosineXZ = COS(angleXZ)\r
+sineYZ = SIN(angleYZ): cosineYZ = COS(angleYZ)\r
+sineXY = SIN(angleXY): cosineXY = COS(angleXY)\r
+sineQX = SIN(angleQX): cosineQX = COS(angleQX)\r
+sineQY = SIN(angleQY): cosineQY = COS(angleQY)\r
+sineQZ = SIN(angleQZ): cosineQZ = COS(angleQZ)\r
+\r
+' Render multiple frames of the pentachoron with varying depth\r
+FOR frame = 1 TO 15 STEP 3\r
+ ' Render a pentachoron (5-cell) with the current camera position and rotation\r
+ RenderPentachoron -10, -10, -10, 0, 10, -10, -10, 0, 0, -10, 10, 0, 0, 10, 0, 0, 0, 0, 0, 10\r
+NEXT frame\r
+\r
+' Get user input for camera control\r
+in$ = INPUT$(1)\r
+\r
+' Handle user input for rotation and movement\r
+SELECT CASE in$\r
+CASE CHR$(27)\r
+ ' ESC key pressed - exit program\r
+ SYSTEM\r
+CASE "q"\r
+ ' Increase rotation angle along XZ axis\r
+ angleXZ = angleXZ + .1\r
+CASE "w"\r
+ ' Decrease rotation angle along XZ axis\r
+ angleXZ = angleXZ - .1\r
+CASE "a"\r
+ ' Increase rotation angle along YZ axis\r
+ angleYZ = angleYZ + .1\r
+CASE "s"\r
+ ' Decrease rotation angle along YZ axis\r
+ angleYZ = angleYZ - .1\r
+CASE "z"\r
+ ' Increase rotation angle along XY axis\r
+ angleXY = angleXY + .1\r
+CASE "x"\r
+ ' Decrease rotation angle along XY axis\r
+ angleXY = angleXY - .1\r
+CASE "e"\r
+ ' Increase rotation angle along QX axis\r
+ angleQX = angleQX + .1\r
+CASE "r"\r
+ ' Decrease rotation angle along QX axis\r
+ angleQX = angleQX - .1\r
+CASE "d"\r
+ ' Increase rotation angle along QY axis\r
+ angleQY = angleQY + .1\r
+CASE "f"\r
+ ' Decrease rotation angle along QY axis\r
+ angleQY = angleQY - .1\r
+CASE "c"\r
+ ' Increase rotation angle along QZ axis\r
+ angleQZ = angleQZ + .1\r
+CASE "v"\r
+ ' Decrease rotation angle along QZ axis\r
+ angleQZ = angleQZ - .1\r
+\r
+' Handle user input for movement in the 4D space\r
+CASE "4"\r
+ ' Move camera left along X axis\r
+ cameraX = cameraX - 3\r
+CASE "6"\r
+ ' Move camera right along X axis\r
+ cameraX = cameraX + 3\r
+CASE "8"\r
+ ' Move camera forward along Z axis\r
+ cameraZ = cameraZ + 3\r
+CASE "2"\r
+ ' Move camera backward along Z axis\r
+ cameraZ = cameraZ - 3\r
+CASE "7"\r
+ ' Move camera up along Y axis\r
+ cameraY = cameraY + 3\r
+CASE "1"\r
+ ' Move camera down along Y axis\r
+ cameraY = cameraY - 3\r
+CASE "+"\r
+ ' Move camera forward along Q axis (4th dimension)\r
+ cameraQ = cameraQ + .3\r
+CASE "-"\r
+ ' Move camera backward along Q axis (4th dimension)\r
+ cameraQ = cameraQ - .3\r
+\r
+END SELECT\r
+\r
+' Loop back to render next frame\r
+GOTO MainLoop\r
+\r
+' Function to calculate the distance between two points in 4D space\r
+FUNCTION CalculateDistance (x1, y1, z1, q1, x2, y2, z2, q2)\r
+ ' Calculate Euclidean distance in 4D space\r
+ CalculateDistance = SQR((x1 - x2) ^ 2 + (y1 - y2) ^ 2 + (z1 - z2) ^ 2 + (q1 - q2) ^ 2)\r
+END FUNCTION\r
+\r
+' Subroutine to calculate the linear interpolation between two points\r
+SUB CalculateInterpolatedLine (originalX1, originalY1, originalZ1, originalQ1, originalX2, originalY2, originalZ2, originalQ2)\r
+ ' Local variables to store coordinates of the two points\r
+ x1 = originalX1: y1 = originalY1: z1 = originalZ1: q1 = originalQ1\r
+ x2 = originalX2: y2 = originalY2: z2 = originalZ2: q2 = originalQ2\r
+\r
+ ' If the first point is in front of the camera and the second is behind,\r
+ ' swap them to ensure proper rendering order\r
+ IF (q1 > cameraQ) AND (q2 < cameraQ) THEN\r
+ SWAP x1, x2\r
+ SWAP y1, y2\r
+ SWAP z1, z2\r
+ SWAP q1, q2\r
+ END IF\r
+\r
+ ' If the first point is in front of the camera and the second is behind,\r
+ ' calculate the intersection point where the line segment crosses the camera plane\r
+ IF (q1 < cameraQ) AND (q2 > cameraQ) THEN\r
+ ' Calculate the difference in Q coordinates\r
+ qDifference = q2 - q1\r
+ ' Calculate how far along the line segment we need to go to reach the camera plane\r
+ qToCamera = cameraQ - q1\r
+ ' Calculate the interpolation factor\r
+ interpolationFactor = qToCamera / qDifference\r
+ ' Increment point counter\r
+ pointCount = pointCount + 1\r
+ ' Calculate interpolated coordinates\r
+ interpolatedX = (x2 - x1) * interpolationFactor + x1\r
+ interpolatedY = (y2 - y1) * interpolationFactor + y1\r
+ interpolatedZ = (z2 - z1) * interpolationFactor + z1 + 50\r
+ ' Project 3D coordinates to 2D screen coordinates and store them\r
+ projectedX(pointCount) = interpolatedX / interpolatedZ * 700 + 320\r
+ projectedY(pointCount) = interpolatedY / interpolatedZ * 700 + 240\r
+ END IF\r
+END SUB\r
+\r
+' Subroutine to get a point at a specific distance along the line segment\r
+SUB GetPointAtDistance (x1, y1, z1, q1, x2, y2, z2, q2, distanceFactor, rx, ry, rz, rq)\r
+ ' Calculate the vector between the two points\r
+ xVector = x2 - x1\r
+ yVector = y2 - y1\r
+ zVector = z2 - z1\r
+ qVector = q2 - q1\r
+\r
+ ' Calculate the coordinates of the point at the specified distance along the line segment\r
+ rx = x1 + (xVector * distanceFactor)\r
+ ry = y1 + (yVector * distanceFactor)\r
+ rz = z1 + (zVector * distanceFactor)\r
+ rq = q1 + (qVector * distanceFactor)\r
+END SUB\r
+\r
+' Subroutine to render a 3D tetrahedron with varying brightness\r
+SUB RenderPentachoron (originalX1, originalY1, originalZ1, originalQ1, originalX2, originalY2, originalZ2, originalQ2, originalX3, originalY3, originalZ3, originalQ3, originalX4, originalY4, originalZ4, originalQ4, originalX5, originalY5, originalZ5 _\r
+, originalQ5)\r
+\r
+ ' Adjust coordinates based on camera position and frame depth\r
+ originalX1 = originalX1 - cameraX\r
+ originalY1 = originalY1 - cameraY\r
+ originalZ1 = originalZ1 - cameraZ\r
+ originalQ1 = originalQ1 - cameraQ - frame\r
+\r
+ originalX2 = originalX2 - cameraX\r
+ originalY2 = originalY2 - cameraY\r
+ originalZ2 = originalZ2 - cameraZ\r
+ originalQ2 = originalQ2 - cameraQ - frame\r
+\r
+ originalX3 = originalX3 - cameraX\r
+ originalY3 = originalY3 - cameraY\r
+ originalZ3 = originalZ3 - cameraZ\r
+ originalQ3 = originalQ3 - cameraQ - frame\r
+\r
+ originalX4 = originalX4 - cameraX\r
+ originalY4 = originalY4 - cameraY\r
+ originalZ4 = originalZ4 - cameraZ\r
+ originalQ4 = originalQ4 - cameraQ - frame\r
+\r
+ originalX5 = originalX5 - cameraX\r
+ originalY5 = originalY5 - cameraY\r
+ originalZ5 = originalZ5 - cameraZ\r
+ originalQ5 = originalQ5 - cameraQ - frame\r
+\r
+ ' Rotate all points based on current rotation angles\r
+ RotatePoint originalX1, originalY1, originalZ1, originalQ1, x1, y1, z1, q1\r
+ RotatePoint originalX2, originalY2, originalZ2, originalQ2, x2, y2, z2, q2\r
+ RotatePoint originalX3, originalY3, originalZ3, originalQ3, x3, y3, z3, q3\r
+ RotatePoint originalX4, originalY4, originalZ4, originalQ4, x4, y4, z4, q4\r
+ RotatePoint originalX5, originalY5, originalZ5, originalQ5, x5, y5, z5, q5\r
+\r
+ ' Initialize point counter\r
+ pointCount = 0\r
+\r
+ ' Calculate interpolated points for all edges of the pentachoron\r
+ CalculateInterpolatedLine x1, y1, z1, q1, x2, y2, z2, q2\r
+ CalculateInterpolatedLine x1, y1, z1, q1, x3, y3, z3, q3\r
+ CalculateInterpolatedLine x1, y1, z1, q1, x4, y4, z4, q4\r
+ CalculateInterpolatedLine x1, y1, z1, q1, x5, y5, z5, q5\r
+\r
+ CalculateInterpolatedLine x2, y2, z2, q2, x3, y3, z3, q3\r
+ CalculateInterpolatedLine x2, y2, z2, q2, x4, y4, z4, q4\r
+ CalculateInterpolatedLine x2, y2, z2, q2, x5, y5, z5, q5\r
+\r
+ CalculateInterpolatedLine x3, y3, z3, q3, x4, y4, z4, q4\r
+ CalculateInterpolatedLine x3, y3, z3, q3, x5, y5, z5, q5\r
+\r
+ CalculateInterpolatedLine x4, y4, z4, q4, x5, y5, z5, q5\r
+\r
+ ' Draw lines between each pair of interpolated points\r
+ FOR pointA = 1 TO pointCount\r
+ FOR pointB = pointA + 1 TO pointCount\r
+ ' Draw line with color based on frame depth (for varying brightness)\r
+ LINE (projectedX(pointA), projectedY(pointA))-(projectedX(pointB), projectedY(pointB)), 15 - frame\r
+ NEXT pointB\r
+ NEXT pointA\r
+\r
+END SUB\r
+\r
+' Subroutine to rotate a point along the specified axes\r
+SUB RotatePoint (x1, y1, z1, q1, x4, y4, z4, q4)\r
+\r
+ ' Rotate the point along the QX axis\r
+ q2 = q1 * sineQX - x1 * cosineQX\r
+ x2 = q1 * cosineQX + x1 * sineQX\r
+\r
+ ' Rotate the point along the QY axis\r
+ q3 = q2 * sineQY - y1 * cosineQY\r
+ y2 = q2 * cosineQY + y1 * sineQY\r
+\r
+ ' Rotate the point along the QZ axis\r
+ q4 = q3 * sineQZ - z1 * cosineQZ\r
+ z2 = q3 * cosineQZ + z1 * sineQZ\r
+\r
+ ' Rotate the point along the XZ axis\r
+ x3 = x2 * sineXZ - z2 * cosineXZ\r
+ z3 = x2 * cosineXZ + z2 * sineXZ\r
+\r
+ ' Rotate the point along the YZ axis\r
+ y3 = y2 * sineYZ - z3 * cosineYZ\r
+ z4 = y2 * cosineYZ + z3 * sineYZ\r
+\r
+ ' Rotate the point along the XY axis\r
+ y4 = y3 * sineXY - x3 * cosineXY\r
+ x4 = y3 * cosineXY + x3 * sineXY\r
+\r
+END SUB\r
+\r
+' Subroutine to set up the color palette\r
+SUB SetupPalette\r
+\r
+ ' Set up a grayscale color palette\r
+ FOR colorIndex = 0 TO 15\r
+ ' Set palette register\r
+ OUT &H3C8, colorIndex\r
+ ' Set RGB values (all equal for grayscale)\r
+ OUT &H3C9, colorIndex * 4\r
+ OUT &H3C9, colorIndex * 4\r
+ OUT &H3C9, colorIndex * 4\r
+ ' Draw a vertical line with this color to visualize the palette\r
+ LINE (colorIndex, 0)-(colorIndex, 400), colorIndex\r
+ NEXT colorIndex\r
+\r
+END SUB\r
+\r
--- /dev/null
+' Program to play sound that resembles security alarm.\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' ?, Initial version\r
+' 2024 - 2025, Enhanced program readability\r
+\r
+SCREEN 1\r
+CLS\r
+\r
+' Initialize main frequency control variable\r
+' This will create the oscillating siren effect by increasing/decreasing value\r
+currentFrequency = 40\r
+\r
+StartLoop:\r
+ ' Play primary oscillating tone (main siren component)\r
+ ' Frequency sweeps up and down between thresholds\r
+ SOUND currentFrequency, .3\r
+\r
+ ' Add secondary fixed-frequency component (200Hz for 1 duration unit)\r
+ ' Creates layered audio effect that makes alarm more realistic\r
+ ' Duration parameter uses QBasic's time units (1 ≈ 0.05 seconds)\r
+ SOUND 200, 1\r
+\r
+ ' Rapidly increase frequency for ascending siren sweep\r
+ ' Jump amount (100) creates dramatic pitch jumps\r
+ currentFrequency = currentFrequency + 100\r
+\r
+ ' Check if we've exceeded upper frequency threshold (1000Hz)\r
+ ' If yes, switch to descending phase\r
+ IF currentFrequency > 1000 THEN GoTo DecreaseFrequency\r
+\r
+ ' Repeat ascending sweep until reaching maximum threshold\r
+ GOTO StartLoop\r
+\r
+DecreaseFrequency:\r
+ ' Continue playing oscillating tone during descending phase\r
+ SOUND currentFrequency, .3\r
+\r
+ ' Add high-pitched pulse (500Hz for short duration)\r
+ ' Creates distinctive alarm "warble" pattern\r
+ ' Shorter duration (.2) adds rhythmic pulsing\r
+ SOUND 500, .2\r
+\r
+ ' Gradually decrease frequency for descending sweep\r
+ ' Smaller decrement (10) creates slower descent than ascent\r
+ currentFrequency = currentFrequency - 10\r
+\r
+ ' Check if we've dropped below lower threshold (200Hz)\r
+ ' If yes, restart ascending phase to complete siren cycle\r
+ IF currentFrequency < 200 THEN GoTo StartLoop\r
+\r
+ ' Continue descending sweep until reaching minimum threshold\r
+ GOTO DecreaseFrequency\r
--- /dev/null
+' This program generates a security alarm sound effect with two alternating patterns\r
+\r
+DEFINT A-Z\r
+\r
+' Start of infinite alarm cycle\r
+1\r
+\r
+ ' Pattern 1: Ascending frequency sweep with counterpoint tone\r
+ ' Increase primary frequency from 100Hz to 1000Hz in steps of 3Hz\r
+ FOR ascendingFrequency = 100 TO 1000 STEP 3\r
+ ' Play main ascending tone\r
+ SOUND ascendingFrequency, .05\r
+\r
+ ' Generate counterpoint tone that decreases as primary increases\r
+ ' Formula creates complementary frequency by subtracting double current frequency\r
+ ' At 100Hz -> 5000-2*100=4800Hz; At 1000Hz -> 5000-2*1000=3000Hz\r
+ counterToneFrequency = 5000 - (ascendingFrequency * 2)\r
+ SOUND counterToneFrequency, .1\r
+ NEXT ascendingFrequency\r
+\r
+ ' Pattern 2: Descending frequency sweep with harmonic enhancement\r
+ ' Decrease frequency from 1000Hz back to 100Hz in larger steps (-5)\r
+ FOR descendingFrequency = 1000 TO 100 STEP -5\r
+ ' Play main descending tone \r
+ SOUND descendingFrequency, .05\r
+\r
+ ' Add harmonic overtone at triple frequency plus small offset\r
+ ' Creates richer, more complex sound texture\r
+ harmonicFrequency = (descendingFrequency * 3) + 10\r
+ SOUND harmonicFrequency, .05\r
+ NEXT descendingFrequency\r
+\r
+' Continuously repeat between both sound patterns\r
+GOTO 1\r
--- /dev/null
+' Program attempts to render imaginary alien text.\r
+' Text is composed by subdividing square into 4 triangles.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2001, Initial version.\r
+' 2024.08, Improved code readability.\r
+\r
+DEFINT A-Z\r
+\r
+' Declare the subroutine which will draw a character at a given position with a given size and color\r
+DECLARE SUB DrawCharacter (characterX, characterY, characterColor, CharacterSize)\r
+\r
+' Define shared array for colors\r
+DIM SHARED characterColors(1 TO 4) AS INTEGER\r
+\r
+' Initialize the color palette\r
+characterColors(1) = 7 ' LightGray\r
+characterColors(2) = 7 ' LightGray\r
+characterColors(3) = 0 ' Black\r
+characterColors(4) = 0 ' Black\r
+\r
+' Set the screen mode and seed the random number generator\r
+SCREEN 12\r
+RANDOMIZE TIMER\r
+\r
+' Clear the screen with black color\r
+PAINT (1, 1), 0\r
+\r
+' Define the size of each character\r
+CONST CharacterSize = 4\r
+\r
+' Initialize counters for drawing characters\r
+DIM tmp AS INTEGER\r
+tmp = 0\r
+\r
+' Outer loop for vertical positioning of characters\r
+FOR characterY = 1 TO 480 - CharacterSize - 2 STEP CharacterSize + (CharacterSize \ 2)\r
+ DIM tmp1 AS INTEGER\r
+ tmp1 = 0\r
+\r
+ ' Inner loop for horizontal positioning of characters\r
+ FOR characterX = 1 TO 640 - CharacterSize - 2 STEP CharacterSize + (CharacterSize \ 2)\r
+ ' Draw a character with random color and specified size at the current position\r
+ CALL DrawCharacter(characterX, characterY, INT(RND * 16), CharacterSize)\r
+\r
+ ' Increment the inner loop counter\r
+ tmp1 = tmp1 + 1\r
+\r
+ ' Add spaces to emulate visual character clusters\r
+ IF tmp1 > 20 THEN\r
+ tmp1 = 0\r
+ characterX = characterX + (CharacterSize)\r
+ END IF\r
+ NEXT characterX\r
+\r
+ ' Increment the outer loop counter\r
+ tmp = tmp + 1\r
+\r
+ ' Add space to group caracters visually into clusters\r
+ IF tmp > 5 THEN\r
+ tmp = 0\r
+ characterY = characterY + (CharacterSize)\r
+ END IF\r
+NEXT characterY\r
+\r
+' Subroutine to draw a character at a given position with a given size and color\r
+SUB DrawCharacter (characterX AS INTEGER, characterY AS INTEGER, characterColor AS INTEGER, CharacterSize AS INTEGER)\r
+ ' Calculate half the size of the character for drawing diagonals\r
+ DIM halfSize AS INTEGER\r
+ halfSize = CharacterSize \ 2\r
+\r
+ ' Randomly select a color from the palette\r
+ DIM randomColor AS INTEGER\r
+ randomColor = characterColors(INT(RND * 3) + 1)\r
+\r
+ ' Draw the top horizontal line and diagonals of the character\r
+ LINE (characterX, characterY)-(characterX + CharacterSize, characterY), randomColor\r
+ LINE (characterX, characterY)-(characterX + halfSize, characterY + halfSize), randomColor\r
+ LINE (characterX + CharacterSize, characterY)-(characterX + halfSize, characterY + halfSize), randomColor\r
+ ' Fill the top right corner of the character\r
+ PAINT (characterX + 2, characterY + 1), randomColor\r
+\r
+ ' Draw the left vertical line and diagonals of the character\r
+ randomColor = characterColors(INT(RND * 3) + 1)\r
+ LINE (characterX, characterY)-(characterX, characterY + CharacterSize), randomColor\r
+ LINE (characterX, characterY)-(characterX + halfSize, characterY + halfSize), randomColor\r
+ LINE (characterX, characterY + CharacterSize)-(characterX + halfSize, characterY + halfSize), randomColor\r
+ ' Fill the middle left of the character\r
+ PAINT (characterX + 1, characterY + 2), randomColor\r
+\r
+ ' Draw the right vertical line and diagonals of the character\r
+ randomColor = characterColors(INT(RND * 3) + 1)\r
+ LINE (characterX + CharacterSize, characterY)-(characterX + CharacterSize, characterY + CharacterSize), randomColor\r
+ LINE (characterX + CharacterSize, characterY)-(characterX + halfSize, characterY + halfSize), randomColor\r
+ LINE (characterX + CharacterSize, characterY + CharacterSize)-(characterX + halfSize, characterY + halfSize), randomColor\r
+ ' Fill the middle right of the character\r
+ PAINT (characterX + CharacterSize - 1, characterY + 2), randomColor\r
+\r
+ ' Draw the bottom horizontal line and diagonals of the character\r
+ randomColor = characterColors(INT(RND * 3) + 1)\r
+ LINE (characterX, characterY + CharacterSize)-(characterX + CharacterSize, characterY + CharacterSize), randomColor\r
+ LINE (characterX, characterY + CharacterSize)-(characterX + halfSize, characterY + halfSize), randomColor\r
+ LINE (characterX + CharacterSize, characterY + CharacterSize)-(characterX + halfSize, characterY + halfSize), randomColor\r
+ ' Fill the bottom left corner of the character\r
+ PAINT (characterX + 2, characterY + CharacterSize - 1), randomColor\r
+END SUB\r
+\r
--- /dev/null
+<!doctype html>
+<html lang="en">
+<head>
+<title>juhend</title>
+<!-- 2018-04-20 Fri 11:08 -->
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<meta name="generator" content="Org-mode">
+<meta name="author" content="Svjatoslav Agejenko">
+
+<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
+<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/js/bootstrap.min.js"></script>
+<style type="text/css">
+/* org mode styles on top of twbs */
+
+html {
+ position: relative;
+ min-height: 100%;
+}
+
+body {
+ font-size: 18px;
+ margin-bottom: 105px;
+}
+
+footer {
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ height: 101px;
+ background-color: #f5f5f5;
+}
+
+footer > div {
+ padding: 10px;
+}
+
+footer p {
+ margin: 0 0 5px;
+ text-align: center;
+ font-size: 16px;
+}
+
+#table-of-contents {
+ margin-top: 20px;
+ margin-bottom: 20px;
+}
+
+blockquote p {
+ font-size: 18px;
+}
+
+pre {
+ font-size: 16px;
+}
+
+.footpara {
+ display: inline-block;
+}
+
+figcaption {
+ font-size: 16px;
+ color: #666;
+ font-style: italic;
+ padding-bottom: 15px;
+}
+
+/* from twbs docs */
+
+.bs-docs-sidebar.affix {
+ position: static;
+}
+@media (min-width: 768px) {
+ .bs-docs-sidebar {
+ padding-left: 20px;
+ }
+}
+
+/* All levels of nav */
+.bs-docs-sidebar .nav > li > a {
+ display: block;
+ padding: 4px 20px;
+ font-size: 14px;
+ font-weight: 500;
+ color: #999;
+}
+.bs-docs-sidebar .nav > li > a:hover,
+.bs-docs-sidebar .nav > li > a:focus {
+ padding-left: 19px;
+ color: #A1283B;
+ text-decoration: none;
+ background-color: transparent;
+ border-left: 1px solid #A1283B;
+}
+.bs-docs-sidebar .nav > .active > a,
+.bs-docs-sidebar .nav > .active:hover > a,
+.bs-docs-sidebar .nav > .active:focus > a {
+ padding-left: 18px;
+ font-weight: bold;
+ color: #A1283B;
+ background-color: transparent;
+ border-left: 2px solid #A1283B;
+}
+
+/* Nav: second level (shown on .active) */
+.bs-docs-sidebar .nav .nav {
+ display: none; /* Hide by default, but at >768px, show it */
+ padding-bottom: 10px;
+}
+.bs-docs-sidebar .nav .nav > li > a {
+ padding-top: 1px;
+ padding-bottom: 1px;
+ padding-left: 30px;
+ font-size: 12px;
+ font-weight: normal;
+}
+.bs-docs-sidebar .nav .nav > li > a:hover,
+.bs-docs-sidebar .nav .nav > li > a:focus {
+ padding-left: 29px;
+}
+.bs-docs-sidebar .nav .nav > .active > a,
+.bs-docs-sidebar .nav .nav > .active:hover > a,
+.bs-docs-sidebar .nav .nav > .active:focus > a {
+ padding-left: 28px;
+ font-weight: 500;
+}
+
+/* Nav: third level (shown on .active) */
+.bs-docs-sidebar .nav .nav .nav {
+ padding-bottom: 10px;
+}
+.bs-docs-sidebar .nav .nav .nav > li > a {
+ padding-top: 1px;
+ padding-bottom: 1px;
+ padding-left: 40px;
+ font-size: 12px;
+ font-weight: normal;
+}
+.bs-docs-sidebar .nav .nav .nav > li > a:hover,
+.bs-docs-sidebar .nav .nav .nav > li > a:focus {
+ padding-left: 39px;
+}
+.bs-docs-sidebar .nav .nav .nav > .active > a,
+.bs-docs-sidebar .nav .nav .nav > .active:hover > a,
+.bs-docs-sidebar .nav .nav .nav > .active:focus > a {
+ padding-left: 38px;
+ font-weight: 500;
+}
+
+/* Show and affix the side nav when space allows it */
+@media (min-width: 992px) {
+ .bs-docs-sidebar .nav > .active > ul {
+ display: block;
+ }
+ /* Widen the fixed sidebar */
+ .bs-docs-sidebar.affix,
+ .bs-docs-sidebar.affix-bottom {
+ width: 213px;
+ }
+ .bs-docs-sidebar.affix {
+ position: fixed; /* Undo the static from mobile first approach */
+ top: 20px;
+ }
+ .bs-docs-sidebar.affix-bottom {
+ position: absolute; /* Undo the static from mobile first approach */
+ }
+ .bs-docs-sidebar.affix .bs-docs-sidenav,.bs-docs-sidebar.affix-bottom .bs-docs-sidenav {
+ margin-top: 0;
+ margin-bottom: 0
+ }
+}
+@media (min-width: 1200px) {
+ /* Widen the fixed sidebar again */
+ .bs-docs-sidebar.affix-bottom,
+ .bs-docs-sidebar.affix {
+ width: 263px;
+ }
+}
+</style>
+<script type="text/javascript">
+$(function() {
+ 'use strict';
+
+ $('.bs-docs-sidebar li').first().addClass('active');
+
+ $(document.body).scrollspy({target: '.bs-docs-sidebar'});
+
+ $('.bs-docs-sidebar').affix();
+});
+</script>
+</head>
+<body>
+<div id="content" class="container">
+<div class="row"><div class="col-md-9"><h1 class="title">juhend</h1>
+<p>
+Kooli Kell programmi kasutusjuhend
+</p>
+
+<ul class="org-ul">
+<li>2002.10
+</li>
+<li>Svjatoslav Agejenko
+</li>
+</ul>
+
+
+<div id="outline-container-sec-1" class="outline-2">
+<h2 id="sec-1"><span class="section-number-2">1</span> Kasutajaliides</h2>
+<div class="outline-text-2" id="text-1">
+<p>
+Programm Kooli Kell on mõldud kella laskmiseks koolis, tundi sisse ja
+välja. Samuti juhib programm arvuti küljes olevat liidest,
+kahekohaliste numbrite näitamiseks (minutid / tunnid), 3 klahvilist
+klaviatuuri ja releed. Tundi sisse minev kell on 1 pikk ning 1 l”em
+helin. Väljaminev kell on 1 tavaline pikk helin. Programm loeb aega
+arvuti süsteemsest kellast. Kella laskmis ajad on organiseeritud
+failidesse *.PP . Aasta või päevaplaani muutmiseks tuleb redakteerida
+vastavaid faile. Programm valib sobiva päevaplaani lähtudes
+aastaplaanist, mis asub failis "aasta.ap" . Programmi saab kasutada
+arvutil millele on printeri pesasse (LPT1) ”endatud spetsiaalne
+liides, liidese skeem on failis "skeem.bmp". Liides omab kolme
+nummerdatud nuppu paigutusega:
+</p>
+
+<p class="verse">
+<1> <2><br >
+   <3><br >
+</p>
+
+<p>
+Programm on ettenähtud iseseisvalt töötama, kuid on ka võimalus
+erandkorras kгitsi kella lasta, aega muuta jne.. Programm eristab
+tavalisi nupuvajutusi ja topeltklõpse. Eesmärgiga suurendada
+funktsionaalsust väheste nuppudega.
+</p>
+</div>
+
+<div id="outline-container-sec-1-1" class="outline-3">
+<h3 id="sec-1-1"><span class="section-number-3">1.1</span> Nuppude funktsioonid peamenüüs:</h3>
+<div class="outline-text-3" id="text-1-1">
+<dl class="org-dl">
+<dt> <1> klõps </dt><dd>laseb kella tundi sisse
+</dd>
+<dt> <1> topeltklõps </dt><dd>laseb kella tunnist välja
+</dd>
+
+<dt> <2> klõps </dt><dd>läheb aja muutmis menüüsse
+</dd>
+<dt> <3> topeltklõps </dt><dd>hakkab tööle uuendatud graafikuga, vajalik pвast
+sisendfailide redigeerimist.
+</dd>
+
+<dt> <3> klõps </dt><dd>ümardab süsteemse aja täistunnini, vajalik aja
+sünkroniseerimiseks.
+</dd>
+<dt> <3> topeltklõps </dt><dd>laeb süsteemse: aasta, kuu, päeva, tunnid,
+minutid failist "sync.txt"
+</dd>
+</dl>
+</div>
+</div>
+
+<div id="outline-container-sec-1-2" class="outline-3">
+<h3 id="sec-1-2"><span class="section-number-3">1.2</span> Nuppude funktsioonid aja muutmis menüüs:</h3>
+<div class="outline-text-3" id="text-1-2">
+<dl class="org-dl">
+<dt> <1> klõps </dt><dd>vähendab süsteemsed tunnid/minutid 1. võrra
+</dd>
+
+<dt> <2> klõps </dt><dd>suurendab süsteemsed tunnid/minutid 1. võrra
+</dd>
+
+<dt> <3> klõps </dt><dd>valib näitamiseks ja redigeerimiseks tunnid või minutid.
+</dd>
+<dt> <3> topeltklõps </dt><dd>läheb tagasi peamenüüsse.
+</dd>
+</dl>
+
+<p>
+Aja muutmis menüüd tunneb ära selle järgi et indikaator tunnid või
+minutid vilgub, mitte ei põle nagu peamenüüs.
+</p>
+</div>
+</div>
+</div>
+
+
+<div id="outline-container-sec-2" class="outline-2">
+<h2 id="sec-2"><span class="section-number-2">2</span> Faili AASTA.AP formaat: (aastaplaan)</h2>
+<div class="outline-text-2" id="text-2">
+<pre class="example">
+v <kuu>-<päev> <kuu>-<päev> <päevaplaan>
+</pre>
+
+<p>
+Sõnast aja vahemik. Paneb paika päevaplaani antud
+ajavahemikus. Esimene daatum peab kindlasti olema väiksem kui
+teine. St. kui on tõesti vaja:
+</p>
+
+<pre class="example">
+v 10-4 2-1 eri
+</pre>
+
+<p>
+tuleb kirjutada:
+</p>
+
+<pre class="example">
+v 10-4 12-31 eri
+v 1-1 2-1 eri
+</pre>
+
+<p>
+Päevaplaan kehtib vahemiku esimesest päevast kuni vahemiku viimase
+päevani.
+</p>
+
+
+<pre class="example">
+n <kuu>-<päev> <kuu>-<päev> <nädalapäev> <päevaplaan>
+</pre>
+
+<p>
+Sõnast nädalapäv. sama mis "v" kuid: paneb paika päevaplaani antud
+ajavahemikus, antud nädalapäeval. Nädalapäeva kirjeldatakse numbriga.
+nädala esimene päev on esmaspäev, talle vastab number 1.
+</p>
+
+
+<pre class="example">
+e <kuu>-<päev> <päevaplaan>
+</pre>
+
+<p>
+Sõnast eriline. Paneb paika antud kuupävale antud pävaplaani. Sobib
+hästi erakorraliste lüendatud või muul moel muudetud päevaplaanide
+kehtestamiseks. Näiteks riigipühad, spordipäev jne.
+</p>
+
+<p>
+Kui teatud päeva kohta ei käinud ühtegi kirjet siis toimib vaikimisi
+"tuhi" päevaplaan. Kui teatud päeva kohta käis mitu kirjet siis jääb
+peale viimane.
+</p>
+</div>
+</div>
+
+
+
+<div id="outline-container-sec-3" class="outline-2">
+<h2 id="sec-3"><span class="section-number-2">3</span> Failide *.PP formaat: (päevaplaanid)</h2>
+<div class="outline-text-2" id="text-3">
+<pre class="example">
+# <tund>:<minut> <kell>
+</pre>
+
+<p>
+Laseb antud ajal antud kella. Võimalikud kella helinad on:
+</p>
+
+<table class="table table-striped table-bordered table-hover table-condensed">
+
+
+<colgroup>
+<col class="left">
+
+<col class="left">
+</colgroup>
+<thead>
+<tr>
+<th scope="col" class="text-left">kella kood</th>
+<th scope="col" class="text-left">vastav helin</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="text-left">sis</td>
+<td class="text-left">kell tundi sisse</td>
+</tr>
+
+<tr>
+<td class="text-left">val</td>
+<td class="text-left">kell tunnist välja</td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+
+<div id="outline-container-sec-4" class="outline-2">
+<h2 id="sec-4"><span class="section-number-2">4</span> Faili SYNC.TXT formaat:</h2>
+<div class="outline-text-2" id="text-4">
+<p>
+faili esimesel kahel real peab olema järgnev:
+</p>
+
+<pre class="example">
+KK-PP-AAAA
+TT:MM
+</pre>
+
+<p>
+kus:
+</p>
+<table class="table table-striped table-bordered table-hover table-condensed">
+
+
+<colgroup>
+<col class="left">
+
+<col class="left">
+</colgroup>
+<thead>
+<tr>
+<th scope="col" class="text-left">kood</th>
+<th scope="col" class="text-left">tähendus</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="text-left">KK</td>
+<td class="text-left">kuu</td>
+</tr>
+
+<tr>
+<td class="text-left">PP</td>
+<td class="text-left">päev</td>
+</tr>
+
+<tr>
+<td class="text-left">AAAA</td>
+<td class="text-left">aasta</td>
+</tr>
+
+<tr>
+<td class="text-left">TT</td>
+<td class="text-left">tunnid</td>
+</tr>
+
+<tr>
+<td class="text-left">MM</td>
+<td class="text-left">minutid</td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+</div><div class="col-md-3"><nav id="table-of-contents">
+<div id="text-table-of-contents" class="bs-docs-sidebar">
+<ul class="nav">
+<li><a href="#sec-1">1. Kasutajaliides</a>
+<ul class="nav">
+<li><a href="#sec-1-1">1.1. Nuppude funktsioonid peamenüüs:</a></li>
+<li><a href="#sec-1-2">1.2. Nuppude funktsioonid aja muutmis menüüs:</a></li>
+</ul>
+</li>
+<li><a href="#sec-2">2. Faili AASTA.AP formaat: (aastaplaan)</a></li>
+<li><a href="#sec-3">3. Failide *.PP formaat: (päevaplaanid)</a></li>
+<li><a href="#sec-4">4. Faili SYNC.TXT formaat:</a></li>
+</ul>
+</div>
+</nav>
+</div></div></div>
+<footer id="postamble" class="">
+<div><p class="author">Author: Svjatoslav Agejenko</p>
+<p class="date">Created: 2018-04-20 Fri 11:08</p>
+<p class="creator"><a href="http://www.gnu.org/software/emacs/">Emacs</a> 25.1.1 (<a href="http://orgmode.org">Org-mode</a> 8.2.10)</p>
+</div>
+</footer>
+</body>
+</html>
--- /dev/null
+Kooli Kell programmi kasutusjuhend
+
+- 2002.10
+- Svjatoslav Agejenko
+
+
+* Kasutajaliides
+Programm Kooli Kell on mõldud kella laskmiseks koolis, tundi sisse ja
+välja. Samuti juhib programm arvuti küljes olevat liidest,
+kahekohaliste numbrite näitamiseks (minutid / tunnid), 3 klahvilist
+klaviatuuri ja releed. Tundi sisse minev kell on 1 pikk ning 1 l”em
+helin. Väljaminev kell on 1 tavaline pikk helin. Programm loeb aega
+arvuti süsteemsest kellast. Kella laskmis ajad on organiseeritud
+failidesse *.PP . Aasta või päevaplaani muutmiseks tuleb redakteerida
+vastavaid faile. Programm valib sobiva päevaplaani lähtudes
+aastaplaanist, mis asub failis "aasta.ap" . Programmi saab kasutada
+arvutil millele on printeri pesasse (LPT1) ”endatud spetsiaalne
+liides, liidese skeem on failis "skeem.bmp". Liides omab kolme
+nummerdatud nuppu paigutusega:
+
+#+BEGIN_VERSE
+ <1> <2>
+ <3>
+#+END_VERSE
+
+Programm on ettenähtud iseseisvalt töötama, kuid on ka võimalus
+erandkorras kгitsi kella lasta, aega muuta jne.. Programm eristab
+tavalisi nupuvajutusi ja topeltklõpse. Eesmärgiga suurendada
+funktsionaalsust väheste nuppudega.
+
+** Nuppude funktsioonid peamenüüs:
+
++ <1> klõps :: laseb kella tundi sisse
++ <1> topeltklõps :: laseb kella tunnist välja
+
++ <2> klõps :: läheb aja muutmis menüüsse
++ <3> topeltklõps :: hakkab tööle uuendatud graafikuga, vajalik pвast
+ sisendfailide redigeerimist.
+
++ <3> klõps :: ümardab süsteemse aja täistunnini, vajalik aja
+ sünkroniseerimiseks.
++ <3> topeltklõps :: laeb süsteemse: aasta, kuu, päeva, tunnid,
+ minutid failist "sync.txt"
+
+** Nuppude funktsioonid aja muutmis menüüs:
+
++ <1> klõps :: vähendab süsteemsed tunnid/minutid 1. võrra
+
++ <2> klõps :: suurendab süsteemsed tunnid/minutid 1. võrra
+
++ <3> klõps :: valib näitamiseks ja redigeerimiseks tunnid või minutid.
++ <3> topeltklõps :: läheb tagasi peamenüüsse.
+
+Aja muutmis menüüd tunneb ära selle järgi et indikaator tunnid või
+minutid vilgub, mitte ei põle nagu peamenüüs.
+
+* Faili AASTA.AP formaat: (aastaplaan)
+: v <kuu>-<päev> <kuu>-<päev> <päevaplaan>
+
+Sõnast aja vahemik. Paneb paika päevaplaani antud
+ajavahemikus. Esimene daatum peab kindlasti olema väiksem kui
+teine. St. kui on tõesti vaja:
+
+: v 10-4 2-1 eri
+
+tuleb kirjutada:
+
+: v 10-4 12-31 eri
+: v 1-1 2-1 eri
+
+Päevaplaan kehtib vahemiku esimesest päevast kuni vahemiku viimase
+päevani.
+
+
+: n <kuu>-<päev> <kuu>-<päev> <nädalapäev> <päevaplaan>
+
+Sõnast nädalapäv. sama mis "v" kuid: paneb paika päevaplaani antud
+ajavahemikus, antud nädalapäeval. Nädalapäeva kirjeldatakse numbriga.
+nädala esimene päev on esmaspäev, talle vastab number 1.
+
+
+: e <kuu>-<päev> <päevaplaan>
+
+Sõnast eriline. Paneb paika antud kuupävale antud pävaplaani. Sobib
+hästi erakorraliste lüendatud või muul moel muudetud päevaplaanide
+kehtestamiseks. Näiteks riigipühad, spordipäev jne.
+
+Kui teatud päeva kohta ei käinud ühtegi kirjet siis toimib vaikimisi
+"tuhi" päevaplaan. Kui teatud päeva kohta käis mitu kirjet siis jääb
+peale viimane.
+
+* Failide *.PP formaat: (päevaplaanid)
+: # <tund>:<minut> <kell>
+
+Laseb antud ajal antud kella. Võimalikud kella helinad on:
+
+| kella kood | vastav helin |
+|------------+--------------------|
+| sis | kell tundi sisse |
+| val | kell tunnist välja |
+
+* Faili SYNC.TXT formaat:
+faili esimesel kahel real peab olema järgnev:
+
+: KK-PP-AAAA
+: TT:MM
+
+kus:
+| kood | tähendus |
+|------+----------|
+| KK | kuu |
+| PP | päev |
+| AAAA | aasta |
+| TT | tunnid |
+| MM | minutid |
--- /dev/null
+v 01-01 12-31 tava\r
+n 01-01 12-31 5 reede\r
+e 10-04 opetajap\r
+e 10-31 rebased\r
+n 01-01 12-31 6 tuhi\r
+n 01-01 12-31 7 tuhi\r
+\r
--- /dev/null
+coff\r
+qb /run kk.bas
\ No newline at end of file
--- /dev/null
+mov dx, 37Ah\r
+mov al, 0\r
+out dx, al\r
+ret
\ No newline at end of file
--- /dev/null
+DECLARE SUB jooks ()\r
+DECLARE SUB suva ()\r
+DECLARE SUB display ()\r
+DECLARE SUB clearBits ()\r
+DEFINT A-Z\r
+DIM SHARED bit(0 TO 16)\r
+\r
+suva\r
+jooks\r
+\r
+clearBits\r
+bit(10) = 0\r
+bit(14) = 0\r
+bit(6) = 0\r
+bit(2) = 0\r
+4\r
+GOTO 4\r
+\r
+SUB clearBits\r
+' This subroutine initializes all bits in the bit array to 1\r
+FOR a = 1 TO 16\r
+ bit(a) = 1\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB display\r
+' This subroutine displays the current state of the bit array using LPT attached display\r
+prt = &H378\r
+d = 0\r
+FOR a = 0 TO 3\r
+ c = 2 ^ a\r
+ FOR b = 4 TO 7\r
+ d = d + 1\r
+ c = c + (bit(d) * 2 ^ b)\r
+ NEXT b\r
+\r
+ OUT prt, c\r
+NEXT a\r
+END SUB\r
+\r
+SUB jooks\r
+' This subroutine demonstrates a simple counting\r
+2\r
+clearBits\r
+FOR a = 1 TO 16\r
+ bit(16) = 1 ' Set the most significant bit to 1\r
+ bit(a - 1) = 1 ' Set the previous bit to 1\r
+ bit(a) = 0 ' Clear the current bit\r
+ PRINT a\r
+ FOR b = 1 TO 1000\r
+ display\r
+ NEXT b\r
+NEXT a\r
+GOTO 2\r
+END SUB\r
+\r
+SUB suva\r
+' This subroutine demonstrates a simple random bit setting algorithm\r
+3\r
+clearBits\r
+FOR b = 1 TO 16\r
+ IF RND * 100 > 50 THEN bit(b) = 0 ' Randomly set bits to 0\r
+NEXT b\r
+FOR b = 1 TO 100\r
+ display\r
+NEXT b\r
+GOTO 3\r
+END SUB\r
+\r
--- /dev/null
+' Program allows scheduling school clock ringing.
+' Timetables are stored in separate files.
+' Also it drives numerical 2 digit led display through parallel LPT printer port.
+' Program is driven by special 3 button keyboard that is also attached to LPT port.
+
+DECLARE SUB num (a%)
+DECLARE SUB mntime ()
+DECLARE SUB showit ()
+DECLARE SUB ekrf (a%)
+DECLARE SUB ekr ()
+DECLARE SUB rese ()
+DECLARE SUB start ()
+DECLARE SUB boot ()
+DECLARE SUB getnad (g%, n%, d%, k%)
+DECLARE SUB initp (b$)
+DECLARE SUB getmd (a$, m, d)
+DECLARE SUB son (a$)
+DEFINT A-Z
+
+DECLARE SUB inita ()
+DECLARE SUB chm ()
+DECLARE SUB chd ()
+DECLARE SUB kell (a%)
+DECLARE SUB sync2 ()
+DECLARE SUB sync ()
+DECLARE SUB mnmain ()
+DECLARE SUB main ()
+DECLARE SUB getkey (kla%)
+DECLARE SUB klnait (k%)
+DECLARE SUB heli (a%)
+DECLARE SUB keys ()
+DECLARE SUB disp ()
+DIM SHARED bit(0 TO 7)
+DIM SHARED kl
+DIM SHARED hist(1 TO 3)
+DIM SHARED ap$(1 TO 500)
+DIM SHARED apl
+DIM SHARED pp$(1 TO 500)
+DIM SHARED ppl
+DIM SHARED prt, prt2
+DIM SHARED timo$
+DIM SHARED dato$
+DIM SHARED sona$(1 TO 50)
+DIM SHARED mitus
+DIM SHARED lp$
+DIM SHARED ndlp
+DIM SHARED pn$(1 TO 7)
+DIM SHARED bitt(1 TO 16)
+DIM SHARED modee, vilgu
+DIM SHARED tul(1 TO 2)
+
+start
+heli 4
+
+disp
+mnmain
+
+SUB chd
+b$ = "tuhi"
+IF apl = 0 THEN inita
+
+a$ = DATE$
+n1 = VAL(RIGHT$(a$, 4))
+n2 = VAL(LEFT$(a$, 2))
+a$ = LEFT$(a$, 5)
+n3 = VAL(RIGHT$(a$, 2))
+getnad n1, n2, n3, ndlp
+LOCATE 10, 1
+PRINT "Week plan:", pn$(ndlp)
+FOR a = 1 TO apl
+son ap$(a)
+SELECT CASE sona$(1)
+CASE "v"
+getmd sona$(2), m1, d1
+getmd sona$(3), m2, d2
+getmd DATE$, m3, d3
+IF m3 < m1 THEN GOTO 9
+IF m3 > m2 THEN GOTO 9
+IF m3 = m1 THEN IF d3 < d1 THEN GOTO 9
+IF m3 = m2 THEN IF d3 > d2 THEN GOTO 9
+b$ = sona$(4)
+CASE "n"
+getmd sona$(2), m1, d1
+getmd sona$(3), m2, d2
+getmd DATE$, m3, d3
+IF m3 < m1 THEN GOTO 9
+IF m3 > m2 THEN GOTO 9
+IF m3 = m1 THEN IF d3 < d1 THEN GOTO 9
+IF m3 = m2 THEN IF d3 > d2 THEN GOTO 9
+IF ndlp <> VAL(sona$(4)) THEN GOTO 9
+b$ = sona$(5)
+CASE "e"
+getmd sona$(2), m1, d1
+getmd DATE$, m2, d2
+IF (m1 = m2) AND (d1 = d2) THEN b$ = sona$(3)
+END SELECT
+9
+NEXT a
+
+IF b$ <> lp$ THEN initp b$
+lp$ = b$
+LOCATE 9, 1
+PRINT "Day plan:", lp$
+END SUB
+
+SUB chm
+showit
+a$ = DATE$
+IF a$ <> dato$ THEN chd
+dato$ = a$
+b = 0
+FOR a = 1 TO ppl
+son pp$(a)
+SELECT CASE sona$(1)
+CASE "#"
+getmd sona$(2), h1, m1
+getmd TIME$, h2, m2
+' PRINT h1, m1, h2, m2
+IF (h2 = h1) AND (m2 = m1) THEN
+IF sona$(3) = "sis" THEN b = 1
+IF sona$(3) = "val" THEN b = 2
+END IF
+END SELECT
+NEXT a
+
+IF b > 0 THEN kell b
+
+END SUB
+
+SUB disp
+CLS
+PRINT "Kooli Kell v 1.2 2002.10.10"
+PRINT "Programmi autor Svjatoslav Agejenko"
+
+END SUB
+
+SUB ekr
+FOR e = 1 TO 10
+c = 1
+c = c + 16 * bitt(1)
+c = c + 32 * bitt(2)
+c = c + 64 * bitt(3)
+c = c + 128 * bitt(4)
+OUT prt2, c
+
+c = 2
+c = c + 16 * bitt(5)
+c = c + 32 * bitt(6)
+c = c + 64 * bitt(7)
+c = c + 128 * bitt(8)
+OUT prt2, c
+
+c = 4
+c = c + 16 * bitt(9)
+c = c + 32 * bitt(10)
+c = c + 64 * bitt(11)
+c = c + 128 * bitt(12)
+OUT prt2, c
+
+c = 8
+c = c + 16 * bitt(13)
+c = c + 32 * bitt(14)
+c = c + 64 * bitt(15)
+c = c + 128 * bitt(16)
+OUT prt2, c
+
+NEXT e
+END SUB
+
+SUB ekrf (a)
+SELECT CASE (a)
+CASE 0
+bitt(1) = 0
+bitt(2) = 0
+bitt(3) = 0
+bitt(7) = 0
+bitt(5) = 0
+bitt(6) = 0
+bitt(8) = 1
+CASE 1
+bitt(2) = 0
+bitt(7) = 0
+CASE 2
+bitt(1) = 0
+bitt(3) = 0
+bitt(5) = 0
+bitt(7) = 0
+bitt(8) = 0
+CASE 3
+bitt(1) = 0
+bitt(2) = 0
+bitt(5) = 0
+bitt(8) = 0
+bitt(7) = 0
+CASE 4
+bitt(2) = 0
+bitt(6) = 0
+bitt(7) = 0
+bitt(8) = 0
+CASE 5
+bitt(1) = 0
+bitt(2) = 0
+bitt(5) = 0
+bitt(6) = 0
+bitt(8) = 0
+CASE 6
+bitt(1) = 0
+bitt(2) = 0
+bitt(3) = 0
+bitt(5) = 0
+bitt(6) = 0
+bitt(8) = 0
+CASE 7
+bitt(2) = 0
+bitt(7) = 0
+bitt(5) = 0
+CASE 8
+bitt(1) = 0
+bitt(2) = 0
+bitt(3) = 0
+bitt(7) = 0
+bitt(5) = 0
+bitt(6) = 0
+bitt(8) = 0
+CASE 9
+bitt(1) = 0
+bitt(2) = 0
+bitt(7) = 0
+bitt(5) = 0
+bitt(6) = 0
+bitt(8) = 0
+CASE 10
+bitt(15) = 0
+bitt(16) = 0
+bitt(12) = 0
+bitt(10) = 0
+bitt(9) = 0
+bitt(4) = 0
+CASE 11
+bitt(15) = 0
+bitt(4) = 0
+CASE 12
+bitt(15) = 0
+bitt(16) = 0
+bitt(9) = 0
+bitt(10) = 0
+bitt(11) = 0
+CASE 13
+bitt(15) = 0
+bitt(4) = 0
+bitt(16) = 0
+bitt(11) = 0
+bitt(9) = 0
+CASE 14
+bitt(15) = 0
+bitt(4) = 0
+bitt(12) = 0
+bitt(11) = 0
+CASE 15
+bitt(9) = 0
+bitt(4) = 0
+bitt(11) = 0
+bitt(12) = 0
+bitt(16) = 0
+CASE 16
+bitt(9) = 0
+bitt(4) = 0
+bitt(11) = 0
+bitt(12) = 0
+bitt(16) = 0
+bitt(10) = 0
+CASE 17
+bitt(4) = 0
+bitt(15) = 0
+bitt(16) = 0
+CASE 18
+bitt(4) = 0
+bitt(15) = 0
+bitt(16) = 0
+bitt(12) = 0
+bitt(11) = 0
+bitt(10) = 0
+bitt(9) = 0
+CASE 19
+bitt(4) = 0
+bitt(15) = 0
+bitt(16) = 0
+bitt(12) = 0
+bitt(11) = 0
+bitt(9) = 0
+END SELECT
+
+END SUB
+
+SUB getkey (kla)
+
+' Read the state of the buttons on the keyboard
+1
+IF vilgu = 1 THEN
+tmr = tmr + 1
+IF tmr > 5 THEN bitt(13) = tul(1): bitt(14) = tul(2) ELSE bitt(13) = 1: bitt(14) = 1
+IF tmr > 10 THEN
+tmr = 0
+END IF
+ELSE
+bitt(13) = tul(1)
+bitt(14) = tul(2)
+END IF
+
+' Get the current time
+b$ = LEFT$(TIME$, 5)
+IF b$ <> timo$ THEN chm
+timo$ = b$
+hist(1) = hist(1) + 1
+IF hist(1) > 20000 THEN hist(1) = 15000
+hist(2) = hist(2) + 1
+IF hist(2) > 20000 THEN hist(2) = 15000
+hist(3) = hist(3) + 1
+IF hist(3) > 20000 THEN hist(3) = 15000
+
+' Read the state of the buttons on the keyboard
+keys
+IF kl > 0 THEN
+ IF hist(kl) > 1 AND hist(kl) < 9 THEN
+ klnait kl + 3
+ kla = kl + 3
+ GOTO 4
+ ELSE
+ hist(kl) = 0
+ END IF
+END IF
+IF hist(1) = 10 THEN klnait 1: kla = 1: GOTO 4
+IF hist(2) = 10 THEN klnait 2: kla = 2: GOTO 4
+IF hist(3) = 10 THEN klnait 3: kla = 3: GOTO 4
+
+IF hist(1) > 11 AND hist(2) > 11 AND hist(3) > 11 THEN klnait 0
+
+' Display current time and date
+LOCATE 7, 1
+PRINT TIME$
+LOCATE 8, 1
+PRINT DATE$
+GOTO 1
+4
+
+' Reset the button press count
+hist(1) = 10000
+hist(2) = 10000
+hist(3) = 10000
+
+' Play a sound to indicate button press
+FOR b = 1 TO 100
+SOUND 0, .1
+NEXT b
+IF kla > 3 THEN SOUND 4000, .1 ELSE SOUND 3000, .1
+
+END SUB
+
+SUB getmd (a$, m, d)
+b$ = LEFT$(a$, 5)
+m = VAL(LEFT$(b$, 2))
+d = VAL(RIGHT$(b$, 2))
+
+END SUB
+
+SUB getnad (g, n, d, k)
+LOCATE 11, 1
+PRINT g, n, d
+p = g
+m = n - 2
+IF n > 2 GOTO 120
+p = p - 1: m = m + 12
+120
+c = INT(p / 100)
+y = p - c * 100
+w = d + INT((13 * m - 1) / 5) + y + INT(y / 4) + INT(c / 4) - 2 * c
+k = w - 7 * INT(w / 7)
+IF k = 0 THEN k = 7
+END SUB
+
+SUB heli (a)
+'GOTO 10
+SELECT CASE a
+CASE 1
+FOR c = 1 TO 5
+SOUND 3000, 1
+SOUND 0, 1
+NEXT c
+
+CASE 2
+FOR c = 1 TO 5
+SOUND 2500, 1
+SOUND 0, 2
+NEXT c
+SOUND 2500, 10
+
+CASE 3
+FOR a = 1 TO 10
+SOUND 500, .5
+SOUND 1500, .5
+SOUND 2000, .5
+SOUND 1520, .5
+NEXT a
+
+CASE 4
+FOR a = 800 TO 1000 STEP 10
+SOUND a, .1
+SOUND a * 3, .1
+SOUND 0, 1
+NEXT a
+10
+
+END SELECT
+
+END SUB
+
+SUB inita
+apl = 0
+OPEN "aasta.ap" FOR INPUT AS #1
+5
+IF EOF(1) <> 0 THEN GOTO 3
+LINE INPUT #1, a$
+apl = apl + 1
+ap$(apl) = a$
+GOTO 5
+3
+CLOSE #1
+END SUB
+
+SUB initp (b$)
+ppl = 0
+OPEN b$ + ".pp" FOR INPUT AS #1
+6
+IF EOF(1) <> 0 THEN GOTO 7
+LINE INPUT #1, a$
+ppl = ppl + 1
+pp$(ppl) = a$
+GOTO 6
+7
+CLOSE #1
+END SUB
+
+SUB kell (a)
+heli 3
+
+SELECT CASE a
+CASE 1
+OUT prt, 255
+FOR b = 1 TO 80
+SOUND 0, 1
+NEXT b
+OUT prt, 0
+FOR b = 1 TO 15
+SOUND 0, 1
+NEXT b
+OUT prt, 255
+FOR b = 1 TO 15
+SOUND 0, 1
+NEXT b
+OUT prt, 0
+
+CASE 2
+OUT prt, 255
+FOR b = 1 TO 80
+SOUND 0, 1
+NEXT b
+OUT prt, 0
+
+END SELECT
+END SUB
+
+SUB keys
+kl = 0
+OUT prt, 0
+8
+a = INP(prt)
+b = INP(prt)
+IF a <> b THEN GOTO 8
+
+b = 128
+FOR c = 0 TO 7
+d = INT(a / b)
+bit(c) = d
+a = a - (b * d)
+b = b / 2
+NEXT c
+
+IF bit(4) = 1 AND bit(6) = 1 THEN bit(4) = 0: bit(6) = 0: kl = 3
+IF bit(6) = 1 THEN kl = 2
+IF bit(4) = 1 THEN kl = 1
+
+a$ = INKEY$
+IF a$ = CHR$(0) + "K" THEN kl = 1
+IF a$ = CHR$(0) + "M" THEN kl = 2
+IF a$ = CHR$(0) + "P" THEN kl = 3
+ekr
+END SUB
+
+SUB klnait (k)
+
+' Highlight the pressed button on the display
+IF k = 3 THEN c = 3 ELSE c = 1
+IF k = 6 THEN c = 14
+LOCATE 5, 6
+COLOR 7, c
+PRINT "<kesk>"
+COLOR 7, 0
+
+' Highlight the pressed button on the display
+IF k = 1 THEN c = 3 ELSE c = 1
+IF k = 4 THEN c = 14
+LOCATE 4, 1
+COLOR 7, c
+PRINT "<vasak>"
+COLOR 7, 0
+
+IF k = 2 THEN c = 3 ELSE c = 1
+IF k = 5 THEN c = 14
+LOCATE 4, 10
+COLOR 7, c
+PRINT "<parem>"
+COLOR 7, 0
+
+END SUB
+
+SUB mnmain
+2
+getkey a
+IF a = 6 THEN sync
+IF a = 3 THEN sync2
+
+IF a = 1 THEN kell 1
+IF a = 4 THEN kell 2
+
+IF a = 2 THEN mntime
+IF a = 5 THEN rese
+GOTO 2
+
+END SUB
+
+SUB mntime
+vilgu = 1
+11
+showit
+getkey a
+
+IF modee = 1 THEN
+ b = VAL(LEFT$(TIME$, 2))
+ c = 0
+ IF a = 1 THEN c = 1: b = b - 1
+ IF a = 2 THEN c = 1: b = b + 1
+ IF b < 0 THEN b = 0
+ IF b > 23 THEN b = 23
+ d$ = STR$(b)
+ IF LEFT$(d$, 1) = " " THEN d$ = RIGHT$(d$, LEN(d$) - 1)
+ IF LEN(d$) < 2 THEN d$ = "0" + d$
+ e$ = d$ + RIGHT$(TIME$, 6)
+ IF c = 1 THEN TIME$ = e$
+ELSE
+ b = VAL(RIGHT$(LEFT$(TIME$, 5), 2))
+ c = 0
+ IF a = 1 THEN c = 1: b = b - 1
+ IF a = 2 THEN c = 1: b = b + 1
+ IF b < 0 THEN b = 0
+ IF b > 59 THEN b = 59
+ d$ = STR$(b)
+ IF LEFT$(d$, 1) = " " THEN d$ = RIGHT$(d$, LEN(d$) - 1)
+ IF LEN(d$) < 2 THEN d$ = "0" + d$
+ e$ = LEFT$(TIME$, 3) + d$ + RIGHT$(TIME$, 3)
+ IF c = 1 THEN TIME$ = e$
+END IF
+
+IF a = 3 THEN
+IF modee = 1 THEN modee = 2 ELSE modee = 1
+END IF
+
+IF a = 6 THEN GOTO 12
+GOTO 11
+12
+vilgu = 0
+modee = 2
+END SUB
+
+SUB num (a)
+
+FOR b = 1 TO 12
+bitt(b) = 1
+NEXT b
+bitt(15) = 1
+bitt(16) = 1
+
+b = INT(a / 10)
+c = a - (10 * b)
+ekrf b
+ekrf c + 10
+END SUB
+
+SUB rese
+heli 4
+timo$ = ""
+dato$ = ""
+apl = 0
+END SUB
+
+SUB showit
+a$ = LEFT$(TIME$, 5)
+IF modee = 1 THEN
+b = VAL(LEFT$(a$, 2))
+tul(1) = 1
+tul(2) = 0
+ELSE
+b = VAL(RIGHT$(a$, 2))
+tul(1) = 0
+tul(2) = 1
+END IF
+LOCATE 15, 1
+PRINT b
+num b
+
+
+END SUB
+
+SUB son (a$)
+
+FOR b = 1 TO 50
+sona$(b) = ""
+NEXT b
+mitus = 0
+
+b = 1
+FOR c = 1 TO LEN(a$)
+d$ = RIGHT$(LEFT$(a$, c), 1)
+IF d$ = " " OR d$ = CHR$(9) THEN
+b = 1
+ELSE
+IF b = 1 THEN b = 0: mitus = mitus + 1
+sona$(mitus) = sona$(mitus) + d$
+END IF
+NEXT c
+
+
+END SUB
+
+SUB start
+pn$(1) = "Monday"
+pn$(2) = "Tuesday"
+pn$(3) = "Wednesday"
+pn$(4) = "Thursday"
+pn$(5) = "Friday"
+pn$(6) = "Saturday"
+pn$(7) = "Sunday"
+
+prt = &H37A
+prt2 = &H378
+hist(1) = 10000
+hist(2) = 10000
+hist(3) = 10000
+
+FOR a = 1 TO 16
+bitt(a) = 1
+NEXT a
+modee = 2
+vilgu = 0
+tul(1) = 1
+tul(2) = 1
+END SUB
+
+SUB sync
+OPEN "sync.txt" FOR INPUT AS #1
+LINE INPUT #1, a$
+DATE$ = a$
+LINE INPUT #1, a$
+TIME$ = a$
+CLOSE #1
+
+heli 2
+END SUB
+
+SUB sync2
+a$ = TIME$
+a$ = LEFT$(a$, 5)
+b = VAL(RIGHT$(a$, 2))
+c = VAL(LEFT$(a$, 2))
+IF b >= 30 THEN c = c + 1
+b = 0
+IF c > 23 THEN c = c - 24
+a$ = RIGHT$(STR$(c), LEN(STR$(c)) - 1)
+b$ = RIGHT$(STR$(b), LEN(STR$(b)) - 1)
+IF LEN(a$) < 2 THEN a$ = "0" + a$
+IF LEN(b$) < 2 THEN b$ = "0" + b$
+a$ = a$ + ":" + b$
+
+'LOCATE 10, 1
+'PRINT a$
+
+TIME$ = a$
+
+heli 1
+END SUB
--- /dev/null
+# 08:30 sis\r
+# 09:15 val\r
+\r
+# 09:25 sis\r
+# 10:10 val\r
+\r
+# 10:20 sis\r
+# 10:45 val\r
+\r
+# 10:55 sis\r
+# 11:20 val\r
+\r
+# 11:40 sis\r
+# 12:05 val\r
+\r
+# 12:15 sis\r
+# 12:40 val\r
+\r
+\r
--- /dev/null
+# 08:30 sis\r
+# 09:10 val\r
+\r
+# 09:20 sis\r
+# 10:00 val\r
+\r
+# 10:10 sis\r
+# 10:50 val\r
+\r
+# 11:30 sis\r
+# 12:10 val\r
+\r
+# 12:20 sis\r
+# 13:00 val\r
+\r
+# 13:10 sis\r
+# 13:50 val\r
+\r
+# 14:00 sis\r
+# 14:40 val\r
+\r
+# 14:45 sis\r
+# 15:30 val\r
--- /dev/null
+# 08:30 sis\r
+# 09:15 val\r
+\r
+# 09:25 sis\r
+# 10:10 val\r
+\r
+# 10:20 sis\r
+# 11:05 val\r
+\r
+# 11:35 sis\r
+# 12:20 val\r
+\r
+# 12:30 sis\r
+# 13:15 val\r
+\r
+# 13:20 sis\r
+# 14:05 val\r
+\r
+# 14:10 sis\r
+# 14:55 val\r
+\r
+# 15:00 sis\r
+# 15:45 val\r
--- /dev/null
+09-06-2002\r
+15:38\r
+\r
+kuu-paev-aasta\r
+tunnid-minutid
\ No newline at end of file
--- /dev/null
+# 08:30 sis\r
+# 09:15 val\r
+\r
+# 09:25 sis\r
+# 10:10 val\r
+\r
+# 10:20 sis\r
+# 11:05 val\r
+\r
+# 11:35 sis\r
+# 12:20 val\r
+\r
+# 12:30 sis\r
+# 13:15 val\r
+\r
+# 13:25 sis\r
+# 14:10 val\r
+\r
+# 14:20 sis\r
+# 15:05 val\r
+\r
+# 15:10 sis\r
+# 15:55 val\r
+\r
+# 16:00 sis\r
+# 16:45 val\r
+\r
+# 16:50 sis\r
+# 17:45 val\r
+\r
+# 17:50 sis\r
+# 18:25 val\r
+\r
+# 18:30 sis\r
+# 19:15 val\r
+\r
--- /dev/null
+v 01-01 12-31 tava\r
+n 01-01 12-31 5 reede\r
+e 10-04 opetajap\r
+e 10-31 rebased\r
+e 04-17 luhend\r
+e 04-18 tuhi\r
+e 04-30 luhend\r
+e 05-01 tuhi\r
+e 06-23 tuhi\r
+e 06-24 tuhi\r
+n 01-01 12-31 6 tuhi\r
+n 01-01 12-31 7 tuhi\r
+v 07-01 08-31 tuhi\r
+\r
--- /dev/null
+DECLARE SUB dispt ()\r
+' Svjatoslav Agejenko\r
+' E-mail: svjatoslav@svjatoslav.eu\r
+' Homepage: www.hot.ee/n0/\r
+\r
+DECLARE SUB dispp ()\r
+DECLARE SUB displukk ()\r
+DECLARE SUB kola (a%)\r
+DECLARE SUB rese ()\r
+DECLARE SUB start ()\r
+DECLARE SUB getnad (g%, n%, d%, k%)\r
+DECLARE SUB initp (b$)\r
+DECLARE SUB getmd (a$, m%, d%)\r
+DECLARE SUB son (a$)\r
+DECLARE SUB inita ()\r
+DECLARE SUB chm ()\r
+DECLARE SUB chd ()\r
+DECLARE SUB kell (a%)\r
+DECLARE SUB sync2 ()\r
+DECLARE SUB sync ()\r
+DECLARE SUB mnmain ()\r
+DECLARE SUB heli (a%)\r
+DECLARE SUB disp ()\r
+DEFINT A-Z\r
+\r
+DIM SHARED ap$(1 TO 500)\r
+DIM SHARED apl\r
+DIM SHARED pp$(1 TO 500)\r
+DIM SHARED ppl\r
+DIM SHARED prt, prt2\r
+DIM SHARED timo$\r
+DIM SHARED dato$\r
+DIM SHARED sona$(1 TO 50)\r
+DIM SHARED mitus\r
+DIM SHARED lp$\r
+DIM SHARED ndlp\r
+DIM SHARED pn$(1 TO 7)\r
+DIM SHARED lk$\r
+DIM SHARED ssave\r
+DIM SHARED ssavel\r
+DIM SHARED timero AS LONG\r
+DIM SHARED kblukk\r
+DIM SHARED tunnidara\r
+\r
+start\r
+\r
+\r
+disp\r
+mnmain\r
+\r
+SUB chd\r
+b$ = "tuhi"\r
+IF apl = 0 THEN inita\r
+\r
+a$ = DATE$\r
+n1 = VAL(RIGHT$(a$, 4))\r
+n2 = VAL(LEFT$(a$, 2))\r
+a$ = LEFT$(a$, 5)\r
+n3 = VAL(RIGHT$(a$, 2))\r
+getnad n1, n2, n3, ndlp\r
+FOR a = 1 TO apl\r
+son ap$(a)\r
+SELECT CASE sona$(1)\r
+CASE "v"\r
+getmd sona$(2), m1, d1\r
+getmd sona$(3), m2, d2\r
+getmd DATE$, m3, d3\r
+IF m3 < m1 THEN GOTO 9\r
+IF m3 > m2 THEN GOTO 9\r
+IF m3 = m1 THEN IF d3 < d1 THEN GOTO 9\r
+IF m3 = m2 THEN IF d3 > d2 THEN GOTO 9\r
+b$ = sona$(4)\r
+CASE "n"\r
+getmd sona$(2), m1, d1\r
+getmd sona$(3), m2, d2\r
+getmd DATE$, m3, d3\r
+IF m3 < m1 THEN GOTO 9\r
+IF m3 > m2 THEN GOTO 9\r
+IF m3 = m1 THEN IF d3 < d1 THEN GOTO 9\r
+IF m3 = m2 THEN IF d3 > d2 THEN GOTO 9\r
+IF ndlp <> VAL(sona$(4)) THEN GOTO 9\r
+b$ = sona$(5)\r
+CASE "e"\r
+getmd sona$(2), m1, d1\r
+getmd DATE$, m2, d2\r
+IF (m1 = m2) AND (d1 = d2) THEN b$ = sona$(3)\r
+END SELECT\r
+9\r
+NEXT a\r
+\r
+IF b$ <> lp$ THEN initp b$\r
+lp$ = b$\r
+tunnidara = 0\r
+dispp\r
+disp\r
+END SUB\r
+\r
+SUB chm\r
+a$ = DATE$\r
+IF a$ <> dato$ THEN chd\r
+dato$ = a$\r
+b = 0\r
+FOR a = 1 TO ppl\r
+son pp$(a)\r
+SELECT CASE sona$(1)\r
+CASE "#"\r
+getmd sona$(2), h1, m1\r
+getmd TIME$, h2, m2\r
+' PRINT h1, m1, h2, m2\r
+IF (h2 = h1) AND (m2 = m1) THEN\r
+IF sona$(3) = "sis" THEN b = 1\r
+IF sona$(3) = "val" THEN b = 2\r
+END IF\r
+END SELECT\r
+NEXT a\r
+\r
+IF (tunnidara = 0) AND (b > 0) THEN kell b\r
+ssave = ssave + 1\r
+END SUB\r
+\r
+SUB disp\r
+CLS\r
+PRINT "Kooli Kell (mini) v 1.1 2003.3"\r
+PRINT "Programmi autor Svjatoslav Agejenko E-mail: n0@hot.ee"\r
+PRINT ""\r
+PRINT "s - kell tundi sisse v - kell tunnist v�lja"\r
+PRINT "a - sisesta uus aeg d - sisesta uus daatum"\r
+PRINT "u - �mardab aja t�istunnini l - laeb aja failist SYNC.TXT"\r
+PRINT "7 - 1 minut tagasi 8 - 1 minut edasi"\r
+PRINT "4 - 1 tund tagasi 5 - 1 tund edasi"\r
+PRINT "r - programmi restart q - programmist v�lja"\r
+PRINT " j - j�tab k�ik tunnid t�na �ra"\r
+\r
+dispp\r
+\r
+LOCATE 12, 15\r
+PRINT "Kuu-P�ev-Aasta (USA standard)"\r
+\r
+\r
+LOCATE 17\r
+\r
+FOR a = 1 TO ppl\r
+IF pp$(a) <> SPACE$(LEN(pp$(a))) THEN\r
+ PRINT pp$(a);\r
+ PRINT SPACE$(15 - LEN(pp$(a)));\r
+END IF\r
+NEXT a\r
+\r
+displukk\r
+dispt\r
+END SUB\r
+\r
+SUB displukk\r
+LOCATE 1, 40\r
+IF kblukk = 1 THEN\r
+ COLOR 0, 7\r
+ PRINT "Klaviatuur lukus! Vajuta CTRL+L"\r
+ COLOR 7, 0\r
+ELSE\r
+ PRINT " "\r
+END IF\r
+END SUB\r
+\r
+SUB dispp\r
+IF ndlp = 0 THEN GOTO 14\r
+LOCATE 14, 1\r
+PRINT "n�dalap�ev:", pn$(ndlp)\r
+LOCATE 15, 1\r
+PRINT "p�evaplaan:", lp$\r
+14\r
+END SUB\r
+\r
+SUB dispt\r
+LOCATE 16, 20\r
+COLOR 12 + 15, 0\r
+IF tunnidara = 1 THEN\r
+ PRINT "T�na on k�ik tunnid �ra j�etud"\r
+ELSE\r
+ PRINT " "\r
+END IF\r
+COLOR 7, 0\r
+END SUB\r
+\r
+SUB getmd (a$, m, d)\r
+b$ = LEFT$(a$, 5)\r
+m = VAL(LEFT$(b$, 2))\r
+d = VAL(RIGHT$(b$, 2))\r
+\r
+END SUB\r
+\r
+SUB getnad (g, n, d, k)\r
+'LOCATE 11, 1\r
+'PRINT g, n, d\r
+p = g\r
+m = n - 2\r
+IF n > 2 GOTO 120\r
+p = p - 1: m = m + 12\r
+120\r
+c = INT(p / 100)\r
+y = p - c * 100\r
+w = d + INT((13 * m - 1) / 5) + y + INT(y / 4) + INT(c / 4) - 2 * c\r
+k = w - 7 * INT(w / 7)\r
+IF k = 0 THEN k = 7\r
+END SUB\r
+\r
+SUB heli (a)\r
+'GOTO 10\r
+SELECT CASE a\r
+CASE 1\r
+FOR c = 1 TO 5\r
+SOUND 3000, 1\r
+SOUND 0, 1\r
+NEXT c\r
+\r
+CASE 2\r
+FOR c = 1 TO 5\r
+SOUND 2500, 1\r
+SOUND 0, 2\r
+NEXT c\r
+SOUND 2500, 10\r
+\r
+CASE 3\r
+FOR a = 1 TO 10\r
+SOUND 500, .5\r
+SOUND 1500, .5\r
+SOUND 2000, .5\r
+SOUND 1520, .5\r
+NEXT a\r
+\r
+\r
+CASE 4\r
+FOR a = 800 TO 1000 STEP 10\r
+SOUND a, .1\r
+SOUND a * 3, .1\r
+SOUND 0, 1\r
+NEXT a\r
+10\r
+\r
+END SELECT\r
+\r
+\r
+END SUB\r
+\r
+SUB inita\r
+apl = 0\r
+OPEN "aasta.ap" FOR INPUT AS #1\r
+5\r
+IF EOF(1) <> 0 THEN GOTO 3\r
+LINE INPUT #1, a$\r
+apl = apl + 1\r
+ap$(apl) = a$\r
+GOTO 5\r
+3\r
+CLOSE #1\r
+END SUB\r
+\r
+SUB initp (b$)\r
+ppl = 0\r
+OPEN b$ + ".pp" FOR INPUT AS #1\r
+6\r
+IF EOF(1) <> 0 THEN GOTO 7\r
+LINE INPUT #1, a$\r
+ppl = ppl + 1\r
+pp$(ppl) = a$\r
+GOTO 6\r
+7\r
+CLOSE #1\r
+END SUB\r
+\r
+SUB kell (a)\r
+b$ = TIME$ + DATE$\r
+IF b$ <> lk$ THEN lk$ = b$ ELSE GOTO 2\r
+\r
+heli 3\r
+\r
+SELECT CASE a\r
+CASE 1\r
+kola 4\r
+FOR b = 1 TO 15\r
+SOUND 0, 1\r
+NEXT b\r
+kola 1\r
+CASE 2\r
+kola 5\r
+END SELECT\r
+2\r
+END SUB\r
+\r
+SUB kola (a)\r
+timero = TIMER\r
+11\r
+FOR b = 1 TO 100\r
+OUT prt, 0\r
+OUT prt, 255\r
+NEXT b\r
+IF ABS(timero - TIMER) < a THEN GOTO 11\r
+END SUB\r
+\r
+SUB mnmain\r
+1\r
+b$ = LEFT$(TIME$, 5)\r
+IF b$ <> timo$ THEN chm\r
+timo$ = b$\r
+\r
+a$ = INKEY$\r
+\r
+IF a$ <> "" THEN\r
+IF ssave > ssavel THEN disp\r
+ssave = 0\r
+END IF\r
+\r
+IF a$ = CHR$(12) THEN\r
+ IF kblukk = 1 THEN kblukk = 0 ELSE kblukk = 1\r
+ displukk\r
+END IF\r
+IF kblukk = 1 THEN a$ = ""\r
+\r
+IF a$ = "s" THEN kell 1\r
+IF a$ = "v" THEN kell 2\r
+\r
+IF a$ = "a" THEN\r
+CLS\r
+PRINT " vana aeg: " + TIME$\r
+INPUT "sisesta uus aeg (TT:MM:SS): ", b$\r
+IF LEN(b$) <> 8 THEN GOTO 12\r
+TIME$ = b$\r
+timo$ = ""\r
+12\r
+disp\r
+END IF\r
+\r
+IF a$ = "d" THEN\r
+CLS\r
+PRINT " vana daatum: " + DATE$\r
+INPUT "sisesta uus daatum (KK-PP-AAAA): ", b$\r
+IF LEN(b$) <> 10 THEN GOTO 13\r
+DATE$ = b$\r
+timo$ = ""\r
+13\r
+disp\r
+END IF\r
+\r
+IF a$ = "7" OR a$ = "8" THEN\r
+ b = VAL(RIGHT$(LEFT$(TIME$, 5), 2))\r
+ IF a$ = "7" THEN b = b - 1\r
+ IF a$ = "8" THEN b = b + 1\r
+ IF b < 0 THEN b = 0\r
+ IF b > 59 THEN b = 59\r
+ d$ = STR$(b)\r
+ IF LEFT$(d$, 1) = " " THEN d$ = RIGHT$(d$, LEN(d$) - 1)\r
+ IF LEN(d$) < 2 THEN d$ = "0" + d$\r
+ e$ = LEFT$(TIME$, 3) + d$ + RIGHT$(TIME$, 3)\r
+ TIME$ = e$\r
+END IF\r
+\r
+IF a$ = "4" OR a$ = "5" THEN\r
+ b = VAL(LEFT$(TIME$, 2))\r
+ IF a$ = "4" THEN b = b - 1\r
+ IF a$ = "5" THEN b = b + 1\r
+ IF b < 0 THEN b = 0\r
+ IF b > 23 THEN b = 23\r
+ d$ = STR$(b)\r
+ IF LEFT$(d$, 1) = " " THEN d$ = RIGHT$(d$, LEN(d$) - 1)\r
+ IF LEN(d$) < 2 THEN d$ = "0" + d$\r
+ e$ = d$ + RIGHT$(TIME$, 6)\r
+ TIME$ = e$\r
+END IF\r
+\r
+IF a$ = "u" THEN sync2\r
+IF a$ = "l" THEN sync\r
+\r
+IF a$ = "r" THEN rese\r
+IF a$ = "q" THEN SYSTEM\r
+\r
+IF a$ = "j" THEN\r
+IF tunnidara = 0 THEN tunnidara = 1 ELSE tunnidara = 0\r
+dispt\r
+END IF\r
+\r
+IF ssave <= ssavel THEN\r
+ LOCATE 11, 1\r
+ PRINT TIME$\r
+ LOCATE 12, 1\r
+ PRINT DATE$\r
+ELSE\r
+ IF ABS(TIMER - timero) > 10 THEN\r
+ CLS\r
+ kblukk = 1\r
+ FOR b = 1 TO 20\r
+ LOCATE RND * 22 + 1, RND * 79 + 1\r
+ IF RND * 100 < 50 THEN PRINT "*" ELSE PRINT "."\r
+ NEXT b\r
+ LOCATE RND * 22 + 1, RND * 50 + 1\r
+ COLOR 0, 7\r
+ PRINT "< " + LEFT$(TIME$, 2);\r
+ COLOR 16, 7\r
+ PRINT ":";\r
+ COLOR 0, 7\r
+ PRINT RIGHT$(LEFT$(TIME$, 5), 2) + " >"\r
+ COLOR 7, 0\r
+ timero = TIMER\r
+ END IF\r
+END IF\r
+GOTO 1\r
+\r
+\r
+END SUB\r
+\r
+SUB rese\r
+heli 4\r
+timo$ = ""\r
+dato$ = ""\r
+apl = 0\r
+END SUB\r
+\r
+SUB son (a$)\r
+\r
+FOR b = 1 TO 50\r
+sona$(b) = ""\r
+NEXT b\r
+mitus = 0\r
+\r
+b = 1\r
+FOR c = 1 TO LEN(a$)\r
+d$ = RIGHT$(LEFT$(a$, c), 1)\r
+IF d$ = " " OR d$ = CHR$(9) THEN\r
+b = 1\r
+ELSE\r
+IF b = 1 THEN b = 0: mitus = mitus + 1\r
+sona$(mitus) = sona$(mitus) + d$\r
+END IF\r
+NEXT c\r
+\r
+\r
+END SUB\r
+\r
+SUB start\r
+pn$(1) = "esmasp�ev"\r
+pn$(2) = "teisip�ev"\r
+pn$(3) = "kolmap�ev"\r
+pn$(4) = "neljap�ev"\r
+pn$(5) = "reede"\r
+pn$(6) = "laup�ev"\r
+pn$(7) = "p�hap�ev"\r
+\r
+prt = &H378\r
+\r
+ssavel = 2\r
+kblukk = 1\r
+tunnidara = 0\r
+END SUB\r
+\r
+SUB sync\r
+OPEN "sync.txt" FOR INPUT AS #1\r
+LINE INPUT #1, a$\r
+DATE$ = a$\r
+LINE INPUT #1, a$\r
+TIME$ = a$\r
+CLOSE #1\r
+\r
+heli 2\r
+END SUB\r
+\r
+SUB sync2\r
+a$ = TIME$\r
+a$ = LEFT$(a$, 5)\r
+b = VAL(RIGHT$(a$, 2))\r
+c = VAL(LEFT$(a$, 2))\r
+IF b >= 30 THEN c = c + 1\r
+b = 0\r
+IF c > 23 THEN c = c - 24\r
+a$ = RIGHT$(STR$(c), LEN(STR$(c)) - 1)\r
+b$ = RIGHT$(STR$(b), LEN(STR$(b)) - 1)\r
+IF LEN(a$) < 2 THEN a$ = "0" + a$\r
+IF LEN(b$) < 2 THEN b$ = "0" + b$\r
+a$ = a$ + ":" + b$\r
+\r
+'LOCATE 10, 1\r
+'PRINT a$\r
+\r
+TIME$ = a$\r
+\r
+heli 1\r
+END SUB\r
+\r
--- /dev/null
+# 08:30 sis\r
+# 09:00 val\r
+\r
+# 09:10 sis\r
+# 09:40 val\r
+\r
+# 09:50 sis\r
+# 10:20 val\r
+\r
+# 10:30 sis\r
+# 11:00 val\r
+\r
+# 11:30 sis\r
+# 12:00 val\r
+\r
+# 12:10 sis\r
+# 12:40 val\r
+\r
+# 12:50 sis\r
+# 13:20 val\r
+\r
+# 13:30 sis\r
+# 14:00 val\r
+\r
+# 14:05 sis\r
+# 14:35 val\r
+\r
--- /dev/null
+# 08:30 sis\r
+# 09:15 val\r
+\r
+# 09:25 sis\r
+# 10:10 val\r
+\r
+# 10:20 sis\r
+# 10:45 val\r
+\r
+# 10:55 sis\r
+# 11:20 val\r
+\r
+# 11:40 sis\r
+# 12:05 val\r
+\r
+# 12:15 sis\r
+# 12:40 val\r
+\r
+\r
--- /dev/null
+# 08:30 sis\r
+# 09:10 val\r
+\r
+# 09:20 sis\r
+# 10:00 val\r
+\r
+# 10:10 sis\r
+# 10:50 val\r
+\r
+# 11:30 sis\r
+# 12:10 val\r
+\r
+# 12:20 sis\r
+# 13:00 val\r
+\r
+# 13:10 sis\r
+# 13:50 val\r
+\r
+# 14:00 sis\r
+# 14:40 val\r
+\r
+# 14:45 sis\r
+# 15:30 val\r
--- /dev/null
+# 08:30 sis\r
+# 09:15 val\r
+\r
+# 09:25 sis\r
+# 10:10 val\r
+\r
+# 10:20 sis\r
+# 11:05 val\r
+\r
+# 11:35 sis\r
+# 12:20 val\r
+\r
+# 12:30 sis\r
+# 13:15 val\r
+\r
+# 13:20 sis\r
+# 14:05 val\r
+\r
+# 14:10 sis\r
+# 14:55 val\r
+\r
+# 15:00 sis\r
+# 15:45 val\r
--- /dev/null
+02-03-2003\r
+11:32\r
+\r
+kuu-paev-aasta\r
+tunnid-minutid
\ No newline at end of file
--- /dev/null
+# 08:30 sis\r
+# 09:15 val\r
+\r
+# 09:25 sis\r
+# 10:10 val\r
+\r
+# 10:20 sis\r
+# 11:05 val\r
+\r
+# 11:35 sis\r
+# 12:20 val\r
+\r
+# 12:30 sis\r
+# 13:15 val\r
+\r
+# 13:25 sis\r
+# 14:10 val\r
+\r
+# 14:20 sis\r
+# 15:05 val\r
+\r
+# 15:10 sis\r
+# 15:55 val\r
+\r
+# 16:00 sis\r
+# 16:45 val\r
+\r
+# 16:50 sis\r
+# 17:35 val
\ No newline at end of file
--- /dev/null
+v 01-01 12-31 tava\r
+n 01-01 12-31 5 reede\r
+e 04-17 luhend\r
+e 04-18 tuhi\r
+e 04-30 luhend\r
+e 05-01 tuhi\r
+e 06-23 tuhi\r
+e 06-24 tuhi\r
+n 01-01 12-31 6 tuhi\r
+n 01-01 12-31 7 tuhi\r
+v 07-01 08-31 tuhi\r
+\r
--- /dev/null
+' Program allows scheduling school clock ringing.\r
+' Timetables are stored in separate files.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' ?, Initial version\r
+' 2024, Improved program readability\r
+\r
+\r
+DECLARE FUNCTION getName$ (a%)\r
+DECLARE FUNCTION getSym$ (a$, b%)\r
+DECLARE SUB editor ()\r
+DECLARE SUB leiaconf ()\r
+DECLARE SUB clrerr ()\r
+DECLARE SUB dispt ()\r
+\r
+DECLARE SUB dispp ()\r
+DECLARE SUB displukk ()\r
+DECLARE SUB kola (a%)\r
+DECLARE SUB rese ()\r
+DECLARE SUB start ()\r
+DECLARE SUB getNad (g%, n%, d%, k%)\r
+DECLARE SUB initp (b$)\r
+DECLARE SUB getMd (a$, m%, d%)\r
+DECLARE SUB son (a$)\r
+DECLARE SUB inita ()\r
+DECLARE SUB chm ()\r
+DECLARE SUB chd ()\r
+DECLARE SUB kell (a%)\r
+DECLARE SUB sync2 ()\r
+DECLARE SUB sync ()\r
+DECLARE SUB mnmain ()\r
+DECLARE SUB heli (a%)\r
+DECLARE SUB disp ()\r
+DEFINT A-Z\r
+\r
+DIM SHARED ap$(1 TO 500)\r
+DIM SHARED apl\r
+DIM SHARED pp$(1 TO 500)\r
+DIM SHARED ppl\r
+DIM SHARED prt, prt2\r
+DIM SHARED timo$\r
+DIM SHARED dato$\r
+DIM SHARED sona$(1 TO 50)\r
+DIM SHARED mitus\r
+DIM SHARED lp$\r
+DIM SHARED ndlp\r
+DIM SHARED pn$(1 TO 7)\r
+DIM SHARED lk$\r
+DIM SHARED ssave\r
+DIM SHARED ssavel\r
+DIM SHARED timero AS LONG\r
+DIM SHARED kblukk\r
+DIM SHARED tunnidara\r
+DIM SHARED errmsg$\r
+DIM SHARED cnflist$(1 TO 200)\r
+\r
+'ON ERROR GOTO 20\r
+\r
+start\r
+disp\r
+mnmain\r
+\r
+20\r
+LOCATE 20, 1\r
+COLOR 0, 15\r
+PRINT "Programmi t88s ilmus j2rgnev t6rge:"\r
+PRINT errmsg$\r
+PRINT "Programmi t2itmine katkestatud! Abi saamiseks lugege juhendit."\r
+SYSTEM\r
+\r
+SUB chd\r
+b$ = "tuhi"\r
+IF apl = 0 THEN inita\r
+\r
+a$ = DATE$\r
+n1 = VAL(RIGHT$(a$, 4))\r
+n2 = VAL(LEFT$(a$, 2))\r
+a$ = LEFT$(a$, 5)\r
+n3 = VAL(RIGHT$(a$, 2))\r
+getNad n1, n2, n3, ndlp\r
+FOR a = 1 TO apl\r
+ son ap$(a)\r
+ SELECT CASE sona$(1)\r
+ CASE "v"\r
+ getMd sona$(2), m1, d1\r
+ getMd sona$(3), m2, d2\r
+ getMd DATE$, m3, d3\r
+ IF m3 < m1 THEN GOTO 9\r
+ IF m3 > m2 THEN GOTO 9\r
+ IF m3 = m1 THEN IF d3 < d1 THEN GOTO 9\r
+ IF m3 = m2 THEN IF d3 > d2 THEN GOTO 9\r
+ b$ = sona$(4)\r
+ CASE "n"\r
+ getMd sona$(2), m1, d1\r
+ getMd sona$(3), m2, d2\r
+ getMd DATE$, m3, d3\r
+ IF m3 < m1 THEN GOTO 9\r
+ IF m3 > m2 THEN GOTO 9\r
+ IF m3 = m1 THEN IF d3 < d1 THEN GOTO 9\r
+ IF m3 = m2 THEN IF d3 > d2 THEN GOTO 9\r
+ IF ndlp <> VAL(sona$(4)) THEN GOTO 9\r
+ b$ = sona$(5)\r
+ CASE "e"\r
+ getMd sona$(2), m1, d1\r
+ getMd DATE$, m2, d2\r
+ IF (m1 = m2) AND (d1 = d2) THEN b$ = sona$(3)\r
+ END SELECT\r
+9\r
+NEXT a\r
+\r
+IF b$ <> lp$ THEN initp b$\r
+lp$ = b$\r
+tunnidara = 0\r
+dispp\r
+disp\r
+END SUB\r
+\r
+SUB chm\r
+a$ = DATE$\r
+IF a$ <> dato$ THEN chd\r
+dato$ = a$\r
+b = 0\r
+FOR a = 1 TO ppl\r
+ son pp$(a)\r
+ SELECT CASE sona$(1)\r
+ CASE "#"\r
+ getMd sona$(2), h1, m1\r
+ getMd TIME$, h2, m2\r
+ ' PRINT h1, m1, h2, m2\r
+ IF (h2 = h1) AND (m2 = m1) THEN\r
+ IF sona$(3) = "sis" THEN b = 1\r
+ IF sona$(3) = "val" THEN b = 2\r
+ END IF\r
+ END SELECT\r
+ NEXT a\r
+\r
+IF (tunnidara = 0) AND (b > 0) THEN kell b\r
+ssave = ssave + 1\r
+END SUB\r
+\r
+SUB clrerr\r
+errmsg$ = "tundmatu viga. V6ibolla on v2he RAM m2lu?"\r
+END SUB\r
+\r
+SUB disp\r
+CLS\r
+PRINT "Kooli Kell 3 2003.09"\r
+PRINT "autor: Svjatoslav Agejenko "\r
+PRINT ""\r
+PRINT "s - kell tundi sisse v - kell tunnist v�lja"\r
+PRINT "a - sisesta uus aeg d - sisesta uus daatum"\r
+PRINT "p - n2itab dokumentatsiooni j - j�tab k�ik tunnid t�na �ra"\r
+PRINT "7 - 1 minut tagasi 8 - 1 minut edasi"\r
+PRINT "4 - 1 tund tagasi 5 - 1 tund edasi"\r
+PRINT "r - programmi restart q - programmist v�lja"\r
+PRINT "k - konfiguratsiooni redaktor CTRL+L - klaviatuuri lukk (sees/v2ljas)"\r
+\r
+dispp\r
+\r
+LOCATE 12, 15\r
+PRINT "Kuu-P�ev-Aasta (USA standard)"\r
+\r
+LOCATE 17\r
+\r
+FOR a = 1 TO ppl\r
+ IF pp$(a) <> SPACE$(LEN(pp$(a))) THEN\r
+ PRINT pp$(a);\r
+ PRINT SPACE$(15 - LEN(pp$(a)));\r
+ END IF\r
+NEXT a\r
+\r
+displukk\r
+dispt\r
+END SUB\r
+\r
+SUB displukk\r
+LOCATE 1, 40\r
+IF kblukk = 1 THEN\r
+ COLOR 0, 7\r
+ PRINT "Klaviatuur lukus! Vajuta CTRL+L"\r
+ COLOR 15, 0\r
+ELSE\r
+ PRINT " "\r
+END IF\r
+END SUB\r
+\r
+SUB dispp\r
+IF ndlp = 0 THEN GOTO 14\r
+LOCATE 14, 1\r
+PRINT "n�dalap�ev:", pn$(ndlp)\r
+LOCATE 15, 1\r
+PRINT "p�evaplaan:", lp$\r
+14\r
+END SUB\r
+\r
+SUB dispt\r
+LOCATE 16, 20\r
+COLOR 12 + 15, 0\r
+IF tunnidara = 1 THEN\r
+ PRINT "T2na on k6ik tunnid 2ra j2etud"\r
+ELSE\r
+ PRINT " "\r
+END IF\r
+COLOR 15, 0\r
+END SUB\r
+\r
+SUB editor\r
+23\r
+leiaconf\r
+CLS\r
+COLOR 0, 15\r
+LOCATE 1, 1\r
+PRINT SPACE$(80);\r
+LOCATE 1, 1\r
+PRINT "Konfiguratsiooni redaktor. Valige v�lja p�eva v6i aasta plaani."\r
+LOCATE 2, 1\r
+PRINT SPACE$(80)\r
+LOCATE 2, 1\r
+PRINT " nr nimi laiend suurus loomisdaatum"\r
+\r
+LOCATE 22, 1\r
+PRINT SPACE$(80)\r
+LOCATE 22, 1\r
+PRINT "K - valitud faili kustutamine U - uus fail ESC - redaktorist v�lja"\r
+p = 0\r
+v = 1\r
+17\r
+FOR a = 3 TO 21\r
+ IF a - 2 + p = v THEN\r
+ COLOR 0, 7\r
+ LOCATE a, 1\r
+ PRINT cnflist$(a - 2 + p) + SPACE$(55 - LEN(cnflist$(a - 2 + p)))\r
+ LOCATE a, 56\r
+ COLOR 31, 0\r
+ PRINT "<=="\r
+ IF cnflist$(a - 2 + p) <> SPACE$(LEN(cnflist$(a - 2 + p))) THEN\r
+ COLOR 15, 0\r
+ PRINT " valitud: " + getName$(v)\r
+ END IF\r
+ COLOR 15, 0\r
+ ELSE\r
+ COLOR 15, 0\r
+ LOCATE a, 1\r
+ PRINT cnflist$(a - 2 + p) + SPACE$(80 - LEN(cnflist$(a - 2 + p)))\r
+ END IF\r
+NEXT a\r
+\r
+a$ = INKEY$\r
+LOCATE 1, 1\r
+'IF a$ <> "" THEN PRINT ASC(RIGHT$(a$, 1)); ASC(LEFT$(a$, 1))\r
+IF a$ = CHR$(27) THEN GOTO 18\r
+IF a$ = "u" OR a$ = "U" THEN SHELL "EDIT": GOTO 23\r
+IF a$ = CHR$(0) + "P" THEN v = v + 1\r
+IF a$ = CHR$(0) + "H" THEN v = v - 1\r
+IF a$ = CHR$(0) + CHR$(73) THEN v = v - 17\r
+IF a$ = CHR$(0) + CHR$(81) THEN v = v + 17\r
+IF a$ = "K" OR a$ = "k" THEN\r
+ IF LEN(getName$(v)) > 2 THEN\r
+ IF getName$(v) = "AASTA.AP" THEN\r
+ SOUND 3000, .1\r
+ ELSE\r
+ KILL getName$(v)\r
+ GOTO 23\r
+ END IF\r
+ ELSE\r
+ SOUND 3000, .1\r
+ END IF\r
+END IF\r
+IF a$ = CHR$(13) THEN\r
+ IF getName$(v) = "." THEN\r
+ SOUND 3000, .1\r
+ ELSE\r
+ SHELL "EDIT " + getName$(v)\r
+ GOTO 23\r
+ END IF\r
+END IF\r
+\r
+IF v < 1 THEN v = 1: SOUND 3000, .2\r
+IF v > 200 THEN v = 200: : SOUND 3000, .2\r
+\r
+21\r
+IF v - p > 19 THEN p = p + 1: GOTO 21\r
+22\r
+IF v - p < 1 THEN p = p - 1: GOTO 22\r
+\r
+GOTO 17\r
+18\r
+COLOR 15, 0\r
+disp\r
+END SUB\r
+\r
+SUB getMd (a$, m, d)\r
+b$ = LEFT$(a$, 5)\r
+m = VAL(LEFT$(b$, 2))\r
+d = VAL(RIGHT$(b$, 2))\r
+\r
+END SUB\r
+\r
+SUB getNad (g, n, d, k)\r
+'LOCATE 11, 1\r
+'PRINT g, n, d\r
+p = g\r
+m = n - 2\r
+IF n > 2 GOTO 120\r
+p = p - 1: m = m + 12\r
+120\r
+c = INT(p / 100)\r
+y = p - c * 100\r
+w = d + INT((13 * m - 1) / 5) + y + INT(y / 4) + INT(c / 4) - 2 * c\r
+k = w - 7 * INT(w / 7)\r
+IF k = 0 THEN k = 7\r
+END SUB\r
+\r
+FUNCTION getName$ (a)\r
+c$ = ""\r
+FOR b = 8 TO 40\r
+ d$ = getSym(cnflist$(a), b)\r
+ IF d$ = " " THEN GOTO 19\r
+ c$ = c$ + d$\r
+NEXT b\r
+19\r
+getName$ = c$ + "." + getSym(cnflist$(a), 17) + getSym(cnflist$(a), 18)\r
+END FUNCTION\r
+\r
+FUNCTION getSym$ (a$, b)\r
+getSym$ = RIGHT$(LEFT$(a$, b), 1)\r
+END FUNCTION\r
+\r
+SUB heli (a)\r
+'GOTO 10\r
+SELECT CASE a\r
+ CASE 1\r
+ FOR c = 1 TO 5\r
+ SOUND 3000, 1\r
+ SOUND 0, 1\r
+ NEXT c\r
+\r
+ CASE 2\r
+ FOR c = 1 TO 5\r
+ SOUND 2500, 1\r
+ SOUND 0, 2\r
+ NEXT c\r
+ SOUND 2500, 10\r
+\r
+ CASE 3\r
+ FOR a = 1 TO 10\r
+ SOUND 500, .5\r
+ SOUND 1500, .5\r
+ SOUND 2000, .5\r
+ SOUND 1520, .5\r
+ NEXT a\r
+\r
+ CASE 4\r
+ FOR a = 800 TO 1000 STEP 10\r
+ SOUND a, .1\r
+ SOUND a * 3, .1\r
+ SOUND 0, 1\r
+ NEXT a\r
+ 10\r
+END SELECT\r
+\r
+END SUB\r
+\r
+SUB inita\r
+apl = 0\r
+errmsg$ = "Ei leia aastaplaani faili! 'aasta.ap'"\r
+OPEN "aasta.ap" FOR INPUT AS #1\r
+clrerr\r
+5\r
+IF EOF(1) <> 0 THEN GOTO 3\r
+LINE INPUT #1, a$\r
+apl = apl + 1\r
+ap$(apl) = a$\r
+GOTO 5\r
+3\r
+CLOSE #1\r
+END SUB\r
+\r
+SUB initp (b$)\r
+ppl = 0\r
+errmsg$ = "Ei leia aastaplaanis mainitud '" + b$ + ".pp' p�evaplaani!"\r
+OPEN b$ + ".pp" FOR INPUT AS #1\r
+clrerr\r
+6\r
+IF EOF(1) <> 0 THEN GOTO 7\r
+LINE INPUT #1, a$\r
+ppl = ppl + 1\r
+pp$(ppl) = a$\r
+GOTO 6\r
+7\r
+CLOSE #1\r
+END SUB\r
+\r
+SUB kell (a)\r
+b$ = TIME$ + DATE$\r
+IF b$ <> lk$ THEN lk$ = b$ ELSE GOTO 2\r
+\r
+heli 3\r
+\r
+SELECT CASE a\r
+ CASE 1\r
+ kola 4\r
+ FOR b = 1 TO 15\r
+ SOUND 0, 1\r
+ NEXT b\r
+ kola 1\r
+\r
+ CASE 2\r
+ kola 5\r
+END SELECT\r
+2\r
+\r
+END SUB\r
+\r
+SUB kola (a)\r
+COLOR 15, 7\r
+s$ = ""\r
+FOR b = 1 TO 80\r
+ s$ = s$ + CHR$(219)\r
+NEXT b\r
+FOR b = 1 TO 30\r
+ PRINT s$;\r
+NEXT b\r
+\r
+timero = TIMER\r
+11\r
+OUT prt, 255\r
+IF ABS(timero - TIMER) < a THEN GOTO 11\r
+OUT prt, 0\r
+COLOR 15, 0\r
+disp\r
+END SUB\r
+\r
+SUB leiaconf\r
+FOR a = 1 TO 200\r
+ cnflist$(a) = ""\r
+NEXT a\r
+c = 1\r
+\r
+SHELL "dir >dir.tmp"\r
+OPEN "dir.tmp" FOR INPUT AS #1\r
+15\r
+IF EOF(1) <> 0 THEN GOTO 16\r
+LINE INPUT #1, a$\r
+IF LEN(a$) < 30 THEN GOTO 15\r
+IF LEFT$(a$, 1) = " " THEN GOTO 15\r
+IF LEFT$(a$, 1) = "." THEN GOTO 15\r
+b$ = RIGHT$(LEFT$(a$, 12), 3)\r
+IF b$ = "PP " OR b$ = "AP " THEN ELSE GOTO 15\r
+d$ = " " + STR$(c)\r
+a$ = RIGHT$(d$, 4) + " " + a$\r
+IF LEN(a$) > 50 THEN a$ = LEFT$(a$, 50)\r
+cnflist$(c) = a$\r
+c = c + 1\r
+GOTO 15\r
+16\r
+CLOSE #1\r
+KILL "dir.tmp"\r
+END SUB\r
+\r
+SUB mnmain\r
+1\r
+b$ = LEFT$(TIME$, 5)\r
+IF b$ <> timo$ THEN chm\r
+timo$ = b$\r
+\r
+a$ = INKEY$\r
+\r
+IF a$ <> "" THEN\r
+ IF ssave > ssavel THEN disp\r
+ ssave = 0\r
+END IF\r
+\r
+IF a$ = CHR$(12) THEN\r
+ IF kblukk = 1 THEN kblukk = 0 ELSE kblukk = 1\r
+ displukk\r
+END IF\r
+IF kblukk = 1 THEN\r
+ IF a$ <> "" THEN SOUND 3000, 1\r
+ a$ = ""\r
+END IF\r
+IF a$ = "k" OR a$ = "K" THEN editor\r
+\r
+IF a$ = "s" OR a$ = "S" THEN kell 1\r
+IF a$ = "v" OR a$ = "V" THEN kell 2\r
+\r
+IF a$ = "a" THEN\r
+ CLS\r
+ PRINT " vana aeg: " + TIME$\r
+ INPUT "sisesta uus aeg (TT:MM:SS): ", b$\r
+ IF LEN(b$) <> 8 THEN GOTO 12\r
+ TIME$ = b$\r
+ timo$ = ""\r
+ 12\r
+ disp\r
+END IF\r
+\r
+IF a$ = "d" OR a$ = "D" THEN\r
+ CLS\r
+ PRINT " vana daatum: " + DATE$\r
+ INPUT "sisesta uus daatum (KK-PP-AAAA): ", b$\r
+ IF LEN(b$) <> 10 THEN GOTO 13\r
+ DATE$ = b$\r
+ timo$ = ""\r
+ 13\r
+ disp\r
+END IF\r
+\r
+IF a$ = "7" OR a$ = "8" THEN\r
+ b = VAL(RIGHT$(LEFT$(TIME$, 5), 2))\r
+ IF a$ = "7" THEN b = b - 1\r
+ IF a$ = "8" THEN b = b + 1\r
+ IF b < 0 THEN b = 0\r
+ IF b > 59 THEN b = 59\r
+ d$ = STR$(b)\r
+ IF LEFT$(d$, 1) = " " THEN d$ = RIGHT$(d$, LEN(d$) - 1)\r
+ IF LEN(d$) < 2 THEN d$ = "0" + d$\r
+ e$ = LEFT$(TIME$, 3) + d$ + RIGHT$(TIME$, 3)\r
+ TIME$ = e$\r
+END IF\r
+\r
+IF a$ = "4" OR a$ = "5" THEN\r
+ b = VAL(LEFT$(TIME$, 2))\r
+ IF a$ = "4" THEN b = b - 1\r
+ IF a$ = "5" THEN b = b + 1\r
+ IF b < 0 THEN b = 0\r
+ IF b > 23 THEN b = 23\r
+ d$ = STR$(b)\r
+ IF LEFT$(d$, 1) = " " THEN d$ = RIGHT$(d$, LEN(d$) - 1)\r
+ IF LEN(d$) < 2 THEN d$ = "0" + d$\r
+ e$ = d$ + RIGHT$(TIME$, 6)\r
+ TIME$ = e$\r
+END IF\r
+\r
+IF a$ = "p" OR a$ = "P" THEN SHELL "EDIT juhend.txt": disp\r
+\r
+IF a$ = "r" OR a$ = "R" THEN rese\r
+IF a$ = "q" OR a$ = "Q" THEN SYSTEM\r
+\r
+IF a$ = "j" OR a$ = "J" THEN\r
+ IF tunnidara = 0 THEN tunnidara = 1 ELSE tunnidara = 0\r
+ dispt\r
+END IF\r
+\r
+IF ssave <= ssavel THEN\r
+ LOCATE 11, 1\r
+ PRINT TIME$\r
+ LOCATE 12, 1\r
+ PRINT DATE$\r
+ELSE\r
+ IF ABS(TIMER - timero) > 10 THEN\r
+ CLS\r
+ kblukk = 1\r
+ FOR b = 1 TO 20\r
+ LOCATE RND * 22 + 1, RND * 79 + 1\r
+ IF RND * 100 < 50 THEN PRINT "*" ELSE PRINT "."\r
+ NEXT b\r
+ LOCATE RND * 22 + 1, RND * 50 + 1\r
+ COLOR 0, 7\r
+ PRINT "< " + LEFT$(TIME$, 2);\r
+ COLOR 16, 7\r
+ PRINT ":";\r
+ COLOR 0, 7\r
+ PRINT RIGHT$(LEFT$(TIME$, 5), 2) + " >"\r
+ COLOR 15, 0\r
+ timero = TIMER\r
+ END IF\r
+END IF\r
+GOTO 1\r
+\r
+END SUB\r
+\r
+SUB rese\r
+heli 4\r
+timo$ = ""\r
+dato$ = ""\r
+apl = 0\r
+END SUB\r
+\r
+SUB son (a$)\r
+\r
+FOR b = 1 TO 50\r
+ sona$(b) = ""\r
+NEXT b\r
+mitus = 0\r
+\r
+b = 1\r
+FOR c = 1 TO LEN(a$)\r
+ d$ = RIGHT$(LEFT$(a$, c), 1)\r
+ IF d$ = " " OR d$ = CHR$(9) THEN\r
+ b = 1\r
+ ELSE\r
+ IF b = 1 THEN b = 0: mitus = mitus + 1\r
+ sona$(mitus) = sona$(mitus) + d$\r
+ END IF\r
+NEXT c\r
+\r
+END SUB\r
+\r
+SUB start\r
+CLS\r
+COLOR 15\r
+pn$(1) = "esmasp�ev"\r
+pn$(2) = "teisip�ev"\r
+pn$(3) = "kolmap�ev"\r
+pn$(4) = "neljap�ev"\r
+pn$(5) = "reede"\r
+pn$(6) = "laup�ev"\r
+pn$(7) = "p�hap�ev"\r
+\r
+prt = &H378\r
+\r
+ssavel = 2\r
+kblukk = 1\r
+tunnidara = 0\r
+\r
+OUT prt, 0\r
+END SUB\r
--- /dev/null
+# 08:30 sis\r
+# 09:00 val\r
+\r
+# 09:10 sis\r
+# 09:40 val\r
+\r
+# 09:50 sis\r
+# 10:20 val\r
+\r
+# 10:30 sis\r
+# 11:00 val\r
+\r
+# 11:30 sis\r
+# 12:00 val\r
+\r
+# 12:10 sis\r
+# 12:40 val\r
+\r
+# 12:50 sis\r
+# 13:20 val\r
+\r
+# 13:30 sis\r
+# 14:00 val\r
+\r
+# 14:05 sis\r
+# 14:35 val\r
+\r
--- /dev/null
+# 08:30 sis\r
+# 09:15 val\r
+\r
+# 09:25 sis\r
+# 10:10 val\r
+\r
+# 10:20 sis\r
+# 11:05 val\r
+\r
+# 11:35 sis\r
+# 12:20 val\r
+\r
+# 12:30 sis\r
+# 13:15 val\r
+\r
+# 13:20 sis\r
+# 14:05 val\r
+\r
+# 14:10 sis\r
+# 14:55 val\r
+\r
+# 15:00 sis\r
+# 15:45 val\r
--- /dev/null
+# 08:30 sis\r
+# 09:15 val\r
+\r
+# 09:25 sis\r
+# 10:10 val\r
+\r
+# 10:20 sis\r
+# 11:05 val\r
+\r
+# 11:35 sis\r
+# 12:20 val\r
+\r
+# 12:30 sis\r
+# 13:15 val\r
+\r
+# 13:25 sis\r
+# 14:10 val\r
+\r
+# 14:20 sis\r
+# 15:05 val\r
+\r
+# 15:10 sis\r
+# 15:55 val\r
+\r
+# 16:00 sis\r
+# 16:45 val\r
+\r
+# 16:50 sis\r
+# 17:35 val
\ No newline at end of file
--- /dev/null
+* Kooli Kell 3 programmi kasutusjuhend\r
+- 2003.09 :: Esimene versioon.\r
+- 2025 :: Parendatud juhendi sõnastus.\r
+\r
+- Programmi, juhendi ja skeemi autor :: Svjatoslav Agejenko\r
+- E-post :: svjatoslav@svjatoslav.eu\r
+- kodulehekülg :: https://www.svjatoslav.eu\r
+\r
+Ettevaatust: Siin tekstis olev info võib olla vananenud, vigane v6i\r
+ebatäielik. Autor ei võta endale vastutust antud süsteemi kasutamisest\r
+tekkinud otsese või kaudse kahju puhul!\r
+\r
+* Üldinfo\r
+\r
+Programm Kooli Kell on mõeldud kella laskmiseks koolis, tundi sisse ja\r
+välja.\r
+\r
+- Tundi sisse minev kell on 1 pikk ning 1 lühem helin.\r
+- Väljaminev kell on 1 tavaline pikk helin.\r
+\r
+Programm loeb aega arvuti süsteemsest kellast. Fail 'AASTA.AP' hoiab\r
+aasta graafikut, kus saab määrata teatud päeva kohta käiva\r
+päevaplaani. Päevaplaanid asuvad failides '*.PP'.\r
+\r
+Aasta või päevaplaani muutmiseks tuleb redigeerida vastavaid faile.\r
+Failides on info esitatud programmile 'Kooli Kell' arusaadavate\r
+käskudena. Kus ühel real on üks käsk, või tühi rida. Rea esimene sõna\r
+peab olema käsk, ning järgnevad sõnad on selle käsu parameetrid. Sõnad\r
+võivad olla eraldatud suvalise 0 suuremate tabulaatorite ja/või\r
+tühikute arvuga. Programmi saab kasutada arvutil millele on ühendatud\r
+spetsiaalne liides, või millel on see liides sisse\r
+monteeritud. Liideses olev relee toimib lülitina, mis kella laskmise\r
+ajaks sulgub. Liides vooluahelasse ise voolu ei anna. Seega on liides\r
+mõeldud kella ja toiteallikaga vooluahelasse jadamisi\r
+ühendamiseks. Või siis olemasoleva mehaanilise kella laskmis nupuga\r
+paralleelselt, siis saab kella lasta nii endisest nupust kui ka\r
+arvutiga.\r
+\r
+Programm on ettenähtud iseseisvalt töötama, kuid on ka võimalus\r
+erandkorras k2sitsi kella lasta, aega muuta jne. Selleks tuleb\r
+vajutada erinevaid klahve klaviatuuril. K2ivitudes kuvab programm\r
+klahvide kirjeldused ekraanile.\r
+\r
+* faili AASTA.AP formaat\r
+\r
+Lõpp 'AP' tuleneb sõnadest Aasta plaan.\r
+\r
+: v <kuu>-<päev> <kuu>-<päev> <päevaplaan>\r
+\r
+Sõnast vahemik. Paneb paika p2evaplaani antud ajavahemikus. Esimene\r
+daatum peab kindlasti olema v2iksem kui teine. St. kui on tõesti vaja:\r
+\r
+: v 10-4 2-1 eri\r
+\r
+tuleb kirjutada:\r
+\r
+: v 10-4 12-31 eri\r
+: v 1-1 2-1 eri\r
+\r
+P2evaplaan kehtib vahemiku esimesest p2evast kuni vahemiku viimase p2evani.\r
+\r
+: n <kuu>-<päev> <kuu>-<päev> <nädalapäev> <päevaplaan>\r
+\r
+Sõnast n2dalap2ev. sama mis "v" kuid: paneb paika p2evaplaani antud\r
+ajavahemikus, antud n2dalap2eval. N2dalap2eva kirjeldatakse numbriga.\r
+n2dala esimene p2ev on esmasp2ev, talle vastab number 1.\r
+\r
+: e <kuu>-<päev> <päevaplaan>\r
+\r
+Sõnast eripäevaplaan. Paneb paika antud kuupäevale antud päevaplaani.\r
+Sobib hästi erakorraliste, lühendatud või uhekordselt kehtivate\r
+päevaplaanide kehtestamiseks. Näiteks riigipühad, spordipäev jne.\r
+\r
+Kui teatud päeva kohta ei käinud ühtegi kirjet siis toimib vaikimisi "tuhi"\r
+päevaplaan. Kui teatud päeva kohta käis mitu kirjet siis jääb peale viimane.\r
+\r
+* failide *.PP formaat\r
+\r
+Lõpp 'PP' tuleneb sõnadest Päeva Plaan.\r
+\r
+: # <tund>:<minut> <kell>\r
+\r
+Laseb antud ajal antud kella. Võimalikud kella helinad on:\r
+\r
+- sis :: -kell tundi sisse\r
+- val :: -kell tunnist välja\r
+\r
+* Raudvara nõuded\r
+\r
+- 286 protsessoriga PC tüüpi arvuti. :: Peaks töötama ka 8086 protsessoril aga pole testinud.\r
+\r
+- 640 KB põhimälu :: Vähemaga pole testinud.\r
+\r
+- 500 KB vaba kettaruumi :: Kõvakettalt töö kiirendab oluliselt\r
+ programmi käivitumist, ja konfiguratsiooni redigeerimist.\r
+\r
+- LPT port.\r
+\r
+- Monitor :: Võib olla mustvalge\r
+\r
+- Klaviatuur.\r
+\r
+* Tarkvara nõuded\r
+\r
+- DOS 6.22 :: Võib ka varasem, kuid pole testinud.\r
+- QB 4.5 :: Piisab 'QB.EXE' failist. Peaks t88tama ka MS QBasic-us.\r
+- EDIT.EXE :: DOSi käsurealt käivituv teksti redaktor.\r
+\r
+* Nõuded inimesele\r
+\r
+Süsteemi kasutamiseks hädavajalik antud juhendist aru saamine.\r
+Süsteemi paigaldamine nõuab elektriku oskusi. Programmi kasutamiseks\r
+on vajalik vähemalt algaja tasemel arvutikasutaja oskus.\r
--- /dev/null
+' An attempt to generate a universally reusable color palette for 256 color limit.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2001, Initial version.\r
+' 2024.08, Enhance program readability\r
+\r
+DEFINT A-Y\r
+SCREEN 13\r
+CLS\r
+\r
+' Initialize color index\r
+colorIndex = 0\r
+\r
+' Generate colors by varying red, green, and blue components from 0 to 5\r
+FOR redComponent = 0 TO 5\r
+ FOR greenComponent = 0 TO 5\r
+ FOR blueComponent = 0 TO 5\r
+ ' Set the color for the next pixel\r
+ OUT &H3C8, colorIndex\r
+ colorIndex = colorIndex + 1\r
+\r
+ ' Output the RGB components to the palette registers\r
+ OUT &H3C9, redComponent * 12\r
+ OUT &H3C9, greenComponent * 12\r
+ OUT &H3C9, blueComponent * 12\r
+ NEXT blueComponent\r
+ NEXT greenComponent\r
+NEXT redComponent\r
+\r
+' Draw a grid of colored squares using the generated color palette\r
+FOR colorIndex = 0 TO 5\r
+ FOR blueComponent = 0 TO 5\r
+ FOR redComponent = 0 TO 5\r
+ ' Draw a square with the calculated color\r
+ LINE (redComponent * 5 + colorIndex * 30, blueComponent * 5)-_\r
+ (redComponent * 5 + 4 + colorIndex * 30, blueComponent * 5 + 4), _\r
+ colorIndex * 36 + blueComponent * 6 + redComponent, BF\r
+ NEXT redComponent\r
+ NEXT blueComponent\r
+NEXT colorIndex\r
+\r
+' Wait for user input before proceeding\r
+a$ = INPUT$(1)\r
+\r
+' Initialize coordinates for pattern drawing\r
+patternEx = -100\r
+patternEy = 0\r
+\r
+' Draw a series of patterns with varying colors\r
+FOR patternZ = 0 TO 75 STEP 15\r
+ ' Calculate the vertices of an equilateral triangle\r
+ x1 = 50 - (patternZ / 2)\r
+ y1 = 50 - (patternZ * .866025)\r
+ x2 = 50 + patternZ\r
+ y2 = 50\r
+ x3 = x1\r
+ y3 = 100 - y1\r
+\r
+ ' Move to the next starting position for the pattern\r
+ patternEx = patternEx + 100\r
+ IF patternZ = 45 THEN\r
+ patternEx = patternEx - 300\r
+ patternEy = patternEy + 101\r
+ END IF\r
+\r
+ ' Draw the pattern by calculating colors based on distance from triangle vertices\r
+ FOR x = 0 TO 100\r
+ FOR y = 0 TO 100\r
+ ' Calculate color components based on distance to each vertex\r
+ r = 7 - (SQR((x1 - x) ^ 2 + (y1 - y) ^ 2) / 15 + 1)\r
+ g = 7 - (SQR((x2 - x) ^ 2 + (y2 - y) ^ 2) / 15 + 1)\r
+ b = 7 - (SQR((x3 - x) ^ 2 + (y3 - y) ^ 2) / 15 + 1)\r
+\r
+ ' Clamp color values within the range of 0 to 5\r
+ IF r < 0 THEN r = 0\r
+ IF g < 0 THEN g = 0\r
+ IF b < 0 THEN b = 0\r
+ IF r > 5 THEN r = 5\r
+ IF g > 5 THEN g = 5\r
+ IF b > 5 THEN b = 5\r
+\r
+ ' Calculate the final color index\r
+ colorIndex = r * 36 + g * 6 + b\r
+\r
+ ' Plot the pixel with the calculated color\r
+ PSET (x + patternEx, y + patternEy), colorIndex\r
+ NEXT y\r
+ NEXT x\r
+NEXT patternZ\r
+\r
+' Wait for user input before proceeding\r
+a$ = INPUT$(1)\r
+\r
+' Reset starting position for the second pattern\r
+patternEx = -100\r
+patternEy = 0\r
+\r
+' Draw a second series of patterns using color dithering, to create\r
+' seemingly smooth color transitions while still having only 8bit colors to work with\r
+FOR patternZ = 0 TO 75 STEP 15\r
+ ' Calculate the vertices of an equilateral triangle with different scaling\r
+ x1 = 50 - (patternZ / 2.5)\r
+ y1 = 50 - (patternZ * .566025)\r
+ x2 = 50 + patternZ / 1.5\r
+ y2 = 50\r
+ x3 = x1\r
+ y3 = 100 - y1\r
+\r
+ ' Move to the next starting position for the pattern\r
+ patternEx = patternEx + 100\r
+ IF patternZ = 45 THEN\r
+ patternEx = patternEx - 300\r
+ patternEy = patternEy + 101\r
+ END IF\r
+\r
+ ' Initialize accumulators for dithering color components\r
+ rSum = 0\r
+ gSum = 0\r
+ bSum = 0\r
+\r
+ ' Draw the pattern by calculating average colors based on distance from triangle vertices\r
+ FOR x = 0 TO 100\r
+ FOR y = 0 TO 100\r
+ ' Calculate color components based on distance to each vertex\r
+ r = 30 - (SQR((x1 - x) ^ 2 + (y1 - y) ^ 2) / 2 + 1)\r
+ g = 30 - (SQR((x2 - x) ^ 2 + (y2 - y) ^ 2) / 2 + 1)\r
+ b = 30 - (SQR((x3 - x) ^ 2 + (y3 - y) ^ 2) / 2 + 1)\r
+\r
+ ' Accumulate the color components\r
+ rSum = rSum + r\r
+ gSum = gSum + g\r
+ bSum = bSum + b\r
+\r
+ ' Calculate the average color components over a span of 5 pixels\r
+ rAvg = rSum / 5\r
+ gAvg = gSum / 5\r
+ bAvg = bSum / 5\r
+\r
+ ' Reset the sums after calculating the averages\r
+ rSum = rSum - (rAvg * 5)\r
+ gSum = gSum - (gAvg * 5)\r
+ bSum = bSum - (bAvg * 5)\r
+\r
+ ' Clamp average color values within the range of 0 to 5\r
+ IF rAvg < 0 THEN rAvg = 0\r
+ IF gAvg < 0 THEN gAvg = 0\r
+ IF bAvg < 0 THEN bAvg = 0\r
+ IF rAvg > 5 THEN rAvg = 5\r
+ IF gAvg > 5 THEN gAvg = 5\r
+ IF bAvg > 5 THEN bAvg = 5\r
+\r
+ ' Calculate the final color index\r
+ colorIndex = rAvg * 36 + gAvg * 6 + bAvg\r
+\r
+ ' Plot the pixel with the calculated color\r
+ PSET (x + patternEx, y + patternEy), colorIndex\r
+ NEXT y\r
+ NEXT x\r
+NEXT patternZ\r
+\r
+' Wait for user input before exiting\r
+a$ = INPUT$(1)
\ No newline at end of file
--- /dev/null
+fload data.ddb\r
+chklin 1 |> s 1\r
+|> c
\ No newline at end of file
--- /dev/null
+// 1 First name\r
+// 2 Last name\r
+// 3 Postal address\r
+// 4 Phone\r
+// 5 Sex M / F\r
+// 6 Registration number in the database\r
+// 7 Birth year\r
+\r
+John |Doe |Marshmelow road 1-23 | +385 123123123 |M|0|1985\r
+Jane |Doe |Candy road 1-23 | +385 123123124 |F|1|1987\r
+\r
--- /dev/null
+' Simple scriptable relational database engine.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2002, Initial version\r
+' 2024, Improved program readability\r
+\r
+DECLARE SUB box (x1%, y1%, x2%, y2%)\r
+DECLARE SUB ssort (s%, m%)\r
+DECLARE SUB sort (s%, w%)\r
+REM $DYNAMIC\r
+DECLARE SUB cmp (a$, b$, r%)\r
+DECLARE SUB boss ()\r
+DECLARE SUB std (a$)\r
+DECLARE FUNCTION cnum$ (a%)\r
+DECLARE SUB fload (a$, b%, c%, d%)\r
+DECLARE SUB putfs (f%, l%, s%, c$)\r
+DECLARE SUB gets (l%, s%, a$)\r
+DECLARE SUB puts (l%, s%, a$)\r
+DECLARE SUB runf (a$)\r
+DECLARE SUB getfil (a%)\r
+DEFINT A-Y\r
+DECLARE SUB mkson (a$)\r
+DECLARE SUB title (a$)\r
+DECLARE SUB strip (a$, b$)\r
+DECLARE SUB cmd (a$)\r
+DECLARE SUB conkey (a$)\r
+DECLARE SUB conn (a$)\r
+DECLARE SUB ch ()\r
+DECLARE SUB chkey (a$)\r
+DECLARE SUB getkey (a$)\r
+DECLARE SUB conm (d$, c)\r
+DECLARE SUB start ()\r
+\r
+DIM SHARED con$(1 TO 50)\r
+DIM SHARED conc(1 TO 50)\r
+DIM SHARED concmd$\r
+DIM SHARED conx\r
+DIM SHARED sona$(1 TO 20)\r
+DIM SHARED mitus\r
+\r
+DIM SHARED buf$(1 TO 5000)\r
+DIM SHARED bufu(1 TO 5000)\r
+DIM SHARED bufl(1 TO 1000, 1 TO 30)\r
+DIM SHARED buflu(1 TO 1000)\r
+DIM SHARED lng\r
+DIM SHARED opf(1 TO 30)\r
+DIM SHARED hist$(1 TO 20)\r
+DIM SHARED histp, histk\r
+DIM SHARED buff(1 TO 30, 1 TO 1000)\r
+DIM SHARED stack(1 TO 2000, 1 TO 10)\r
+DIM SHARED stackl(1 TO 10)\r
+DIM SHARED stdl\r
+\r
+start\r
+\r
+1\r
+ch\r
+GOTO 1\r
+\r
+REM $STATIC\r
+SUB boss\r
+y1 = 0\r
+yp1 = 100\r
+y2 = 0\r
+yp2 = 100\r
+\r
+lx = 160\r
+ly = 100\r
+lxp = 1\r
+lyp = -1\r
+\r
+SCREEN 13\r
+\r
+GOSUB 18\r
+16\r
+a$ = INKEY$\r
+IF a$ = CHR$(0) + "H" THEN yp1 = yp1 - 25\r
+IF a$ = CHR$(0) + "P" THEN yp1 = yp1 + 25\r
+IF a$ = CHR$(27) THEN GOTO 17\r
+\r
+LINE (10, y1 - 35)-(20, y1 + 35), 0, B\r
+LINE (11, y1 - 34)-(19, y1 + 34), 15, B\r
+\r
+LINE (310, y2 - 35)-(300, y2 + 35), 0, B\r
+LINE (309, y2 - 34)-(301, y2 + 34), 15, B\r
+\r
+LINE (lx - 10, ly - 10)-(lx + 10, ly + 10), 0, B\r
+LINE (lx - 9, ly - 9)-(lx + 9, ly + 9), 15, B\r
+\r
+lx = lx + lxp\r
+ly = ly + lyp\r
+IF ly < 20 THEN lyp = 1\r
+IF ly > 180 THEN lyp = -1\r
+IF lx < 30 THEN\r
+ lxp = 1\r
+ IF ly < y1 - 35 OR ly > y1 + 35 THEN SOUND 1000, 1\r
+END IF\r
+IF lx > 290 THEN\r
+ lxp = -1\r
+ GOSUB 18\r
+END IF\r
+\r
+IF yp1 > 0 THEN y1 = y1 + 1: yp1 = yp1 - 1\r
+IF yp1 < 0 THEN y1 = y1 - 1: yp1 = yp1 + 1\r
+IF yp2 > 0 THEN y2 = y2 + 1: yp2 = yp2 - 1\r
+IF yp2 < 0 THEN y2 = y2 - 1: yp2 = yp2 + 1\r
+\r
+SOUND 0, .1\r
+GOTO 16\r
+\r
+18\r
+tlx = lx\r
+tly = ly\r
+tlyp = lyp\r
+tlxp = lxp\r
+\r
+19\r
+lx = lx + lxp\r
+ly = ly + lyp\r
+IF ly < 20 THEN lyp = 1\r
+IF ly > 180 THEN lyp = -1\r
+IF lx < 30 THEN lxp = 1\r
+IF lx > 290 THEN\r
+ yp2 = ly - y2\r
+ELSE\r
+ GOTO 19\r
+END IF\r
+\r
+SWAP lx, tlx\r
+SWAP ly, tly\r
+SWAP lyp, tlyp\r
+SWAP lxp, tlxp\r
+RETURN\r
+\r
+17\r
+SCREEN 0\r
+WIDTH 80, 50\r
+VIEW PRINT 1 TO 50\r
+END SUB\r
+\r
+SUB box (x1, y1, x2, y2)\r
+b$ = ""\r
+c$ = ""\r
+FOR a = x1 TO x2\r
+ b$ = b$ + " "\r
+ c$ = c$ + "-"\r
+NEXT a\r
+\r
+b$ = "|" + b$ + "|"\r
+c$ = "|" + c$ + "|"\r
+\r
+COLOR 14, 0\r
+LOCATE y1, x1\r
+PRINT c$\r
+LOCATE y2, x1\r
+PRINT c$\r
+FOR a = y1 + 1 TO y2 - 1\r
+ LOCATE a, y1\r
+ PRINT b$\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB ch\r
+chkey a$\r
+IF a$ <> "" THEN conkey a$\r
+\r
+END SUB\r
+\r
+SUB chkey (a$)\r
+a$ = INKEY$\r
+IF a$ <> "" THEN\r
+ IF a$ = CHR$(0) + "M" THEN a$ = "pa"\r
+ IF a$ = CHR$(0) + "K" THEN a$ = "va"\r
+ IF a$ = CHR$(0) + "H" THEN a$ = "ul"\r
+ IF a$ = CHR$(0) + "P" THEN a$ = "al"\r
+END IF\r
+\r
+END SUB\r
+\r
+SUB cmd (a$)\r
+IF a$ = SPACE$(LEN(a$)) THEN GOTO 5\r
+conm a$, 14\r
+\r
+mkson a$\r
+IF mitus = 0 THEN GOTO 5\r
+\r
+SELECT CASE sona$(1)\r
+CASE "help"\r
+ title "help"\r
+ conm "help - for help", 7\r
+ conm "quit - quit program", 7\r
+ conm "b - boss screen", 7\r
+ conm "memstat- show info about memory blocks", 7\r
+ conm "memput <addr> <data> - put data to specified memory block", 7\r
+ conm "memlist <addr> <amount> - show memory blocks, starting from <addr>", 7\r
+ conm "runf <file.ext> - run script file", 7\r
+ conm "lnstat - show info about memory lines", 7\r
+ conm "lnput <line> <word> <data> <data> ... put data in <line> starting from <word>", 7\r
+ conm "lnlist <addr> <amount> - show contenc of memory lines", 7\r
+ conm "fstat - show info about memory files", 7\r
+ conm "fput <file> <line> <word> <data> <data> ... put data in memory file", 7\r
+ conm "fload <filename.ext> <file> <line> <word>- load data file into memory file", 7\r
+ conm "cls - clear screen", 7\r
+ conm "stclear <stack> - clear stack", 7\r
+ conm "chklin <page> <from line> <to line> - determine used line numbers to STDOUT", 7\r
+ conm "stacksize <stack> - determine stack size to STDOUT", 7\r
+ conm "filtand <stack> <word> <mask> <word> <mask> ... filters out lines to STDOUT", 7\r
+ conm "filtor <stack> <word> <mask> <word> <mask> ... filters out lines to STDOUT", 7\r
+ conm "disp <stack> <word> <word> ... display formatted selected cells to STDOUT", 7\r
+ conm "sort <stack> <word> - sort elements by <word> value, lower first", 7\r
+ conm "swap <stack> - swap stack elements (backwards)", 7\r
+ conm "ssort <stack> <word> - sort stack in alphabetical order", 7\r
+ conm "memget <pointer> - allocates memory block, and puts there -", 7\r
+ conm "liststack <stack> <from line> <to line> - show stack values to STDOUT", 7\r
+ conm "ask <question> <file> <line> <word> - asks question, and stores result", 7\r
+ conm "flnget <file> <pointer> - get unused line in file", 7\r
+GOTO 5\r
+\r
+CASE "quit"\r
+SYSTEM\r
+\r
+CASE "memstat"\r
+title "memory blocks summary"\r
+c = 0\r
+lng = 0\r
+FOR b = 1 TO 5000\r
+ IF bufu(b) > 0 THEN c = c + 1\r
+ lng = lng + LEN(buf$(b))\r
+NEXT b\r
+d$ = "memory blocks used:" + STR$(c) + " total 5000"\r
+conm d$, 7\r
+d$ = "data size:" + STR$(lng)\r
+conm d$, 7\r
+GOTO 5\r
+\r
+CASE "memput"\r
+b = VAL(sona$(2))\r
+strip sona$(3), c$\r
+IF c$ = "" THEN\r
+ bufu(b) = 0\r
+ buf$(b) = ""\r
+ELSE\r
+ bufu(b) = 1\r
+ buf$(b) = sona$(3)\r
+END IF\r
+GOTO 5\r
+\r
+CASE "memlist"\r
+b = VAL(sona$(2))\r
+c = VAL(sona$(3))\r
+IF b = 0 THEN b = 1\r
+IF c = 0 THEN c = 1\r
+\r
+FOR d = b TO 5000\r
+ IF c = 0 THEN GOTO 5\r
+ IF bufu(d) > 0 THEN\r
+ e$ = cnum(d) + ":" + SPACE$(5 - LEN(cnum(d)))\r
+ e$ = e$ + buf$(d)\r
+ conm e$, 7\r
+ c = c - 1\r
+ END IF\r
+NEXT d\r
+GOTO 5\r
+\r
+CASE "runf"\r
+runf sona$(2)\r
+GOTO 5\r
+\r
+CASE "lnstat"\r
+title "memory lines summary"\r
+c = 0\r
+d = 0\r
+FOR b = 1 TO 1000\r
+ IF buflu(b) > 0 THEN c = c + 1: d = d + buflu(b)\r
+NEXT b\r
+d$ = "memory lines used:" + STR$(c) + " total 1000"\r
+conm d$, 7\r
+d$ = "total number of words in lines:" + STR$(d)\r
+conm d$, 7\r
+GOTO 5\r
+\r
+CASE "lnput"\r
+b = VAL(sona$(2))\r
+c = VAL(sona$(3))\r
+e = mitus\r
+IF e < 4 THEN e = 4\r
+FOR d = 4 TO e\r
+ puts b, c + d - 4, sona$(d)\r
+NEXT d\r
+GOTO 5\r
+\r
+CASE "lnlist"\r
+b = VAL(sona$(2))\r
+c = VAL(sona$(3))\r
+\r
+FOR d = b TO 1000\r
+ IF c = 0 THEN GOTO 5\r
+ IF buflu(d) > 0 THEN\r
+ e$ = cnum(d) + ":"\r
+ e$ = e$ + SPACE$(5 - LEN(e$))\r
+ e$ = e$ + cnum(buflu(d))\r
+ e$ = e$ + SPACE$(8 - LEN(e$))\r
+\r
+ FOR g = 1 TO 10\r
+ gets d, g, f$\r
+ e$ = e$ + " >" + f$\r
+ NEXT g\r
+ conm e$, 7\r
+ c = c - 1\r
+ END IF\r
+NEXT d\r
+GOTO 5\r
+\r
+CASE "fstat"\r
+title "Memory files summary"\r
+FOR b = 1 TO 30\r
+ e = 0\r
+ FOR c = 1 TO 1000\r
+ IF buff(b, c) > -1 THEN\r
+ IF e = 0 THEN\r
+ d$ = "File number:" + STR$(b)\r
+ conm d$, 7\r
+ e = e + 1\r
+ END IF\r
+ d$ = "on line:" + STR$(c) + " allocated memory line: " + STR$(buff(b, c))\r
+ conm d$, 7\r
+ END IF\r
+ NEXT c\r
+NEXT b\r
+GOTO 5\r
+\r
+CASE "fput"\r
+b = VAL(sona$(2))\r
+c = VAL(sona$(3))\r
+d = VAL(sona$(4))\r
+f = mitus\r
+IF f < 5 THEN f = 5\r
+FOR e = 5 TO f\r
+ putfs b, c, d + e - 5, sona$(e)\r
+NEXT e\r
+GOTO 5\r
+\r
+CASE "cls"\r
+FOR b = 1 TO 50\r
+ conm " ", 7\r
+NEXT b\r
+GOTO 5\r
+\r
+CASE "fload"\r
+b = VAL(sona$(3))\r
+c = VAL(sona$(4))\r
+d = VAL(sona$(5))\r
+IF b = 0 THEN b = 1\r
+IF c = 0 THEN c = 1\r
+IF d = 0 THEN d = 1\r
+fload sona$(2), b, c, d\r
+GOTO 5\r
+\r
+CASE "stclear"\r
+b = VAL(sona$(2))\r
+IF b = 0 THEN b = 1\r
+stackl(b) = 0\r
+GOTO 5\r
+\r
+CASE "chklin"\r
+b = VAL(sona$(2))\r
+c = VAL(sona$(3))\r
+d = VAL(sona$(4))\r
+IF b = 0 THEN b = 1\r
+IF c = 0 THEN c = 1\r
+IF d = 0 THEN d = 1000\r
+\r
+FOR e = c TO d\r
+ IF buff(b, e) > 0 THEN std cnum(buff(b, e))\r
+NEXT e\r
+GOTO 5\r
+\r
+CASE "stacksize"\r
+b = VAL(sona$(2))\r
+IF b = 0 THEN b = 1\r
+std cnum(stackl(b))\r
+GOTO 5\r
+\r
+CASE "b"\r
+boss\r
+conm "returning", 7\r
+GOTO 5\r
+\r
+CASE "filtor"\r
+b = VAL(sona$(2))\r
+FOR e = 1 TO stackl(b)\r
+ FOR c = 3 TO mitus STEP 2\r
+ gets stack(e, b), VAL(sona$(c)), f$\r
+ cmp f$, sona$(c + 1), d\r
+ IF d = 1 THEN\r
+ std cnum(stack(e, b))\r
+ GOTO 20\r
+ END IF\r
+ NEXT c\r
+20\r
+NEXT e\r
+GOTO 5\r
+\r
+CASE "disp"\r
+b = VAL(sona$(2))\r
+DIM tmp1(1 TO 100)\r
+DIM tmp2(1 TO 100)\r
+\r
+FOR d = 1 TO 100\r
+ tmp2(d) = 0\r
+NEXT d\r
+d = 0\r
+\r
+FOR e = 3 TO mitus\r
+ d = d + 1\r
+ tmp1(d) = VAL(sona$(e))\r
+NEXT e\r
+\r
+FOR c = 1 TO stackl(b)\r
+ FOR e = 1 TO d\r
+ gets stack(c, b), tmp1(e), f$\r
+ IF tmp2(e) < LEN(f$) THEN tmp2(e) = LEN(f$)\r
+ NEXT e\r
+NEXT c\r
+\r
+FOR c = 1 TO stackl(b)\r
+ g$ = ""\r
+ FOR e = 1 TO d\r
+ gets stack(c, b), tmp1(e), f$\r
+ f$ = f$ + SPACE$(tmp2(e) - LEN(f$))\r
+ g$ = g$ + f$ + " # "\r
+ NEXT e\r
+ conm g$, 10\r
+NEXT c\r
+\r
+ERASE tmp2\r
+ERASE tmp1\r
+GOTO 5\r
+\r
+CASE "filtand"\r
+b = VAL(sona$(2))\r
+FOR e = 1 TO stackl(b)\r
+ FOR c = 3 TO mitus STEP 2\r
+ gets stack(e, b), VAL(sona$(c)), f$\r
+ cmp f$, sona$(c + 1), d\r
+ IF d = 0 THEN GOTO 21\r
+ NEXT c\r
+ std cnum(stack(e, b))\r
+21\r
+NEXT e\r
+GOTO 5\r
+\r
+CASE "sort"\r
+b = VAL(sona$(2))\r
+c = VAL(sona$(3))\r
+sort b, c\r
+GOTO 5\r
+\r
+CASE "swap"\r
+b = VAL(sona$(2))\r
+c = stackl(b)\r
+FOR d = 1 TO c / 2\r
+ SWAP stack(d, b), stack(c - d + 1, b)\r
+NEXT d\r
+GOTO 5\r
+\r
+CASE "ssort"\r
+b = VAL(sona$(2))\r
+c = VAL(sona$(3))\r
+IF b = 0 THEN b = 1\r
+IF c = 0 THEN c = 1\r
+ssort b, c\r
+GOTO 5\r
+\r
+CASE "memget"\r
+b = VAL(sona$(2))\r
+IF b = 0 THEN b = 1\r
+FOR c = 1 TO 5000\r
+IF bufu(c) = 0 THEN bufu(c) = 1: buf$(c) = "-": stack(b, 10) = c: GOTO 23\r
+NEXT c\r
+23\r
+IF stackl(10) < b THEN stackl(10) = b\r
+GOTO 5\r
+\r
+CASE "liststack"\r
+b = VAL(sona$(2))\r
+c = VAL(sona$(3))\r
+d = VAL(sona$(4))\r
+IF b = 0 THEN b = 1\r
+IF c = 0 THEN c = 1\r
+IF d = 0 THEN d = stackl(b)\r
+FOR e = c TO d\r
+ std cnum(stack(e, b))\r
+NEXT e\r
+GOTO 5\r
+\r
+CASE "ask"\r
+b$ = sona$(2)\r
+IF b$ = "" THEN b$ = "input"\r
+c = VAL(sona$(3))\r
+d = VAL(sona$(4))\r
+e = VAL(sona$(5))\r
+box 5, 5, 75, 11\r
+LOCATE 7, 7\r
+PRINT b$\r
+LOCATE 9, 7\r
+INPUT "", f$\r
+putfs c, d, e, f$\r
+conm "'" + f$ + "' accepted", 7\r
+GOTO 5\r
+\r
+CASE "flnget"\r
+b = VAL(sona$(2))\r
+c = VAL(sona$(3))\r
+FOR d = 1 TO 1000\r
+ IF buff(b, d) = -1 THEN\r
+ stack(c, 10) = d\r
+ IF stackl(10) < c THEN stackl(10) = c\r
+ GOTO 24\r
+ END IF\r
+NEXT d\r
+24\r
+GOTO 5\r
+\r
+END SELECT\r
+\r
+conm "Invalid command", 12\r
+5\r
+END SUB\r
+\r
+SUB cmp (a$, b$, r%)\r
+IF a$ = b$ THEN r% = 1 ELSE r% = 0\r
+END SUB\r
+\r
+FUNCTION cnum$ (a)\r
+b$ = STR$(a)\r
+cnum$ = RIGHT$(b$, LEN(b$) - 1)\r
+END FUNCTION\r
+\r
+SUB conkey (a$)\r
+b$ = concmd$ + SPACE$(85)\r
+b$ = LEFT$(b$, 80)\r
+\r
+IF a$ = "va" THEN conx = conx - 1\r
+IF a$ = "pa" THEN conx = conx + 1\r
+IF a$ = "ul" THEN\r
+ b$ = hist$(histk)\r
+ histk = histk - 1\r
+ IF histk < 1 THEN histk = 20\r
+END IF\r
+IF a$ = "al" THEN\r
+ b$ = hist$(histk)\r
+ histk = histk + 1\r
+ IF histk > 20 THEN histk = 1\r
+END IF\r
+\r
+IF LEN(a$) = 1 THEN\r
+ IF a$ = CHR$(13) THEN\r
+ strip b$, c$\r
+ histp = histp + 1\r
+ IF histp > 20 THEN histp = 1\r
+ histk = histp\r
+ hist$(histp) = c$\r
+ cmd c$\r
+ b$ = ""\r
+ conx = 1\r
+ GOTO 4\r
+ END IF\r
+\r
+ IF a$ = CHR$(8) THEN\r
+ IF conx > 1 THEN\r
+ b$ = LEFT$(b$, conx - 2) + RIGHT$(b$, 81 - conx)\r
+ conx = conx - 1\r
+ END IF\r
+ GOTO 4\r
+ END IF\r
+\r
+ b$ = LEFT$(b$, conx - 1) + a$ + RIGHT$(b$, 81 - conx)\r
+ conx = conx + 1\r
+END IF\r
+4\r
+\r
+IF conx < 1 THEN conx = 1\r
+IF conx > 80 THEN conx = 80\r
+\r
+b$ = b$ + SPACE$(85)\r
+concmd$ = LEFT$(b$, 80)\r
+LOCATE 50, 1\r
+COLOR 15, 1\r
+PRINT concmd$;\r
+LOCATE 50, conx\r
+COLOR 0, 14\r
+PRINT RIGHT$(LEFT$(concmd$, conx), 1);\r
+\r
+\r
+END SUB\r
+\r
+SUB conm (d$, c)\r
+a$ = d$\r
+\r
+14\r
+IF LEN(a$) > 78 THEN\r
+ b$ = LEFT$(a$, 78)\r
+ conm b$, c\r
+ a$ = " >> " + RIGHT$(a$, LEN(a$) - 78)\r
+ GOTO 14\r
+END IF\r
+\r
+b$ = a$ + SPACE$(80 - LEN(a$))\r
+con$(50) = b$\r
+conc(50) = c\r
+\r
+FOR a = 1 TO 49\r
+ con$(a) = con$(a + 1)\r
+ conc(a) = conc(a + 1)\r
+NEXT a\r
+\r
+FOR a = 1 TO 49\r
+ LOCATE a, 1\r
+ COLOR conc(a), 0\r
+ PRINT con$(a)\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB fload (a$, b, c, d)\r
+getfil h\r
+\r
+j = c\r
+l = 0\r
+\r
+OPEN a$ FOR INPUT AS #h\r
+12\r
+IF EOF(h) <> 0 THEN GOTO 13\r
+LINE INPUT #h, e$\r
+\r
+IF LEFT$(e$, 3) = "// " THEN\r
+ conm e$, 10\r
+ GOTO 12\r
+END IF\r
+IF e$ = SPACE$(LEN(e$)) THEN GOTO 12\r
+\r
+e$ = e$ + "|"\r
+l = l + 1\r
+h$ = ""\r
+i = d\r
+FOR f = 1 TO LEN(e$)\r
+ g$ = RIGHT$(LEFT$(e$, f), 1)\r
+ IF g$ = "|" THEN\r
+ putfs b, j, i, h$\r
+ h$ = ""\r
+ g$ = ""\r
+ i = i + 1\r
+ END IF\r
+ IF g$ = CHR$(9) THEN g$ = ""\r
+ h$ = h$ + g$\r
+NEXT f\r
+\r
+j = j + 1\r
+GOTO 12\r
+13\r
+CLOSE #h\r
+\r
+opf(h) = 0\r
+\r
+k$ = "file: " + a$ + " loaded." + STR$(l) + " lines in file"\r
+conm k$, 7\r
+END SUB\r
+\r
+SUB getfil (a)\r
+FOR b = 1 TO 30\r
+ IF opf(b) = 0 THEN\r
+ opf(b) = 1\r
+ a = b\r
+ GOTO 7\r
+ END IF\r
+NEXT b\r
+7\r
+END SUB\r
+\r
+SUB gets (l, s, a$)\r
+\r
+b = bufl(l, s)\r
+\r
+IF b = -1 THEN\r
+ a$ = ""\r
+ELSE\r
+ a$ = buf$(b)\r
+END IF\r
+\r
+END SUB\r
+\r
+SUB mkson (a$)\r
+\r
+mitus = 0\r
+\r
+d = 1\r
+FOR b = 1 TO LEN(a$)\r
+ c$ = RIGHT$(LEFT$(a$, b), 1)\r
+ IF c$ = " " THEN\r
+ d = 1\r
+ ELSE\r
+ IF d = 1 THEN\r
+ mitus = mitus + 1\r
+ sona$(mitus) = ""\r
+ d = 0\r
+ END IF\r
+ sona$(mitus) = sona$(mitus) + c$\r
+ END IF\r
+NEXT b\r
+\r
+'conm "sonad_______", 10\r
+'FOR b = 1 TO mitus\r
+'conm sona$(b), 14\r
+'NEXT b\r
+\r
+FOR a = 1 TO mitus\r
+ IF LEFT$(sona$(a), 2) = "|>" THEN\r
+ IF sona$(a + 1) = "c" THEN stdl = 1\r
+ IF sona$(a + 1) = "s" THEN stdl = 10 + VAL(sona$(a + 2))\r
+ mitus = a - 1\r
+ GOTO 15\r
+ END IF\r
+ IF LEFT$(sona$(a), 2) = "|@" THEN\r
+ sona$(a) = cnum(stack(VAL(RIGHT$(sona$(a), LEN(sona$(a)) - 2)), 10))\r
+ END IF\r
+NEXT a\r
+\r
+15\r
+FOR a = mitus + 1 TO 20\r
+ sona$(a) = ""\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB putfs (f, l, s, c$)\r
+\r
+'DIM SHARED buff(1 TO 30, 1 TO 1000)\r
+\r
+la = buff(f, l)\r
+\r
+IF la = -1 THEN\r
+ FOR a = 1 TO 1000\r
+ IF buflu(a) = 0 THEN\r
+ la = a\r
+ GOTO 10\r
+ END IF\r
+ NEXT a\r
+10\r
+END IF\r
+\r
+puts la, s, c$\r
+IF buflu(la) = 0 THEN\r
+ buff(f, l) = -1\r
+ELSE\r
+ buff(f, l) = la\r
+END IF\r
+END SUB\r
+\r
+SUB puts (l, s, a$)\r
+'PRINT l, s\r
+IF a$ = "|" THEN a$ = ""\r
+IF a$ = "||" THEN GOTO 11\r
+'conm a$, 13\r
+b = bufl(l, s)\r
+\r
+IF b = -1 THEN\r
+ FOR c = 1 TO 10000\r
+ IF bufu(c) = 0 THEN\r
+ GOTO 6\r
+ END IF\r
+ NEXT c\r
+6\r
+ b = c\r
+ bufu(b) = 1\r
+ buflu(l) = buflu(l) + 1\r
+END IF\r
+\r
+strip a$, c$\r
+\r
+IF c$ = "" THEN\r
+ bufu(b) = 0\r
+ buf$(b) = ""\r
+ bufl(l, s) = -1\r
+ buflu(l) = buflu(l) - 1\r
+ELSE\r
+ buf$(b) = c$\r
+ bufl(l, s) = b\r
+END IF\r
+11\r
+\r
+END SUB\r
+\r
+SUB runf (a$)\r
+getfil h\r
+\r
+OPEN a$ FOR INPUT AS #h\r
+9\r
+IF EOF(h) <> 0 THEN GOTO 8\r
+LINE INPUT #h, b$\r
+cmd b$\r
+GOTO 9\r
+8\r
+CLOSE #h\r
+\r
+opf(h) = 0\r
+\r
+END SUB\r
+\r
+SUB sort (s, w)\r
+DIM tmp1(1 TO 10000)\r
+DIM tmp2(1 TO 10000)\r
+\r
+b = stackl(s)\r
+\r
+FOR a = 1 TO b\r
+ gets stack(a, s), w, c$\r
+ tmp1(a) = VAL(c$)\r
+ tmp2(a) = a\r
+NEXT a\r
+\r
+d = 1\r
+FOR a = 1 TO b\r
+ e = 32000\r
+\r
+ FOR c = d TO b\r
+ IF tmp1(c) < e THEN\r
+ e = tmp1(c)\r
+ f = c\r
+ END IF\r
+ NEXT c\r
+ SWAP tmp1(a), tmp1(f)\r
+ SWAP tmp2(a), tmp2(f)\r
+ d = d + 1\r
+NEXT a\r
+\r
+FOR a = 1 TO b\r
+ stack(a, s) = tmp2(a)\r
+NEXT a\r
+\r
+END SUB\r
+\r
+SUB ssort (s, m)\r
+DIM tbti(1 TO 2000)\r
+DIM tbtp(1 TO 2000)\r
+DIM tbt$(1 TO 2000)\r
+\r
+FOR a = 1 TO stackl(s)\r
+ gets stack(a, s), m, b$\r
+ tbt$(a) = b$\r
+ tbtp(a) = a\r
+NEXT a\r
+\r
+b = stackl(s)\r
+FOR a = 1 TO stackl(s)\r
+d$ = tbt$(1)\r
+e = 1\r
+f = ASC(LEFT$(d$, 1))\r
+FOR c = 2 TO b\r
+IF ASC(LEFT$(tbt$(c), 1)) = f THEN\r
+IF d$ <> tbt$(c) THEN\r
+g$ = d$ + CHR$(0)\r
+h$ = tbt$(c) + CHR$(0)\r
+i = LEN(g$)\r
+IF LEN(h$) > i THEN i = LEN(h$)\r
+FOR j = 1 TO i\r
+k = ASC(RIGHT$(LEFT$(g$, j), 1))\r
+l = ASC(RIGHT$(LEFT$(h$, j), 1))\r
+IF k < l THEN GOTO 22\r
+IF l < k THEN e = c: d$ = tbt$(c): f = ASC(LEFT$(d$, 1)): GOTO 22\r
+NEXT j\r
+END IF\r
+END IF\r
+IF ASC(LEFT$(tbt$(c), 1)) < f THEN f = ASC(LEFT$(tbt$(c), 1)): e = c: d$ = tbt$(c)\r
+22\r
+NEXT c\r
+\r
+ tbti(a) = tbtp(e)\r
+ tbt$(e) = tbt$(b)\r
+ tbtp(e) = tbtp(b)\r
+ b = b - 1\r
+NEXT a\r
+\r
+FOR a = 1 TO stackl(s)\r
+ stack(a, s) = tbti(a)\r
+NEXT a\r
+\r
+conm "done", 7\r
+\r
+END SUB\r
+\r
+SUB start\r
+WIDTH 80, 50\r
+VIEW PRINT 1 TO 50\r
+CLS\r
+conx = 1\r
+histp = 1\r
+histk = 1\r
+stdl = 1\r
+\r
+conm "DDBASE, (Dos Data BASE) 0.0", 7\r
+conm "Copyright Svjatoslav Agejenko. All Rights Reserved.", 7\r
+conm "starting...", 7\r
+FOR a = 1 TO 5000\r
+ bufu(a) = 0\r
+ buf$(a) = ""\r
+NEXT a\r
+\r
+FOR a = 1 TO 30\r
+ FOR b = 1 TO 1000\r
+ bufl(b, a) = -1\r
+ buff(a, b) = -1\r
+ NEXT b\r
+ opf(a) = 0\r
+NEXT a\r
+\r
+FOR a = 1 TO 1000\r
+ buflu(a) = 0\r
+NEXT a\r
+\r
+FOR a = 1 TO 10\r
+ stackl(a) = 0\r
+NEXT a\r
+\r
+a$ = "runf auto.scr"\r
+FOR b = 1 TO LEN(a$)\r
+ c$ = RIGHT$(LEFT$(a$, b), 1)\r
+ conkey c$\r
+NEXT b\r
+conkey CHR$(13)\r
+\r
+END SUB\r
+\r
+SUB std (a$)\r
+'conm a$, 2\r
+\r
+SELECT CASE stdl\r
+CASE 1\r
+ conm a$, 10\r
+CASE 11 TO 20\r
+ b = stdl - 10\r
+ stackl(b) = stackl(b) + 1\r
+ stack(stackl(b), b) = VAL(a$)\r
+\r
+ c$ = a$ + " > " + cnum(stackl(b)) + " ! " + cnum(b)\r
+END SELECT\r
+\r
+END SUB\r
+\r
+SUB strip (a$, b$)\r
+b$ = a$\r
+2\r
+IF LEFT$(b$, 1) = " " THEN\r
+ b$ = RIGHT$(b$, LEN(b$) - 1)\r
+ GOTO 2\r
+END IF\r
+3\r
+IF RIGHT$(b$, 1) = " " THEN\r
+ b$ = LEFT$(b$, LEN(b$) - 1)\r
+ GOTO 3\r
+END IF\r
+\r
+END SUB\r
+\r
+SUB title (a$)\r
+conm " ", 10\r
+conm "================> " + a$ + " <===============", 7\r
+\r
+END SUB\r
--- /dev/null
+flnget 1 1\r
+ask Eesnimi 1 |@1 1\r
+ask Perekonnanimi 1 |@1 2\r
+ask Aadress 1 |@1 3\r
+ask Telefon 1 |@1 4\r
+ask Sugu_M_voi_N 1 |@1 5\r
+ask S\81nniaasta 1 |@1 7\r
+stclear 1\r
+chklin 1 |> s 1\r
+stacksize 1 |> c\r
+\r
--- /dev/null
+#+TITLE: Mouse driver for QBasic programs\r
+#+LANGUAGE: en\r
+#+LATEX_HEADER: \usepackage[margin=1.0in]{geometry}\r
+#+LATEX_HEADER: \usepackage{parskip}\r
+#+LATEX_HEADER: \usepackage[none]{hyphenat}\r
+\r
+#+OPTIONS: H:20 num:20\r
+#+OPTIONS: author:nil\r
+\r
+* Overview\r
+\r
+QBasic, a popular programming language in the DOS era, lacks native\r
+mouse support. This limitation can be a hurdle for developers looking\r
+to create interactive applications. To bridge this gap, I developed a\r
+workaround that allows QBasic to use mouse input.\r
+\r
+* High-level idea\r
+\r
+Workaround to access mouse involves a Terminate and Stay Resident\r
+(TSR) program written in x86 assembly. This TSR program must be\r
+started before running QBasic program that depends on mouse. This TSR\r
+program hooks into the system's interrupt mechanism, specifically the\r
+timer interrupt (IRQ 0), allowing it to regularly check for mouse\r
+activity several times per second.\r
+\r
+When this timer interrupt triggers, the TSR reads the latest mouse's\r
+horizontal and vertical movements and button states using mouse\r
+interrupts. This data is then stored in a dedicated memory location —\r
+a data table within the TSR's memory space. The TSR uses interrupt 79h\r
+as a pointer to this data table, making it accessible to other\r
+programs, including the QBasic application.\r
+\r
+While QBasic originally is not able to read mouse, it is able to read\r
+(and write) arbitrary location in system RAM. The QBasic demonstration\r
+program begins by retrieving the address of the TSR mouse data table\r
+from the interrupt vector table using interrupt 79h. By checking a\r
+predefined magic number (1983) in the data table, the program confirms\r
+that the mouse driver is loaded. Once verified, the QBasic program\r
+continuously reads mouse data from this shared memory location, while\r
+TSR keeps updating it with latest mouse state simultaneously.\r
+\r
+* Terminate and Stay Resident module\r
+\r
+A DOS TSR program that hooks into the system's interrupt mechanism to\r
+regularly read mouse input and store it in a dedicated memory\r
+location.\r
+\r
+Files:\r
+- [[file:qbext.asm][qbext.asm - x86 Assembly source code]]\r
+- [[file:qbext.com][qbext.com - binary COM executable for DOS]]\r
+\r
+\r
+Here is the detailed technical specification for an in-memory table\r
+used to exchange mouse coordinates between a TSR program and a QBasic\r
+program.\r
+\r
+| Offset | Size (bytes) | Description |\r
+|--------+--------------+-------------------------|\r
+| 0x00 | 2 | Magic Number (1983) |\r
+| 0x02 | 2 | Horizontal Movement (X) |\r
+| 0x04 | 2 | Vertical Movement (Y) |\r
+| 0x06 | 2 | Button Status |\r
+| 0x08 | 1 | Update counter |\r
+\r
+- Update counter :: Signals to the QBasic program that new mouse data\r
+ is available in the shared memory table. It ensures that the QBasic\r
+ program only reads fresh data and avoids processing outdated or\r
+ repeated data. When the TSR updates the mouse data, it increments\r
+ this flag by 1 to signal the QBasic program that new data is\r
+ available. QBasic can compare this number against last retrieved\r
+ value. If value has been increased, then there had been update\r
+ meanwhile.\r
+\r
+* QBasic demonstration program\r
+\r
+A QBasic program that reads mouse data from the memory location\r
+populated by the TSR and demonstrates mouse movement and button\r
+clicks.\r
+\r
+\r
+#+attr_html: :class responsive-img\r
+#+attr_latex: :width 1000px\r
+[[file:mousedrv.bas][file:screenshot.png]]\r
+\r
+[[file:mousedrv.bas][mousedrv.bas - source code]]\r
+\r
+Here are more practical examples where this mouse driver is being\r
+used: Within [[https://www3.svjatoslav.eu/projects/qbasicapps/3D%20GFX/Space/index.html][Space themed 3D graphics]], see:\r
+- Galaxy explorer\r
+- Universe explorer\r
--- /dev/null
+' QBasic does not have mouse support. Here is demonstration of custom mouse driver.\r
+' In order to use mouse, special custom TSR (Terminate and Stay Resident) mouse driver\r
+' has to be loaded before running this demo.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2004.01, Initial version\r
+' 2025, Improve program readability\r
+\r
+DECLARE SUB mousedemo ()\r
+DECLARE SUB putword (addr!, dat!)\r
+DECLARE FUNCTION getword! (addr!)\r
+DECLARE FUNCTION getbyte! (addr!)\r
+DECLARE SUB start ()\r
+\r
+DIM SHARED extSEG, extADDR\r
+\r
+start\r
+mousedemo\r
+\r
+FUNCTION getbyte (addr)\r
+ ' This function retrieves a byte from the specified address in RAM.\r
+ getbyte = PEEK(extADDR + addr)\r
+END FUNCTION\r
+\r
+FUNCTION getword (addr)\r
+ ' This function retrieves a word (2 bytes) from the specified address in RAM.\r
+ a = PEEK(extADDR + addr) ' Read the first byte\r
+ b = PEEK(extADDR + addr + 1) ' Read the second byte\r
+ c$ = HEX$(a) ' Convert the first byte to hexadecimal\r
+ IF LEN(c$) = 1 THEN c$ = "0" + c$ ' Ensure two digits\r
+ IF LEN(c$) = 0 THEN c$ = "00" ' Ensure two digits if empty\r
+ ' Combine the two bytes into a single word.\r
+ c = VAL("&H" + HEX$(b) + c$) ' Combine the two bytes into a word\r
+ getword = c\r
+END FUNCTION\r
+\r
+SUB mousedemo\r
+ ' This subroutine demonstrates mouse movement and button clicks.\r
+ cx = 150 ' Initial x-coordinate\r
+ cy = 100 ' Initial y-coordinate\r
+ maxmove = 50 ' Maximum movement in one step\r
+ frm = 0 ' Frame counter\r
+1\r
+ frm = frm + 1 ' Increment frame counter\r
+ ' Check for user input on keyboard and exit if any key is pressed\r
+ IF INKEY$ <> "" THEN SYSTEM\r
+\r
+ ' Print the current coordinates and frame number.\r
+ LOCATE 1, 1\r
+ PRINT "X: " + STR$(cx) + " Y:" + STR$(cy) + " " ' Print current x and y coordinates\r
+ PRINT "Frame #" + STR$(frm) ' Print current frame number\r
+\r
+ ' Erase circle at the old mouse position by drawing black circle\r
+ CIRCLE (cx, cy), 10, 0\r
+\r
+ ' Retrieve the x and y movement values from the mouse.\r
+ xp = getword(2) ' Get horizontal movement\r
+ putword 2, 0 ' Reset horizontal movement counter\r
+ yp = getword(4) ' Get vertical movement\r
+ putword 4, 0 ' Reset vertical movement counter\r
+\r
+ ' Retrieve the button status from the mouse.\r
+ butt = getword(6) ' Get button status\r
+ putword 6, 0 ' Reset button status\r
+\r
+ ' Print the button status if a button is pressed.\r
+ IF butt <> 0 THEN\r
+ LOCATE 5\r
+ PRINT butt ' Print button status if pressed\r
+ END IF\r
+\r
+ ' Limit the mouse movement to within maxmove.\r
+ IF xp < -maxmove THEN xp = -maxmove\r
+ IF xp > maxmove THEN xp = maxmove\r
+\r
+ cx = cx + xp ' Update x-coordinate\r
+\r
+ IF yp < -maxmove THEN yp = -maxmove\r
+ IF yp > maxmove THEN yp = maxmove\r
+ cy = cy + yp ' Update y-coordinate\r
+\r
+ ' Draw a circle at the new mouse position.\r
+ CIRCLE (cx, cy), 10, 10 ' Draw a circle with radius 10\r
+\r
+ ' Use sound command for adding short delay\r
+ SOUND 0, .05\r
+\r
+ ' Repeat the loop to continuously update the mouse position.\r
+ GOTO 1\r
+END SUB\r
+\r
+SUB putword (addr, dat)\r
+ ' This subroutine stores a word (2 bytes) at the specified address in RAM.\r
+ b$ = HEX$(dat) ' Convert data to hexadecimal\r
+\r
+2\r
+ IF LEN(b$) < 4 THEN b$ = "0" + b$: GOTO 2 ' Ensure four digits\r
+\r
+ ' Split the word into two bytes.\r
+ n1 = VAL("&H" + LEFT$(b$, 2)) ' First byte\r
+ n2 = VAL("&H" + RIGHT$(b$, 2)) ' Second byte\r
+\r
+ ' Store the bytes at the specified address.\r
+ POKE (extADDR + addr), n2 ' Store the first byte\r
+ POKE (extADDR + addr + 1), n1 ' Store the second byte\r
+END SUB\r
+\r
+SUB start\r
+ ' This subroutine initializes the screen and retrieves the segment and address of the mouse driver.\r
+ SCREEN 13 ' Set graphics mode\r
+ DEF SEG = 0 ' Read from interrupt table\r
+\r
+ ' Retrieve mouse data table address within TSR as pointed by interrupt 79h\r
+ extSEG = PEEK(&H79 * 4 + 3) * 256\r
+ extSEG = extSEG + PEEK(&H79 * 4 + 2)\r
+\r
+ ' Retrieve the offset address of the mouse driver.\r
+ extADDR = PEEK(&H79 * 4 + 1) * 256\r
+ extADDR = extADDR + PEEK(&H79 * 4 + 0)\r
+ DEF SEG = extSEG ' Set segment for memory access\r
+\r
+ ' Check if the mouse driver is loaded by verifying the magic number (1983).\r
+ IF getword(0) <> 1983 THEN\r
+ PRINT "FATAL ERROR: you must load"\r
+ PRINT "QBasic extension TSR first!"\r
+ SYSTEM ' Exit program if mouse driver is not loaded\r
+ END IF\r
+END SUB\r
+\r
--- /dev/null
+; DOS Terminate and Stay Resident (TSR) program that allows QBasic to read mouse input.\r
+;\r
+; This program is free software: released under Creative Commons Zero (CC0) license\r
+; by Svjatoslav Agejenko.\r
+; Email: svjatoslav@svjatoslav.eu\r
+; Homepage: http://www.svjatoslav.eu\r
+;\r
+; Changelog:\r
+; 2004.01, Initial version\r
+; 2025, Improved program readability\r
+\r
+\r
+\r
+org 100h ; Origin set to 100h for COM files\r
+myint = 79h ; Define interrupt number to hook for data table\r
+\r
+ ; Display startup message\r
+ mov dx, msg ; DX points to the message to display\r
+ mov ah, 9 ; AH = 9 to display string\r
+ int 21h ; Call DOS interrupt to display message\r
+\r
+ ; Save old interrupt vector so that we can call in from new interrupt handler\r
+ mov ax, 0 ; AX = 0 to access interrupt vector table\r
+ mov es, ax ; ES set to interrupt vector segment\r
+ mov eax, [es:32] ; Save old interrupt vector at offset 32h\r
+ mov [oldVector], eax\r
+\r
+ ; Install our TSR as a new timer interrupt handler (IRQ 0)\r
+ cli ; Temporarily disable interrupts to safely update vector\r
+ mov ax, cs ; AX = code segment\r
+ shl eax, 16 ; Shift left by 16 to make room for offset\r
+ mov ax, custom ; AX = offset of custom handler\r
+ mov [es:32], eax ; Set new interrupt vector for IRQ 0\r
+\r
+ ; Here we use interrupt table (Interrupt # 79h) to point to data structure with mouse info within our TSR.\r
+ ; QBasic can then also read interrupt table and locate this important data structure within the RAM to read mouse status.\r
+ ; Here we hope that nobody else is using interrupt 79h, so that we can use it as a pointer to RAM instead.\r
+ mov ax, dataTable ; AX = offset of data table\r
+ mov [es:4 * myint], eax ; Set interrupt vector for INT 79h\r
+ sti ; Re-enable interrupts\r
+\r
+ ; Calculate RAM size that this TSR needs and tell DOS to make this program resident.\r
+ mov ax, endPointer ; Calculate memory size needed by TSR\r
+ add ax, 32 ; Add 32 bytes for safety margin\r
+ mov dx, 0 ; DX = 0 for division\r
+ mov bx, 16 ; BX = 16 for paragraph alignment\r
+ div bx ; Divide AX by BX, result in AX\r
+ mov dx, ax ; DX = memory size in paragraphs\r
+ mov ax, 3100h ; AX = function 31h (Keep Program Resident)\r
+ int 21h ; Call DOS to terminate and stay resident\r
+\r
+\r
+; Following code gets executed by timer interrupt in background multiple times per second\r
+custom:\r
+ pushf ; Save flags\r
+ call dword [cs:oldVector] ; Call original interrupt handler\r
+\r
+ ; Ensure that TSR is not executed multiple times simultaneously\r
+ cmp [cs:isRunning], 0 ; Check if routine is already active\r
+ jne EndOfRoutine ; If active, jump to end\r
+ mov [cs:isRunning], 1 ; Set active flag.\r
+\r
+ ; Ensure that TSR will not affert state of program that it interrupted\r
+ pusha ; Save all general-purpose registers\r
+ push ds ; Save DS segment register\r
+ push es ; Save ES segment register\r
+\r
+ ; Read mouse moevement and button states and store them to dedicated RAM table\r
+ cli ; Disable interrupts for safe memory access\r
+ mov ax, 0bh ; AH = 0Bh, function to read mouse motion counters\r
+ int 33h ; Call mouse interrupt\r
+ add [CS:mouseHorisontal], cx ; Update horizontal movement counter\r
+ add [CS:mouseVertical], dx ; Update vertical movement counter\r
+ mov ax, 3 ; AH = 3, function to read mouse buttons\r
+ int 33h ; Call mouse interrupt\r
+ or [CS:mouseButtons], bx ; Update mouse button states\r
+ inc byte [CS:updated] ; Increment update flag. So that QBasic registers mouse update event.\r
+ sti ; Re-enable interrupts\r
+\r
+ ; Restore interrupted program state and return control to it\r
+ pop es ; Restore ES segment register\r
+ pop ds ; Restore DS segment register\r
+ popa ; Restore all general-purpose registers\r
+ mov [cs:isRunning], 0 ; Clear active flag\r
+ EndOfRoutine:\r
+ iret ; Return from interrupt\r
+\r
+oldVector dd 0 ; Storage for old interrupt vector. Our new interrupt handler will also call old handler to not break it.\r
+isRunning db 0 ; Flag to check if routine is running\r
+dataTable:\r
+ dw 1983 ; Check number indicating module is loaded\r
+ mouseHorisontal dw 0 ; Horizontal mouse movement counter\r
+ mouseVertical dw 0 ; Vertical mouse movement counter\r
+ mouseButtons dw 0 ; Mouse button states\r
+ updated db 0 ; Flag indicating data was updated\r
+\r
+endPointer: ; End of resident code pointer\r
+\r
+msg: ; Message to display at start\r
+file 'readme.txt' ; Include content of readme.txt\r
+ db '$' ; End of string marker\r
--- /dev/null
+' Program tries to render fancy rocket control system with password protection.\r
+' When entered password is wrong, program will halt in 3 attempts.\r
+' When password is correct, program will exit and return control to the user.\r
+' Password is stored in "passw.dat" file.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2002, Initial version.\r
+' 2024, Improved program readability.\r
+\r
+\r
+DECLARE SUB checkPassword (a$)\r
+DECLARE SUB startProgram ()\r
+DECLARE SUB makeVerticalLines (s%, C%)\r
+DECLARE SUB drawBox (x1%, y1%, x2%, y2%)\r
+\r
+DIM SHARED cha\r
+DIM SHARED password$\r
+\r
+startProgram\r
+\r
+' Initialize variables\r
+x = 25\r
+x2 = 10\r
+x3 = 0\r
+B$ = ""\r
+\r
+1\r
+' Update position of the bouncing ball\r
+x = x + xs\r
+IF x > 0 THEN\r
+ ' Decrease speed if ball is moving right\r
+ xs = xs - .5\r
+ELSE\r
+ ' Increase speed if ball is moving left\r
+ xs = xs + .5\r
+END IF\r
+' Gradually decrease the speed\r
+xs = xs - (xs / 8)\r
+\r
+' Draw a vertical line and a dot\r
+IF x2 > 100 THEN\r
+ ' Reset the position of the line\r
+ x2 = 10\r
+ELSE\r
+ LINE (x2, 10)-(x2, 60), 0\r
+ PSET (x2, x + 35), 10\r
+END IF\r
+' Draw another vertical line next to the first one\r
+IF x2 < 99 THEN\r
+ LINE (x2 + 1, 10)-(x2 + 1, 60), 3\r
+END IF\r
+\r
+' Update position of the lines\r
+x2 = x2 + 1\r
+x3 = x3 + 1\r
+\r
+' Play a sound when the ball hits the right edge\r
+IF x3 > 40 THEN\r
+ x3 = 0\r
+ xs = xs - 5\r
+ SOUND 1000, 1\r
+END IF\r
+\r
+SOUND 0, .5\r
+\r
+a$ = INKEY$\r
+' Check if the Enter key is pressed\r
+IF a$ = CHR$(13) THEN\r
+ ' Validate the entered password\r
+ checkPassword B$\r
+ ' Clear the input buffer\r
+ B$ = ""\r
+ GOTO 2\r
+END IF\r
+\r
+' Check if any other key is pressed\r
+IF a$ <> "" THEN\r
+ ' Handle backspace\r
+ IF a$ = CHR$(8) THEN\r
+ ' Remove the last character from the input buffer\r
+ IF LEN(B$) > 0 THEN\r
+ B$ = LEFT$(B$, LEN(B$) - 1)\r
+ END IF\r
+ GOTO 2\r
+ END IF\r
+ ' Add the pressed key to the input buffer\r
+ B$ = B$ + a$\r
+ ' Limit the length of the input buffer\r
+ IF LEN(B$) > 10 THEN\r
+ B$ = LEFT$(B$, 10)\r
+ END IF\r
+2\r
+ ' Draw the characters in the input buffer\r
+ FOR a = 1 TO 10\r
+ ' Determine the color of the character\r
+ IF a <= LEN(B$) THEN\r
+ C = 5\r
+ ELSE\r
+ C = 1\r
+ END IF\r
+ ' Draw the character\r
+ CIRCLE (a * 15 + 20, 150), 6, C\r
+ PAINT (a * 15 + 20, 150), C\r
+ NEXT a\r
+END IF\r
+\r
+GOTO 1\r
+\r
+SUB checkPassword (a$)\r
+ cha = cha - 1\r
+\r
+ ' Check if the entered password is correct\r
+ IF a$ = password$ THEN\r
+ CLS\r
+ SCREEN 2\r
+ SYSTEM\r
+ END IF\r
+\r
+ ' Draw the background of the error message box\r
+ DIM buf(1 TO 3000)\r
+ GET (79, 80)-(241, 141), buf(1)\r
+\r
+ ' Draw the borders of the error message box\r
+ drawBox 80, 90, 240, 140\r
+\r
+ ' Display the error message\r
+ LOCATE 14, 14\r
+ COLOR 12\r
+ PRINT "Wrong password"\r
+\r
+ ' Display the number of remaining attempts\r
+ COLOR 5\r
+ LOCATE 16, 13\r
+ PRINT STR$(cha) + " chances left"\r
+\r
+ ' Play a sound to indicate an error\r
+ FOR a = 1 TO 30\r
+ SOUND 0, 1\r
+ NEXT a\r
+\r
+ ' Display the final message when all attempts are exhausted\r
+ IF cha = 0 THEN\r
+ DIM buf2(1000)\r
+ GET (79, 138)-(241, 140), buf2\r
+ FOR a = 1 TO 40\r
+ PUT (79, 138 + a), buf2, PSET\r
+ SOUND 0, .5\r
+ NEXT a\r
+\r
+ LOCATE 19, 14\r
+ COLOR 12\r
+ PRINT "SYSTEM HALTED"\r
+ LOCATE 21, 14\r
+ PRINT "SUCCESSFULLY!!"\r
+3\r
+ GOTO 3\r
+ END IF\r
+\r
+ ' Restore the background of the error message box\r
+ PUT (79, 80), buf(1), PSET\r
+END SUB\r
+\r
+DEFINT A-Z\r
+SUB drawBox (x1%, y1%, x2%, y2%)\r
+ ' Draw the top border of the box\r
+ LINE (x1 + 1, y1 + 1)-(x2 - 1, y2 - 1), 0, BF\r
+ ' Draw the bottom border of the box\r
+ LINE (x1, y1)-(x2, y2), 10, B\r
+ ' Draw the left and right borders of the box\r
+ LINE (x1, y1)-(x2, y1 - 9), 14, BF\r
+ LINE (x1, y1)-(x2, y1 - 9), 10, B\r
+\r
+ ' Draw the top left corner of the box\r
+ LINE (x2 - 2, y1 - 2)-(x2 - 7, y1 - 7), 7, BF\r
+ ' Draw the top right corner of the box\r
+ LINE (x2 - 9, y1 - 2)-(x2 - 14, y1 - 7), 7, BF\r
+\r
+ ' Draw the diagonal lines in the top left corner\r
+ LINE (x2 - 2, y1 - 2)-(x2 - 7, y1 - 7), 0\r
+ LINE (x2 - 2, y1 - 7)-(x2 - 7, y1 - 2), 0\r
+\r
+ ' Draw the horizontal line in the top left corner\r
+ LINE (x2 - 10, y1 - 3)-(x2 - 13, y1 - 3), 0\r
+END SUB\r
+\r
+SUB makeVerticalLines (s%, C%)\r
+ ' Draw vertical lines\r
+ FOR x = 160 TO 319 STEP s\r
+ LINE (x, 0)-(x, 199), C\r
+ LINE (320 - x, 0)-(320 - x, 199), C\r
+ NEXT x\r
+\r
+ ' Draw horizontal lines\r
+ FOR y = 100 TO 199 STEP s\r
+ LINE (0, y)-(319, y), C\r
+ LINE (0, 200 - y)-(319, 200 - y), C\r
+ NEXT y\r
+END SUB\r
+\r
+DEFSNG A-Z\r
+SUB startProgram\r
+ ' Read the password from the file\r
+ OPEN "passw.dat" FOR INPUT AS #1\r
+ LINE INPUT #1, password$\r
+ CLOSE #1\r
+\r
+ ' Set the screen mode\r
+ SCREEN 13\r
+\r
+ ' Initialize the number of remaining attempts\r
+ cha = 3\r
+\r
+ ' Draw vertical lines with increasing spacing\r
+ s = 2\r
+ FOR C = 16 TO 31\r
+ s = s * 1.4\r
+ makeVerticalLines INT(s), INT(C)\r
+ NEXT C\r
+ makeVerticalLines INT(s), 0\r
+\r
+ ' Draw the main box\r
+ drawBox 70, 20, 270, 90\r
+\r
+ ' Display the initial message\r
+ COLOR 5\r
+ LOCATE 8, 10\r
+ PRINT " stack dump:"\r
+ LOCATE 9, 10\r
+ PRINT "010010010010010010010100"\r
+\r
+ ' Display the running message\r
+ LOCATE 10, 10\r
+ PRINT "Running rocket ground"\r
+ LOCATE 11, 10\r
+ PRINT "control system..."\r
+\r
+ ' Draw the input box\r
+ drawBox 9, 9, 101, 61\r
+\r
+ ' Draw the password input box\r
+ drawBox 20, 130, 300, 190\r
+\r
+ ' Display the password prompt\r
+ LOCATE 18, 5\r
+ PRINT "ENTER PASSWORD:"\r
+END SUB\r
+\r
--- /dev/null
+jerry
\ No newline at end of file
--- /dev/null
+' Utility to print information about pressed keyboard buttons.\r
+'\r
+\r
+MainLoop:\r
+ ' Wait for a key press and store it in userInput$\r
+ userInput$ = INKEY$\r
+\r
+ ' If no key has been pressed, jump back to the main loop\r
+ IF userInput$ = "" THEN GOTO MainLoop\r
+\r
+ ' Print the character that was typed by the user\r
+ PRINT "You typed: "; userInput$\r
+\r
+ ' Calculate the ASCII value of the first character (if input is more than one character)\r
+ ' and print it\r
+ IF LEN(userInput$) > 0 THEN\r
+ PRINT "ASCII value of the first character ('"; LEFT$(userInput$, 1); "'): "; ASC(LEFT$(userInput$, 1))\r
+ END IF\r
+\r
+ ' Calculate the ASCII value of the last character and print it\r
+ IF LEN(userInput$) > 0 THEN\r
+ PRINT "ASCII value of the last character ('"; RIGHT$(userInput$, 1); "'): "; ASC(RIGHT$(userInput$, 1))\r
+ END IF\r
+\r
+ ' Jump back to the main loop to wait for another key press\r
+ GOTO MainLoop
\ No newline at end of file
--- /dev/null
+' Utility to determine available video modes.\r
+'\r
+' Written by Svjatoslav Agejenko\r
+' Homepage: svjatoslav.eu\r
+' Email: svjatoslav@svjatoslav.eu\r
+\r
+' 2001, initial version\r
+' 2024.08, used AI to enhance program readability\r
+\r
+DIM SHARED AvailableModes(1 TO 100) AS INTEGER\r
+ON ERROR GOTO ErrorHandler\r
+\r
+' Initialize the video mode counter and the current mode number.\r
+currentModeIndex = 1\r
+currentModeNumber = 0\r
+\r
+' Start the loop to test each video mode.\r
+DO\r
+ ' Attempt to set the screen to the current video mode.\r
+ SCREEN currentModeNumber\r
+\r
+ ' Increment the mode number for the next iteration.\r
+ currentModeNumber = currentModeNumber + 1\r
+\r
+ ' Store the successful video mode in the array.\r
+ AvailableModes(currentModeIndex) = currentModeNumber - 1\r
+\r
+ ' Move to the next index in the array.\r
+ currentModeIndex = currentModeIndex + 1\r
+\r
+LOOP\r
+\r
+' Error handling routine when an error occurs (e.g., invalid video mode).\r
+ErrorHandler:\r
+' Increment the mode number to continue testing after an error.\r
+currentModeNumber = currentModeNumber + 1\r
+\r
+' Check if we have reached the maximum number of modes to test.\r
+IF currentModeNumber > 1000 THEN\r
+ ' Reset the screen to text mode (usually mode 1).\r
+ SCREEN 1\r
+\r
+ ' Display the list of available video modes.\r
+ PRINT "Available video modes on this computer:"\r
+ FOR modeIndex = 1 TO currentModeIndex - 1\r
+ PRINT AvailableModes(modeIndex)\r
+ NEXT modeIndex\r
+\r
+ ' End the program after displaying the results.\r
+ END\r
+END IF\r
+\r
+' Resume execution after an error to continue testing modes.\r
+RESUME
\ No newline at end of file
--- /dev/null
+' Text mode windowing system. Each window can display text file.\r
+' Window content can be scrolled horizontally and vertically.\r
+' Window can have arbitrary size and location on the screen.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+\r
+' Changelog:\r
+' 2003, Initial version\r
+' 2024-2025, Improved program readability\r
+\r
+DECLARE SUB demo ()\r
+DECLARE FUNCTION GetLineFromWindow$ (windowNum%, lineNum%)\r
+DECLARE SUB LoadFileIntoWindow (fileName$, windowNum%)\r
+DECLARE SUB SendLineToWindow (windowNum%, lineNum%, newString$)\r
+DECLARE FUNCTION GetFreeLineIndex% ()\r
+DECLARE SUB RefreshAllWindows ()\r
+DECLARE FUNCTION AddWindow% (x%, y%, widt%, haigh%, title$)\r
+DECLARE SUB DrawBox (x%, y%, widt%, haigh%, edgeStyle$)\r
+DEFINT A-Z\r
+DECLARE SUB ShowWindow (windowNum)\r
+DECLARE SUB InitializeSystem ()\r
+\r
+' Global variables for text storage\r
+DIM SHARED maxStorage%\r
+maxStorage% = 5000\r
+DIM SHARED textStorage$(1 TO maxStorage%)\r
+DIM SHARED storagePointer%\r
+\r
+' Window-related global arrays\r
+DIM SHARED windowData(1 TO 10, 1 TO 1000) ' Stores line indices for each window\r
+DIM SHARED windowX(1 TO 10), windowY(1 TO 10) ' Position of each window\r
+DIM SHARED windowWidth(1 TO 10), windowHeight(1 TO 10) ' Size of each window\r
+DIM SHARED windowActiveStatus(1 TO 10) ' Whether window is active\r
+DIM SHARED windowTitle$(1 TO 10) ' Title of each window\r
+\r
+' Window scrolling/shifting\r
+DIM SHARED windowShiftX(1 TO 10) ' Horizontal shift\r
+DIM SHARED windowShiftY(1 TO 10) ' Vertical shift\r
+\r
+DIM SHARED currentActiveWindow% ' Currently active window for display\r
+\r
+InitializeSystem\r
+\r
+demo\r
+\r
+FUNCTION AddWindow% (x%, y%, widt%, heigh%, title$)\r
+ ' Adds a new window to the system\r
+\r
+ ' Find an empty window slot\r
+ FOR windowNum% = 1 TO 10\r
+ IF windowActiveStatus(windowNum%) = 0 THEN\r
+ foundWindow% = windowNum%\r
+ GOTO FoundEmptySlot\r
+ END IF\r
+ NEXT windowNum%\r
+\r
+FoundEmptySlot:\r
+ ' Initialize the window properties\r
+ windowActiveStatus(foundWindow%) = 1\r
+ windowX(foundWindow%) = x%\r
+ windowY(foundWindow%) = y%\r
+ windowWidth(foundWindow%) = widt%\r
+ windowHeight(foundWindow%) = heigh%\r
+ windowTitle$(foundWindow%) = title$\r
+\r
+ ' Return the window number\r
+ AddWindow% = foundWindow%\r
+END FUNCTION\r
+\r
+SUB ClearWindowContent (windowNum%)\r
+ ' Clears all content from a window\r
+\r
+ FOR lineNum% = 1 TO 1000\r
+ IF windowData(windowNum%, lineNum%) > 0 THEN\r
+ textStorage$(windowData(windowNum%, lineNum%)) = ""\r
+ windowData(windowNum%, lineNum%) = 0\r
+ END IF\r
+ NEXT lineNum%\r
+END SUB\r
+\r
+SUB demo\r
+ ' Create three windows with different sizes and titles\r
+ window1% = AddWindow%(1, 1, 30, 10, "window 1.")\r
+ window2% = AddWindow%(1, 12, 80, 30, "second window")\r
+ window3% = AddWindow%(31, 2, 30, 10, "last window")\r
+\r
+ ' Load the same file into all windows\r
+ LoadFileIntoWindow "wsystem.bas", window2%\r
+ LoadFileIntoWindow "wsystem.bas", window1%\r
+ LoadFileIntoWindow "wsystem.bas", window3%\r
+\r
+AnimateWindows:\r
+ ' Randomly select an active window to animate\r
+ currentActiveWindow% = INT(RND * 3) + 1\r
+ RefreshAllWindows\r
+\r
+ ' Animate the windows by shifting their content\r
+ FOR animationFrame% = 1 TO 100\r
+ windowShiftX(currentActiveWindow%) = SIN(animationFrame% / 10) * 10 + 10\r
+ windowShiftY(currentActiveWindow%) = animationFrame%\r
+ ShowWindow currentActiveWindow%\r
+ ' split-second delay\r
+ SOUND 0, 1\r
+ IF INKEY$ <> "" THEN SYSTEM\r
+ NEXT animationFrame%\r
+\r
+ GOTO AnimateWindows\r
+END SUB\r
+\r
+FUNCTION GetFreeLineIndex%\r
+ ' Finds a free line in text storage\r
+\r
+FindNextLine:\r
+ IF storagePointer% > 1000 THEN\r
+ storagePointer% = 1\r
+ END IF\r
+\r
+ IF textStorage$(storagePointer%) = "" THEN\r
+ GetFreeLineIndex% = storagePointer%\r
+ storagePointer% = storagePointer% + 1\r
+ ELSE\r
+ storagePointer% = storagePointer% + 1\r
+ GOTO FindNextLine\r
+ END IF\r
+END FUNCTION\r
+\r
+FUNCTION GetLineFromWindow$ (windowNum%, lineNum%)\r
+ ' Retrieve a line from a window's memory\r
+\r
+ IF windowData(windowNum%, lineNum%) = 0 THEN\r
+ GetLineFromWindow$ = ""\r
+ ELSE\r
+ GetLineFromWindow$ = textStorage$(windowData(windowNum%, lineNum%))\r
+ END IF\r
+END FUNCTION\r
+\r
+SUB LoadFileIntoWindow (fileName$, windowNum%)\r
+ ' Load a file into a window's memory\r
+\r
+ OPEN fileName$ FOR INPUT AS #1\r
+ FOR lineNum% = 1 TO 1000\r
+ IF EOF(1) <> 0 THEN\r
+ GOTO FileLoaded\r
+ END IF\r
+ LINE INPUT #1, lineContent$\r
+ SendLineToWindow windowNum%, lineNum%, lineContent$\r
+ NEXT lineNum%\r
+\r
+FileLoaded:\r
+ CLOSE #1\r
+\r
+ ' Fill the remaining lines with empty strings\r
+ FOR blankLineNum% = lineNum% TO 1000\r
+ SendLineToWindow windowNum%, blankLineNum%, ""\r
+ NEXT blankLineNum%\r
+END SUB\r
+\r
+SUB RefreshAllWindows\r
+ ' Redraw all active windows\r
+\r
+ CLS\r
+ FOR windowNum% = 1 TO 10\r
+ IF windowActiveStatus(windowNum%) > 0 THEN\r
+ ShowWindow windowNum%\r
+ END IF\r
+ NEXT windowNum%\r
+END SUB\r
+\r
+SUB SendLineToWindow (windowNum%, lineNum%, newString$)\r
+ ' Stores a string in a window's memory\r
+\r
+ lineContent$ = newString$\r
+\r
+ ' Remove trailing spaces from the string\r
+ IF lineContent$ = SPACE$(LEN(lineContent$)) THEN\r
+ lineContent$ = ""\r
+ END IF\r
+\r
+ IF LEN(lineContent$) > 0 THEN\r
+TrimRight:\r
+ IF RIGHT$(lineContent$, 1) = " " THEN\r
+ lineContent$ = LEFT$(lineContent$, LEN(lineContent$) - 1)\r
+ GOTO TrimRight\r
+ END IF\r
+ END IF\r
+\r
+ ' Update the window memory with the new string\r
+ IF lineContent$ = "" THEN\r
+ IF windowData(windowNum%, lineNum%) > 0 THEN\r
+ textStorage$(windowData(windowNum%, lineNum%)) = "": windowData(windowNum%, lineNum%) = 0\r
+ END IF\r
+ ELSE\r
+ IF windowData(windowNum%, lineNum%) = 0 THEN\r
+ windowData(windowNum%, lineNum%) = GetFreeLineIndex%\r
+ END IF\r
+ textStorage$(windowData(windowNum%, lineNum%)) = lineContent$\r
+ END IF\r
+END SUB\r
+\r
+SUB ShowWindow (windowNum%)\r
+ ' Draws a window on the screen\r
+\r
+ ' Determine background color based on active window\r
+ IF windowNum% = currentActiveWindow% THEN\r
+ bgColor% = 1\r
+ ELSE\r
+ bgColor% = 0\r
+ END IF\r
+\r
+ x% = windowX(windowNum%)\r
+ y% = windowY(windowNum%)\r
+ widt% = windowWidth(windowNum%)\r
+ heigh% = windowHeight(windowNum%)\r
+ title$ = windowTitle$(windowNum%)\r
+\r
+ COLOR 11, bgColor%\r
+\r
+ ' Create border components\r
+ FOR borderSegment% = 1 TO widt% - 2\r
+ topBottom$ = topBottom$ + CHR$(205)\r
+ NEXT borderSegment%\r
+ borderTop$ = CHR$(201) + topBottom$ + CHR$(187)\r
+ borderBottom$ = CHR$(200) + topBottom$ + CHR$(188)\r
+\r
+ ' Draw top border\r
+ LOCATE y%, x%\r
+ PRINT borderTop$\r
+\r
+ ' Draw bottom border\r
+ LOCATE y% + heigh% - 1, x%\r
+ PRINT borderBottom$\r
+\r
+ ' Draw window content\r
+ FOR lineNum% = 1 TO heigh% - 2\r
+ LOCATE y% + lineNum%, x%\r
+ lineContent$ = GetLineFromWindow$(windowNum%, lineNum% + windowShiftY(windowNum%))\r
+ lineContent$ = lineContent$ + SPACE$(300)\r
+ lineContent$ = RIGHT$(lineContent$, LEN(lineContent$) - windowShiftX(windowNum%))\r
+ lineContent$ = LEFT$(lineContent$, widt% - 2)\r
+ PRINT CHR$(186) + lineContent$ + CHR$(186)\r
+ NEXT lineNum%\r
+\r
+ ' Draw window title\r
+ titleX% = INT(x% + (widt% / 2) - (LEN(title$) / 2) - 2)\r
+ LOCATE y%, titleX%\r
+ PRINT "[ "\r
+ titleX% = titleX% + 2\r
+\r
+ COLOR 10\r
+ LOCATE y%, titleX%\r
+ PRINT title$\r
+\r
+ titleX% = titleX% + LEN(title$)\r
+ COLOR 11\r
+ LOCATE y%, titleX%\r
+ PRINT " ]"\r
+ COLOR 7, 0\r
+END SUB\r
+\r
+SUB InitializeSystem\r
+ ' Initialize the screen and shared memory\r
+\r
+ WIDTH 80, 50\r
+ VIEW PRINT 1 TO 50\r
+\r
+ FOR storageIndex% = 1 TO maxStorage%\r
+ textStorage$(storageIndex%) = ""\r
+ NEXT storageIndex%\r
+\r
+ storagePointer% = 1\r
+END SUB
\ No newline at end of file
--- /dev/null
+' Simple COM port terminal\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+\r
+CLS\r
+\r
+1\r
+ ' Read the status of the COM port\r
+ portStatus = INP(&H3FD)\r
+\r
+ ' Check if data is available\r
+ IF portStatus = 97 THEN\r
+ ' Read the data from the COM port\r
+ comData = INP(&H3F8)\r
+\r
+ ' Print the character and its ASCII value\r
+ PRINT CHR$(comData);\r
+ PRINT comData;\r
+ END IF\r
+\r
+ ' Get user input\r
+ userInput$ = INKEY$\r
+\r
+ ' If there is any input, print it and send to COM port\r
+ IF userInput$ <> "" THEN\r
+ PRINT userInput$;\r
+\r
+ ' Send the ASCII value of the input character to the COM port\r
+ OUT &H3F8, ASC(userInput$)\r
+ END IF\r
+\r
+' Repeat the process\r
+GOTO 1\r
--- /dev/null
+This is sample encoded message!\r
--- /dev/null
+This is sample encoded message!\r
--- /dev/null
+' Utility that reduces high frequency noise/hiss in audio file.\r
+' In some casus it can help when recovering digital data from sound file.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003.12, Initial version\r
+\r
+\r
+DECLARE SUB start ()\r
+DEFINT A-Y\r
+DIM SHARED avb(1 TO 100)\r
+DIM SHARED byte AS STRING * 1\r
+DIM SHARED po, pod\r
+DIM SHARED file1$, file2$\r
+\r
+start\r
+\r
+INPUT "average factor:", po\r
+INPUT "divide factor:", pod\r
+\r
+OPEN file2$ FOR BINARY AS #1\r
+OPEN file1$ FOR BINARY AS #2\r
+\r
+SCREEN 12\r
+px = 0\r
+1\r
+GET #1, , byte\r
+c = ASC(byte)\r
+IF c > 127 THEN c = c - 255\r
+\r
+FOR a = 1 TO po - 1\r
+avb(a) = avb(a + 1)\r
+NEXT a\r
+avb(po) = c\r
+\r
+b = 0\r
+FOR a = 1 TO po\r
+b = b + avb(a)\r
+NEXT a\r
+\r
+b = b / pod\r
+'LINE (px + 1, 0)-(px + 1, 260), 14\r
+LINE (px, 0)-(px, 260), 0\r
+PSET (px, c + 130), 12\r
+PSET (px, b + 130), 14\r
+px = px + 1\r
+IF px > 639 THEN px = 1\r
+IF b < 0 THEN b = b + 255\r
+IF b > 255 THEN b = 255\r
+byte = CHR$(b)\r
+PUT #2, , byte\r
+'c$ = INPUT$(1)\r
+IF EOF(1) = 0 THEN GOTO 1\r
+\r
+CLOSE #2\r
+CLOSE #1\r
+\r
+SUB start\r
+\r
+IF COMMAND$ = "" THEN END\r
+b$ = COMMAND$\r
+file2$ = b$\r
+file1$ = ""\r
+FOR a = 1 TO LEN(b$)\r
+c$ = RIGHT$(LEFT$(b$, a), 1)\r
+IF c$ = "." OR c$ = " " THEN GOTO 2\r
+file1$ = file1$ + c$\r
+NEXT a\r
+2\r
+file1$ = file1$ + ".awe"\r
+\r
+END SUB\r
+\r
--- /dev/null
+#+TITLE: Data over analog audio\r
+#+LANGUAGE: en\r
+#+LATEX_HEADER: \usepackage[margin=1.0in]{geometry}\r
+#+LATEX_HEADER: \usepackage{parskip}\r
+#+LATEX_HEADER: \usepackage[none]{hyphenat}\r
+\r
+#+OPTIONS: H:20 num:20\r
+#+OPTIONS: author:nil\r
+\r
+* msg2xi: Text to Sound Encoder\r
+\r
+*msg2xi* is a utility designed to encode arbitrary text messages into an\r
+8-bit sound file. This program allows users to convert digital data\r
+into analog audio signals, making it possible to transmit text\r
+messages over traditional analog mediums such as telephone lines or\r
+magnetic tapes.\r
+\r
+*How It Works:* The program reads text from an input file, processing\r
+it byte by byte. Each byte is broken down into its constituent bits.\r
+For each bit, a sine wave is generated. Different waveforms represent\r
+'1's and '0's (implementing frequency modulation). The generated\r
+waveforms are combined into a single audio file, encoding the original\r
+text message. A special pure sinewave header tone is added to the\r
+beginning of the audio file to mark the start of the encoded message,\r
+facilitating synchronization during decoding.\r
+\r
+Download source code: [[file:msg2xi.bas][Source code]]\r
+\r
+* xi2msg: Sound to Text Decoder\r
+\r
+The *xi2msg* utility is designed to decode digital information from an\r
+audio file, specifically an 8-bit sound file. This program is part of\r
+a suite of utilities that enable the transmission of digital data over\r
+analog audio mediums, such as telephone lines or magnetic tapes.\r
+\r
+The *xi2msg* utility works by analyzing the audio file to locate peaks\r
+between waveforms. It calculates the distance between these peaks to\r
+determine whether each segment represents a '0' or a '1' bit. This\r
+process involves several key steps:\r
+\r
+- Header Detection :: The program starts by searching for a special\r
+ header tone in the audio file. This header tone marks the beginning\r
+ of the encoded message and helps synchronize the decoding process.\r
+\r
+- Peak Analysis :: The utility measures the distance between peaks in\r
+ the audio waveform. Long distances between peaks are interpreted as\r
+ '0' bits, while short distances are interpreted as '1' bits.\r
+\r
+- Bit Assembly :: The detected bits are sequentially assembled into\r
+ bytes. Each byte is then converted into its corresponding character.\r
+\r
+- Output :: The decoded message is displayed on the screen and written\r
+ to an output file, making it accessible for further use or analysis.\r
+\r
+The program relies on frequency modulation for decoding data, which\r
+was chosen for its resilience to amplitude distortions that can occur\r
+during analog transmission. This makes the utility particularly\r
+effective for decoding messages recorded on cassette tapes or\r
+transmitted over telephone lines.\r
+\r
+[[file:screenshot.png]]\r
+\r
+\r
+Download source code: [[file:xi2msg.bas][Source code]]\r
+\r
+* aver\r
+\r
+The *aver.bas* utility is designed to reduce noise in digitized audio\r
+files by smoothing out noise peaks, which is particularly beneficial\r
+for audio files transmitted over analog mediums like telephone lines\r
+or magnetic tapes, where noise interference is common.\r
+\r
+The program starts by asking the user for two critical factors: the\r
+averaging factor and the divide factor. These parameters determine the\r
+intensity of the noise reduction applied.\r
+\r
+For each byte read from the input file, the program stores the last N\r
+values (where N is the averaging factor). These values are averaged,\r
+and the result is scaled by the divide factor. This averaging\r
+technique helps to smooth out noise spikes in the audio data.\r
+\r
+The program provides a graphical representation of the original and\r
+smoothed audio. This allows for visual comparison of the original and\r
+processed signals on the screen. The smoothed audio data is written to\r
+an output file, which should have reduced noise compared to the input\r
+file.\r
+\r
+The program uses command-line input to determine the filenames for\r
+input and output, defaulting to appending .awe to the input filename\r
+for the output file.\r
+\r
+Download source code: [[file:aver.bas][Source code]]\r
--- /dev/null
+' Utility that encodes arbitrary text message into 8 bit sound file.
+' This audio can be now transferred over telephone line or recorded to magnetic tape.
+'
+' This program is free software: released under Creative Commons Zero (CC0) license
+' by Svjatoslav Agejenko.
+' Email: svjatoslav@svjatoslav.eu
+' Homepage: http://www.svjatoslav.eu
+'
+' Changelog:
+' 2001, Initial version
+' 2024.09, Improved program readability
+
+DECLARE SUB StartProgram ()
+DECLARE SUB AddIWave ()
+DECLARE SUB AddOWave ()
+DECLARE SUB ByteToSound (soundByte AS SINGLE)
+
+DIM SHARED iwaveArray(1 TO 20)
+DIM SHARED owaveArray(1 TO 41)
+DIM SHARED iwaveData$
+DIM SHARED owaveData$
+DIM SHARED inputFile$
+DIM SHARED outputFile$
+DIM SHARED byte AS STRING * 1
+
+StartProgram
+
+inputFile$ = "input.txt"
+outputFile$ = "sound.xi"
+
+' Open the input and output files for binary access
+OPEN inputFile$ FOR BINARY AS #2
+OPEN outputFile$ FOR BINARY AS #1
+
+' Add data start header/marker to the audio file
+FOR a = 1 TO 50
+ AddIWave
+NEXT a
+AddOWave
+
+' Read each byte from the input file and convert it to sound
+2
+GET #2, , byte
+ByteToSound ASC(byte)
+IF EOF(2) = 0 THEN GOTO 2
+
+' Close the files after processing
+CLOSE #2
+CLOSE #1
+
+PRINT "Encoding of message into sound completed"
+
+SUB ByteToSound (soundByte AS SINGLE)
+' Convert a byte to 8-bit wave sound data
+ soundByte = soundByte + 1
+
+ ' Check if the byte value is greater than 128.
+ ' If yes, set most significant bit to 1, otherwise 0
+ IF soundByte > 128 THEN
+ soundByte = soundByte - 128
+ AddIWave
+ ELSE
+ AddOWave
+ END IF
+
+ ' Check if the byte value is greater than 64 to set next bit
+ IF soundByte > 64 THEN
+ soundByte = soundByte - 64
+ AddIWave
+ ELSE
+ AddOWave
+ END IF
+
+ IF soundByte > 32 THEN
+ soundByte = soundByte - 32
+ AddIWave
+ ELSE
+ AddOWave
+ END IF
+
+ IF soundByte > 16 THEN
+ soundByte = soundByte - 16
+ AddIWave
+ ELSE
+ AddOWave
+ END IF
+
+ IF soundByte > 8 THEN
+ soundByte = soundByte - 8
+ AddIWave
+ ELSE
+ AddOWave
+ END IF
+
+ IF soundByte > 4 THEN
+ soundByte = soundByte - 4
+ AddIWave
+ ELSE
+ AddOWave
+ END IF
+
+ IF soundByte > 2 THEN
+ soundByte = soundByte - 2
+ AddIWave
+ ELSE
+ AddOWave
+ END IF
+
+ ' Check if the byte value is greater than 1
+ IF soundByte > 1 THEN
+ AddIWave
+ ELSE
+ AddOWave
+ END IF
+END SUB
+
+SUB AddIWave
+' Write iwaveData to the output file
+ PUT #1, , iwaveData$
+END SUB
+
+SUB AddOWave
+' Write owaveData to the output file
+ PUT #1, , owaveData$
+END SUB
+
+SUB StartProgram
+' Initialize wave data arrays
+
+ pi = 3.141592653999996#
+
+ ' Generate sine wave values to represent 1
+ b = 0
+ FOR a = pi / 2 TO 2.5 * pi STEP (2 * pi / 20)
+ b = b + 1
+ iwaveArray(b) = SIN(a) * 100
+ IF iwaveArray(b) < 0 THEN
+ iwaveArray(b) = iwaveArray(b) + 255
+ END IF
+ NEXT a
+
+ ' Generate sine wave values to represent 0
+ b = 0
+ FOR a = pi / 2 TO 2.5 * pi STEP (2 * pi / 40)
+ b = b + 1
+ owaveArray(b) = SIN(a) * 100
+ IF owaveArray(b) < 0 THEN
+ owaveArray(b) = owaveArray(b) + 255
+ END IF
+ NEXT a
+
+' Convert wave arrays to string data
+
+ ' Convert iwaveArray to string because strings are more computationally efficient to write into output file.
+ FOR a = 1 TO 20
+ iwaveData$ = iwaveData$ + CHR$(iwaveArray(a))
+ NEXT a
+
+ ' Convert owaveArray to string
+ FOR a = 1 TO 40
+ owaveData$ = owaveData$ + CHR$(owaveArray(a))
+ NEXT a
+
+END SUB
--- /dev/null
+' Utility that decodes text message from 8 bit audio recording.
+'
+' This program is free software: released under Creative Commons Zero (CC0) license
+' by Svjatoslav Agejenko.
+' Email: svjatoslav@svjatoslav.eu
+' Homepage: http://www.svjatoslav.eu
+'
+' Changelog:
+' 2001, Initial version
+' 2024 - 2025, Improved program readability
+'
+' Data is encoded in the audio by using frequency modulation.
+' When decoding data, program locates peaks between waveforms.
+' Then it calculates distance between peaks.
+' Long between peak distance is interpreted as 0 bit, short distance is 1 bit.
+' Bits 0 and 1 are then sequentially added into bytes and complete
+' message is decoded and shown on the screen. In addition, message is written out to
+' the file.
+'
+' Frequency modulation was chosen over amplitude modulation because
+' my tests with cassette tape recorder showed that distortions affect mostly
+' signal amplitude, but do not affect signal frequency that much.
+'
+' Data carrying audio is preceded with special header tone. Program detects header tone
+' and uses it to calculate baseline signal frequency that it will use later to decode bits.
+' Also header allows to mark precise data starting point.
+
+DEFINT A-Y
+DECLARE SUB bysf (a$, d)
+DECLARE SUB messa (a$)
+DECLARE SUB pfo (f, t, it)
+DECLARE SUB anal ()
+DECLARE SUB start ()
+DECLARE SUB iadd ()
+DECLARE SUB oadd ()
+DECLARE SUB byt (a)
+
+DIM SHARED file1$
+DIM SHARED file2$
+
+' Contains the actual audio waveform samples
+DIM SHARED audioBuffer(-100 TO 10000)
+DIM SHARED bus AS STRING * 1000
+DIM SHARED bufi
+DIM SHARED bg
+DIM SHARED sm
+DIM SHARED beg
+DIM SHARED wai
+DIM SHARED old2
+
+' Statistical Analysis Array (contains measured peak distances)
+DIM SHARED statisticalArray(1 TO 10)
+DIM SHARED statl
+DIM SHARED aver
+DIM SHARED byte AS STRING * 1
+DIM SHARED avv
+
+DIM SHARED li
+DIM SHARED oc
+DIM SHARED px
+
+start
+messa "Searching for beginning..."
+
+OPEN "output.txt" FOR BINARY AS #1
+OPEN "sound.xi" FOR BINARY AS #2
+SEEK #2, 360
+
+2
+GET #2, , bus
+FOR a = 1 TO 1000
+ b$ = RIGHT$(LEFT$(bus, a), 1)
+ bufi = bufi + 1
+ c = ASC(b$)
+ IF c > 127 THEN c = c - 255
+ audioBuffer(bufi) = c
+NEXT a
+IF (EOF(2) = 0) AND (bufi < 8000) THEN GOTO 2
+anal
+IF EOF(2) = 0 THEN GOTO 2
+
+CLOSE #2
+CLOSE #1
+
+SYSTEM
+
+SUB anal
+ ' Draw a vertical line to represent the buffer data
+ LINE (1, 170)-(200, 430), 0, BF
+
+ FOR a = 1 TO bufi - (avv - 1)
+ ' Draw horizontal lines at key points
+ LINE (100, 170)-(100, 430), 13
+ LINE (old2 - a + 100, 170)-(old2 - a + 100, 430), 11
+ LINE (0, 300)-(200, 300), 13
+
+ ' Plot the buffer data points
+ FOR b = 0 TO 200
+ PSET (b, audioBuffer(b + a - 101) + 300), 0
+ PSET (b, audioBuffer(b + a - 100) + 300), 14
+ NEXT b
+
+ LINE (old2 - a + 100, 170)-(old2 - a + 100, 430), 0
+
+ ' Calculate the average value of the buffer segment
+ c = 0
+ FOR b = a TO a + (avv - 1)
+ c = c + audioBuffer(b)
+ NEXT b
+ c = c / (avv / 2)
+
+ ' Determine if we are in a high or low state
+ IF c > oc THEN
+ IF li = -1 THEN
+ li = 1
+ pfo a + ((avv - 1) / 2 - 1), 1, oc
+ GOTO 3
+ END IF
+ END IF
+
+ IF c < oc THEN
+ IF li = 1 THEN
+ li = -1
+ pfo a + ((avv - 1) / 2 - 1), 2, oc
+ GOTO 3
+ END IF
+ END IF
+
+ 3
+ ' Update the current average value
+ oc = c
+ NEXT a
+
+ ' Shift the buffer data to the left
+ FOR a = bufi - (avv - 2) TO bufi
+ audioBuffer(a - (bufi - (avv - 2)) + 1) = audioBuffer(a)
+ NEXT a
+
+ ' Update the starting index of the buffer
+ old2 = old2 - (bufi - (avv - 2)) + 1
+ bufi = avv - 1
+
+END SUB
+
+SUB bysf (a$, d)
+ ' Draw a horizontal line to represent the byte data
+ LINE (201, 170)-(639, 430), 1, B
+
+ IF d = 10 THEN px = 0: a$ = "": GOTO 5
+
+ px = px + 1
+ IF px > 53 THEN
+ px = 1
+ 5
+ DIM tempr(1 TO 32000)
+ GET (201, 186)-(639, 430), tempr(1)
+ PUT (201, 170), tempr(1), PSET
+ LINE (201, 414)-(639, 430), 0, BF
+ END IF
+
+ ' Print the byte data to the screen
+ LOCATE 26, 26 + px
+ PRINT a$
+
+ ' Convert the byte value to a character and write it to the output file
+ byte = CHR$(d)
+ PUT #1, , byte
+
+END SUB
+
+SUB byt (a)
+
+ ' Draw a horizontal line to represent the bit data
+ LINE (410, 0)-(639, 169), 1, B
+
+ statl = statl + 1
+ IF statl > 8 THEN
+ statl = 1
+ b = 0
+ IF statisticalArray(1) = 1 THEN b = b + 128
+ IF statisticalArray(2) = 1 THEN b = b + 64
+ IF statisticalArray(3) = 1 THEN b = b + 32
+ IF statisticalArray(4) = 1 THEN b = b + 16
+ IF statisticalArray(5) = 1 THEN b = b + 8
+ IF statisticalArray(6) = 1 THEN b = b + 4
+ IF statisticalArray(7) = 1 THEN b = b + 2
+ IF statisticalArray(8) = 1 THEN b = b + 1
+
+ ' Print the byte value to the screen
+ LOCATE 10, 69
+ PRINT b
+
+ ' Print the hexadecimal representation of the byte value
+ LOCATE 10, 75
+ PRINT HEX$(b)
+
+ ' Print the character representation of the byte value
+ LOCATE 10, 79
+ c$ = CHR$(b)
+
+ ' Replace control characters with a space
+ IF b = 7 OR b = 8 OR b = 10 OR b = 12 OR b = 13 THEN c$ = " "
+
+ PRINT c$
+
+ bysf c$, b
+
+ DIM tempr(1 TO 10000)
+ GET (410, 16)-(639, 169), tempr(1)
+ PUT (410, 0), tempr(1), PSET
+ LINE (410, 153)-(639, 169), 0, BF
+ END IF
+
+ ' Print the bit value to the screen
+ LOCATE 10, 50 + (statl * 2)
+
+ statisticalArray(statl) = a
+
+ PRINT a
+
+END SUB
+
+SUB messa (a$)
+ ' Draw a horizontal line to represent the message data
+ LINE (0, 0)-(409, 169), 1, B
+
+ DIM tempr(1 TO 20000)
+
+ GET (0, 16)-(409, 169), tempr(1)
+
+ PUT (0, 0), tempr(1), PSET
+
+ LINE (0, 153)-(409, 169), 0, BF
+
+ ' Print the message to the screen
+ LOCATE 10, 1
+
+ PRINT a$
+
+END SUB
+
+SUB pfo (f, t, it)
+ IF t = 2 THEN
+ bg = it
+
+ IF wai > 0 THEN wai = wai - 1
+
+ ' Check if we have found data start header
+ IF (bg - sm > 6) AND (beg = 0) THEN
+ beg = 1
+ wai = 10
+ messa "Beginning point found!"
+ END IF
+
+ ' Perform statistical analysis if needed
+ IF (wai = 0) AND (beg = 1) THEN
+ IF statl = 0 THEN messa "Beginning statistical analyze"
+
+ statl = statl + 1
+
+ IF statl > 10 THEN
+ FOR a = 1 TO 10
+ aver = aver + statisticalArray(a)
+ NEXT a
+
+ aver = aver * 1.5 / 10
+
+ beg = 2
+
+ statl = 1
+
+ messa "Statistical analyze completed!"
+ END IF
+
+ ' Store the current frame index
+ statisticalArray(statl) = f - old2
+ END IF
+
+ ' Decode the bits if we are in the decoding state
+ IF beg = 2 THEN
+ IF f - old2 >= aver THEN
+ beg = 3
+
+ statl = 0
+
+ FOR a = 1 TO 8
+ statisticalArray(a) = 0
+ NEXT a
+
+ GOTO 4
+ END IF
+ END IF
+
+ ' Decode the bits based on the current state
+ IF beg = 3 THEN
+ IF f - old2 >= aver THEN
+ byt 0
+ ELSE
+ byt 1
+ END IF
+ END IF
+
+ 4
+
+ old2 = f
+ ELSE
+ sm = it
+ END IF
+END SUB
+
+SUB start
+
+ ' Set the screen mode to graphics
+ SCREEN 12
+
+ ' Initialize buffer index and other variables
+ bufi = 0
+
+ beg = 0
+
+ statl = 0
+
+ aver = 0
+
+ px = 0
+
+ avv = 7
+
+ li = 1
+
+ oc = -9999
+
+END SUB
\ No newline at end of file
--- /dev/null
+#+TITLE: LPT Communication Driver\r
+#+LANGUAGE: en\r
+#+LATEX_HEADER: \usepackage[margin=1.0in]{geometry}\r
+#+LATEX_HEADER: \usepackage{parskip}\r
+#+LATEX_HEADER: \usepackage[none]{hyphenat}\r
+\r
+#+OPTIONS: H:20 num:20\r
+#+OPTIONS: author:nil\r
+\r
+* Overview\r
+\r
+This is weird networking solution. It allows to send data using\r
+parallel LPT port serially(!) by bit-banging between two connected\r
+computers :)\r
+\r
+Out of [[https://en.wikipedia.org/wiki/Parallel_port][25 physical wires in LPT port]], only 3 are used:\r
+\r
+- Pin 14 :: Carries a synchronization signal which uses a periodic\r
+ pattern (e.g., 010101...) to maintain timing alignment between the\r
+ communicating computers.\r
+\r
+- Pin 17 :: Functions as the bidirectional data line, responsible for\r
+ transmitting and receiving data between the connected computers.\r
+\r
+- Pin 18 :: Acts as the ground connection, providing a common\r
+ reference for electrical signals to ensure consistency in\r
+ communication.\r
+\r
+[[file:diagram.png]]\r
+\r
+By utilizing only three wires and software controlled bit-banging\r
+algorithm, custom, comparatively simple, cheap and long cable can be\r
+built to connect 2 computers in a DIY network setup.\r
+\r
+* LPT Communication Driver\r
+\r
+** Overview\r
+\r
+The LPT Communication Driver is a Terminate and Stay Resident (TSR)\r
+driver designed to facilitate communication between computers using\r
+parallel printer ports (LPT). This driver uses bit-banging to send and\r
+receive data serially over the LPT port, utilizing only three wires\r
+for communication.\r
+\r
+Driver hooks into the system's IRQ 0 to ensure that system timer\r
+always keeps executing it in the background. While operating as a\r
+background process, it periodically monitors LPT port to detect\r
+incoming transmission. When transmission is detected, driver receives,\r
+decodes and stores it into preallocated 5000 byte receive buffer.\r
+\r
+Applications can then communicate with the driver on their own\r
+schedule using INT 63h to poll for and retrieve received messages, if\r
+any. Applications can also send outgoing messages into 5000 byte\r
+driver outbox memory buffer. Thereafter driver will transmit those\r
+messages in background mode over the wire.\r
+\r
+The driver is half-duplex: it prioritizes receiving over sending and\r
+does not transmit while receiving.\r
+\r
+During active transmission/reception, the driver can consume 100% CPU\r
+due to busy-wait loops in the IRQ handler, potentially causing random\r
+temporary hiccups for application running in the\r
+foreground. Unsuitable for real-time systems.\r
+\r
+Download:\r
+- Source code: [[file:lptdrv.asm][lptdrv.asm]]\r
+- Compiled binary: [[file:lptdrv.com][lptdrv.com]]\r
+\r
+** Data transmission implementation details\r
+\r
+When there is incoming data transmission, the TSR driver detects it\r
+during its periodic execution in the IRQ 0 (timer) handler, which runs\r
+approximately every 55ms.\r
+\r
+Driver checks for possible transmission comparatively rarely (every 55\r
+ms) and for this reason it is important to have quite long\r
+transmission start indicator/header before actual data is sent. This\r
+allows long enough time for recipient computer communication driver to\r
+detect that transmission line is active and start listening to it now\r
+in exclusive busy-wait loop. So, the TSR driver steals 100% of the CPU\r
+for the duration of transmission.\r
+\r
+The start of transmission is detected by reading the port (37Ah)\r
+value, and checking if bit 3 of the raw input is high. It then enters\r
+a "skip header" loop. Once bit 1 goes low, bit reception begins. The\r
+end is detected via a timeout: during bit reception, a counter\r
+increments on each poll. If there is no change in the port value for\r
+30 consecutive polls (indicating no new bit transition), it assumes\r
+the transmission is complete, appends a 2-byte length to the receive\r
+buffer, and exits the routine.\r
+\r
+So, both receive and send routines execute within the IRQ 0 handler\r
+using busy-wait polling loops (for receive) or timed output loops (for\r
+send). These can hold the CPU for the full duration of a transmission,\r
+as the handler does not yield until complete.\r
+\r
+It bit-bangs data by treating the LPT control port (37Ah) as both\r
+output and input, using bit 3 (pin 17, data line) for the serial data\r
+bit and bit 1 (pin 14, sync line) for a clock that alternates (low on\r
+even bit indices, high on odd) to signal transitions.\r
+\r
+For sending: the port is first set to 0xFF (all bits high) as a\r
+header, held for ~110ms (2 timer ticks).\r
+\r
+For receiving: after start detection, it polls the port for value\r
+changes (transitions). On each change, it reads the port again (to\r
+ensure that synchronization bit did not arrive ahead data bit over the\r
+separate physical wire), extracts bit 3 as the data bit, shifts it\r
+into a byte accumulator, and resets the timeout counter. Once a full\r
+byte is accumulated, it stores it in the receive buffer. No ACK or\r
+error checking.\r
+\r
+Driver can receive multiple transmissions into its 5000-byte receive\r
+buffer before the client program reads it out. Each incoming\r
+transmission appends its data bytes followed by a 2-byte length word\r
+directly to the end of the buffer (updating dbufsiz to the new total\r
+used). As long as the cumulative size doesn't exceed 5000 bytes,\r
+multiple can queue up. The buffer acts as a FIFO for concatenated\r
+packets; overflows are not handled (it would corrupt without\r
+checks). The client retrieves the entire buffer contents at once when\r
+polling.\r
+\r
+When the client program reads received data from the TSR (via INT 63h\r
+AH=2), the driver copies the full buffer contents (up to dbufsiz\r
+bytes) to the client's specified ES:DI pointer, returns the byte count\r
+in AX, and immediately resets dbufsiz to 0, clearing the buffer. This\r
+ensures the data is not served again on subsequent reads, as the\r
+buffer is emptied after each retrieval. If no data is available, AX=0\r
+is returned.\r
+\r
+** Driver API\r
+\r
+The driver uses INT 63h for its API, with functions selected via the\r
+AH register. It maintains two internal buffers:\r
+\r
+- Download Buffer: 5000 bytes for incoming (received) data. Multiple\r
+ transmissions can be queued here, each appended with a 2-byte length\r
+ footer.\r
+- Upload Buffer: 5000 bytes for outgoing (to-be-sent) data. Data is\r
+ copied here and transmitted when the line is free.\r
+\r
+\r
+Communication is polling-based for applications; the driver handles\r
+transmission/reception in the background.\r
+\r
+No error checking, acknowledgments, or flow control; it's a simple,\r
+unidirectional-per-turn protocol.\r
+\r
+To use the driver:\r
+- Load the TSR (e.g., run lptdrv.com).\r
+- Activate it via the API.\r
+- Poll for received data or queue sends as needed.\r
+- Deactivate when done.\r
+\r
+API overview:\r
+| AH register | API function |\r
+|-------------+---------------------------------------------------------|\r
+| 0 | [[id:a7aaa0e6-92de-467c-bcd4-b3d3216b15d4][Deactivate the driver]] |\r
+| 1 | [[id:944be7b6-d3ba-486a-98bd-1a66cfffe6e5][Activate the driver]] |\r
+| 2 | [[id:49350196-55b9-4d50-b672-b3c6d6d55e53][Retrieve downloaded data from the driver's input buffer]] |\r
+| 3 | [[id:53fd0c68-4057-4e9e-b908-87fab6eab5c8][Upload data to the driver's output buffer for transmission]] |\r
+\r
+*** Deactivate the driver\r
+:PROPERTIES:\r
+:ID: a7aaa0e6-92de-467c-bcd4-b3d3216b15d4\r
+:END:\r
+\r
+Disables the driver, stopping background monitoring and\r
+transmission. The LPT port is reset (set to 0).\r
+\r
+- AH: 0\r
+- Parameters: None\r
+- Returns: None\r
+- Side Effects: Clears the enabled flag.\r
+- Usage Notes: Call this before unloading the TSR or when\r
+ communication is no longer needed to free system resources.\r
+\r
+*** Activate the driver\r
+:PROPERTIES:\r
+:ID: 944be7b6-d3ba-486a-98bd-1a66cfffe6e5\r
+:END:\r
+\r
+Enables the driver, starting background LPT port monitoring for\r
+incoming data. The LPT port is reset (set to 0) upon activation.\r
+\r
+- AH: 1\r
+- Parameters: None\r
+- Returns: None\r
+- Side Effects: Sets the enabled flag. Existing buffer contents are\r
+ preserved.\r
+- Usage Notes: Must be called after loading the TSR and before any\r
+ send/receive operations. Can be called multiple times; redundant\r
+ activations are harmless.\r
+\r
+*** Retrieve downloaded data from the driver's input buffer\r
+:PROPERTIES:\r
+:ID: 49350196-55b9-4d50-b672-b3c6d6d55e53\r
+:END:\r
+\r
+Copies all accumulated received data from the driver's download buffer\r
+to the caller's memory location and clears the buffer.\r
+\r
+- *AH* : 2\r
+- *Parameters* :\r
+ - *ES:DI* : Pointer to the buffer where received data should be\r
+ copied (must be large enough to hold up to 5000 bytes).\r
+- *Returns* :\r
+ - *AX* : Number of bytes copied (0 if no data available).\r
+- *Side Effects* : Resets the download buffer size to 0, preventing\r
+ re-retrieval of the same data.\r
+- *Usage Notes* :\r
+ - Data is retrieved as a concatenated stream of all queued\r
+ transmissions.\r
+ - Each transmission in the buffer ends with a 2-byte length word\r
+ (little-endian) indicating its payload size (excluding the length\r
+ itself).\r
+ - Poll this function periodically in a loop to check for new data.\r
+ - If AX=0, no copy occurs.\r
+ - Example: In assembly, set ES:DI to your receive buffer and call\r
+ INT 63h; then process AX bytes if >0.\r
+\r
+*** Upload data to the driver's output buffer for transmission\r
+:PROPERTIES:\r
+:ID: 53fd0c68-4057-4e9e-b908-87fab6eab5c8\r
+:END:\r
+\r
+Copies the specified data to the driver's upload buffer for background\r
+transmission. Transmission occurs when the line is free (no incoming\r
+data).\r
+\r
+- *AH* : 3\r
+- *Parameters* :\r
+ - *DS:SI* : Pointer to the data to upload.\r
+ - *CX* : Number of bytes to upload (must not exceed remaining upload\r
+ buffer space; no checks performed).\r
+- *Returns* : None\r
+- *Side Effects* : Appends data to the upload buffer and updates its\r
+ size. Transmission is asynchronous.\r
+- *Usage Notes* :\r
+ - Data is sent as a single transmission (no automatic framing;\r
+ caller can add headers if needed).\r
+ - If the buffer is full (total >5000 bytes), behavior is undefined\r
+ (overflow).\r
+ - Multiple calls can queue data sequentially in the buffer.\r
+ - Transmission starts in the next IRQ 0 tick if the line is idle.\r
+ - The driver adds no footer; the receiver sees exactly the sent bytes.\r
+ - Example: Load DS:SI with your message, CX with length, call INT\r
+ 63h; the driver handles sending.\r
--- /dev/null
+; Svjatoslav Agejenko\r
+; 2002.08\r
+; compile with FASM - Flat Assembler\r
+\r
+; TSR driver for LPT1 communication.\r
+; Functions by INT 63h:\r
+\r
+; Deactivate\r
+; AH = 0\r
+\r
+; Activate\r
+; AH = 1\r
+\r
+; Get downloaded data\r
+; AH = 2\r
+; ES:DI - pointer where to place downloaded data\r
+; on return:\r
+; AX = Number of bytes downloaded\r
+\r
+; copies downloaded data from driver input buffers to\r
+; specified place. \r
+\r
+; Upload data\r
+; AH = 3\r
+; DS:SI - pointer for data to be uploaded\r
+; CX - amount of bytes to upload \r
+\r
+; After interrupt, data will be immediately\r
+; moved to communication driver own output buffer,\r
+; and sent when line becomes avaiable.\r
+ \r
+myint = 63h ; interrupt to hook\r
+upbuf = 5000 ; upload buffer size\r
+downbuf = 5000 ; download buffer size\r
+InPort = 37ah ; input port, for Parallel Printer Port Control Register\r
+defspd = 3 ; Default communication speed\r
+upbufp = last + downbuf\r
+\r
+\r
+org 100h\r
+\r
+;============================ TSR initialization ====================\r
+\r
+mov dx, InPort ; reset line\r
+mov al, 0\r
+out dx, al\r
+\r
+mov ax, 0 ; Saves old interrupt vector\r
+mov es, ax\r
+mov eax, [es:32]\r
+mov [d2], eax \r
+\r
+cli\r
+mov ax, cs ; Set new interrupt vector for IRQ 0\r
+shl eax, 16\r
+mov ax, custom\r
+mov [es:32], eax\r
+mov ax, int63 ; Set new interrupt vector for INT 63\r
+mov [es:4 * myint], eax\r
+sti\r
+\r
+\r
+mov ax, last ; Calculate needed memory size, begin TSR\r
+add ax, upbuf + downbuf + 1000\r
+mov dx, 0\r
+mov bx, 16\r
+div bx\r
+mov dx, ax\r
+mov ax, 3100h\r
+int 21h\r
+d2 dd 0\r
+\r
+;============================ IRQ 0 handler =========================\r
+\r
+custom:\r
+pushf ; Execute default code in old int vector\r
+call dword [cs:d2]\r
+\r
+;pusha ; Write 1 character, for debugging\r
+;mov ax, 0e01h\r
+;mov bx, 0\r
+;int 10h\r
+;popa\r
+\r
+inc byte [cs:tmr] ; Update timer\r
+\r
+cmp [cs:progress], 0 ; Check if custom routine is already active\r
+jne EndOfRoutine\r
+cmp [cs:enabled], 0 ; Check if driver is enabled\r
+je EndOfRoutine\r
+\r
+mov [cs:progress], 1 ; Set active flag\r
+pusha\r
+push ds\r
+push es\r
+\r
+mov dx, InPort\r
+in al, dx\r
+shl al, 4\r
+cmp al, 128\r
+jb checkdone\r
+\r
+;============================ download data from LPT ================\r
+\r
+mov ax, cs\r
+mov es, ax\r
+mov ds, ax\r
+mov di, last\r
+add di, [dbufsiz]\r
+mov bh, 0\r
+\r
+SkipHeader:\r
+in al, dx\r
+shl al, 6\r
+cmp al, 128\r
+jae SkipHeader\r
+mov ah, 255\r
+mov cx, 0\r
+\r
+SkipBit:\r
+inc cx\r
+cmp cx, 30\r
+je MkHeader\r
+in al, dx\r
+cmp al, ah\r
+je SkipBit\r
+in al, dx\r
+\r
+mov cx, 0\r
+mov ah, al\r
+shr al, 3\r
+or al, 254\r
+sub al, 254\r
+\r
+shl bl, 1\r
+add bl, al\r
+inc bh\r
+cmp bh, 8\r
+jb SkipBit\r
+\r
+mov al, bl\r
+stosb\r
+mov bh, 0\r
+mov bl, bh\r
+jmp SkipBit\r
+\r
+MkHeader:\r
+mov ax, di\r
+sub ax, last\r
+sub ax, [dbufsiz]\r
+stosw\r
+mov ax, di\r
+sub ax, last\r
+mov [dbufsiz], ax\r
+\r
+checkdone:\r
+cmp word [cs:ubufsiz], 0\r
+je alldone\r
+\r
+; =========================== send data to LPT ======================\r
+\r
+mov ax, cs\r
+mov ds, ax\r
+mov byte [tmr], 0\r
+\r
+mov dx, InPort\r
+mov al, 255\r
+out dx, al\r
+mov si, upbufp\r
+mov cx, [ubufsiz]\r
+\r
+sti\r
+SendHeader:\r
+cmp byte [tmr], 2\r
+jb SendHeader\r
+cli\r
+\r
+SendByte:\r
+cmp cx, 0\r
+je sent\r
+\r
+mov bl, 0\r
+lodsb\r
+\r
+SendBit:\r
+push ax\r
+push cx\r
+shr al, 4\r
+or al, 247\r
+sub al, 247\r
+mov bh, bl\r
+or bh, 254\r
+sub bh, 254\r
+shl bh, 1\r
+add al, bh\r
+\r
+mov ch, 0\r
+mov cl, [spd]\r
+WaitForBit:\r
+out dx, al\r
+loop WaitForBit\r
+pop cx\r
+pop ax\r
+inc bl\r
+shl al, 1\r
+cmp bl, 8\r
+jb SendBit\r
+\r
+dec cx\r
+jmp SendByte\r
+sent:\r
+\r
+mov al, 0\r
+out dx, al\r
+mov word [ubufsiz], 0\r
+\r
+\r
+alldone:\r
+pop es\r
+pop ds\r
+popa\r
+mov [cs:progress], 0 ; Terminate active flag\r
+EndOfRoutine:\r
+iret\r
+\r
+progress db 0\r
+enabled db 0\r
+dbufsiz dw 0\r
+ubufsiz dw 0\r
+tmr db 0\r
+spd db defspd\r
+\r
+;============================ INT 63h handler =======================\r
+\r
+int63:\r
+cmp ah, 0\r
+je set_unactive\r
+cmp ah, 1\r
+je set_active\r
+cmp ah, 2\r
+je get_data\r
+cmp ah, 3\r
+je send_data\r
+jmp EndOfRoutine\r
+\r
+set_active:\r
+mov dx, InPort ; reset line\r
+mov al, 0\r
+out dx, al\r
+mov [cs:enabled], 1\r
+jmp EndOfRoutine\r
+\r
+set_unactive:\r
+mov [cs:enabled], 0\r
+jmp EndOfRoutine\r
+\r
+get_data:\r
+push ds\r
+mov ax, cs\r
+mov ds, ax\r
+mov si, last\r
+mov cx, [dbufsiz]\r
+rep movsb\r
+pop ds\r
+mov ax, [cs:dbufsiz]\r
+mov [cs:dbufsiz], 0\r
+jmp EndOfRoutine\r
+\r
+send_data:\r
+push es\r
+mov dx, cx\r
+mov bx, cs\r
+mov es, bx\r
+mov di, upbufp\r
+add di, [cs:ubufsiz]\r
+rep movsb\r
+add [cs:ubufsiz], dx\r
+pop es\r
+jmp EndOfRoutine\r
+\r
+last:\r
--- /dev/null
+; simple driver test\r
+\r
+org 100h\r
+\r
+mov ah, 1 ; activate driver\r
+int 63h\r
+\r
+l1:\r
+mov di, last\r
+mov ah, 2\r
+int 63h\r
+cmp ax, 0\r
+je l2\r
+\r
+cmp byte [last], 0\r
+jne l3\r
+call send4kb\r
+jmp l2\r
+l3:\r
+\r
+add ax, last\r
+mov di, ax\r
+mov byte [ds:di], 36\r
+\r
+mov ah, 9\r
+mov dx, d1\r
+int 21h\r
+\r
+\r
+l2:\r
+\r
+mov ah, 0bh\r
+int 21h\r
+cmp al, 0\r
+je l1\r
+\r
+\r
+mov ah, 0\r
+int 16h\r
+cmp al, 27\r
+je quit\r
+cmp al, 13\r
+je send\r
+cmp al, 32\r
+je TestSpeed\r
+\r
+jmp l1\r
+\r
+quit:\r
+mov ah, 0 ; deactivate driver\r
+int 63h\r
+ret\r
+\r
+send:\r
+mov cx, d1 - d2\r
+mov si, d2\r
+mov ah, 3\r
+int 63h\r
+jmp l1\r
+\r
+send4kb:\r
+mov cx, 4096\r
+mov si, last\r
+mov ah, 3\r
+int 63h\r
+ret\r
+\r
+TestSpeed:\r
+mov byte [last], 0\r
+mov cx, 0\r
+\r
+l5:\r
+push cx\r
+call send4kb\r
+l4:\r
+mov di, last + 1\r
+mov ah, 2\r
+int 63h\r
+cmp ax, 0\r
+je l4\r
+pop cx\r
+\r
+mov dx, d3\r
+mov ah, 9\r
+int 21h\r
+\r
+inc cx\r
+cmp cx, 100\r
+jb l5\r
+\r
+mov dx, d4\r
+mov ah, 9\r
+int 21h\r
+jmp l1\r
+\r
+d3 db '. $'\r
+d4 db 13, 10, 'done', 13, 10, '$'\r
+d2 db 'Quick brown fox jumped over the lazy dogs. 0123456789ABCDEF'\r
+d1 db 13,10,'Data recieved:'\r
+last:\r
--- /dev/null
+' Program to control voltage on individual LPT port pins.\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2002, Initial version\r
+' 2024.08, Improved program readability\r
+'\r
+' Use keyboard keys 1 - 8 to toggle on/off individual pins.\r
+\r
+DECLARE SUB display ()\r
+DECLARE SUB transmit ()\r
+DIM SHARED bit(1 TO 8)\r
+DIM SHARED printerPort\r
+\r
+printerPort = &H378\r
+FOR a = 1 TO 8\r
+ bit(a) = 0\r
+NEXT a\r
+SCREEN 13\r
+\r
+MainLoop:\r
+display\r
+transmit\r
+keyInput$ = INPUT$(1)\r
+IF VAL(keyInput$) > 0 THEN\r
+ keyValue = VAL(keyInput$)\r
+ IF bit(keyValue) = 0 THEN\r
+ bit(keyValue) = 1\r
+ ELSE\r
+ bit(keyValue) = 0\r
+ END IF\r
+END IF\r
+\r
+GOTO MainLoop\r
+\r
+SUB display\r
+\r
+ ' Display the current status of each pin\r
+ LOCATE 3, 1\r
+ PRINT " 1 2 3 4 5 6 7 8"\r
+\r
+ FOR a = 1 TO 8\r
+ LINE (a * 16, 1)-(a * 16 + 8, 9), bit(a), BF\r
+ NEXT a\r
+\r
+END SUB\r
+\r
+SUB transmit\r
+\r
+ ' Calculate the byte to be sent based on the status of each pin\r
+ outputByte = 0\r
+ FOR a = 1 TO 8\r
+ outputByte = outputByte * 2\r
+ outputByte = outputByte + bit(a)\r
+ NEXT a\r
+\r
+ OUT printerPort, outputByte\r
+END SUB\r
--- /dev/null
+' This is quite unusual program. It sends data from LPT port (parallel\r
+' printer port) to COM (serial mouse) port. It does it by bit-banging\r
+' the data out of the LPT port. If you connect appropriate wire from\r
+' LPT port output bit (pin #3) to COM port input bit, you can send\r
+' data from LPT to COM.\r
+'\r
+' Note:\r
+' - Ground wire must be connected between LPT and COM ports too.\r
+' - Use this program at your own risk. It may not work on your system or may even damage it.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2002, Initial version\r
+' 2024, Improved program readability\r
+\r
+DEFINT A-Z\r
+DECLARE SUB sendChar (char$)\r
+DIM SHARED port\r
+port = &H378 ' LPT port\r
+\r
+PRINT "Type something. All keyboard strokes will be transmitted."\r
+PRINT "ESC to exit"\r
+\r
+1\r
+inputChar$ = INPUT$(1)\r
+IF inputChar$ = CHR$(27) THEN SYSTEM\r
+PRINT inputChar$;\r
+sendChar inputChar$\r
+GOTO 1\r
+\r
+SUB sendChar (char$)\r
+ ' Convert the character into its ASCII value\r
+ asciiValue = ASC(char$)\r
+\r
+ DIM bitArray(0 TO 8)\r
+ bitArray(0) = 0\r
+ bitArray(8) = 0\r
+\r
+ bValue = 64\r
+ cIndex = 7\r
+2\r
+ ' Convert the ASCII value into a binary representation\r
+ IF asciiValue >= bValue THEN\r
+ bitArray(cIndex) = 1\r
+ asciiValue = asciiValue - bValue\r
+ ELSE\r
+ bitArray(cIndex) = 0\r
+ END IF\r
+\r
+ ' Divide the value by 2 and move to the next bit\r
+ bValue = bValue / 2\r
+ cIndex = cIndex - 1\r
+\r
+ IF cIndex <> 0 GOTO 2\r
+\r
+ ' Send each bit of the character through the LPT port\r
+ FOR a = 0 TO 8\r
+ IF bitArray(a) = 0 THEN\r
+ bValue = 255\r
+ ELSE\r
+ bValue = 0\r
+ END IF\r
+\r
+ ' Adjust this loop based on your system and QBasic interpreter speed\r
+ FOR c = 0 TO 9\r
+ OUT port, bValue\r
+ NEXT c\r
+ NEXT a\r
+\r
+ ' Reset the LPT port to 0 after sending the character\r
+ OUT port, 0\r
+\r
+END SUB\r
--- /dev/null
+' Plays entered text in morse code audio beeps using PC-speaker.\r
+'\r
+' This program is free software: released under Creative Commons Zero (CC0) license\r
+' by Svjatoslav Agejenko.\r
+' Email: svjatoslav@svjatoslav.eu\r
+' Homepage: http://www.svjatoslav.eu\r
+'\r
+' Changelog:\r
+' 2003, Initial version\r
+' 2024.08, Improved program readability\r
+\r
+DECLARE SUB say()\r
+DECLARE SUB laus(a$)\r
+DECLARE SUB char(a!)\r
+DIM SHARED mors(0 TO 255, 0 TO 9)\r
+DIM SHARED spd\r
+spd = 1\r
+CLS\r
+\r
+' Open the Morse code file for reading\r
+OPEN "morse.txt" FOR INPUT AS #1\r
+\r
+' Label to read each line from the file\r
+2\r
+IF EOF(1) THEN GOTO 1\r
+LINE INPUT #1, a$\r
+\r
+' Process each character in the current line\r
+FOR b = 1 TO LEN(a$)\r
+ c = ASC(RIGHT$(LEFT$(a$, b), 1))\r
+ IF b = 1 THEN m = c\r
+ IF b > 2 THEN\r
+ d = 0\r
+ IF c = ASC(".") THEN d = 1\r
+ IF c = ASC("-") THEN d = 2\r
+ mors(m, b - 2) = d\r
+ END IF\r
+NEXT b\r
+GOTO 2\r
+\r
+' Label to close the file\r
+1\r
+CLOSE\r
+\r
+' Prompt user for input\r
+PRINT "Type '.bye' to quit"\r
+\r
+' Main loop to read and process user input\r
+3\r
+PRINT ""\r
+INPUT "", a$\r
+IF a$ = ".bye" THEN SYSTEM\r
+laus a$\r
+GOTO 3\r
+\r
+' Subroutine to play Morse code for a single character\r
+SUB char(a)\r
+ PRINT CHR$(a);\r
+\r
+ ' Loop through each part of the Morse code sequence\r
+ FOR b = 0 TO 9\r
+ IF mors(a, b) = 1 THEN\r
+ ' Play short beep for a dot\r
+ SOUND 1000, 1 * spd\r
+ SOUND 0, 1 * spd\r
+ END IF\r
+\r
+ IF mors(a, b) = 2 THEN\r
+ ' Play long beep for a dash\r
+ SOUND 1000, 3 * spd\r
+ SOUND 0, 1 * spd\r
+ END IF\r
+ NEXT b\r
+\r
+ ' Short pause between Morse code characters\r
+ FOR a = 0 TO 160\r
+ SOUND 0, .1\r
+ NEXT a\r
+END SUB\r
+\r
+' Subroutine to process and play Morse code for an entire string\r
+SUB laus(a$)\r
+ ' Loop through each character in the input string\r
+ FOR b = 1 TO LEN(a$)\r
+ c = ASC(RIGHT$(LEFT$(a$, b), 1))\r
+\r
+ ' Call char subroutine to play Morse code for the current character\r
+ char c\r
+ NEXT b\r
+END SUB
\ No newline at end of file
--- /dev/null
+a .-\r
+b -...\r
+c -.-.\r
+d -..\r
+e .\r
+f ..-.\r
+g --.\r
+h ....\r
+i ..\r
+j .---\r
+k -.-\r
+l .-..\r
+m --\r
+n -.\r
+o ---\r
+p .--.\r
+q --.-\r
+r .-.\r
+s ...\r
+t -\r
+u ..-\r
+v ...-\r
+w .--\r
+x -..-\r
+y -.--\r
+z --..\r
+0 -----\r
+1 .----\r
+2 ..---\r
+3 ...--\r
+4 ....-\r
+5 .....\r
+6 -....\r
+7 --...\r
+8 ---..\r
+9 ----.
\ No newline at end of file
--- /dev/null
+#!/bin/bash
+
+# This script launches IntelliJ IDEA with the current project
+# directory. The script is designed to be run by double-clicking it in
+# the GNOME Nautilus file manager.
+
+# First, we change the current working directory to the directory of
+# the script.
+
+# "${0%/*}" gives us the path of the script itself, without the
+# script's filename.
+
+# This command basically tells the system "change the current
+# directory to the directory containing this script".
+
+cd "${0%/*}"
+
+# Then, we move up one directory level.
+# The ".." tells the system to go to the parent directory of the current directory.
+# This is done because we assume that the project directory is one level up from the script.
+cd ..
+
+# Now, we use the 'setsid' command to start a new session and run
+# IntelliJ IDEA in the background. 'setsid' is a UNIX command that
+# runs a program in a new session.
+
+# The command 'idea .' opens IntelliJ IDEA with the current directory
+# as the project directory. The '&' at the end is a UNIX command that
+# runs the process in the background. The '> /dev/null' part tells
+# the system to redirect all output (both stdout and stderr, denoted
+# by '&') that would normally go to the terminal to go to /dev/null
+# instead, which is a special file that discards all data written to
+# it.
+
+setsid idea . &>/dev/null &
+
+# The 'disown' command is a shell built-in that removes a shell job
+# from the shell's active list. Therefore, the shell will not send a
+# SIGHUP to this particular job when the shell session is terminated.
+
+# '-h' option specifies that if the shell receives a SIGHUP, it also
+# doesn't send a SIGHUP to the job.
+
+# '$!' is a shell special parameter that expands to the process ID of
+# the most recent background job.
+disown -h $!
+
+
+sleep 2
+
+# Finally, we use the 'exit' command to terminate the shell script.
+# This command tells the system to close the terminal window after
+# IntelliJ IDEA has been opened.
+exit
--- /dev/null
+#!/bin/bash
+cd "${0%/*}"; if [ "$1" != "T" ]; then gnome-terminal -e "'$0' T"; exit; fi;
+cd ..
+
+# Function to export org to html using emacs in batch mode
+export_org_to_html() {
+ local org_file=$1
+ local dir=$(dirname "$org_file")
+
+ (
+ cd "$dir" || return 1
+ local html_file="index.html"
+
+ # Remove existing index.html if it exists
+ if [ -f "$html_file" ]; then
+ rm -f "$html_file"
+ fi
+
+ # Export org to html
+ if [ -f "index.org" ]; then
+ echo "Exporting: $dir/index.org → $html_file"
+ emacs --batch -l ~/.emacs --visit=index.org --funcall=org-html-export-to-html --kill
+ if [ $? -eq 0 ]; then
+ echo "✓ Successfully exported $dir"
+ else
+ echo "✗ Failed to export $dir"
+ fi
+ else
+ echo "Warning: index.org not found in $dir"
+ fi
+ )
+}
+
+echo "🔍 Searching for index.org files recursively..."
+echo "======================================="
+
+# Find all index.org files recursively (including current directory)
+# Use -path to match exactly "*/index.org" pattern
+mapfile -t ORG_FILES < <(find . -type f -path "*/index.org" | sort)
+
+if [ ${#ORG_FILES[@]} -eq 0 ]; then
+ echo "❌ No index.org files found!"
+ echo ""
+ echo "Press ENTER to close this window."
+ read
+ exit 1
+fi
+
+echo "Found ${#ORG_FILES[@]} index.org file(s):"
+printf '%s\n' "${ORG_FILES[@]}"
+echo "======================================="
+
+# Export all found org files
+SUCCESS_COUNT=0
+FAILED_COUNT=0
+
+for org_file in "${ORG_FILES[@]}"; do
+ export_org_to_html "$org_file"
+ if [ $? -eq 0 ]; then
+ ((SUCCESS_COUNT++))
+ else
+ ((FAILED_COUNT++))
+ fi
+done
+
+echo "======================================="
+echo "📊 SUMMARY:"
+echo " ✓ Successful: $SUCCESS_COUNT"
+echo " ✗ Failed: $FAILED_COUNT"
+echo " Total: $((SUCCESS_COUNT + FAILED_COUNT))"
+echo ""
+
+# Upload project homepage to the server (same as before)
+echo "📤 Uploading to server..."
+rsync -avz --delete -e 'ssh -p 10006' ./ \
+ --include="*/" \
+ --include="*.html" \
+ --include="*.png" \
+ --include="*.bas" \
+ --include="*.dat" \
+ --include="*.webm" \
+ --include="*.jpeg" \
+ --include="*.blend" \
+ --include="*.com" \
+ --include="*.asm" \
+ --exclude="*" \
+ n0@www3.svjatoslav.eu:/mnt/big/projects/qbasicapps/
+
+if [ $? -eq 0 ]; then
+ echo "✓ Upload completed successfully!"
+else
+ echo "✗ Upload failed!"
+fi
+
+echo ""
+echo "Press ENTER to close this window."
+read
\ No newline at end of file
--- /dev/null
+' This program demonstrates a basic "Hello World" example in QuickBasic.
+' It is designed to be simple and easy to understand for novice programmers.
+
+' The following line prints a greeting message to the console.
+PRINT "Hello world!"
+
+' When you run this program, it will output the string "Hello world!" to the screen.
+' This is a traditional first step in learning any new programming language.
+
+' To execute this program, press F5 while in the QuickBasic editor environment.
--- /dev/null
+' This QuickBasic program demonstrates basic arithmetic operations
+' and the use of variables. It will perform a series of calculations
+' on a single variable and print the results after each operation.
+
+CLS ' Clears the screen to provide a clean output area
+
+' Initialize a variable with the value 3
+DIM initialValue AS INTEGER
+initialValue = 3
+
+' Print the current value of initialValue
+PRINT "The initial value is: "; initialValue
+
+' Perform multiplication and assign the result back to initialValue
+initialValue = initialValue * 2
+
+' Print the new value after multiplication
+PRINT "After doubling, the value is: "; initialValue
+
+' Perform subtraction and decrease initialValue by 1
+initialValue = initialValue - 1
+
+' Print the final value after subtraction
+PRINT "After decrementing by 1, the value is: "; initialValue
--- /dev/null
+' This program demonstrates basic arithmetic operations in QuickBasic
+
+CLS ' Clears the screen to provide a clean output area
+
+' Declare a variable 'a' and assign it the value of 7
+DIM a AS INTEGER
+a = 7
+
+' Print the current value of 'a' to the console
+PRINT "The value contained in variable 'a' is: "; a
+
+' Perform a series of arithmetic operations on the value of 'a'
+' and print the result
+PRINT "Performing some calculations with 'a':";
+PRINT (a + 2.1234) / 3 * 4 - 6
+
+' Explanation of the calculation:
+' 1. Add 2.1234 to 'a'
+' 2. Divide the result by 3
+' 3. Multiply the new result by 4
+' 4. Subtract 6 from the final result
--- /dev/null
+' This program demonstrates how to use semicolon and comma as separators\r
+' in PRINT statements within Microsoft QuickBasic.\r
+\r
+CLS ' Clears the screen before starting the program\r
+\r
+' Semicolon Separator Example\r
+\r
+' The semicolon is used to print multiple items on the same line, without\r
+' advancing to a new line after each item. It is useful for formatting output\r
+' in a single line of text.\r
+\r
+PRINT "Semicolon separator:"\r
+PRINT 12; 314; 122; 1; 43 ' Prints numbers separated by semicolons on the same line\r
+PRINT 312; 4; 1; 3111; 3 ' Continues printing more numbers on the next line\r
+PRINT 3; 2344; 12231; 1; 12333 ' Final set of numbers printed on the last line\r
+\r
+' Print an empty line for better readability\r
+PRINT ' This statement prints an empty line to separate different sections\r
+\r
+' Comma Separator Example\r
+\r
+' The comma is used as a separator in PRINT statements to print multiple items,\r
+' each followed by a space and advancing to the next tab column (default is 14\r
+' characters apart). If there are more items than columns, it will start\r
+' a new line.\r
+\r
+PRINT "Comma separator:"\r
+PRINT 12, 314, 122, 1, 43 ' Prints numbers separated by commas, with spacing\r
+PRINT 312, 4, 1, 3111, 3 ' Numbers are printed in tabular form\r
+PRINT 3, 2344, 12231, 1, 12333 ' Continues the tabular output\r
+\r
+' End of program\r
+END ' This statement marks the end of the QuickBasic program\r
+\r
--- /dev/null
+' This program prompts the user to enter a number and then prints that number back to the screen.
+' It demonstrates basic input/output operations in QuickBasic.
+
+DEFINT A-Z ' Declare all variables as integers for simplicity
+
+' Declare a variable to store the user's input
+DIM num AS INTEGER
+
+' Use the INPUT statement to prompt the user and read their input
+PRINT "Please enter a number:";
+INPUT num
+
+' Print a message to the screen along with the entered number
+PRINT "You entered: "; num
+
+' End of program
+END
--- /dev/null
+REM **** Guess a Number Game ****
+
+DEFINT A-Z ' Define all variables as integers for performance and clarity
+
+' Main game loop
+DO
+ ' Prompt the user to enter a number
+ INPUT "Enter a number between 1 and 10: "; guess
+
+ ' Check if the user guessed the correct number
+ IF guess = 5 THEN
+ ' If the guess is correct, congratulate the user and exit the loop
+ PRINT "Correct!!! You've guessed the secret number."
+ EXIT DO
+ ELSEIF guess < 5 THEN
+ ' If the guess is too low, prompt the user to try a higher number
+ PRINT "Try a bigger number."
+ ELSEIF guess > 5 THEN
+ ' If the guess is too high, prompt the user to try a lower number
+ PRINT "Try a smaller number."
+ END IF
+LOOP
+
+' End of the program
+PRINT "Thank you for playing! Goodbye."
+END
--- /dev/null
+CLS ' Clear the screen
+
+' This program demonstrates a simple counting loop in QuickBasic.
+' It will print the current value of 'a' and increment it by 1 each time.
+' The loop continues until 'a' is no longer less than 10.
+
+DIM a AS INTEGER ' Declare variable 'a' as an integer
+
+' Initialize the counter variable 'a' to start at 1
+a = 1
+
+' Start of the counting loop
+DO WHILE a < 10
+ ' Print the current value of 'a' with a label
+ PRINT "current:"; a
+
+ ' Increment 'a' by 1
+ a = a + 1
+LOOP
+
+' The program will end after the loop finishes
+END
--- /dev/null
+' This program demonstrates a simple FOR loop in Microsoft QuickBasic
+
+CLS ' Clears the screen, preparing it for output
+
+' We are about to use a FOR loop to print numbers from 1 to 10
+FOR i = 1 TO 10 ' Initialize a counter variable 'i' starting at 1
+ ' For each iteration of the loop, print the current value of 'i'
+ PRINT "current: "; i ' Outputs the message with the current number
+NEXT i ' Increment 'i' by 1 and repeat the loop until 'i' is no longer less than or equal to 10
+
+' The program has now finished executing and will end
+END ' This marks the end of the QuickBasic program
--- /dev/null
+' This program demonstrates how to use a FOR loop and the SOUND statement
+' in QuickBasic. It plays a series of tones at increasing frequencies
+' from 100 Hz to 1000 Hz, in steps of 50 Hz, with each tone lasting for
+' one duration unit as defined by the SOUND statement.
+
+CLS ' Clears the screen before starting the program
+
+' Initialize the frequency variable to the starting value
+LET frequency = 100
+
+' Loop from the initial frequency (100 Hz) to the maximum frequency (1000 Hz),
+' increasing by 50 Hz on each iteration
+FOR frequency = 100 TO 1000 STEP 50
+ ' Print the current frequency value to the console
+ PRINT "Current Frequency:"; frequency; " Hz"
+
+ ' Play a sound at the specified frequency and duration
+ ' The SOUND statement takes two arguments: frequency and duration
+ SOUND frequency, 1 ' The duration is set to 1 (shortest possible sound)
+NEXT frequency
+
+' End of program execution
+END
--- /dev/null
+REM This program demonstrates how to generate random numbers\r
+REM and use them to create sound effects in QuickBasic.\r
+\r
+CLS ' Clear the screen before starting the program\r
+\r
+' Define constants for the range of random numbers\r
+FOR i = 1 TO 20 ' Loop 20 times to generate and play 20 random sounds\r
+ ' Generate a random floating-point number between LOWER_BOUND and UPPER_BOUND\r
+ n = RND * 1000\r
+ ' Print the generated random number to the screen\r
+ PRINT "Random number: "; n\r
+\r
+ ' Play a sound with a frequency based on the random number\r
+ ' The QuickBasic SOUND statement takes two arguments: frequency and duration\r
+ ' We add 40 to the random number to shift the frequency range\r
+ ' so that it is more audible\r
+ SOUND n + 40, 1 ' Play the sound for a short duration (1/89th of a second)\r
+\r
+NEXT i\r
+\r
+END ' End the program\r
+\r
--- /dev/null
+' This example program demonstrates how to use the WIDTH and COLOR\r
+' statements in QuickBasic to change the text font size and text colors.\r
+\r
+' Set the text window to a smaller font size suitable for displaying\r
+' 50 lines of text within an 80-column width.\r
+WIDTH 80, 50\r
+\r
+' Define constants for the number of colors available in standard\r
+' QuickBasic color palette.\r
+CONST NumColors = 32\r
+\r
+' Loop through all possible colors (0 to 31) and display a message\r
+' with each color to illustrate the different text color options.\r
+FOR colorIndex = 0 TO NumColors - 1\r
+ ' Set the current text color using the COLOR statement.\r
+ ' Colors range from 0 to 15 are solid, while colors 16 to 31\r
+ ' will blink slowly or quickly depending on the terminal.\r
+ COLOR colorIndex\r
+\r
+ ' Print a message indicating which color number is currently being used.\r
+ ' Note that color numbers 16 and above will produce blinking text.\r
+ PRINT "This is text color number "; colorIndex; "."\r
+\r
+NEXT colorIndex\r
+\r
--- /dev/null
+' This program demonstrates how to use the COLOR statement and LOCATE function
+' in Microsoft QuickBasic to change the text color and cursor position
+' on the console screen.
+
+CLS ' Clears the screen before starting
+
+' Set the text color to yellow (color code 14) and position the cursor
+' at row 1, column 50. Then print a message at that location.
+COLOR 14
+LOCATE 1, 50 ' Sets the cursor location to <row=1, column=50>
+PRINT "Yellow text at 1, 50"
+
+' Change the text color to pink (color code 12) and move the cursor
+' to row 6, column 5. Print a message with the new color and position.
+COLOR 12
+LOCATE 6, 5 ' Sets the cursor location to <row=6, column=5>
+PRINT "Pink text at 6, 5"
+
+' Update the text color to green (color code 10) and set the cursor
+' to row 20, column 40. Display a message at this new location.
+COLOR 10
+LOCATE 20, 40 ' Sets the cursor location to <row=20, column=40>
+PRINT "Green text at 20, 40"
+
+' The program finishes execution here. Users can add more statements
+' below this line to experiment with different colors and positions.
+END ' End of the program
--- /dev/null
+' This program demonstrates the use of FOR loops, color manipulation,
+' and string output in QuickBasic. It also shows how to prevent the
+' cursor from moving to a new line after printing a string.
+
+CLS ' Clears the screen before starting the program
+
+' The first loop demonstrates changing text colors using the COLOR statement
+' inside a FOR loop, which iterates from 1 to 15 (the number of available
+' color attributes in QuickBasic).
+FOR ColorIndex = 1 TO 15
+ COLOR ColorIndex ' Set the current text color to the loop index
+ PRINT "This is a test" ' Print the string with the new color
+NEXT ColorIndex
+
+PRINT ' Print a blank line for better readability
+
+' The second loop does the same as the first one, but it uses a semicolon
+' at the end of the PRINT statement to prevent the cursor from moving
+' to the start of a new line after each string output. This results in
+' all strings being printed on the same line.
+FOR ColorIndex = 1 TO 15
+ COLOR ColorIndex ' Change the text color for each iteration
+ PRINT "This is a test"; ' Print the string and keep the cursor on the same line
+NEXT ColorIndex
--- /dev/null
+' This example QuickBasic program demonstrates the difference between
+' normal division and integer division with rounding.
+
+CLS ' Clears the screen to provide a clean output area
+
+' Perform normal division which results in a floating-point number
+' and print the result
+PRINT "Normal division (70 / 4):"; 70 / 4
+
+' Explain the use of backslash (\) for integer division with rounding
+' Perform integer division with rounding and print the result
+PRINT "Integer division with rounding (70 \ 4):"; 70 \ 4
+
+' Provide a brief conclusion to summarize what was demonstrated
+PRINT
+PRINT "In QuickBasic, '/' performs normal division, while '\' does integer division"
+PRINT "and rounds the result to the nearest whole number."
+
+END ' End of program
--- /dev/null
+' This program demonstrates the use of nested FOR loops in QuickBasic\r
+' to draw a simple pattern on the screen.\r
+\r
+CLS ' Clears the screen and prepares for output\r
+\r
+' Outer loop will run 15 times, representing rows\r
+FOR row = 1 TO 15\r
+\r
+ ' Inner loop will run 60 times, representing columns within each row\r
+ FOR column = 1 TO 60\r
+ PRINT "#"; ' Print a '#' character followed by no space to create a continuous line\r
+ NEXT column\r
+\r
+ ' After completing one row, print a newline character to move to the next line\r
+ PRINT\r
+\r
+NEXT row\r
+\r
--- /dev/null
+' QuickBasic example program to demonstrate the use of nested loops
+' and how to control the flow of a loop using the STEP keyword.
+
+CLS ' Clears the screen before starting the program
+
+' This outer loop will iterate from 1 to 10
+FOR b = 1 TO 10
+ ' The inner loop will print "A" b times, where b is the current
+ ' value of the outer loop iterator
+ FOR a = 1 TO b
+ PRINT "A"; ' Print "A" followed by a semicolon to prevent newline
+ NEXT a
+
+ ' After each inner loop iteration, print a newline to start the next line
+ PRINT
+NEXT b
+
+' Print a blank line to separate the two parts of the demonstration
+PRINT
+
+' This outer loop will iterate from 60 to 0, decrementing by 8 each time
+FOR b = 60 TO 0 STEP -8
+ ' The inner loop will print "B" b times, where b is the current
+ ' value of the outer loop iterator
+ FOR a = 1 TO b
+ PRINT "B"; ' Print "B" followed by a semicolon to prevent newline
+ NEXT a
+
+ ' After each inner loop iteration, print a newline to start the next line
+ PRINT
+NEXT b
+
+' End of the program
+END
--- /dev/null
+' This example QuickBasic program demonstrates how to use the built-in
+' timer, as well as how to display the current system time and date.
+' It also shows a simple loop structure and the use of the CLS statement
+' to clear the screen.
+
+' To stop the program, press CTRL + PAUSE/BREAK.
+
+DO
+ ' Clear the screen to provide a clean display for each iteration.
+ CLS
+
+ ' Retrieve and print the current value of the system timer.
+ ' The TIMER function returns the number of seconds that have
+ ' elapsed since midnight, not counting leap seconds.
+ PRINT "System Timer: "; TIMER; " seconds since midnight."
+
+ ' Retrieve and print the current system time using TIME$.
+ ' TIME$ returns a string in the format "HH:MM:SS".
+ PRINT "Current System Time: "; TIME$; "."
+
+ ' Retrieve and print the current system date using DATE$.
+ ' DATE$ returns a string in the format "M/D/YYYY" or "DD/MM/YYYY"
+ ' depending on regional settings.
+ PRINT "Current System Date: "; DATE$; "."
+
+ ' Pause for a moment to allow the user to see the output before
+ ' it is cleared again in the next iteration of the loop.
+ ' The Sleep statement requires including the QB.BI library.
+ SLEEP 1
+
+LOOP
--- /dev/null
+' This example program demonstrates the use of the RND function
+' to generate random numbers in Microsoft QuickBasic.
+
+' Clear the screen before starting the program
+CLS
+
+' The first loop will print ten random numbers. However, these
+' numbers may not seem truly random because the random number
+' generator needs to be seeded with a varying value.
+
+PRINT "First group of 'random' numbers without seeding:"
+FOR b = 1 TO 10
+ PRINT RND
+NEXT b
+
+' Print an empty line for better readability between the two groups
+PRINT
+
+' Seed the random number generator using the TIMER function, which
+' returns the number of seconds since midnight. This ensures that
+' subsequent calls to RND will yield different sequences of numbers
+' each time the program is run after being restarted.
+RANDOMIZE TIMER
+PRINT "Second group of truly random numbers with seeding:"
+
+' Now, print another ten random numbers after seeding the generator
+FOR b = 1 TO 10
+ PRINT RND
+NEXT b
+
+' End of program
--- /dev/null
+' This program demonstrates how to use the QuickBasic functions RND (random number generator),\r
+' COLOR (sets text and background color), LOCATE (positions the cursor on the screen), PRINT (displays text),\r
+' SOUND (generates a tone through the PC speaker)\r
+\r
+CLS ' Clears the screen before starting the program\r
+\r
+' Generate random coordinates (x, y) for text placement on the screen\r
+' and a random color (c) for the text.\r
+' The screen has 80 columns (0-79) and 25 lines (0-24), but we start counting from 1.\r
+\r
+\r
+' INKEY$ returns a string containing any keystroke; if no key is pressed, it returns an empty string\r
+DO WHILE INKEY$ = ""\r
+ x = INT(RND * 80) + 1 ' Random column, ensuring it is within the screen width\r
+ y = INT(RND * 25) + 1 ' Random line, ensuring it is within the screen height\r
+ c = INT(RND * 16) ' Random color index (0-15), where 0 is black and 15 is white\r
+\r
+ ' Set the text color to the randomly chosen color\r
+ COLOR c\r
+\r
+ ' Position the cursor at the random coordinates\r
+ LOCATE y, x\r
+\r
+ ' Print an "x" character at the current cursor position\r
+ PRINT "x"; ' The semicolon prevents advancing to the next line\r
+\r
+ ' Generate a sound with a frequency based on the x coordinate and a duration of 0.1 seconds\r
+ SOUND x * 100 + 100, 1\r
+\r
+LOOP\r
+\r
--- /dev/null
+CLS
+
+' This program demonstrates how to use the SOUND statement in QuickBasic
+' to play tones with varying frequency and duration.
+
+' Play a sequence of tones with increasing frequency
+' Each tone has a fixed duration of 2 time units
+PRINT "Playing tones with increasing frequency:"
+SOUND 1000, 2 ' Play a tone at 1000 Hz for 2 time units
+SOUND 2000, 2 ' Play a tone at 2000 Hz for 2 time units
+SOUND 3000, 2 ' Play a tone at 3000 Hz for 2 time units
+
+' Wait for 10 time units to create a pause
+PRINT "Pausing for 10 time units..."
+SOUND 0, 10 ' Pause for 10 time units (silence)
+
+' Play a sequence of tones with a fixed frequency
+' Each tone has an increasing duration
+PRINT "Playing tones with fixed frequency and increasing length:"
+SOUND 1000, 1 ' Play a tone at 1000 Hz for 1 time unit
+SOUND 0, 10 ' Pause for 10 time units (silence)
+
+SOUND 1000, 2 ' Play a tone at 1000 Hz for 2 time units
+SOUND 0, 10 ' Pause for 10 time units (silence)
+
+SOUND 1000, 4 ' Play a tone at 1000 Hz for 4 time units
+SOUND 0, 10 ' Pause for 10 time units (silence)
+
+SOUND 1000, 8 ' Play a tone at 1000 Hz for 8 time units
+SOUND 0, 10 ' Pause for 10 time units (silence)
+
+' Notes:
+' - The SOUND statement takes two arguments: frequency and duration.
+' - Frequency is specified in Hertz (Hz), and duration is specified in time units.
+' - A frequency of 0 results in silence, which can be used to create pauses.
+' - Time units are not precisely defined by QuickBasic and may vary depending
+' on the hardware and system configuration. They provide a relative measure
+' for timing musical tones.
--- /dev/null
+' Simple Sound Sweep Program\r
+\r
+' Start label for infinite loop\r
+beginLoop:\r
+\r
+' Increase speed on each pass - this controls how quickly frequencies change\r
+speed = speed + 1\r
+\r
+' Show current speed multiplier to user\r
+PRINT speed; "x"\r
+\r
+' Forward frequency sweep from 100Hz to 1000Hz\r
+FOR currentFrequency = 100 TO 1000 STEP speed\r
+ ' Create sound with current frequency for 0.1 seconds\r
+ ' SOUND format: SOUND frequency, duration\r
+ SOUND currentFrequency, .1\r
+NEXT currentFrequency\r
+\r
+' Reverse frequency sweep from 1000Hz to 100Hz\r
+FOR currentFrequency = 1000 TO 100 STEP -speed\r
+ ' Create sound with current frequency for 0.1 seconds\r
+ SOUND currentFrequency, .1\r
+NEXT currentFrequency\r
+\r
+' Jump back to beginning for continuous effect\r
+GOTO beginLoop\r
--- /dev/null
+' This program demonstrates basic user input and string manipulation in QuickBasic.
+' It greets the user by name and asks how they are doing, using colors to enhance the output.
+
+CLS ' Clears the screen to provide a clean start for the program.
+
+' Prompt the user for their name and store it in a variable called userName$.
+INPUT "Hi, what is your name: ", userName$
+
+' Set the text color to a bright green (color code 10) for a pleasant visual effect.
+COLOR 10
+
+' Greet the user by printing "Hello" followed by their name and an exclamation mark.
+PRINT "Hello " + userName$ + "!"
+
+' Ask the user how they are doing by appending their name to the question.
+PRINT userName$ + ", how are you?"
--- /dev/null
+CLS\r
+\r
+' Initialize the string variable with "-two-"\r
+stringValue$ = "-two-"\r
+PRINT stringValue$\r
+\r
+' Append "three" to the existing string\r
+stringValue$ = stringValue$ + "three"\r
+PRINT stringValue$\r
+\r
+' Prepend "one" to the string to form a complete sequence\r
+stringValue$ = "one" + stringValue$\r
+PRINT stringValue$\r
--- /dev/null
+CLS
+
+' This program creates a simple text-based box in the console window.
+' The user specifies the horizontal and vertical size of the box within
+' certain constraints to ensure it fits on the screen.
+
+' Prompt the user for the horizontal size of the box (between 2 and 79)
+INPUT "Enter the Horizontal Size of the Box (2 to 79): ", hs
+
+' Validate the horizontal size input
+WHILE hs < 2 OR hs > 79
+ PRINT "Invalid input. Please enter a number between 2 and 79."
+ INPUT "Enter the Horizontal Size of the Box (2 to 79): ", hs
+WEND
+
+' Prompt the user for the vertical size of the box (between 2 and 23)
+INPUT "Enter the Vertical Size of the Box (2 to 23): ", vs
+
+' Validate the vertical size input
+WHILE vs < 2 OR vs > 23
+ PRINT "Invalid input. Please enter a number between 2 and 23."
+ INPUT "Enter the Vertical Size of the Box (2 to 23): ", vs
+WEND
+
+' Draw the top line of the box
+FOR i = 1 TO hs
+ PRINT "#";
+NEXT i
+PRINT
+
+' Draw the middle section of the box
+FOR y = 1 TO vs - 2
+ ' Print the left side of the box
+ PRINT "#";
+
+ ' Print the interior of the box
+ FOR i = 1 TO hs - 2
+ PRINT ".";
+ NEXT i
+
+ ' Print the right side of the box
+ PRINT "#"
+NEXT y
+
+' Draw the bottom line of the box
+FOR i = 1 TO hs
+ PRINT "#";
+NEXT i
+PRINT
+
+' The program has finished drawing the box and now ends
+END
--- /dev/null
+' several commans may be at the single line, when separated by colon.\r
+\r
+1 a = a + 1: PRINT a; "x 7 ="; a * 7: IF a < 10 THEN GOTO 1\r
+\r
+\r
--- /dev/null
+REM This program demonstrates basic input/output and conditional logic in QuickBasic.
+REM It prompts the user to enter a number and then evaluates that number
+REM with respect to the value 5 using various comparison operators.
+
+PRINT "Please enter a number:"
+INPUT n
+
+REM Check if the number is less than 5
+IF n < 5 THEN
+ PRINT "The number you entered is smaller than 5."
+END IF
+
+REM Check if the number is greater than 5
+IF n > 5 THEN
+ PRINT "The number you entered is greater than 5."
+END IF
+
+REM Check if the number is exactly equal to 5
+IF n = 5 THEN
+ PRINT "The number you entered is equal to 5."
+END IF
+
+REM Check if the number is less than or equal to 5
+IF n <= 5 THEN
+ PRINT "The number you entered is 5, or less."
+END IF
+
+REM Check if the number is greater than or equal to 5
+IF n >= 5 THEN
+ PRINT "The number you entered is 5, or greater."
+END IF
+
+REM Check if the number is not equal to 5
+IF n <> 5 THEN
+ PRINT "The number you entered is not 5."
+END IF
--- /dev/null
+CLS
+
+' This program simulates a login prompt for a nuclear rocket control system.
+' It asks the user to enter a password and checks if the entered password is correct.
+' If the password is incorrect, it prompts the user again.
+
+' Define a constant for the correct password for better security practices
+CONST CorrectPassword = "jerry"
+
+' Function to display the welcome message
+SUB DisplayWelcomeMessage
+ LOCATE 1, 1
+ COLOR 14
+ PRINT " ========================================"
+ PRINT " Welcome to nuclear rocket control system"
+ PRINT " ========================================"
+END SUB
+
+' Function to display the rocket artwork
+SUB DisplayRocketArt
+ COLOR 10, 1
+ PRINT "..............................................................."
+ PRINT ".....MMMMMM................MM...MMMMMMM.MMMMMM.MMM..MMMMMMM..MM"
+ PRINT "MMMMMMMMMMMMMMM...MM.M....MMMMM.MM.MMMMMMMMMMMMMMMMMMMMMMM.MM.."
+ PRINT ".MMMMMMMMMMM.M.....MMM...MM.....MMMMMMMMMMMMMMMMMMMMMM.M......."
+ PRINT "..MMMMMMMMMMMM..............MMMMMMMMMMMMMMMMMMMMMMMMMM..M ....."
+ PRINT "....MMMMMMMM...............MMMM..MMMMM.MMMMMMMMMMMMM.MM........"
+ PRINT ".....MMMMMMM.............MMMMMMMM..MMM..MMMMMM.MMMMM.M........."
+ PRINT "........MM...............MMMMMMMMMM.M.....MM...........M......."
+ PRINT "......MMMMMM................MMMMMMM....................M......."
+ PRINT ".....MMMMMMMM.................MMMMMM....................MMM...."
+ PRINT "......MMMMMMM.................MMMMM...................MMMMMM..."
+ PRINT "........MMMMMM..................MM....................MMMMMMM.."
+ PRINT "..........MMMMM ...........................................MM.."
+END SUB
+
+' Function to play a simple tune
+SUB PlayTune
+ FOR a = 9 TO 23
+ SOUND 1.5 ^ a, 3
+ NEXT a
+END SUB
+
+' Main program execution starts here
+DO
+ ' Clear the screen and prompt the user for the password
+ CLS
+ COLOR 7
+ PRINT "Enter password: ";
+
+ ' Temporarily set text color to black to hide the password input
+ COLOR 0
+ INPUT "", UserPassword$
+
+ ' Restore original text color
+ COLOR 7
+LOOP UNTIL UserPassword$ = CorrectPassword
+
+' Clear the screen for the welcome message
+CLS
+
+' Call the function to display the welcome message
+DisplayWelcomeMessage
+
+' Call the function to display the rocket artwork
+DisplayRocketArt
+
+' Locate and display our location with a special color
+LOCATE 7, 34
+COLOR 12 + 16
+PRINT "*"
+
+' Play the simple tune using the sound command
+PlayTune
+
+' Restore default text color
+COLOR 7, 0
+
+' End of the program
+END
--- /dev/null
+' This program demonstrates the use of string manipulation functions
+' in Microsoft QuickBasic. It shows how to extract substrings from a
+' given string using the LEFT$ and RIGHT$ functions.
+
+DEFSTR A-Z ' Define all variables as strings to avoid type mismatches
+
+' Initialize a string variable with the value "software"
+SoftwareName$ = "software"
+
+' Print the full name of the software
+PRINT "Full software name: "; SoftwareName$
+
+' Extract and print the first four characters from the left of the string
+LEFTPart$ = LEFT$(SoftwareName$, 4) ' Get the leftmost substring
+PRINT "Left part (first 4 characters): "; LEFTPart$
+
+' Extract and print the last four characters from the right of the string
+RIGHTPart$ = RIGHT$(SoftwareName$, 4) ' Get the rightmost substring
+PRINT "Right part (last 4 characters): "; RIGHTPart$
+
+END ' End of program
--- /dev/null
+CLS\r
+\r
+' This program demonstrates basic user input and string manipulation in QuickBasic.\r
+\r
+' Prompt the user to enter some text and store it in a variable called 'userInput$'.\r
+INPUT "Enter some text: ", userInput$\r
+\r
+' Print the text that the user entered in three different ways:\r
+' 1. Concatenating the prompt with the entered text using the '+' operator.\r
+' 2. Using a comma to separate the prompt from the entered text, which is more efficient.\r
+' 3. Using a colon to print on the same line without a space between the prompt and the input.\r
+PRINT "You entered: " + userInput$\r
+\r
+' Calculate the length of the entered text using the LEN function.\r
+' Then, print out the length, formatting it as a sentence.\r
+PRINT "Its length is" + STR$(LEN(userInput$)) + " characters."\r
+\r
+' Use a FOR loop to iterate from 1 to the length of the user input.\r
+' In each iteration, extract a substring from the left using the LEFT$ function\r
+' and print it to demonstrate string extraction from the beginning.\r
+FOR index = 1 TO LEN(userInput$)\r
+ PRINT "Leftmost " + STR$(index) + " character(s): " + LEFT$(userInput$, index)\r
+NEXT index\r
+\r
+' Print a blank line for better readability of the output.\r
+PRINT\r
+\r
+' Similar to the previous loop, but now we use the RIGHT$ function to extract\r
+' substrings from the right end of the user input, demonstrating string extraction\r
+' from the end of the string.\r
+FOR index = 1 TO LEN(userInput$)\r
+ PRINT "Rightmost " + STR$(index) + " character(s): " + RIGHT$(userInput$, index)\r
+NEXT index\r
+\r
+' End of the program.\r
+END\r
+\r
--- /dev/null
+' Simple Character Extractor Program\r
+' This program takes user input and prints each character individually\r
+\r
+CLS\r
+\r
+' Get user input\r
+INPUT "Enter some text:", userInput$\r
+\r
+' Process each character in the input string\r
+FOR charPosition = 1 TO LEN(userInput$)\r
+ ' Get the left portion of the string up to current position\r
+ leftPortion$ = LEFT$(userInput$, charPosition)\r
+\r
+ ' Extract the current character (rightmost character of left portion)\r
+ currentChar$ = RIGHT$(leftPortion$, 1)\r
+\r
+ ' Print the current character with label\r
+ PRINT "letter:"; currentChar$\r
+NEXT charPosition\r
--- /dev/null
+' This program demonstrates the basics of animation and control flow in QuickBasic.
+' It shows a simple text bouncing up and down on the screen, simulating a "jumping" effect.
+
+' Declare variables with descriptive names to hold the position and movement direction
+DIM yPosition AS INTEGER ' Current vertical position of the text
+DIM ySpeed AS INTEGER ' Vertical speed (or direction) of the text
+
+' Initialize the starting position and speed
+yPosition = 10
+ySpeed = 1
+
+' Main animation loop
+DO
+ ' Clear the screen before drawing the next frame
+ CLS
+
+ ' Update the vertical position based on the current speed
+ yPosition = yPosition + ySpeed
+
+ ' Check if the text has hit the top boundary and change direction if it has
+ IF yPosition > 20 THEN
+ ySpeed = -1
+ ENDIF
+
+ ' Check if the text has hit the bottom boundary and change direction if it has
+ IF yPosition < 2 THEN
+ ySpeed = 1
+ ENDIF
+
+ ' Set the cursor position to the current vertical position
+ LOCATE yPosition
+
+ ' Print the "jumping" text at the new position
+ PRINT "This is jumping text";
+
+ ' Play a sound with a frequency that varies based on the vertical position
+ ' The frequency is calculated to give an audible effect as the text jumps
+ SOUND yPosition * 200 + 100, 1
+
+ ' Pause briefly before drawing the next frame (adjust this value for faster or slower animation)
+ DELAY 0.1
+LOOP
+
+' Note: The program will run indefinitely due to the DO LOOP structure.
+' To stop the program, you can press Ctrl+Break on most systems.
--- /dev/null
+' This program demonstrates basic animation and boundary checking in QuickBasic.\r
+' It simulates a simple ball bouncing around the screen.\r
+\r
+CLS ' Clear the screen before starting the animation\r
+\r
+' Initialize variables representing the ball's position and velocity\r
+DIM x AS INTEGER ' Ball's X coordinate\r
+DIM y AS INTEGER ' Ball's Y coordinate\r
+DIM xs AS INTEGER ' Ball's speed in the X direction\r
+DIM ys AS INTEGER ' Ball's speed in the Y direction\r
+\r
+x = 12 ' Initial X position of the ball\r
+y = 7 ' Initial Y position of the ball\r
+xs = 1 ' Initial velocity in the X direction (rightward)\r
+ys = 1 ' Initial velocity in the Y direction (downward)\r
+\r
+' Main animation loop\r
+DO\r
+ ' Erase the ball at its current position by printing a space\r
+ LOCATE y, x: PRINT " ";\r
+\r
+ ' Update the ball's position based on its velocities\r
+ x = x + xs\r
+ y = y + ys\r
+\r
+ ' Draw the ball at its new position\r
+ LOCATE y, x: PRINT "O";\r
+\r
+ ' Check if the ball hits the right or left boundaries and reverse X velocity\r
+ IF x >= 79 THEN\r
+ xs = -1\r
+ SOUND 1000, 1 ' Play a sound when hitting the boundary\r
+ END IF\r
+ IF x <= 1 THEN\r
+ xs = 1\r
+ SOUND 1000, 1 ' Play a sound when hitting the boundary\r
+ END IF\r
+\r
+ ' Check if the ball hits the bottom or top boundaries and reverse Y velocity\r
+ IF y >= 22 THEN\r
+ ys = -1\r
+ SOUND 1000, 1 ' Play a sound when hitting the boundary\r
+ END IF\r
+ IF y <= 1 THEN\r
+ ys = 1\r
+ SOUND 1000, 1 ' Play a sound when hitting the boundary\r
+ END IF\r
+\r
+ ' Pause briefly to control the speed of the animation\r
+ SOUND 0, 1\r
+LOOP\r
+\r
+' The program will continue running indefinitely, creating an animated bouncing ball effect\r
+\r
--- /dev/null
+' This program demonstrates how to use the SOUND statement in QuickBasic
+' to produce different tones when pressing keys "0" through "9".
+' It also shows how to exit the program by pressing the Escape key.
+
+CLS
+PRINT "Press keys '0'-'9' for different sounds."
+PRINT "Press Esc to exit the program."
+
+' Start an infinite loop to continuously check for user input
+DO
+ ' Read a single character from the keyboard
+ a$ = INPUT$(1)
+
+ ' Play a sound corresponding to the key pressed
+ SELECT CASE a$
+ CASE "0"
+ ' Generate a low-pitched tone
+ SOUND 1900, 2
+ CASE "1"
+ ' Generate a slightly higher pitched tone
+ SOUND 1000, 2
+ CASE "2"
+ ' Generate a tone with a frequency of 1100 Hz
+ SOUND 1100, 2
+ CASE "3"
+ ' Generate a tone with a frequency of 1200 Hz
+ SOUND 1200, 2
+ CASE "4"
+ ' Generate a tone with a frequency of 1300 Hz
+ SOUND 1300, 2
+ CASE "5"
+ ' Generate a tone with a frequency of 1400 Hz
+ SOUND 1400, 2
+ CASE "6"
+ ' Generate a tone with a frequency of 1500 Hz
+ SOUND 1500, 2
+ CASE "7"
+ ' Generate a high-pitched tone
+ SOUND 1600, 2
+ CASE "8"
+ ' Generate a very high-pitched tone
+ SOUND 1700, 2
+ CASE "9"
+ ' Generate the highest pitched tone available
+ SOUND 1800, 2
+ CASE CHR$(27)
+ ' Check if the Escape key is pressed to exit the program
+ SYSTEM
+ CASE ELSE
+ ' If any other key is pressed, do nothing
+ END SELECT
+
+ ' Loop indefinitely until the user decides to exit
+LOOP
--- /dev/null
+' This program demonstrates how to use a FOR loop and the CHR$ function
+' in QuickBasic to print out characters from the ASCII table.
+
+CLS ' Clears the screen before printing
+
+' The FOR loop iterates over ASCII values starting from 32 (space character)
+' up to 255, which is beyond the standard ASCII range but includes extended
+' ASCII characters in QuickBasic.
+FOR a = 32 TO 255
+ ' CHR$ function converts an ASCII value to its corresponding character
+ PRINT " " + CHR$(a); ' Prints each character with a leading space for readability
+NEXT a
+
+' Print two new lines to separate the ASCII table from the greeting message
+PRINT
+PRINT
+
+' Greet the user in a friendly manner
+' The CHR$(1) represents the Start of Header (SOH) control character, which is
+' typically not visible and may be interpreted differently depending on the
+' environment. It is used here for demonstration purposes to show how
+' non-printable characters can be included in strings.
+PRINT "Hi there! " + CHR$(1)
+
+' End of the program
+END
--- /dev/null
+' This program demonstrates how to capture and process keyboard input in QuickBASIC.
+' It listens for a key press, then prints out the character and its ASCII code.
+' Special keys like Escape, Enter, Backspace, Tabulator, and Space are given custom names.
+
+CLS ' Clears the screen before starting the program
+PRINT "Press any key..." ' Prompts the user to press a key
+
+' Main loop starts here
+DO
+ ' Capture a single character of input from the user
+ a$ = INPUT$(1)
+
+ ' Print the pressed key, if it is a printable character (ASCII code > 32)
+ PRINT "Pressed key was: ";
+ IF ASC(a$) > 32 THEN
+ PRINT a$
+ END IF
+
+ ' Check for special keys and print their names
+ SELECT CASE ASC(a$)
+ CASE 27 ' ASCII code for Escape key
+ PRINT "Escape"
+ CASE 13 ' ASCII code for Enter key
+ PRINT "Enter"
+ CASE 8 ' ASCII code for Backspace key
+ PRINT "Backspace"
+ CASE 9 ' ASCII code for Tabulator key
+ PRINT "Tabulator"
+ CASE 32 ' ASCII code for Space key
+ PRINT "Space"
+ CASE ELSE
+ ' If the key is not special, print its ASCII character
+ IF ASC(a$) > 32 THEN
+ PRINT a$
+ END IF
+ END SELECT
+
+ ' Print the ASCII code of the pressed key
+ PRINT "ASCII code is: "; ASC(a$)
+LOOP ' Continue listening for more key presses
--- /dev/null
+' This program demonstrates how to handle keyboard input in QuickBasic
+' and move a character around the screen using the numeric keypad.
+
+CLS
+
+' Inform the user about the controls and how to exit the program
+PRINT "Use keys 4, 8, 6, 2 for movement, make sure the NumLock is on"
+PRINT "ESC to exit"
+
+' Clear a line for better visibility
+PRINT " "
+
+' Wait for the user to press any key to start
+PRINT "Press any key to continue..."
+a$ = INPUT$(1)
+
+' Set the text color to bright yellow
+COLOR 14
+
+' Initialize the starting position of the character
+x = 40
+y = 10
+
+' Main loop for handling input and drawing the character
+DO
+ CLS ' Clear the screen before redrawing
+
+ ' Set the cursor position to the current character coordinates
+ LOCATE y, x
+
+ ' Print the character at the current position
+ PRINT CHR$(2); ' The semicolon prevents moving to the next line
+
+ ' Read a single character of input without waiting
+ a$ = INPUT$(1)
+
+ ' Check for movement inputs and update the character's position
+ SELECT CASE a$
+ CASE "4" ' Left arrow
+ x = x - 1
+ CASE "6" ' Right arrow
+ x = x + 1
+ CASE "8" ' Up arrow
+ y = y - 1
+ CASE "2" ' Down arrow
+ y = y + 1
+ CASE CHR$(27) ' Escape key
+ ' Exit the program
+ SYSTEM
+ END SELECT
+
+ ' Prevent the character from going off-screen
+ IF x < 1 THEN x = 1
+ IF x > 80 THEN x = 80
+ IF y < 1 THEN y = 1
+ IF y > 25 THEN y = 25
+
+LOOP ' Continue the main loop indefinitely
--- /dev/null
+CLS
+
+' Main program loop starts here
+DO
+ ' Clear the screen and print the menu options
+ CLS
+ PRINT "******** Select action: ********"
+ PRINT " "
+ PRINT "1 - Exit program"
+ PRINT "2 - Make a sound"
+ PRINT "3 - Draw a box"
+
+ ' Prompt the user to enter their choice and store it in variable 'userChoice'
+ INPUT "Enter your choice (1-3): ", userChoice
+
+ ' Exit the program if the user chooses option 1
+ IF userChoice = 1 THEN
+ PRINT "Exiting program..."
+ EXIT DO
+ END IF
+
+ ' Play a sound if the user chooses option 2
+ IF userChoice = 2 THEN
+ ' Generate a sound with a frequency of 2000 Hz for 2 seconds
+ SOUND 2000, 2
+
+ ' Draw a box if the user chooses option 3
+ ELSEIF userChoice = 3 THEN
+ ' Outer loop to draw the top and bottom edges of the box
+ FOR row = 1 TO 15
+ ' Inner loop to draw the left and right edges of the box
+ FOR col = 1 TO 50
+ PRINT "#";
+ NEXT col
+ ' Move to the next line after drawing each row
+ PRINT
+ NEXT row
+
+ ' Inform the user if they have entered a number greater than 3
+ ELSEIF userChoice > 3 THEN
+ PRINT "Number too large. Please enter a value between 1 and 3."
+
+ ' Inform the user if they have entered a number less than 1
+ ELSEIF userChoice < 1 THEN
+ PRINT "Number too small. Please enter a value between 1 and 3."
+ END IF
+
+ ' Wait for the user to press a key before continuing
+ PRINT "Press any key to continue..."
+ WHILE INKEY$ = ""
+ ' Do nothing, just wait for a key press
+ WEND
+
+LOOP WHILE TRUE
+
+' End of program
--- /dev/null
+' This program demonstrates how to set the video mode to 320x200 with 256 colors
+' and how to draw a single point on the screen using QuickBasic.
+
+SCREEN 13 ' Set video mode to 320 x 200 with 256 colors
+
+' Greet the user with a simple message
+PRINT "Hello..."
+
+' Define constants for the center of the screen for readability
+CONST CenterX = 160
+CONST CenterY = 100
+
+' Draw a point on the screen at the defined center coordinates
+' with a specified color.
+PSET (CenterX, CenterY), 10 ' Draws a point at (x=160, y=100) with color 10
+
+' Wait for a key press before exiting the program
+PRINT "Press any key to exit..."
+WHILE INKEY$ = ""
+ ' Do nothing until a key is pressed
+WEND
--- /dev/null
+' QuickBasic example program to demonstrate drawing pixels on the screen
+' and generating simple sound with varying frequency.
+
+SCREEN 13 ' Set the graphics mode to 320x200 resolution with 256 colors
+
+' Loop to draw a vertical line of pixels from y-coordinate 50 to 150
+FOR y = 50 TO 150
+ ' Loop to draw a horizontal line of pixels from x-coordinate 100 to 200
+ FOR x = 100 TO 200
+ PSET (x, y), 10 ' Set the pixel at (x, y) to color 10
+ NEXT x
+
+ ' Generate a sound with a frequency corresponding to the y-coordinate
+ ' The SOUND statement takes two arguments: frequency and duration
+ ' Here, the frequency is set to the current value of y, and the duration
+ ' is set to 1 tick (approximately 1/18th of a second)
+ SOUND y, 1
+NEXT y
--- /dev/null
+' This program demonstrates how to create a simple drawing application
+' using Microsoft QuickBasic. It defines a subroutine called 'box' that
+' draws a rectangle on the screen with specified coordinates and color.
+
+' Declare the 'box' subroutine so it can be used in the main program
+DECLARE SUB box (x1 AS SINGLE, y1 AS SINGLE, x2 AS SINGLE, y2 AS SINGLE, c AS INTEGER)
+
+' Set the screen mode to 13h which is a 320x200 pixel graphics mode with 256 colors
+SCREEN 13
+
+' Draw three boxes on the screen using the 'box' subroutine
+' Each box has different starting and ending coordinates as well as color
+box 10, 10, 100, 100, 15
+box 30, 80, 300, 120, 11
+box 140, 20, 180, 180, 10
+
+' Define the 'box' subroutine
+SUB box (x1 AS SINGLE, y1 AS SINGLE, x2 AS SINGLE, y2 AS SINGLE, c AS INTEGER)
+ ' Use nested FOR loops to iterate over every pixel within the rectangle
+ DIM x AS SINGLE, y AS SINGLE
+ FOR y = y1 TO y2
+ FOR x = x1 TO x2
+ ' Set the color of the current pixel to the specified color 'c'
+ PSET (x, y), c
+ NEXT x
+ NEXT y
+END SUB
--- /dev/null
+' This program demonstrates how to use QuickBasic to draw a simple\r
+' graphic on the screen. It initializes the graphics mode, draws a\r
+' rectangle, and then draws a circle within that rectangle.\r
+\r
+' Set the graphics mode to 320x200 with 256 colors (mode 13)\r
+SCREEN 13\r
+\r
+' Draw a line\r
+LINE (10, 10)-(200, 100), 14\r
+\r
+' Draw a circle centered at (100, 100) with a radius of 80 pixels\r
+' using color 10 (bright green). The circle is drawn within the\r
+' previously defined rectangle.\r
+CIRCLE (100, 100), 80, 10\r
+\r
--- /dev/null
+' This example program demonstrates how to draw different types of\r
+' lines and boxes on the screen using Microsoft QuickBasic.\r
+\r
+' First, we set the screen mode to 13 which provides a graphics\r
+' resolution of 320x200 with 256 colors available.\r
+SCREEN 13\r
+\r
+' Now we will draw three different objects using the LINE statement:\r
+\r
+' Draw an filled box from coordinates (10, 10) to (50, 50).\r
+LINE (10, 10)-(50, 50), 14, BF\r
+\r
+' Draw an unfilled box with coordinates (100, 10) to (150, 50).\r
+LINE (100, 10)-(150, 50), 14, B\r
+\r
+' Draw a line with coordinates (200, 10) to (250, 50).\r
+LINE (200, 10)-(250, 50), 14\r
+\r
+' To finish the program and allow users to see the drawn objects\r
+' before the screen closes, we wait for a key press from the user.\r
+PRINT "Press any key to exit..."\r
+WHILE NOT INKEY$ <> ""\r
+ ' Loop until a key is pressed\r
+WEND\r
+\r
--- /dev/null
+' QuickBasic example program to demonstrate drawing lines with varying colors\r
+\r
+SCREEN 13 ' Set the screen mode to 13h which provides 256 color graphics\r
+\r
+' Draw vertical lines across the screen with colors from 0 to 255\r
+FOR xPosition = 0 TO 255\r
+ ' Draw a line from coordinates (xPosition, 50) to (xPosition, 100) using color xPosition\r
+ LINE (xPosition, 50)-(xPosition, 100), xPosition\r
+NEXT xPosition\r
+\r
+' Keep the window open until the user presses a key\r
+PRINT "Press any key to exit..."\r
+WHILE INKEY$ = ""\r
+WEND\r
+\r
--- /dev/null
+' This program demonstrates basic graphics drawing in QuickBasic.\r
+' It uses the SCREEN function to set the graphics mode, draws a circle\r
+' and a line using CIRCLE and LINE commands respectively, waits for user\r
+' input, and then uses the PAINT command to fill an area with a solid color.\r
+\r
+' Set the screen to mode 13 which is 320x200 pixels with 256 colors.\r
+SCREEN 13\r
+\r
+' Draw a circle centered at (160, 100) with a radius of 80 pixels\r
+' and use color 15 for the outline of the circle.\r
+CIRCLE (160, 100), 80, 15\r
+\r
+' Draw a line from (100, 10) to (200, 180) using color 15.\r
+LINE (100, 10)-(200, 180), 15\r
+\r
+' Print a message to the screen prompting the user to press any key.\r
+PRINT "Press any key to fill part of the circle..."\r
+\r
+' Wait for the user to press a key and store the input in variable 'a$'.\r
+a$ = INPUT$(1)\r
+\r
+' Fill the area inside the circle with color 15 starting from point (180, 100).\r
+' Note that PAINT fills an area bounded by the specified color at the start point.\r
+PAINT (180, 100), 15\r
+\r
+END ' End the program (although END is not strictly necessary in QuickBasic)\r
+\r
--- /dev/null
+' This program demonstrates how to use subroutines and drawing
+' commands in QuickBasic. It draws a simple figure consisting of
+' concentric circles and intersecting lines.
+
+DECLARE SUB DrawFigure (xCenter AS DOUBLE, yCenter AS DOUBLE)
+SCREEN 13 ' Set the screen mode for high-resolution graphics
+
+' To see a list of subroutines, press F2
+' This is useful when navigating through larger programs
+
+' Draw figures at different locations on the screen
+DrawFigure 100, 100
+DrawFigure 200, 50
+DrawFigure 180, 150
+
+SUB DrawFigure (xCenter AS DOUBLE, yCenter AS DOUBLE)
+ ' Draw three concentric circles with a specified center point
+ CIRCLE (xCenter, yCenter), 10, 15
+ CIRCLE (xCenter, yCenter), 20, 15
+ CIRCLE (xCenter, yCenter), 30, 15
+
+ ' Draw two lines intersecting at the center point
+ LINE (xCenter, yCenter - 50)-(xCenter, yCenter + 50), 15
+ LINE (xCenter - 50, yCenter)-(xCenter + 50, yCenter), 15
+END SUB
--- /dev/null
+' This program demonstrates how to draw sine and cosine waves on the screen
+' using Microsoft QuickBasic. It is intended for beginners learning
+' programming in QuickBasic.
+
+' First, we set the graphics mode to 13 which provides a 320x200 pixel
+' resolution with 256 colors.
+SCREEN 13
+
+' We will draw two waves: one for sine and another for cosine. The amplitude
+' of both waves is scaled by a factor of 50, and they are vertically
+' centered on the screen by adding 100 to the y-coordinate.
+
+' The FOR loop iterates over the x-axis from 0 to 319 pixels, which covers
+' the entire width of the screen in this graphics mode.
+FOR x = 0 TO 319
+ ' Calculate the y-coordinate for the sine wave. We divide x by 10 to
+ ' reduce the frequency of the wave so it fits nicely on the screen.
+ ' The SIN function returns a value between -1 and 1, which we scale
+ ' and shift to get the desired waveform.
+ ysine = SIN(x / 10) * 50 + 100
+
+ ' Use PSET (Pixel SET) to plot a point on the screen for the sine wave
+ PSET (x, ysine), 14
+
+ ' Similarly, calculate and plot the cosine wave with color 12
+ ycosine = COS(x / 10) * 50 + 100
+ PSET (x, ycosine), 12
+
+ ' The loop continues to the next x-coordinate until it reaches 319.
+NEXT x
+
+' After the loop completes, both sine and cosine waves will be drawn on
+' the screen, with each point of the wave plotted in its respective color.
--- /dev/null
+' This program demonstrates how to draw a simple circle using QuickBasic.\r
+' It utilizes trigonometric functions SIN and COS to calculate the position of points on a circle.\r
+\r
+SCREEN 13 ' Set the screen mode to 13, which is 320x200 with 256 colors\r
+\r
+' Define pi (π) as a constant for calculations\r
+CONST pi = 3.141592653589789#\r
+\r
+' Define the number of points to be drawn on the circular shape\r
+DIM mi AS INTEGER\r
+mi = 12\r
+\r
+' Calculate the angle increment for each iteration of the loop\r
+' This will determine how many points we draw on the circle\r
+DIM angleStep AS SINGLE\r
+angleStep = pi * 2 / mi\r
+\r
+' Loop through angles from 0 to 2π (360 degrees) with the calculated step\r
+FOR a = 0 TO pi * 2 STEP angleStep\r
+\r
+ ' Calculate the x-coordinate of the current point on the circle\r
+ ' We multiply by 50 to scale the radius and add 100 for centering\r
+ DIM x AS SINGLE\r
+ x = SIN(a) * 50 + 100\r
+\r
+ ' Calculate the y-coordinate of the current point on the circle\r
+ ' Similarly, we scale and center the point\r
+ DIM y AS SINGLE\r
+ y = COS(a) * 50 + 100\r
+\r
+ ' Set the pixel at coordinates (x, y) with color 10\r
+ PSET (x, y), 10\r
+\r
+NEXT a\r
+\r
+' Wait for a key press before ending the program\r
+PRINT "Press any key to exit..."\r
+WHILE INKEY$ = ""\r
+WEND\r
+\r
--- /dev/null
+' This program demonstrates basic QuickBasic graphics and sound capabilities.\r
+' It is designed for novice programmers to learn about drawing lines, plotting points,\r
+' handling user input, and generating simple sounds.\r
+\r
+' Set the graphics mode to 320x200 with 16 colors (mode 13).\r
+SCREEN 13\r
+\r
+' Draw a grid on the screen with horizontal and vertical lines every 10 pixels.\r
+' This loop demonstrates the use of the LINE function to draw lines.\r
+FOR i = 0 TO 320 STEP 10\r
+ ' Draw a horizontal line from the left edge to the right edge at y-coordinate i.\r
+ LINE (0, i)-(319, i), 5\r
+ ' Draw a vertical line from the top edge to the bottom edge at x-coordinate i.\r
+ LINE (i, 0)-(i, 199), 5\r
+NEXT i\r
+\r
+' Draw a horizontal line across the middle of the screen (y=100)\r
+LINE (0, 100)-(319, 100), 10\r
+\r
+' Prompt the user to press any key before continuing.\r
+PRINT "Press any key to continue..."\r
+' Wait for the user to press a key and store the input in variable a$.\r
+a$ = INPUT$(1)\r
+\r
+' Initialize variables for the bouncing ball animation and sound.\r
+DIM y AS SINGLE ' The vertical position of the ball, using single precision for smooth motion.\r
+DIM ys AS SINGLE ' The vertical speed of the ball.\r
+DIM t AS INTEGER ' A counter for the main animation loop.\r
+\r
+' Set the initial vertical position of the ball to the middle of the screen (y=100).\r
+y = 100\r
+' Set the initial vertical speed of the ball to a negative value for upward motion.\r
+ys = -1\r
+\r
+' The main animation loop runs from t=0 to t=300, simulating the passage of time.\r
+FOR t = 0 TO 300\r
+ ' Plot the current position of the ball with a specific color (14).\r
+ PSET (t, y), 14\r
+\r
+ ' Update the vertical speed of the ball by adding gravity-like acceleration (ys = ys + .01).\r
+ ys = ys + .01\r
+ ' Update the vertical position of the ball based on the current speed (y = y + ys).\r
+ y = y + ys\r
+\r
+ ' Generate a sound with a frequency that varies inversely with the ball's vertical position.\r
+ ' As the ball falls, the pitch of the sound increases.\r
+ SOUND 300 - y, .1\r
+NEXT t\r
+\r
+' The program ends here; to exit, press any key.\r
+PRINT "Press any key to exit..."\r
+a$ = INPUT$(1)\r
+\r
--- /dev/null
+' This program demonstrates basic mathematical operations in QuickBasic.
+' It includes examples of rounding, taking the absolute value,
+' and finding the remainder of a division operation.
+
+DIM a AS SINGLE ' Declare variable 'a' as type SINGLE for floating-point arithmetic
+
+' Assign a negative floating-point number to variable 'a'
+a = -12.7
+
+' Print the original value of 'a'
+PRINT "Normal: "; a
+
+' Use the INT function to round down 'a' to the nearest whole number
+' and print the result
+PRINT "Rounded down (INT): "; INT(a)
+
+' Use the ABS function to get the absolute value of 'a',
+' which is always non-negative, and print the result
+PRINT "Absolute value: "; ABS(a)
+
+' Calculate the remainder of 10 divided by 4 using the MOD operator
+' and store the result in an implicitly declared variable
+' Then print the result
+DIM reminder AS INTEGER
+reminder = 10 MOD 4
+PRINT "Remainder of 10 / 4 is: "; reminder
--- /dev/null
+DECLARE SUB sort (x1!, x2!)\r
+DECLARE SUB check ()\r
+DECLARE SUB di (r1!, r2!, c!)\r
+DECLARE SUB disp ()\r
+DIM SHARED siz\r
+siz = 15000\r
+DIM SHARED arr(1 TO siz)\r
+DIM SHARED mark(1 TO siz)\r
+DIM SHARED bck(1 TO siz)\r
+DIM SHARED dbg\r
+WIDTH 80, 50\r
+\r
+dbg = 1\r
+CLS\r
+FOR i = 1 TO 1000\r
+LOCATE 5, 40\r
+PRINT i\r
+RANDOMIZE i\r
+siz = 45\r
+\r
+FOR a = 1 TO siz\r
+ arr(a) = INT(RND * 100)\r
+ bck(a) = arr(a)\r
+NEXT a\r
+11\r
+\r
+sort 1, siz\r
+disp\r
+\r
+\r
+fail = 0\r
+FOR i2 = 1 TO siz - 1\r
+ IF arr(i2) > arr(i2 + 1) THEN\r
+ PRINT "wrong!"\r
+ a$ = INPUT$(1)\r
+ fail = 1\r
+ GOTO 10\r
+ END IF\r
+NEXT i2\r
+10\r
+\r
+IF fail = 1 THEN\r
+ FOR i2 = 1 TO siz\r
+ arr(i2) = bck(i2)\r
+ NEXT i2\r
+ dbg = 1\r
+ GOTO 11\r
+END IF\r
+\r
+NEXT i\r
+\r
+SUB di (r1, r2, c)\r
+\r
+mark(r1) = c\r
+mark(r2) = c\r
+disp\r
+mark(r1) = 0\r
+mark(r2) = 0\r
+\r
+\r
+END SUB\r
+\r
+SUB disp\r
+FOR i = 1 TO siz\r
+ LOCATE i, 1\r
+ COLOR 15, mark(i)\r
+ PRINT arr(i), " ", i\r
+NEXT i\r
+\r
+IF dbg = 1 THEN a$ = INPUT$(1)\r
+'SOUND 0, .05\r
+END SUB\r
+\r
+SUB sort (x1, x2)\r
+min = 99999\r
+max = -99999\r
+FOR i = x1 TO x2\r
+ IF arr(i) > max THEN max = arr(i)\r
+ IF arr(i) < min THEN min = arr(i)\r
+NEXT i\r
+sv = (max + min) / 2\r
+LOCATE 1, 50\r
+PRINT sv\r
+'disp\r
+di x1, x2, 4\r
+IF x1 >= x2 THEN GOTO 3\r
+\r
+IF x1 + 1 = x2 THEN\r
+ IF arr(x1) > arr(x2) THEN SWAP arr(x1), arr(x2)\r
+ GOTO 3\r
+END IF\r
+\r
+xl1 = x1\r
+xl2 = x2\r
+\r
+\r
+1\r
+di xl1, xl2, 1\r
+IF arr(xl1) > sv THEN\r
+2\r
+ IF arr(xl2) < sv THEN\r
+ SWAP arr(xl1), arr(xl2)\r
+ xl1 = xl1 + 1\r
+ xl2 = xl2 - 1\r
+ ELSE\r
+ xl2 = xl2 - 1\r
+ di xl1, xl2, 1\r
+ IF xl1 = xl2 THEN GOTO 4\r
+ GOTO 2\r
+ END IF\r
+ELSE\r
+ xl1 = xl1 + 1\r
+END IF\r
+\r
+IF xl1 < xl2 THEN GOTO 1\r
+'IF arr(xl1) < sv THEN xl1 = xl1 + 1\r
+'IF arr(xl1) < sv THEN xl1 = xl1 + 1\r
+4\r
+mark(xl1) = 14\r
+disp\r
+mark(xl1) = 0\r
+\r
+IF xl1 = x2 THEN\r
+ sort x1, xl1 - 1\r
+ELSE\r
+ IF arr(xl1) > sv THEN\r
+ sort x1, xl1 - 1\r
+ sort xl1, x2\r
+ ELSE\r
+ sort x1, xl1\r
+ sort xl1 + 1, x2\r
+ END IF\r
+END IF\r
+3\r
+END SUB\r
+\r
--- /dev/null
+#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
+#+TITLE: BASIC applications collection
+#+LANGUAGE: en
+#+LATEX_HEADER: \usepackage[margin=1.0in]{geometry}
+#+LATEX_HEADER: \usepackage{parskip}
+#+LATEX_HEADER: \usepackage[none]{hyphenat}
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+ .flex-center {
+ display: flex; /* activate flexbox */
+ justify-content: center; /* horizontally center anything inside */
+ }
+
+ .flex-center video {
+ width: min(90%, 1000px); /* whichever is smaller wins */
+ height: auto; /* preserve aspect ratio */
+ }
+
+ .responsive-img {
+ width: min(100%, 1000px);
+ height: auto;
+ }
+</style>
+#+end_export
+
+
+* Overview
+This collection contains lots of applications:
+
+- [[id:ebafd8a3-54d4-4834-a03d-a942b535a82f][2D Graphics]]
+ - [[file:2D%20GFX/Animations/index.html][Animations]]
+ - [[id:38f8f88a-3f72-4c43-91c6-08d5c7aa54e6][Fractals]]
+ - [[id:97adc6df-353e-4800-b27a-4b2ae9d93b6b][Spiral series]]
+ - [[id:6e59af62-d7bf-41dc-a680-677000ef0e85][Algorithmic textures]]
+
+- [[id:63fd5d58-9bce-4c0a-99d4-ed2d025258f0][3D Graphics]]
+ - [[file:3D GFX/Space/index.html][Miscellaneous 3D demo applications collection]]
+ - [[file:3D GFX/Space/index.html][Space themed applications collection]]
+ - [[file:3D%20GFX/3D%20Synthezier/doc/index.html][3D synthezier - language and processor to generate complex 3D worlds]]
+
+- [[id:aa195f33-6d69-48ff-9af5-3f761a51dcb2][Games]]
+
+- [[id:aa195f33-6d69-48ff-9af5-3f761a51dcb2][Math]]
+ - [[file:Math/Plotting/index.html][Collection of mathematical plots]]
+ - [[file:Math/Simulation/index.html][Collection of math based simulations]]
+
+- [[id:3587240c-1d50-478d-b850-04ebc8dc63c7][Miscellaneous applications that are hard to categorize]]
+
+- [[id:f80fb0ad-64b7-4360-9081-11358d2ef745][Networking]]
+
+I wrote them at around year 2000, mostly in QBasic.
+
+* 2D GFX
+:PROPERTIES:
+:ID: ebafd8a3-54d4-4834-a03d-a942b535a82f
+:END:
+** Animations
+
+Collection of various 2D animations. Good for demonstrating various
+algorithms and getting fun looking results quite easily.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:2D%20GFX/Animations/index.html][file:2D%20GFX/Animations/logo.png]]
+
+[[file:2D%20GFX/Animations/index.html][See entire animations collection]]
+
+** Fractals
+:PROPERTIES:
+:ID: 38f8f88a-3f72-4c43-91c6-08d5c7aa54e6
+:END:
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:2D%20GFX/Fractals/index.html][file:2D%20GFX/Fractals/fractal%20squares,%202.png]]
+
+[[file:2D GFX/Fractals/index.html][See entire fractals collection]]
+
+** Spiral series
+:PROPERTIES:
+:ID: 97adc6df-353e-4800-b27a-4b2ae9d93b6b
+:END:
+
+Small collection of programs that are result of exploratory
+programming, for fun. It started out from drawing spiral on the
+screen. Every iteration built upon previous result.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:2D%20GFX/Spirals/index.html][file:2D%20GFX/Spirals/logo.png]]
+
+[[file:2D%20GFX/Spirals/index.html][See entire spiral collection]]
+
+** Algorithmic textures
+:PROPERTIES:
+:ID: 6e59af62-d7bf-41dc-a680-677000ef0e85
+:END:
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:2D%20GFX/Textures/index.html][file:2D%20GFX/Textures/logo.png]]
+
+[[file:2D%20GFX/Textures/index.html][See entire texture collection]]
+
+** Miscellaneous
+*** Hello friend
+
+This QBasic program is a simple yet engaging demonstration of 2D
+graphics capabilities. It showcases various graphical techniques such
+as pixel manipulation, geometric shapes, and simple animations.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:2D%20GFX/Hello%20friend.bas][file:2D%20GFX/Hello%20friend.png]]
+
+Download source code: [[file:2D%20GFX/Hello%20friend.bas][Hello friend.bas]]
+
+#+INCLUDE: "2D GFX/Hello friend.bas" src basic-qb45
+
+*** People
+
+This QBasic program is a slideshow presentation tool that includes
+animated transitions and effects.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="2D GFX/People.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+Download source code: [[file:2D%20GFX/People.bas][People.bas]]
+
+*** Stroboscope
+
+This QBasic program is an educational presentation on how to build a
+stroboscope. It uses graphical animations and text to illustrate the
+schematics involved in constructing a stroboscope. The program is
+designed to be visually engaging, with animated transitions and
+diagrams.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:2D%20GFX/Stroboscope.bas][file:2D%20GFX/Stroboscope.png]]
+
+Download source code: [[file:2D%20GFX/Stroboscope.bas][Stroboscope.bas]]
+
+*** Truncated cone
+
+This QBasic program is designed to draw a 3D representation of a
+truncated cone, which consists of three main parts: a top cylinder
+with diagonal hatching, a middle frustum (truncated cone), and a
+bottom smaller cylinder. The primary goal of this program is to test
+the viability of generating images of 3D shapes using code.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:2D%20GFX/Truncated%20cone.bas][file:2D%20GFX/Truncated%20cone.png]]
+
+Download source code: [[file:2D%20GFX/Truncated%20cone.bas][Truncated cone.bas]]
+
+#+INCLUDE: "2D GFX/Truncated cone.bas" src basic-qb45
+
+* 3D GFX
+:PROPERTIES:
+:ID: 63fd5d58-9bce-4c0a-99d4-ed2d025258f0
+:END:
+** Miscellaneous 3D demos
+:PROPERTIES:
+:ID: e4c643d1-edf9-4da9-bf6f-462535a5a7d9
+:END:
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:3D%20GFX/Miscellaneous/index.html][file:3D%20GFX/Miscellaneous/logo.png]]
+
+[[file:3D GFX/Space/index.html][See entire miscellaneous 3D demo applications collection]]
+
+** Space related animations
+:PROPERTIES:
+:ID: 32fb6839-1e9b-4d44-a47e-1875c727cc54
+:END:
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:3D%20GFX/Space/index.html][file:3D%20GFX/Space/logo.png]]
+
+[[file:3D GFX/Space/index.html][See entire space themed applications collection]]
+
+** 3D Synthezier
+
+Parses scene definition language and creates 3D world based on
+it. Result will be in a [[https://en.wikipedia.org/wiki/Wavefront_.obj_file][wavefront obj file]], witch can be then
+visualized using external renderer.
+
+See directory:
+: 3D GFX/3D Synthetizer/
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:3D%20GFX/3D%20Synthezier/doc/index.html][file:3D%20GFX/3D%20Synthezier/doc/hexagonal%20city,%202.jpeg]]
+
+[[file:3D%20GFX/3D%20Synthezier/doc/index.html][Read more]]
+
+** Helicopter demo
+
+This QBasic program is a demonstration of real-time 3D graphics
+rendering. Also it shows 3D transformations, fractal terrain
+generation, and simple animation.
+
+A fractal algorithm is used to create a realistic terrain by
+iteratively subdividing and perturbing pixel values.
+
+The program includes an animated sequence featuring a helicopter that
+moves across the terrain and picks up objects.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:3D%20GFX/Helicopter/Helicopter.bas][file:3D%20GFX/Helicopter/screenshot,%201.png]]
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:3D%20GFX/Helicopter/Helicopter.bas][file:3D%20GFX/Helicopter/screenshot,%202.png]]
+
+[[https://www2.svjatoslav.eu/gitweb/?p=qbasicapps.git;a=tree;f=3D+GFX/Helicopter;hb=HEAD][Project files]]
+
+** Swapping 3D engine
+
+This QBasic program is a 3D wireframe rendering engine designed to
+render potentially infinite 3D worlds. It achieves this by dynamically
+managing world data through a partitioning system that loads and
+offloads cube-shaped fragments of the world into and out of RAM as
+needed. This allows for the efficient use of memory, making it
+possible to explore large virtual environments without excessive
+resource consumption.
+
+World data is stored on disk, and only the necessary parts are loaded
+into RAM, allowing for the potential rendering of very large worlds.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:3D%20GFX/Swapping%203D%20engine/screenshot.png]]
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:3D%20GFX/Swapping%203D%20engine/screenshot,%202.png]]
+
+Download source code: [[file:3D%20GFX/Swapping%203D%20engine/engine.bas][engine.bas]]
+
+** 3D land
+
+This QBasic program creates a visually engaging 3D shaded landscape
+with perspective and distortion effects.
+
+The program loops through each point in the grid, applying a cosine
+distortion based on the distance from the center of the grid. This
+creates a wavy, undulating effect across the landscape. Perspective
+transformation is then applied to give the illusion of depth.
+
+The transformed coordinates are used to draw quadrilaterals, which are
+filled with colors that alternate to create a checkerboard pattern.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="3D%20GFX/3D%20land.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+Download source code: [[file:3D%20GFX/3D%20land.bas][3D land.bas]]
+
+#+INCLUDE: "3D GFX/3D land.bas" src basic-qb45
+
+** Anaglyph
+
+This QBasic program creates a real-time anaglyph projection featuring
+bouncing cubes. Cubes are created and placed within a 3D space. Each
+cube has its own position and velocity, which determine its movement
+and interactions within the environment.
+
+Anaglyph images are used to provide a stereoscopic 3D effect when
+viewed with glasses that have two different colored lenses, typically
+red and cyan. The program provides insight into how anaglyph images
+work, which can be a fun and educational project for those interested
+in stereoscopy and 3D visualization.
+
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:3D%20GFX/Anaglyph.bas][file:3D%20GFX/Anaglyph.png]]
+
+[[file:3D%20GFX/Anaglyph.bas][Anaglyph.bas]]
+
+** Ray casting engine
+
+This QBasic program is a real-time 3D rendering engine that uses a ray
+casting technique to create a dynamic 3D landscape. The landscape
+includes various features such as hills and towers.
+
+Real-time Rendering: The engine adjusts the rendering quality
+dynamically to maintain a constant frame rate of 10 frames per second,
+ensuring smooth performance even on older hardware like an Intel
+Pentium 200 MHz in DOS mode.
+
+Users can move around the landscape using arrow keys and other
+specified keys to turn, look up/down, and even jump.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:3D%20GFX/Ray%20casting%20engine.bas][file:3D%20GFX/Ray%20casting%20engine.png]]
+
+Download source code: [[file:3D%20GFX/Ray%20casting%20engine.bas][Ray casting engine.bas]]
+
+* Games
+:PROPERTIES:
+:ID: aa195f33-6d69-48ff-9af5-3f761a51dcb2
+:END:
+
+** Pomppu Paavo
+
+Player controls small character that has to collect coins and move
+between screens. Player has to avoid contact with evil hedgehogs.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Games/Pomppu%20Paavo.bas][file:Games/Pomppu%20Paavo.png]]
+
+[[file:Games/Pomppu%20Paavo.bas][Source code]]
+
+** Pomppu Paavo 2
+
+Player controls small character that has to collect coins and move
+between screens. Player has to avoid contact with evil snails.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[https://www2.svjatoslav.eu/gitweb/?p=qbasicapps.git;a=tree;f=Games/Pomppu+Paavo][file:Games/Pomppu%20Paavo%202/screenshot.png]]
+
+[[https://www2.svjatoslav.eu/gitweb/?p=qbasicapps.git;a=tree;f=Games/Pomppu+Paavo+2][Source code]]
+
+Source code organization:
+#+begin_example
+├── img <- Visual game assets
+│ ├── 0.i01
+│ ├── 1.i01
+│ ├── 2.i01
+│ ├── ...
+├── Pomppu Paavo.bas <- Main game executable
+#+end_example
+
+** Multiplayer game of worms
+
+Game supports up to 5 players. Any amount of those players can be AI
+controlled. Game has multiple levels. After worms have eaten certain
+amount of fruits, game advances to the next level. Each worm has
+limited amount of lives. When worm runs into the wall or another worm,
+it loses one life.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="Games/Worm/screencast.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+[[file:Games/Worm/worm.bas][Source code]]
+
+Levels are stored in [[https://www2.svjatoslav.eu/gitweb/?p=qbasicapps.git;a=tree;f=Games/Worm;hb=HEAD]['lvl' files]] that are directly editable using text
+editor.
+
+** Checkers
+
+This program is implementation of the game of Checkers, written in
+QBasic. It provides a mostly functional two-player experience on a
+10x10 grid, where players can move and capture pieces according to the
+traditional rules of Checkers. User is playing against AI. AI is quite
+primitive. It has many hard-coded patterns that it tries to detect and
+utilize when possible.
+
+[[file:Games/checkers.bas][Source code]]
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Games/checkers.bas][file:Games/checkers.png]]
+
+** Checkers 2
+
+This more advanced implementation of checkers. User can play checkers
+against the AI. AI does not have hard-coded patterns anymore. Instead
+it does recursive lookahead for possible own moves and following
+possible opponent moves up to determined cut-off depth. While
+crunching through all possible moves (up-to fixed depth), it chooses
+the best possible move for itself.
+
+Board size is reduced to 6x6 grid to gain reasonable AI
+performance. Possible combinations count exponentially explodes with
+larder board size.
+
+[[file:Games/checkers2.bas][Source code]]
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Games/checkers2.bas][file:Games/checkers2.png]]
+
+* Math
+:PROPERTIES:
+:ID: aa195f33-6d69-48ff-9af5-3f761a51dcb2
+:END:
+** Game of life animation
+
+This QBasic program creates a visually engaging 3D animation that
+combines elements of cellular automata with dynamic graphics. The
+program simulates a rotating 3D scene composed of cubes that appear
+and disappear according to Conway's Game of Life rules. This classic
+algorithm models the life cycles of cells on a grid, where each cell
+can live, die, or reproduce based on its neighbors.
+
+The Game of Life is a zero-player game, meaning that its evolution is
+determined by its initial state, requiring no further input.
+
+The main loop of the program continuously updates the camera position
+and rotation angles, generating a dynamic view of the 3D scene. Cubes
+are drawn based on the current state of the Game of Life grid, and the
+scene is rendered frame by frame.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="Math/Game%20of%20life%20in%203D.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+Download source code: [[file:Math/Game%20of%20life%20in%203D.bas][Source code]]
+
+** Game of life studio
+
+Game of life studio. One interacts with the Game of Life by creating
+an initial configuration and observing how it evolves. This program
+provides a platform to simulate, edit, and save different
+configurations of the Game of Life.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Math/Game%20of%20life/Game%20of%20life.bas][file:Math/Game%20of%20life/screenshot.png]]
+
+[[https://www2.svjatoslav.eu/gitweb/?p=qbasicapps.git;a=tree;f=Math/Game+of+life;hb=HEAD][Source code]]
+
+** Math functions plot
+
+Collection of programs that produce 2D and 3D plots of mathematical
+functions.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Math/Plotting/index.html][file:Math/Plotting/logo.png]]
+
+[[file:Math/Plotting/index.html][See entire collection of mathematical plots]]
+
+** Simulations
+
+Collection of programs that implement simulations of various
+mathematical and physical effects.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Math/Simulation/index.html][file:Math/Simulation/logo.png]]
+
+[[file:Math/Simulation/index.html][See entire collection of simulations]]
+
+** Truth table calculator
+
+Program allows user to input logical equation. Thereafter program
+computes and displays all possible states for equation (aka. truth
+table).
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Math/Truth%20table/index.html][file:Math/Truth%20table/img/screenshot,%202.png]]
+
+[[file:Math/Truth%20table/index.html][Read more about truth table calculator]]
+
+** Multiplication trainer
+
+This QBasic program is an educational tool designed to help users
+practice and test their multiplication skills. It is particularly
+useful for students learning basic arithmetic or anyone looking to
+brush up on their multiplication tables.
+
+The program generates random multiplication questions by selecting two
+numbers between 0 and 9.
+
+The user is prompted to enter the product of the two numbers. The
+program validates the input and provides immediate feedback.
+
+The program keeps track of correct and incorrect answers. After the
+specified number of questions, it calculates the user's score and
+assigns a grade based on the percentage of correct answers.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Math/Multiplication%20trainer.bas][file:Math/Multiplication%20trainer.png]]
+
+[[file:Math/Multiplication%20trainer.bas][Source code]]
+
+** Alternative sine calculator
+
+Here simple and finite function was invented to compute sine
+values. Custom sine values are shown alongside standard built-in sine
+function to compare results. 1 pixel vertical shift is intentional.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Math/Sine%20computation.bas][file:Math/Sine%20computation.png]]
+
+[[file:Math/Multiplication%20trainer.bas][Source code]]
+
+** Lottery analysis
+
+This QBasic program is designed to analyze historical lottery data,
+providing various graphical representations and statistical
+insights. It is a useful tool for anyone interested in exploring
+patterns and trends in lottery numbers over time. The program reads
+data from a text file and offers multiple visualization options to
+help users understand the data better.
+
+Note: In the example data there are made-up numbers and there are
+repetitions in example data on-purpose. Those repeating patterns
+become easily detectable in visual graphs.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Math/Lottery/Lottery%20analysis.bas][file:Math/Lottery/screenshot,%203.png]]
+
+Graphical Representations:
+
+- Dot Graph :: Displays lottery numbers as dots on a graph, with
+ vertical lines representing each draw. This visualization helps in
+ identifying the frequency and distribution of numbers.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Math/Lottery/Lottery%20analysis.bas][file:Math/Lottery/screenshot,%202.png]]
+
+- Line Graph :: Shows a dynamic line graph connecting consecutive
+ lottery numbers, providing a visual representation of number trends
+ over time. This can be useful for spotting trends or anomalies in
+ the data.
+
+- Combinatorics Graph :: This graph fits the data to every possible
+ resolution, making it easier to spot patterns that might not be
+ visible at a single resolution. This feature introduces the concept
+ of combinatorics and pattern recognition in data visualization.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Math/Lottery/Lottery%20analysis.bas][file:Math/Lottery/screenshot,%201.png]]
+
+[[file:Math/Lottery/Lottery%20analysis.bas][Source code]]
+
+* Misc
+:PROPERTIES:
+:ID: 3587240c-1d50-478d-b850-04ebc8dc63c7
+:END:
+
+** Mouse driver for QBasic
+
+QBasic, a popular programming language in the DOS era, lacks native
+mouse support. This limitation can be a hurdle for developers looking
+to create interactive applications. To bridge this gap, I developed a
+solution that involves a Terminate and Stay Resident (TSR) program
+written in x86 assembly and a QBasic demonstration program.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Miscellaneous/Mouse%20driver/index.html][file:Miscellaneous/Mouse%20driver/screenshot.png]]
+
+[[file:Miscellaneous/Mouse%20driver/index.html][Read more about mouse driver for QBasic]]
+
+** Alien font
+
+This QBasic program is a creative attempt to generate and display an
+imaginary alien script. The program constructs characters by
+subdividing a square into four triangles, creating an abstract and
+visually intriguing text pattern. It is an artistic exploration that
+can inspire those interested in procedural generation, graphics, and
+abstract art.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Miscellaneous/Alien%20font.bas][file:Miscellaneous/Alien%20font.png]]
+
+** Custom palette
+
+This QBasic program generates a universally reusable color palette
+designed for a 256-color limit, which was a common constraint in older
+computer graphics. The program demonstrates how to create a diverse
+set of colors by varying the red, green, and blue components and then
+uses these colors to draw patterns on the screen.
+
+Each component is varied from 0 to 5, and the resulting RGB values are
+output to the palette registers, creating a total of 216 unique colors
+(6x6x6).
+
+After generating the color palette, the program draws a grid of
+colored squares. Each square is filled with a color from the generated
+palette, providing a visual representation of all available colors:
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Miscellaneous/Custom%20palette.bas][file:Miscellaneous/Custom%20palette.png]]
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Miscellaneous/Custom%20palette.bas][file:Miscellaneous/Custom%20palette,%202.png]]
+
+The dithering process helps to mitigate the limitations of the
+256-color palette, making the gradients appear smoother to the eye:
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Miscellaneous/Custom%20palette.bas][file:Miscellaneous/Custom%20palette,%203.png]]
+
+** Alarm 1
+
+This QBasic program simulates the sound of a security alarm siren. It
+creates an oscillating sound effect by varying the frequency of the
+primary tone, mimicking the familiar rise-and-fall pattern of a siren.
+
+The program works by initializing a frequency variable and playing a
+primary oscillating tone alongside secondary fixed-frequency
+tones. This combination produces a realistic alarm sound. The
+frequency of the primary tone increases and decreases within set
+thresholds, controlled by conditional checks and loops.
+
+#+begin_export html
+<div class="flex-center">
+ <audio controls>
+ <source src="Miscellaneous/Alarm 1.mp3" type="audio/mpeg">
+ Your browser does not support the audio element.
+ </audio>
+</div>
+#+end_export
+
+#+INCLUDE: "Miscellaneous/Alarm 1.bas" src basic-qb45
+
+Download source code: [[file:Miscellaneous/Alarm,%201.bas][Alarm 1.bas]]
+
+** Alarm 2
+
+This QBasic program generates a security alarm sound effect by
+alternating between two distinct audio patterns. The first pattern
+features an ascending sweep of frequencies from 100 Hz to 1000 Hz,
+paired with a counterpoint tone that decreases in frequency. The
+second pattern involves a descending sweep from 1000 Hz back to 100
+Hz, enhanced with a harmonic overtone to create a richer sound
+texture.
+
+#+begin_export html
+<div class="flex-center">
+ <audio controls>
+ <source src="Miscellaneous/Alarm 2.mp3" type="audio/mpeg">
+ Your browser does not support the audio element.
+ </audio>
+</div>
+#+end_export
+
+#+INCLUDE: "Miscellaneous/Alarm 2.bas" src basic-qb45
+
+Download source code: [[file:Miscellaneous/Alarm,%202.bas][Alarm 2.bas]]
+
+** 4D engine
+
+Implementation of 4 dimensional (4D) engine. It's like 3D (X, Y, Z)
+but with additional extra dimension that I decided to call Q.
+
+*** Polygon -> Tetrahedron -> Pentatope
+
+- In 2D world you can have polygon. It takes 3 vertices (points) to
+ define. It is the minimal object in 2D world to have surface.
+
+- In 3D world you can have tetrahedron. It takes 4 vertices to
+ define. It is the minimal object in 3D world to have volume.
+
+- In 4D world you can have 5-cell (aka. pentatope). It takes 5
+ vertices to define. It is the minimal object in 4D world to have
+ hypervolume (aka. 4D volume).
+
+*** Planes or rotation in 3D world vs 4D world
+
+In 3D space, the planes of rotation correspond to rotations around the
+three principal axes, and they are as follows:
+
+- The yz-plane, corresponding to rotation around the x-axis.
+- The xz-plane, corresponding to rotation around the y-axis.
+- The xy-plane, corresponding to rotation around the z-axis.
+
+
+In 4D space, there are six possible planes of rotation, which can be
+described by the combinations of two axes out of four. These are:
+
+- The yz-plane (same as in 3D space)
+- The xz-plane (same as in 3D space)
+- The xy-plane (same as in 3D space)
+- The xq-plane (novel plane)
+- The yq-plane (novel plane)
+- The zq-plane (novel plane)
+
+*** Representing higher-dimensional objects through lower-dimensional slices
+
+The concept of representing higher-dimensional objects through
+lower-dimensional slices involves taking cross-sections along one
+dimension and viewing the resulting shapes.
+
+Here’s how it applies to both 3D to 2D and 4D to 3D representations:
+
+- *Representing a 3D Shape in 2D*:
+ - A 3D object can be represented as a series of 2D slices by taking
+ cross-sections along one axis (e.g., the z-axis). Each slice is a
+ flat, 2D shape that corresponds to the intersection of the 3D
+ object with a plane at a particular position along that axis.
+ - By stacking these 2D slices together in sequence, you can
+ reconstruct the 3D object. This method is akin to how CT scans
+ create images of the inside of a body by combining multiple
+ cross-sectional X-ray images.
+
+- *Representing a 4D Object in 3D*:
+ - Similarly, a 4D object can be represented in 3D space by taking
+ cross-sections along the fourth dimension. Each cross-section is a
+ 3D shape that represents the intersection of the 4D object with a
+ hyperplane at a particular position along the fourth axis (e.g.,
+ Q-axis).
+ - By viewing these 3D slices in sequence, you can form an idea of
+ the structure and shape of the 4D object. This process allows us
+ to visualize a 4D object by observing how the 3D cross-sections
+ change over the fourth dimension.
+
+In both cases, the method of "slicing" allows us to understand and
+visualize objects in dimensions that we cannot directly perceive, by
+breaking them down into more manageable and comprehensible
+lower-dimensional pieces.
+
+*** Implementation
+
+Current 4D engine renders single pentatope. Each pentatope vertex is
+defined by 4 coordinates within 4D space:X, Y, Z, Q.
+
+You can rotate pentatope around any plane in 4D space (all 6 are
+supported). Also you as a viewer can move around any axis in 4D space
+(all 4 are supported).
+
+4D pentatope is shown on a screen as a series of 3D slices with
+varying brightness along the new Q axis.
+
+Wireframe rendering is quite useful in this case because it allows to
+see multiple overlayed 3D shapes at the same time.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Miscellaneous/4D%20engine.bas][file:Miscellaneous/4D%20engine.png]]
+
+It is interesting how 3D slices of 4D pentatope stay as familiar
+tetrahedrons while you rotate the shape along familiar X,Y,Z axis. But
+shape starts changing in weird ways when you start rotating it along
+novel planes of 4D space.
+
+Download source code: [[file:Miscellaneous/4D%20engine.bas][4D engine.bas]]
+
+** Windowing system
+
+This QBasic program implements a text mode windowing system, allowing
+users to create and manage multiple windows on the screen. Each window
+can display the contents of a text file and supports horizontal and
+vertical scrolling. The program is designed to demonstrate basic
+window management and text display functionalities in a text-based
+environment.
+
+Windows are drawn on the screen with borders and titles.
+
+The program includes a simple animation loop that shifts the content
+of the active window, creating a dynamic visual effect.
+
+#+begin_export html
+<div class="flex-center">
+ <video controls loop autoplay>
+ <source src="Miscellaneous/Windowing%20system.webm" type="video/webm">
+ Your browser does not support the video tag.
+ </video>
+</div>
+#+end_export
+
+Download source code: [[file:Miscellaneous/Windowing%20system.bas][Windowing system.bas]]
+
+** Password lock
+
+This QBasic program simulates a retro-styled rocket control system
+interface with a password protection mechanism. The program is
+designed to provide a visually engaging experience reminiscent of
+early computer systems.
+
+The password is stored in an external file (passw.dat).
+
+The program captures and processes user input for password entry,
+including handling special keys like Enter and Backspace.
+
+When the user presses Enter, the program checks the entered password
+against the stored password. If the password is correct, the program
+exits. If not, it displays an error message and decreases the number
+of remaining attempts.
+
+The user has three attempts to enter the correct password. After three
+failed attempts, the program halts and displays a "SYSTEM HALTED"
+message.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Miscellaneous/Password%20lock/passw.bas][file:Miscellaneous/Password%20lock/screenshot,%201.png]]
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Miscellaneous/Password%20lock/passw.bas][file:Miscellaneous/Password%20lock/screenshot,%202.png]]
+
+Download source code: [[file:Miscellaneous/Password%20lock/passw.bas][passw.bas]]
+
+* Networking
+:PROPERTIES:
+:ID: f80fb0ad-64b7-4360-9081-11358d2ef745
+:END:
+** LPT port pin control
+
+This QBasic program is designed to control the voltage on individual
+pins of an LPT (Line Print Terminal) port, commonly known as a
+parallel port. This type of port was traditionally used for connecting
+printers to computers but can also be used for simple hardware control
+tasks.
+
+The program allows users to toggle the voltage on each of the 8 pins
+of the LPT port using keys 1 through 8 on the keyboard. When a key is
+pressed, the corresponding pin's state is toggled between on (high
+voltage) and off (low voltage).
+
+The program uses bit manipulation to control individual pins.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Networking/LPT%20pin%20control.bas][file:Networking/LPT%20pin%20control.png]]
+
+Download source code: [[file:Networking/LPT%20pin%20control.bas][LPT pin control.bas]]
+
+** COM port text terminal
+
+[[https://en.wikipedia.org/wiki/Serial_port][The COM port, short for "Communication Port" was a serial port
+interface]] found on older personal computers. It was primarily used for
+serial communication, where data is transmitted one bit at a time over
+a communication channel.
+
+The COM port facilitated bidirectional communication between the
+computer and connected devices, such as modems, mice, and keyboards.
+
+Typically available as 9-pin (DE-9) connectors, COM ports adhered to
+the RS-232 standard for serial communication.
+
+Mice, before the prevalence of USB, commonly connected to computers
+via COM ports, transmitting movement and button-click data through
+this serial interface.
+
+COM ports operated using a UART (Universal Asynchronous
+Receiver/Transmitter), which managed the conversion of data between
+parallel form (used by the computer) and serial form (used by the
+communication line).
+
+This program is a simple text mode terminal for communicating through
+a COM port.
+
+How it Works:
+- The program continuously checks the COM port status.
+- If data is available, it reads the data and prints it to the screen
+ along with its ASCII value.
+- It captures keyboard input from the user and sends it out through
+ the COM port.
+- This creates a bidirectional communication channel between the
+ user's keyboard and the COM port device, typical of terminal
+ emulation software.
+
+#+INCLUDE: "Networking/COM port terminal.bas" src basic-qb45
+
+Download source code: [[file:Networking/COM%20port%20terminal.bas][COM port terminal.bas]]
+
+** Parallel port to COM port text terminal
+
+This QBasic program demonstrates a clever method of transmitting data
+from a parallel (LPT) port to a serial (COM) port using a technique
+known as bit-banging.
+
+How It Works:
+- The program initializes the parallel port and waits for keyboard
+ input.
+- Each character input from the keyboard is converted into its ASCII
+ value.
+- The ASCII value is converted into an 8-bit binary array, with each
+ array element representing a bit of the character.
+- Each bit is then sent to the parallel port by toggling the output
+ lines accordingly. The bits are transmitted sequentially, simulating
+ serial data transmission.
+- A loop holds each bit value for a predefined duration, mimicking
+ clock cycles necessary for serial communication.
+- The program exits when the Escape key is pressed.
+
+#+INCLUDE: "Networking/LPT to COM port data transfer.bas" src basic-qb45
+
+Download source code: [[file:Networking/LPT%20to%20COM%20port%20data%20transfer.bas][LPT to COM port data transfer.bas]]
+
+** LPT communication driver
+
+TSR driver that allows 2 computers to communicate over parallel port serially.
+
+[[file:Networking/LPT%20communication%20driver/index.html][Read more]]
+
+** Data over analog audio CODEC
+
+Utilities to encode digital data to sound file and back.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Networking/Digital%20data%20over%20analog%20audio/index.html][file:Networking/Digital%20data%20over%20analog%20audio/screenshot.png]]
+
+[[file:Networking/Digital%20data%20over%20analog%20audio/index.html][Read more]]
+
+** Morse
+
+This QBasic program allows users to input text and hear it played back
+in Morse code using the PC speaker. It's a fun and educational tool
+for anyone interested in learning Morse code.
+
+It reads Morse code patterns from an external file named
+[[file:Networking/Morse.txt][Morse.txt]]. Each line in the file represents a character and its
+corresponding Morse code:
+
+#+INCLUDE: "Networking/Morse.txt" src txt
+
+For each character in the input text, the program looks up its Morse
+code pattern and plays it back using the PC speaker. Dots are
+represented by short beeps, and dashes by longer beeps.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Networking/Morse.bas][file:Networking/Morse.png]]
+
+Download source code: [[file:Networking/Morse.bas][Morse.bas]]
+
+* Download
+** Getting the source code
+
+Programs author is Svjatoslav Agejenko
+- Homepage: https://svjatoslav.eu (See also [[https://www.svjatoslav.eu/projects/][other software projects]].)
+- Email: mailto://svjatoslav@svjatoslav.eu
+
+*These programs are free software: released under Creative Commons
+Zero (CC0) license.*
+
+- [[https://www2.svjatoslav.eu/gitweb/?p=qbasicapps.git;a=summary][Browse Git repository online]].
+- [[https://www2.svjatoslav.eu/gitweb/?p=qbasicapps.git;a=snapshot;h=HEAD;sf=tgz][Download latest snapshot in TAR GZ format]].
+- You can clone Git repository using git:
+ : git clone https://www3.svjatoslav.eu/git/qbasicapps.git
+
+** Installation and Usage
+
+To run these programs, you can copy them onto computer or virtual
+machine that has Microsoft DOS and QBasic or QuickBasic installed.
+
+Alternatively you can use [[https://www3.svjatoslav.eu/projects/crtbasic/][pure Java BASIC interpreter called CRT
+Basic]].
+
+* See also
+
+- Programs found in the March 1975 3rd printing of David Ahl's 101
+ BASIC Computer Games, published by Digital Equipment Corp:
+ https://github.com/maurymarkowitz/101-BASIC-Computer-Games
+
+- QB64 is a modern extended BASIC programming language that retains
+ QBasic/QuickBASIC 4.5 compatibility and compiles native binaries for
+ Windows, Linux, and macOS: https://qb64.com/