As a coding exercise, I wanted to make use of DRAW statements to get plot points for regular polygons repeated around an axis to create geometric mandalas.
Saturday, June 27, 2026
🪲 Fix in The Works: DRAW statement: Circle Creation: The problem of Asymmetric Pixels
I want to write about a little problem I think I've fixed (in the development version of BASIC Anywhere Machine), and I hope to soon release this fix in a new version of BASIC Anywhere Machine:
🪲 Asymetric pixels in the quadrants or a circle generated with the DRAW statement.
By quadrants, I mean each pie shape created by dividing the top-bottom, and left-right parts of the circle:
By the way, later, keep in mind that from the center coordinate of the circle:
- travelling directly right, that is at an angle of 0 degrees
- travelling directly up, that is at an angle of 90 degrees
- travelling directly left, that is at an angle of 180 degrees
- travelling directly down, that is at an angle of 270 degrees
Here's a little program using DRAW to create a circle on a small-resolution screen:
SCREEN _NEWIMAGE( d% * 2 + 1, d% * 2 + 1, 17)
FOR A% = 0 TO 359 STEP 1
COLOR 63
draw "BM " + d% + "," + d%
DRAW "TA " + A%
DRAW "BU" + (d% - 1)
pset (point(0), point(1)), 61
NEXT A%
The Result:
In each highlighted part of the circle, we find cases where the pixels in the mirror image across the vertical axis, and/or the mirror image across the horizontal axis, do not match.
In the scheme of things, this wouldn't matter in regards to the job of creating circles. The asymmetry is noticeable at low resolutions, but becomes indistinguishable by the naked eye at high resolutions.
However, this does cause some noticeable problems, even at high resolutions, when using this process to create polygons which ought to have one or more perfectly horizontal and/or perfectly vertical sides, like this triangle, for example:
SCREEN _NEWIMAGE( d% * 2, d% * 2, 17)
FOR A% = 0 TO 360 STEP 120
COLOR 63
draw "BM " + d% + "," + d%
DRAW "TA " + A%
DRAW "BU" + (d% - 1)
NEWX% = POINT(0) : NEWY% = POINT(1)
IF A% > 0 THEN COLOR 7 : _
LINE (NEWX%, NEWY%) TO (LASTX%, LASTY%)
LASTX% = NEWX% : LASTY% = NEWY%
NEXT A%
I suspect (without, for lack of interest, researching this thoroughly) that I'm dealing with what might be either a floating point issue, and/or the following, and/or some other related issue(s):
From Google AI's answer to "Using javascript, why would the process of creating a circle of a certain radius not result in symmetric pixels between the quadrants ?":
- Off-Center Origins: If your radius is an even number (e.g., \(r = 10\)), there is no single middle pixel, forcing the circle to round up or down on the grid. This shifts the center, making left/right or up/down sizes unequal. [1]
- Coordinate Truncation: Converting float coordinates to whole pixels (using
Math.round(),Math.floor(), orMath.ceil()) can bias where lines fall on the grid, stretching or shrinking one quadrant over another. [1]- Aspect Ratio: If the canvas CSS scales the element unevenly (e.g., non-square pixels or mismatched
widthandheightsettings), what should be a symmetrical equation acts like an oval, shifting pixel densities per quadrant. [1]- Algorithm Bias: Algorithms like the Midpoint Circle or Bresenham’s often use directional bias (preferring to step horizontally, vertically, or diagonally) to optimize speed. This "step" decision breaks quadrant reflection. [1]
What I've decided to do (I wanted to solve this on my own without looking for already existing solutions):
Modify BAM's implementation of DRAW such that whatever angle is used to draw (using the TA command to set the angle and/or whatever angles needed to perform commands like U,D,R,L = Up,Down,Right,Left) convert that angle to the equivalent between 0 and 90 degree, figure out the X and Y coordinates for the destination pixel, and then negate the value of X and/or Y (if applicable) to get the symmetric point for the originally intended angle.
For your interest, here's the relevant javascript code to figure out the destination pixel:
var xstep = 0;
var ystep = 0;
var tota = (+draw_angle + +a) % 360;
var af = tota;
if (tota > 90 && tota < 180) {af = 180 - tota;}
else if (tota > 180 && tota < 270) {af = tota - 180;}
else if (tota > 270) {af = 360 - tota;}
af = af * Math.PI / 180;
if (tota % 180 === 0) { xstep = n; }
else if (tota % 90 === 0) { ystep = n; }
else {xstep = n * Math.cos(af); ystep = n * Math.sin(af);}
xstep=Math.round(xstep); ystep=Math.round(ystep);
if ((tota % 360 > 90) && (tota % 360 < 270)) { xstep = -xstep; }
if ((tota % 360 < 180)) { ystep = -ystep; }
Step(xstep,ystep);
}
- a is the angle if the pen movement
- tota is the calculated angle of movement
- a would be, for example:
- 0 degrees if the drawing command is Right
- 90 degrees if the drawing command is Up
- 180 degrees if the drawing command is Left
- 270 degrees if the drawing command is Down
- draw_angle would be an angular offset applied with a TA command; for example, an offset of 5 degrees would result in:
- 5 degrees if the drawing command is Right
- 95 degrees if the drawing command is Up
- 185 degrees if the drawing command is Left
- 275 degrees if the drawing command is Down
- af is the tota angle transposed to the first quadrant (between 0 and 90 degrees)
- n is the distance (the number of pixels) travelled from the current pen position to the destination pen position
- xstep and ystep are the relative destination coordinates of the pen based on wherever the pen is currently located when the DRAW statement is performed)
WOOHOO !
If you want to try the BASIC programs above, before the next release of BAM:
- The "production" version of BAM (with the "asymmetric" issue)
- The "development" version of BAM (with the fix)
Sunday, June 21, 2026
📚 How I go about testing a little fix to a DRAW statement bug
EDIT: After this video, I did some more "proof in the pudding" testing of my supposed fix, and discovered that although the fix worked for a triangle of that size, the fix broke the triangle at a size that was working before.
Monday, June 15, 2026
🖥 Circular Meander
About Meanders: read this Wikipedia article.
This program is based on the image shared by bplus in this post (QB64 Phoenix Edition forum).
NOTE: Somebody is insisting (or "some may insist") that the graphic generated by my program is NOT a meander. To me, although the program's process does not draw the pattern in one continuous line, the result is "a decorative border that is a continuous line, shaped into a repeated motif."
This animated program repeatedly draws the same style of meander in an infinite loop, with plot points that are relative to each other, but together varying depending on random screen resolution on every iteration, and random colors.
This is an unstructured program, coded very organically/incrementally without any planning, and without any desire to minimize the amount of code.
Although I originally created the program to generate the graph in one step, I've setup the animation to draw the graph in four steps. This gives a visual idea of how circles are used, and plot points used at specific angles on points of each of the eight circles.
The program has short pauses throughout. At any time, you can click/touch the screen to pause the animation.
Thursday, June 11, 2026
🖥 Golden Ball 1 Crop Circle
Over in the QB64 Phoenix Edition community, bplus (one of their prolific programmers) suggested (in this post) a little programming challenge to recreate the pretty awesome "Golden Ball Hill" crop circles:
In this program, I tackled the formation that interested me the most, but stopped short of the partial doughnut holes in the "half moon" shapes in the formation. For me, the gist of this as a "brain age" kind of exercise involved just getting the fundamental process figured out, and graphing the thing via a simple animation in an infinite loop with random colors:
Monday, June 8, 2026
🖥 Café Wall Illusion
This program is based on the graphic output of a BBC-BASIC-for-SDL program created by Kurt Moerman and shared with the "BASIC Programming Language" Facebook Group. (Although Kurt's post cannot be shared, his code is available on Github here.)
This BAM program:
Wednesday, May 20, 2026
🎉 New version of Blitkrieg Stratagem Chooser
Barely a moment after sharing the program, I decided to immediately tackle a few personal annoyances:
- I decided to let my coding style freak flag fly That involved:
- slight reorganization of the code to fit my tastes, including moving some bode into GOSUB routines
- some "strategic" use of emojis here and there to help me quickly spot certain particular things
- naming conventions for my GOSUB routines (I like to start them with an alphabetic character followed by a three digit number, and an emoji)
- I added the ability to, at any time, copy the current A.I. Turn statistics to the clipboard, which you can then paste anywhere of use
- I figured, if the program is presenting that info, might as well make it possible to "export" that info via the no fuss no muss approach that is making use of the clipboard.
- I pasted sample output at the bottom of this post
- Because I needed different actions when clicking/touching the screen:
- I modified the program to require clicking a defined area of the screen related to getting the stratagem for the A.I. Bot's Next Turn
- I added another defined area of the screen related to sending game statistics to the clipboard
- I reconsidered my use of colors in the bottom half of the screen to keep usage of color to a minimum (as in only for those very important things we really want to highlight)
Statistics:
BigGun: 4CounterAttack: 4EconomicWarfare: 2ForTheGlory: 4RapidDeployment: 3ResearchAndDevelopment: 6Secure: 2SteamRoll: 6Turn Stratagem---- ---------1 CounterAttack2 EconomicWarfare3 ForTheGlory4 BigGun5 SteamRoll (BigGun)6 ResearchAndDevelopment7 ForTheGlory8 EconomicWarfare9 CounterAttack10 Secure11 CounterAttack12 ResearchAndDevelopment13 CounterAttack14 ForTheGlory15 SteamRoll (ForTheGlory)16 RapidDeployment17 SteamRoll (RapidDeployment)18 Secure19 ResearchAndDevelopment20 SteamRoll (ResearchAndDevelopment)21 BigGun22 SteamRoll (BigGun)23 ResearchAndDevelopment24 SteamRoll (ResearchAndDevelopment)25 RapidDeployment
Monday, May 18, 2026
🖥 Blizkrieg Stratagem Chooser
UPDATE: 🎉 New version of Blitkrieg Stratagem Chooser
I really enjoy tabletop games, particularly games that I can play solo: 1-player games, multiplayer games that have official solo rules, and multiplayer tabletop games that have fan-created solo variants.
Right up there among my favourites, you'll find Blitkrieg! World War Two In 20 Minutes (about the game at BGG).
This two-player game is fantastic, and the included solo rules are very well designed.
However, no matter the tabletop game: I do get a little bit annoyed by cumbersome/fiddly and/or time-consuming mechanisms/processes.
With Blitkrieg!, although I'm quite happy to draw "unit tokens" after every turn, I get annoyed with the process of drawing a stratagem token at the start of the A.I. Bot's turn (when playing solo.)
I have no idea why I'm annoyed, and I don't really care. I think: "what am I going to do about it?"
That problem is just a fun programming exercise. Since my heart belongs to the BASIC programming language, then it is BAM to the rescue.
Saturday, May 16, 2026
🖥 Stratagem Icons for Blitzkrieg! World War Two in 20 Minutes
📚 Custom Characters Tool Use Case: 16x16 bit (or 2x2 character) graphics
I'm building some 16x16 bit icons for a program I'd like to create (a randomly generated stratagem chooser for the solo variant of "Blitkrieg! World War Two In 20 Minutes".
To keep things simple, I will be using the Custom Characters Tool to create, for each icon, the four character definitions (in a 2x2 grid of characters) to give me (when the four characters are PRINTed together, a 16x16 pixel icon.
From the board game's documentation, here is the "Big Guns" stratagem token:
Using the Custom Characters Tool, I created each of the 8x8 bit quadrants:
BigGuns1$ = ".......................................................X......XX"
BigGuns2$ = "............X......XXX....XXX....XXXX...XXXX....XXX.....XX......"
BigGuns3$ = ".....XXX......XX.....XXX.....XXX.XXXXXXX........................"
BigGuns4$ = "X.XXX....XXXXX...XXXXX...XXXXX..X.XXX..........................."
SCREEN _NEWIMAGE(100,80,14)
COLOR 63,60
LETCHR$( 1, BigGuns1$ ) : LETCHR$( 2, BigGuns2$ )
PRINT CHR$(1) + CHR$(2)
PRINT CHR$(3) + CHR$(4)
And the 16 bit graphic looks like this:
This is a good enough 16-bit icon for my needs. No fuss, no muss. Rock'n roll !
Friday, May 15, 2026
🪲 Fixed: Custom Characters Tool
At some point, I did something that broke the Custom Characters Tool, and I only noticed the problem tonight a few hours after releasing a new version of BAM.
Seeing as I've fixed the problem, why would I wait to release the fix at any other date/time than now?
BAM provides the ability to assign new custom 8 x 8 characters (defined via simple strings) to ASCII codes. You do this with a LETCHR$ statement. For example:
+ "........" _
+ "..XXXX.." _
+ ".XX XX." _
+ ".XX XX." _
+ "..XXXX.." _
+ "........" _
+ "........")
PRINT CHR$(1);
Use the "Custom Characters" tool to graphically design your custom characters.
Clicking on the menu item will open a "Custom Characters Manager" dialog.
You will see that I'm in the process of creating multiple characters. I want to create some 16x16 bit icons, each icon using 2x2 characters.
Clicking an edit button will open the character editor in a brand new window. (This allows you to edit any number of characters simultaneously, each character in its own character editor window.)
Click a square in the grid to toggle pixels on/off.
As you create your character, you will find templates for the equivalent LETCHR$ statement that creates the same character. (one statement with a horizontal layout, and one statement with a vertical layout.) You can then copy whichever statement you prefer into your program. Just replace the "???" with an ASCII character code you don't mind changing.
🎉 New Version of BASIC Anywhere Machine
EDIT: ARG! Shortly after releasing this new version of BAM, I discovered a problem with the Custom Characters Tool. So I updated the released version of BAM below with the fix described in this follow-up post: 🪲 Fixed: Custom Characters Tool
Although the BAM IDE, as per the TiddlyWiki instance it is, always behaved on touch devices, running BAM programs never behaved correctly with touch devices. (The same applied to programs running from BAM and to programs exported from BAM for running as stand-alone web pages.)
Today's new version of BAM should produce programs that behave well on touchscreen devices.
Well, all works well with my cheapo Android tablet running the Chrome web browser.
Time will tell if all works well on other devices and/or web browsers, and time will tell if anybody reports such problems?
Please note that BAM programs disable multi-touch and double-taps.
- The new version of BASIC Anywhere Machine
- The previous version of BASIC Anywhere Machine
- "issues37" for letting me know touch-handling was not working with BAM programs
- "dbox" for giving me the javascript "preventDefault" tip
Saturday, May 2, 2026
🖥 Animated "100 Doors"
EDIT 2026-05-11: Something was causing this program to not work on mobile devices. I'm guessing I had exported and uploaded the wrong version (an earlier non-working one) of this program. A newly exported version now works (with my tablet, anyway.) (New test version)
This program is an animated version of the "100 Doors" programming task described on the Rosetta Code website.
Other than the tackling the task and enhancing it with some simple animation (to visualize the process), I also wanted to showcase a few features of BAM's BASIC implementation:
- Using expressions in GOSUB statements
- Using emojis to facilitate finding/noticing program sections and identifiers/labels
- Using the IFF function
- Using the BETWEEN function
- Pausing the program with help from the _MOUSEBUTTON function
Thursday, April 30, 2026
📚 A BAM Use-Case: Giving a New Lease on Life to Old BASIC Programs
One BAM's top goals is to make it fairly easy to port old BASIC programs so that they can be shared via the web for running in any web browser.
Is there a better/easier way to keep old gems around for posterity?
Anyway, I just discovered this website by Michael Coorlim via which he shares his refactors and adaptations of type-in listings from the 80's books and magazines. Some of these programs (ones that are not machine-specific) were refactored and adapted for BASIC Anywhere Machine in order to share the running programs.
The list of programs are in the link provided above, with mention of BASIC Anywhere Machine on the About page.
For folk like me who grew up in the age of the home computer revolution, Michael Coorlim's efforts are really cool.
Tuesday, April 28, 2026
🪲 PAINT issue fixed
It's funny how a little extra time can bring about a change of mind, especially when the solution materializes in one's sponge while having a hard time falling asleep...
The issue (and workaround) I described in my previous post, I decided to build that into PAINT's implementation, so it isn't anything we have to think about while programming whatever fun stuff in BASIC.
So, as per the following screenshot, the examples that were not working are now working just fine:
Monday, April 27, 2026
📚 TIP: PAINT: Clearing an area before painting it
Please keep this in mind when using the PAINT statement:
Although painting will not go beyond a pixel coordinate with the specified area edge color, painting will also not go beyond a screen coordinate with the specified paint color.
It is easier to explain and understand the behaviour via some code.
The goal is to create two overlapping circles, and to fill the right-most circle with the same color as the edge color of the left-most circle. So we want code that will create:
The following three snippets of code demonstrate the behaviour of PAINT, as implemented in BASIC Anywhere Machine:
CIRCLE( 40, 20 ), 20, 62
CIRCLE( 82, 20 ), 20, 63
CIRCLE( 102, 20 ), 20, 62
PAINT( 101, 20 ), 63, 62 'paint just left of the edge
CIRCLE( 144, 20 ), 20, 63
CIRCLE( 164, 20 ), 20, 62
PAINT( 165, 20 ), 63, 62 'paint just right of the edge
Saturday, April 25, 2026
🖥 Swirling Circles
This strange animation is the result of me wondering:
- What if I drew circles at each end of a piston, and that piston moved up and down a fixed point on the screen.
- And then made that piston go up and down.
- Then, what if I made the fixed point the center of a circle, and then drew similar pistons at different angles in that circle.
- And then made all the pistons go "up and down".
- And then rotated the circle of pistons around the axis of that circle.
And then I went down the rabbit hole of "what kind of randomness can I add to this thing?"
Friday, April 24, 2026
🎉 New version of BASIC Anywhere Machine
- Discuss: BAM Reddit or BAM Discord or BAM Café
Changes / Enhancements
Summary
- Rename NVL$ to FNEV
- "EVAL" clause removed from GOTO, GOSUB and RESTORE statements
- INPUT now allows expressions as the prompt argument
Details
Rename NVL$ to FNEV
I don't know what I was thinking. "NVL" is a proprietary function name originating from Oracle SQL. I've got no business, I think, calling my function that.
So, I've decided to rename NVL$ (which I was using to mean "No VaLue") to FNEV (First Non-Empty Value).
This function can be used with strings and with numbers. (That's why the function name does not have a "$" suffix.)
For the immediate future, this function accepts two parameters. If the first parameter is not empty ( "" is an empty string; 0 is an empty number), then the first parameter is returned. Otherwise, the second parameter is returned.
Someday, I will change this function to allow more parameters, and set it up so that it returns the first "non-empty" value found.
"EVAL" clause removed from GOTO, GOSUB and RESTORE statements
The EVAL keyword was intended to indicate a parameter that is an expression and not a line identifier/number.
Really, parentheses are enough to indicate an expression is being provided instead of a line identifier/number.
INPUT now allows expressions as the prompt argument
Saturday, April 18, 2026
🖥 Orbs
EDIT 2026-04-19Apparently, there are many "very similar" versions of this program "out there."
I think it would be a stretch to believe that all of these programs ought to be attributed to one person. Anybody, at any time, can have an "original thought" that is completely independent from an identical "original thought" by somebody else in a different place and a different time.When somebody shares a program, I assume it is their original code, and any port/mod of mine will give credit to the author of the source code I ported. I'm not going to spend time investigating the origins of any program I find on the web. (Well, if it is easy for me to give credit to all the shoulders on which I'm standing tall, I'll do that because I do enjoy doing that.)
Some may believe that all programs similar to this one should be attributed to Jan Vibe as author of a similar program written in BBC BASIC. I leave it up to you: credit Jan Vibe for my port/mod if you wish. Regardless, it would seem Jan Vibe made some significant contributions, which you might find worth researching.
This program is a port and mod of a BazzBasic program by EkBass, shared by EkBass via the GotBASIC discord server.
Note that I've setup some random "color randomness" to each drawing cycle loop (which generates a finite number of orbs each loop to create interesting patterns because of small empty spaces with no orbs.)
Friday, April 17, 2026
📚 Some ado about DONOTHING
For whatever reason, the "NOT" keyword has always been a kind of cognitive stick in my wheels.
"IF NOT ... THEN" just annoys the daylight out of me.
So, since I'm maintaining my own version of BASIC, why on earth would I put up with that? Life is too short to put up with irritants.
Hence "DONOTHING".
I've been mocked for adding that statement, and I've received all kinds of suggestions on how to write code in such that I can avoid adding "DONOTHING" to my version of the BASIC programming language.
Pff. I've been hobby-programming for 38 years, and I've been programming professionally for the last 30 years. In that time, I've cranked out enough code to figure out what works for me and what doesn't.
Very likely, I'm the only one who would ever use the statement, and that's fine. It is there for me.
Here's an example of DONOTHING, in a very silly program that shows a few other little nuggets about BAM's BASIC implementation:
LET DoorIsClosed = NOT TRUE
END SUB
SUB CloseTheDoor()
LET DoorIsClosed = TRUE
END SUB
FUNCTION StatusOfDoor$()
StatusOfDoor$ = "The door is " + IFF( DoorIsClosed, "closed.", "open.")
END FUNCTION
SCREEN _NEWIMAGE( 320, 24, 0 )
CALL OpenTheDoor()
PRINT StatusOfDoor$()
SLEEP 1
IF DoorIsClosed THEN DONOTHING ELSE CALL CloseTheDoor()
PRINT StatusOfDoor$()
Oh sure, we would not need DONOTHING if the program had a "DoorIsOpen" perspective. As in "is the door open" instead of "is the door closed?" It all depends on how you like to think of things. For me, I prefer ask a question that has the state I want the door to be in, rather than ask a question with the state I do NOT want the door to be in.
Kind of like "have you taken your medicine?" versus "have you NOT taken your medicine?":
- "Yes"
- "Yes what?"
- "Yes, I have not taken my medicine"
Ugh...
🖥 Geometric Mandalas
As a coding exercise, I wanted to make use of DRAW statements to get plot points for regular polygons repeated around an axis to create geom...
-
EDIT 2026-05-11: Something was causing this program to not work on mobile devices. I'm guessing I had exported and uploaded the wrong v...
-
This program is a port and mod of Steve Justice's program presented in the "Fractals in Focus" article found in the May 1985 i...
-
A port and mod of a program shared by Ardi Ardi with the "BASIC Programming Language" Facebook group via this post . This program ...



