Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
plotting shapes not working
#1
I collected together some basic shape plotting routines (circle, ellipse, semicircle, line, etc.) which plot shapes to a character array and display it on the screen (see attached or code box below).

They all seem to work great sending in fixed values, but when I try random values, in many cases the shapes are not visible when they ought to be. 

For example:

Code Problem
PlotCircleFillTopLeft 38, 11, 4, "#", arrScreen() the rightmost row of the circle is missing
PlotCircleTopLeft 59, 25, 1, "#", arrScreen() shows nothing where the crosshairs indicate the shape should be
PlotEllipse 61, 27, 9, 4, "#", arrScreen() " "
PlotEllipseFill 75, 10, 7, 8, "#", arrScreen() " "
PlotEllipseFillTopLeft 91, 16, 2, 1, "#", arrScreen() " "
PlotSemiCircle 63, 2, 1,1, "#", arrScreen() " "
PlotSemiCircleTopLeft 63, 6, 7,2, "#", arrScreen() " "
PlotLine 66, 13, 97, 18, "#", arrScreen() " "
PlotCircle 62, 8, 1, "#", arrScreen() " "

I have code to make sure the random values keep the shapes within the bounds of the array and screen, so I'm not sure why this would be happening. 

I have been beating my head against the wall with this, and am starting to see stars! 

If anyone can give this a look and help fix problem, that would be great. 

Code: (Select All)
Option _Explicit
$Color:32
' 32-bit color names  = Black Blue Green Cyan Red Magenta Brown White Gray LightBlue LightGreen LightCyan LightRed LightMagenta Yellow BrightWhite
' ================================================================================================================================================================
' BEGIN GLOBAL CONSTANTS
' ================================================================================================================================================================
' SCREEN SIZE
Const cScreenSizeX = 1024 ' 1920 ' 1024
Const cScreenSizeY = 768 ' 1080 ' 768
' Enables or disables debugging
Const cDebugEnabled = _FALSE
' ================================================================================================================================================================
' END GLOBAL CONSTANTS
' ================================================================================================================================================================
' ================================================================================================================================================================
' BEGIN TYPES
' ================================================================================================================================================================
' (none)
' ================================================================================================================================================================
' END TYPES
' ================================================================================================================================================================
' ================================================================================================================================================================
' BEGIN GLOBAL VARIABLES
' ================================================================================================================================================================
' Program info
Dim Shared m_ProgramPath As String: m_ProgramPath = Left$(Command$(0), _InStrRev(Command$(0), "\")) ' executable path
Dim Shared m_ProgramName As String: m_ProgramName = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1) ' executable filename
' For debugging
Dim Shared m_sDebugFile As String: m_sDebugFile = m_ProgramPath + m_ProgramName + ".txt"
' For error trapping
Dim Shared ErrCount&: ErrCount& = 0 ' count errors
Dim Shared LastRoutine$: LastRoutine$ = "" ' routine name we are in
Dim Shared LastCode$: LastCode$ = "" ' where in the code we are (last command attempted)
Dim Shared ErrDesc$: ErrDesc$ = "" ' description of error
Dim Shared LastError$: LastError$ = "" ' last error message
Dim Shared debug$: debug$ = "" ' for debug messages
' Map dimensions
Dim Shared MaxRow As Integer
Dim Shared MaxCol As Integer
' Arrays
ReDim Shared arrScreen(0, 0) As String * 1 ' arrScreen(y, x) = The map array
' ================================================================================================================================================================
' END GLOBAL VARIABLES
' ================================================================================================================================================================
' ================================================================================================================================================================
' BEGIN EXECUTION STARTS HERE
' ================================================================================================================================================================
' LOCAL VARIABLES
Dim in$
' Start the program
Main
' DONE!
End
' ================================================================================================================================================================
' END EXECUTION STARTS HERE
' ================================================================================================================================================================
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN GLOBAL ERROR HANDLER
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ErrorHandler:
'' COUNT THE ERROR
ErrCount& = ErrCount& + 1
' SHOW ERROR + WHERE IN THE PROGRAM WE WERE WHEN ERROR HAPPENED
LastError$ = "Error #" + _ToStr$(Err)
' TRY TO GET ERROR DESCRIPTION
If Err >= 1 And Err <= 1 Then
    ErrDesc$ = "Legacy error: NEXT without FOR"
ElseIf Err >= 8 And Err <= 8 Then
    ErrDesc$ = "Legacy error: Label not defined"
ElseIf Err >= 12 And Err <= 12 Then
    ErrDesc$ = "Legacy error: Illegal in direct mode"
ElseIf Err >= 14 And Err <= 14 Then
    ErrDesc$ = "Legacy error: Out of string space"
ElseIf Err >= 16 And Err <= 16 Then
    ErrDesc$ = "Legacy error: String formula too complex"
ElseIf Err >= 17 And Err <= 17 Then
    ErrDesc$ = "Legacy error: Cannot continue"
ElseIf Err >= 18 And Err <= 18 Then
    ErrDesc$ = "Legacy error: Function not defined"
ElseIf Err >= 19 And Err <= 19 Then
    ErrDesc$ = "Legacy error: No RESUME"
ElseIf Err >= 24 And Err <= 24 Then
    ErrDesc$ = "Legacy error: Device timeout"
ElseIf Err >= 25 And Err <= 25 Then
    ErrDesc$ = "Legacy error: Device fault"
ElseIf Err >= 26 And Err <= 26 Then
    ErrDesc$ = "Legacy error: FOR without NEXT"
ElseIf Err >= 27 And Err <= 27 Then
    ErrDesc$ = "Legacy error: Out of paper"
ElseIf Err >= 29 And Err <= 29 Then
    ErrDesc$ = "Legacy error: WHILE without WEND"
ElseIf Err >= 30 And Err <= 30 Then
    ErrDesc$ = "Legacy error: WEND without WHILE"
ElseIf Err >= 33 And Err <= 33 Then
    ErrDesc$ = "Legacy error: Duplicate label"
ElseIf Err >= 35 And Err <= 35 Then
    ErrDesc$ = "Legacy error: Subprogram not defined"
ElseIf Err >= 37 And Err <= 37 Then
    ErrDesc$ = "Legacy error: Argument-count mismatch"
ElseIf Err >= 38 And Err <= 38 Then
    ErrDesc$ = "Legacy error: Array not defined"
ElseIf Err >= 40 And Err <= 40 Then
    ErrDesc$ = "Legacy error: Variable required"
ElseIf Err >= 56 And Err <= 56 Then
    ErrDesc$ = "Legacy error: FIELD statement active"
ElseIf Err >= 57 And Err <= 57 Then
    ErrDesc$ = "Legacy error: Device I/O error"
ElseIf Err >= 58 And Err <= 58 Then
    ErrDesc$ = "Legacy error: File already exists"
ElseIf Err >= 61 And Err <= 61 Then
    ErrDesc$ = "Legacy error: Disk full"
ElseIf Err >= 67 And Err <= 67 Then
    ErrDesc$ = "Legacy error: Too many files"
ElseIf Err >= 69 And Err <= 69 Then
    ErrDesc$ = "Legacy error: Communication-buffer overflow"
ElseIf Err >= 71 And Err <= 71 Then
    ErrDesc$ = "Legacy error: Disk not ready"
ElseIf Err >= 72 And Err <= 72 Then
    ErrDesc$ = "Legacy error: Disk-media error"
ElseIf Err >= 73 And Err <= 73 Then
    ErrDesc$ = "Legacy error: Feature unavailable"
ElseIf Err >= 74 And Err <= 74 Then
    ErrDesc$ = "Legacy error: Rename across disks"
ElseIf Err >= 11 And Err <= 11 Then
    ErrDesc$ = "Critical error: Division by zero"
ElseIf Err >= 256 And Err <= 256 Then
    ErrDesc$ = "Critical error: Out of stack space"
ElseIf Err >= 257 And Err <= 257 Then
    ErrDesc$ = "Critical error: Out of memory"
ElseIf Err >= 259 And Err <= 259 Then
    ErrDesc$ = "Critical error: Cannot find dynamic library file"
ElseIf Err >= 260 And Err <= 261 Then
    ErrDesc$ = "Critical error: Sub/Function does not exist in dynamic library"
ElseIf Err >= 270 And Err <= 270 Then
    ErrDesc$ = "Critical error: _GL command called outside of SUB _GL's scope"
ElseIf Err >= 271 And Err <= 271 Then
    ErrDesc$ = "Critical error: END/SYSTEM called within SUB _GL's scope"
ElseIf Err >= 300 And Err <= 300 Then
    ErrDesc$ = "Critical error: Memory region out of range"
ElseIf Err >= 301 And Err <= 301 Then
    ErrDesc$ = "Critical error: Invalid size"
ElseIf Err >= 302 And Err <= 302 Then
    ErrDesc$ = "Critical error: Source memory region out of range"
ElseIf Err >= 303 And Err <= 303 Then
    ErrDesc$ = "Critical error: Destination memory region out of range"
ElseIf Err >= 304 And Err <= 304 Then
    ErrDesc$ = "Critical error: Source and destination memory regions out of range"
ElseIf Err >= 305 And Err <= 305 Then
    ErrDesc$ = "Critical error: Source memory has been freed"
ElseIf Err >= 306 And Err <= 306 Then
    ErrDesc$ = "Critical error: Destination memory has been freed"
ElseIf Err >= 307 And Err <= 307 Then
    ErrDesc$ = "Critical error: Memory already freed"
ElseIf Err >= 308 And Err <= 308 Then
    ErrDesc$ = "Critical error: Memory has been freed"
ElseIf Err >= 309 And Err <= 309 Then
    ErrDesc$ = "Critical error: Memory not initialized"
ElseIf Err >= 310 And Err <= 310 Then
    ErrDesc$ = "Critical error: Source memory not initialized"
ElseIf Err >= 311 And Err <= 311 Then
    ErrDesc$ = "Critical error: Destination memory not initialized"
ElseIf Err >= 312 And Err <= 312 Then
    ErrDesc$ = "Critical error: Source and destination memory not initialized"
ElseIf Err >= 313 And Err <= 313 Then
    ErrDesc$ = "Critical error: Source and destination memory have been freed"
ElseIf Err >= 314 And Err <= 314 Then
    ErrDesc$ = "Critical error: _ASSERT failed"
ElseIf Err >= 315 And Err <= 315 Then
    ErrDesc$ = "Critical error: _ASSERT failed (check console for description)"
ElseIf Err >= 502 And Err <= 518 Then
    ErrDesc$ = "Critical error: Out of memory"
ElseIf Err >= 2 And Err <= 2 Then
    ErrDesc$ = "Recoverable error: Syntax error"
ElseIf Err >= 3 And Err <= 3 Then
    ErrDesc$ = "Recoverable error: RETURN without GOSUB"
ElseIf Err >= 4 And Err <= 4 Then
    ErrDesc$ = "Recoverable error: Out of DATA"
ElseIf Err >= 5 And Err <= 5 Then
    ErrDesc$ = "Recoverable error: Illegal function call"
ElseIf Err >= 6 And Err <= 6 Then
    ErrDesc$ = "Recoverable error: Overflow"
ElseIf Err >= 7 And Err <= 7 Then
    ErrDesc$ = "Recoverable error: Out of memory"
ElseIf Err >= 9 And Err <= 9 Then
    ErrDesc$ = "Recoverable error: Subscript out of range"
ElseIf Err >= 10 And Err <= 10 Then
    ErrDesc$ = "Recoverable error: Duplicate definition"
ElseIf Err >= 13 And Err <= 13 Then
    ErrDesc$ = "Recoverable error: Type mismatch"
ElseIf Err >= 20 And Err <= 20 Then
    ErrDesc$ = "Recoverable error: RESUME without error"
ElseIf Err >= 50 And Err <= 50 Then
    ErrDesc$ = "Recoverable error: FIELD overflow"
ElseIf Err >= 51 And Err <= 51 Then
    ErrDesc$ = "Recoverable error: Internal error"
ElseIf Err >= 52 And Err <= 52 Then
    ErrDesc$ = "Recoverable error: Bad file name or number"
ElseIf Err >= 53 And Err <= 53 Then
    ErrDesc$ = "Recoverable error: File not found"
ElseIf Err >= 54 And Err <= 54 Then
    ErrDesc$ = "Recoverable error: Bad file mode"
ElseIf Err >= 55 And Err <= 55 Then
    ErrDesc$ = "Recoverable error: File already open"
ElseIf Err >= 59 And Err <= 59 Then
    ErrDesc$ = "Recoverable error: Bad record length"
ElseIf Err >= 62 And Err <= 62 Then
    ErrDesc$ = "Recoverable error: Input past end of file"
ElseIf Err >= 63 And Err <= 63 Then
    ErrDesc$ = "Recoverable error: Bad record number"
ElseIf Err >= 64 And Err <= 64 Then
    ErrDesc$ = "Recoverable error: Bad file name"
ElseIf Err >= 68 And Err <= 68 Then
    ErrDesc$ = "Recoverable error: Device unavailable"
ElseIf Err >= 70 And Err <= 70 Then
    ErrDesc$ = "Recoverable error: Permission denied"
ElseIf Err >= 75 And Err <= 75 Then
    ErrDesc$ = "Recoverable error: Path/File access error"
ElseIf Err >= 76 And Err <= 76 Then
    ErrDesc$ = "Recoverable error: Path not found"
ElseIf Err >= 258 And Err <= 258 Then
    ErrDesc$ = "Recoverable error: Invalid handle"
Else
    ErrDesc$ = "Unknown error"
End If
LastError$ = LastError$ + " (" + ErrDesc$ + ") " + _
    "in " + LastRoutine$ + " " + _
    "at line " + _ToStr$(_ErrorLine) + " " + _
    ": " + LastCode$
debug$ = _InputBox$(m_ProgramName, "An unrecoverable error occurred (details below). Click OK to exit.", LastError$)
System
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END GLOBAL ERROR HANDLER
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN PLOT SHAPES DEMO
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' /////////////////////////////////////////////////////////////////////////////
' USES GLOBAL VARIABLES:
' ReDim Shared arrScreen(0, 0) As String * 1 ' arrScreen(y, x) = The map array
' AND MAYBE:
' ReDim Shared arrNext(0, 0) As String * 1 ' arrNext(y, x) = Next generation map = Used by cellular automata algorithm:
Sub Main
    Dim RoutineName As String:: RoutineName = "PlotshapesDemo": LastRoutine$ = RoutineName
    'ReDim arrScreen(-1, -1) As String
    Dim in$
    Dim X As Integer
    Dim Y As Integer
    Dim R As Integer
    Dim S As String
    Dim XC As Integer
    Dim YC As Integer
    Dim xRadius As Integer
    Dim yRadius As Integer
    Dim Q As Integer
    Dim L As Integer
    Dim MinX As Integer
    Dim MaxX As Integer
    Dim MinY As Integer
    Dim MaxY As Integer
    Dim x1 As Integer
    Dim x2 As Integer
    Dim y1 As Integer
    Dim y2 As Integer
    Dim iCount As Integer
    Dim sNextFunction As String
    Dim sNextParams As String
    Dim GuideX1 As Integer
    Dim GuideY1 As Integer
    Dim GuideX2 As Integer
    Dim GuideY2 As Integer
    Dim bRandomValues As Integer
   
    On Error GoTo ErrorHandler
    ' Initialize screen + get dimensions
    Screen _NewImage(cScreenSizeX, cScreenSizeY, 32)
    _ScreenMove 0, 0
    MaxRow = _Height / _FontHeight
    MaxCol = _Width / _FontWidth
    ' Define map boundaries
    ReDim arrScreen(0 To MaxRow, 0 To MaxCol) As String * 1
   
    ' Initialize
    MinY = 0
    MaxY = MaxRow - 3
    MinX = 0
    MaxX = MaxCol
    S = "#"
    bRandomValues = _FALSE
   
    ' Get first choice
    Cls , Black
    Color Black, Cyan:
    Locate MaxRow - 2, 5
    Input "Enter R to continue with random values, F for fixed values or Q to quit"; in$
    in$ = _Trim$(UCase$(in$)): If in$ = "Q" Then Exit Sub
    If in$ = "R" Then
        bRandomValues = _TRUE
    Else
        bRandomValues = _FALSE
    End If
   
    ' Plot shapes
    iCount = 0
    Do
        iCount = iCount + 1
       
        ' CLEAR DISPLAY ARRAY
        For Y = LBound(arrScreen, 1) To UBound(arrScreen, 1)
            For X = LBound(arrScreen, 2) To UBound(arrScreen, 2)
                arrScreen(Y, X) = " "
            Next X
        Next Y
       
        Select Case iCount
            Case 1:
                If bRandomValues = _TRUE Then
                    R = RandomNumber%(1, 10)
                    ' FIX: Center (X, Y) must be at least R away from the screen edges
                    X = RandomNumber%(MinX + R, MaxX - R)
                    Y = RandomNumber%(MinY + R, MaxY - R)
                Else
                    R = 5
                    X = 10
                    Y = 15
                End If
                GuideX1 = X: GuideY1 = Y: GuideX2 = MinX - 1: GuideY2 = MinY - 1
                sNextFunction = "PlotCircle X, Y, R, S, arrScreen()"
                sNextParams = "PlotCircle " + _ToStr$(X) + ", " + _ToStr$(Y) + ", " + _ToStr$(R) + ", " + Chr$(34) + S + Chr$(34) + ", " + "arrScreen()"
                PlotCircle X, Y, R, S, arrScreen()
               
            Case 2:
                If bRandomValues = _TRUE Then
                    R = RandomNumber%(1, 10)
                    ' FIX: Top-Left corner (X, Y) must be at least 2*R away from MaxX/MaxY
                    X = RandomNumber%(MinX, MaxX - 2 * R)
                    Y = RandomNumber%(MinY, MaxY - 2 * R)
                Else
                    R = 5
                    X = 10
                    Y = 15
                End If
                GuideX1 = X: GuideY1 = Y: GuideX2 = MinX - 1: GuideY2 = MinY - 1
                sNextFunction = "PlotCircleTopLeft X, Y, R, S, arrScreen()"
                sNextParams = "PlotCircleTopLeft " + _ToStr$(X) + ", " + _ToStr$(Y) + ", " + _ToStr$(R) + ", " + Chr$(34) + S + Chr$(34) + ", " + "arrScreen()"
                PlotCircleTopLeft X, Y, R, S, arrScreen()
               
            Case 3:
                If bRandomValues = _TRUE Then
                    R = RandomNumber%(1, 10)
                    ' FIX: Center (XC, YC) must be at least R away from the screen edges
                    XC = RandomNumber%(MinX + R, MaxX - R)
                    YC = RandomNumber%(MinY + R, MaxY - R)
                Else
                    R = 5
                    XC = 10
                    YC = 15
                End If
                GuideX1 = XC: GuideY1 = YC: GuideX2 = MinX - 1: GuideY2 = MinY - 1
                sNextFunction = "PlotCircleFill XC, YC, R, S, arrScreen()"
                sNextParams = "PlotCircleFill " + _ToStr$(XC) + ", " + _ToStr$(YC) + ", " + _ToStr$(R) + ", " + Chr$(34) + S + Chr$(34) + ", " + "arrScreen()"
                PlotCircleFill XC, YC, R, S, arrScreen()
               
            Case 4:
                If bRandomValues = _TRUE Then
                    R = RandomNumber%(1, 10)
                    ' FIX: Top-Left corner (XC, YC) must be at least 2*R away from MaxX/MaxY
                    XC = RandomNumber%(MinX, MaxX - 2 * R)
                    YC = RandomNumber%(MinY, MaxY - 2 * R)
                Else
                    R = 5
                    XC = 10
                    YC = 15
                End If
                GuideX1 = XC: GuideY1 = YC: GuideX2 = MinX - 1: GuideY2 = MinY - 1
                sNextFunction = "PlotCircleFillTopLeft XC, YC, R, S, arrScreen()"
                sNextParams = "PlotCircleFillTopLeft " + _ToStr$(XC) + ", " + _ToStr$(YC) + ", " + _ToStr$(R) + ", " + Chr$(34) + S + Chr$(34) + ", " + "arrScreen()"
                PlotCircleFillTopLeft XC, YC, R, S, arrScreen()
               
            Case 5:
                If bRandomValues = _TRUE Then
                    xRadius = RandomNumber%(1, 10)
                    yRadius = RandomNumber%(1, 10)
                    ' FIX: Center (XC, YC) must be at least xRadius/yRadius away from screen edges
                    XC = RandomNumber%(MinX + xRadius, MaxX - xRadius)
                    YC = RandomNumber%(MinY + yRadius, MaxY - yRadius)
                Else
                    xRadius = 5
                    yRadius = 8
                    XC = 10
                    YC = 15
                End If
                GuideX1 = XC: GuideY1 = YC: GuideX2 = MinX - 1: GuideY2 = MinY - 1
                sNextFunction = "PlotEllipse XC, YC, xRadius, yRadius, S, arrScreen()"
                sNextParams = "PlotEllipse " + _ToStr$(XC) + ", " + _ToStr$(YC) + ", " + _ToStr$(xRadius) + ", " + _ToStr$(yRadius) + ", " + Chr$(34) + S + Chr$(34) + ", " + "arrScreen()"
                PlotEllipse XC, YC, xRadius, yRadius, S, arrScreen()
               
            Case 6:
                If bRandomValues = _TRUE Then
                    xRadius = RandomNumber%(1, 10)
                    yRadius = RandomNumber%(1, 10)
                    ' FIX: Top-Left corner (X, Y) must be at least 2*xRadius/2*yRadius away from MaxX/MaxY
                    X = RandomNumber%(MinX, MaxX - 2 * xRadius)
                    Y = RandomNumber%(MinY, MaxY - 2 * yRadius)
                Else
                    xRadius = 5
                    yRadius = 8
                    X = 10
                    Y = 15
                End If
                GuideX1 = X: GuideY1 = Y: GuideX2 = MinX - 1: GuideY2 = MinY - 1
                sNextFunction = "PlotEllipseTopLeft X, Y, xRadius, yRadius, S, arrScreen()"
                sNextParams = "PlotEllipseTopLeft " + _ToStr$(X) + ", " + _ToStr$(Y) + ", " + _ToStr$(xRadius) + ", " + _ToStr$(yRadius) + ", " + Chr$(34) + S + Chr$(34) + ", " + "arrScreen()"
                PlotEllipseTopLeft X, Y, xRadius, yRadius, S, arrScreen()
               
            Case 7:
                If bRandomValues = _TRUE Then
                    xRadius = RandomNumber%(1, 10)
                    yRadius = RandomNumber%(1, 10)
                    ' FIX: Center (XC, YC) must be at least xRadius/yRadius away from screen edges
                    XC = RandomNumber%(MinX + xRadius, MaxX - xRadius)
                    YC = RandomNumber%(MinY + yRadius, MaxY - yRadius)
                Else
                    xRadius = 5
                    yRadius = 8
                    XC = 10
                    YC = 15
                End If
                GuideX1 = XC: GuideY1 = YC: GuideX2 = MinX - 1: GuideY2 = MinY - 1
                sNextFunction = "PlotEllipseFill XC, YC, xRadius, yRadius, S, arrScreen()"
                sNextParams = "PlotEllipseFill " + _ToStr$(XC) + ", " + _ToStr$(YC) + ", " + _ToStr$(xRadius) + ", " + _ToStr$(yRadius) + ", " + Chr$(34) + S + Chr$(34) + ", " + "arrScreen()"
                PlotEllipseFill XC, YC, xRadius, yRadius, S, arrScreen()
               
            Case 8:
                If bRandomValues = _TRUE Then
                    xRadius = RandomNumber%(1, 10)
                    yRadius = RandomNumber%(1, 10)
                    ' FIX: Top-Left corner (X, Y) must be at least 2*xRadius/2*yRadius away from MaxX/MaxY
                    X = RandomNumber%(MinX, MaxX - 2 * xRadius)
                    Y = RandomNumber%(MinY, MaxY - 2 * yRadius)
                Else
                    xRadius = 5
                    yRadius = 8
                    X = 10
                    Y = 15
                End If
                GuideX1 = X: GuideY1 = Y: GuideX2 = MinX - 1: GuideY2 = MinY - 1
                sNextFunction = "PlotEllipseFillTopLeft X, Y, xRadius, yRadius, S, arrScreen()"
                sNextParams = "PlotEllipseFillTopLeft " + _ToStr$(X) + ", " + _ToStr$(Y) + ", " + _ToStr$(xRadius) + ", " + _ToStr$(yRadius) + ", " + Chr$(34) + S + Chr$(34) + ", " + "arrScreen()"
                PlotEllipseFillTopLeft X, Y, xRadius, yRadius, S, arrScreen()
               
            Case 9:
                If bRandomValues = _TRUE Then
                    R = RandomNumber%(1, 10)
                    ' FIX: Center (XC, YC) must be at least R away from the screen edges
                    XC = RandomNumber%(MinX + R, MaxX - R)
                    YC = RandomNumber%(MinY + R, MaxY - R)
                    Q = RandomNumber%(1, 4) ' 1=top right, 2=bottom right, 3=bottom left, 4=top left
                Else
                    R = 8
                    XC = 10
                    YC = 12
                    Q = 3
                End If
                GuideX1 = XC: GuideY1 = YC: GuideX2 = MinX - 1: GuideY2 = MinY - 1
                sNextFunction = "PlotSemiCircle XC, YC, R, Q, S, arrScreen()"
                sNextParams = "PlotSemiCircle " + _ToStr$(XC) + ", " + _ToStr$(YC) + ", " + _ToStr$(R) + ", " + _ToStr$(Q) + ", " + Chr$(34) + S + Chr$(34) + ", " + "arrScreen()"
                PlotSemiCircle XC, YC, R, Q, S, arrScreen()
               
            Case 10:
                If bRandomValues = _TRUE Then
                    R = RandomNumber%(1, 10)
                    ' FIX: Top-Left corner (X, Y) must be at least 2*R away from MaxX/MaxY
                    X = RandomNumber%(MinX, MaxX - 2 * R)
                    Y = RandomNumber%(MinY, MaxY - 2 * R)
                    Q = RandomNumber%(1, 4) ' 1=top right, 2=bottom right, 3=bottom left, 4=top left
                Else
                    R = 8
                    X = 10
                    Y = 12
                    Q = 3
                End If
                GuideX1 = X: GuideY1 = Y: GuideX2 = MinX - 1: GuideY2 = MinY - 1
                sNextFunction = "PlotSemicircleTopLeft X, Y, R, Q, S, arrScreen()"
                sNextParams = "PlotSemicircleTopLeft " + _ToStr$(X) + ", " + _ToStr$(Y) + ", " + _ToStr$(R) + ", " + _ToStr$(Q) + ", " + Chr$(34) + S + Chr$(34) + ", " + "arrScreen()"
                PlotSemicircleTopLeft X, Y, R, Q, S, arrScreen()
            Case 11:
                If bRandomValues = _TRUE Then
                    R = RandomNumber%(1, 10)
                    ' FIX: Center (XC, YC) must be at least R away from the screen edges
                    XC = RandomNumber%(MinX + R, MaxX - R)
                    YC = RandomNumber%(MinY + R, MaxY - R)
                    Q = RandomNumber%(1, 4) ' 1=top right, 2=bottom right, 3=bottom left, 4=top left
                Else
                    R = 8
                    XC = 10
                    YC = 12
                    Q = 3
                End If
                GuideX1 = XC: GuideY1 = YC: GuideX2 = MinX - 1: GuideY2 = MinY - 1
                sNextFunction = "PlotSemiCircleFill XC, YC, R, Q, S, arrScreen()"
                sNextParams = "PlotSemiCircleFill " + _ToStr$(XC) + ", " + _ToStr$(YC) + ", " + _ToStr$(R) + ", " + _ToStr$(Q) + ", " + Chr$(34) + S + Chr$(34) + ", " + "arrScreen()"
                PlotSemiCircleFill XC, YC, R, Q, S, arrScreen()
               
            Case 12:
                If bRandomValues = _TRUE Then
                    R = RandomNumber%(1, 10)
                    ' FIX: Top-Left corner (X, Y) must be at least 2*R away from MaxX/MaxY
                    X = RandomNumber%(MinX, MaxX - 2 * R)
                    Y = RandomNumber%(MinY, MaxY - 2 * R)
                    Q = RandomNumber%(1, 4) ' 1=top right, 2=bottom right, 3=bottom left, 4=top left
                Else
                    R = 8
                    X = 10
                    Y = 12
                    Q = 3
                End If
                GuideX1 = X: GuideY1 = Y: GuideX2 = MinX - 1: GuideY2 = MinY - 1
                sNextFunction = "PlotSemiCircleFillTopLeft X, Y, R, Q, S, arrScreen()"
                sNextParams = "PlotSemiCircleFillTopLeft " + _ToStr$(X) + ", " + _ToStr$(Y) + ", " + _ToStr$(R) + ", " + _ToStr$(Q) + ", " + Chr$(34) + S + Chr$(34) + ", " + "arrScreen()"
                PlotSemiCircleFillTopLeft X, Y, R, Q, S, arrScreen()
               
            Case 13:
                If bRandomValues = _TRUE Then
                    L = RandomNumber%(1, 10)
                    ' FIX: Top-Left corner (X, Y) must be at least L away from MaxX/MaxY
                    X = RandomNumber%(MinX, MaxX - L)
                    Y = RandomNumber%(MinY, MaxY - L)
                Else
                    X = 5
                    Y = 3
                    L = 4
                End If
                GuideX1 = X: GuideY1 = Y: GuideX2 = MinX - 1: GuideY2 = MinY - 1
                sNextFunction = "PlotSquare X, Y, L, S, arrScreen()"
                sNextParams = "PlotSquare " + _ToStr$(X) + ", " + _ToStr$(Y) + ", " + _ToStr$(L) + ", " + Chr$(34) + S + Chr$(34) + ", " + "arrScreen()"
                PlotSquare X, Y, L, S, arrScreen()
               
            Case Else:
                If bRandomValues = _TRUE Then
                    ' Line endpoints are already within the boundary Min/Max X/Y. No change needed.
                    y1 = RandomNumber%(MinY, MaxY): y2 = y1
                    x1 = RandomNumber%(MinX, MaxX): x2 = x1
                    Do
                        y2 = RandomNumber%(MinY, MaxY)
                        x2 = RandomNumber%(MinX, MaxX)
                    Loop Until y2 <> y1 Or x2 <> x1
                Else
                    x1 = 3
                    y1 = 5
                    x2 = 6
                    y2 = 9
                End If
                GuideX1 = x1: GuideY1 = y1: GuideX2 = x2: GuideY2 = y2
                sNextFunction = "PlotLine x1, y1, x2, y2, S, arrScreen()"
                sNextParams = "PlotLine " + _ToStr$(x1) + ", " + _ToStr$(y1) + ", " + _ToStr$(x2) + ", " + _ToStr$(y2) + ", " + Chr$(34) + S + Chr$(34) + ", " + "arrScreen()"
                PlotLine x1, y1, x2, y2, S, arrScreen()
               
                iCount = 0
        End Select
        ' REFRESH DISPLAY
        PlotShapesPrintScreen GuideY1, GuideX1, GuideY2, GuideX2
        ' SHOW VALUES AND PROMPT USER TO TOGGLE RANDOM OR
        Color Black, Cyan:
       
        Locate MaxRow - 5, 5
        Print "Generated with " + _IIf(bRandomValues, "random", "fixed") + " values";
   
        Locate MaxRow - 4, 5
        Print sNextFunction;
   
        Locate MaxRow - 3, 5
        Print sNextParams;
   
        Locate MaxRow - 2, 5
       
        If bRandomValues = _TRUE Then
            Input "Enter R to continue with random values, F for change to fixed values, or Q to quit"; in$
        Else
            Input "Enter R to change to random values, F for continue with fixed values, or Q to quit"; in$
        End If
        in$ = _Trim$(UCase$(in$))
        If in$ = "R" Then
            bRandomValues = _TRUE
        ElseIf in$ = "F" Then
            bRandomValues = _FALSE
        ElseIf in$ = "Q" Then
            Exit Do
        Else
            '(UNCHANGED)
        End If
    Loop
End Sub ' PlotshapesDemo
' /////////////////////////////////////////////////////////////////////////////
' Requires the following populated global variable:
'   Dim Shared MaxRow As Integer
'   Dim Shared MaxCol As Integer
'   ReDim Shared arrScreen(0 To MaxRow, 0 To MaxCol) As String * 1
' Receives GuideY, GuideX
' draws a horizontal line at Y = GuideY
' and a vertical line at X = GuideX
' as a visual guide to line up where we expect the shape to be
Sub PlotShapesPrintScreen (iGuideY1 As Integer, iGuideX1 As Integer, iGuideY2 As Integer, iGuideX2 As Integer)
    Dim RoutineName As String:: RoutineName = "PlotShapesPrintScreen": LastRoutine$ = RoutineName
    Dim OffsetX As Integer
    Dim OffsetY As Integer
    Dim iX As Integer
    Dim iY As Integer
    Dim sValue As String
    Dim sNext As String
    Dim ToX As Integer
    Dim ToY As Integer
    Dim fg As _Unsigned Long
    Dim bg As _Unsigned Long
    Dim GuideY1 As Integer
    Dim GuideX1 As Integer
    Dim GuideY2 As Integer
    Dim GuideX2 As Integer
    Dim r As Integer
    Dim g As Integer
    Dim b As Integer
    ReDim arrDisplay(0 To MaxRow, 0 To MaxCol) As String * 1
   
    On Error GoTo ErrorHandler
   
    ' ADJUST GUIDELINES PER OFFSET FOR X AND Y COORDINATE NUMBERS
    OffsetX = 3
    OffsetY = 3
    GuideY1 = iGuideY1 + OffsetY
    GuideX1 = iGuideX1 + OffsetX
    GuideY2 = iGuideY2 + OffsetY
    GuideX2 = iGuideX2 + OffsetX
   
    ' CLEAR DISPLAY ARRAY
    For iY = LBound(arrDisplay, 1) To UBound(arrDisplay, 1)
        For iX = LBound(arrDisplay, 2) To UBound(arrDisplay, 2)
            arrDisplay(iY, iX) = " "
        Next iX
    Next iY
    ' ADD Y COORDINATE NUMBERS ALONG LEFT EDGE
    iX = LBound(arrDisplay, 2)
    For iY = LBound(arrDisplay, 1) To (UBound(arrDisplay, 1) - OffsetY)
        sValue = PadLeft$(_ToStr$(iY), 3)
        arrDisplay(iY + OffsetY, iX + 0) = Mid$(sValue, 1, 1)
        arrDisplay(iY + OffsetY, iX + 1) = Mid$(sValue, 2, 1)
        arrDisplay(iY + OffsetY, iX + 2) = Mid$(sValue, 3, 1)
    Next iY
   
    ' ADD X COORDINATE NUMBERS ALONG TOP EDGE
    iY = LBound(arrDisplay, 1)
    For iX = LBound(arrDisplay, 2) To (UBound(arrDisplay, 2) - OffsetX)
        sValue = PadLeft$(_ToStr$(iX), 3)
        arrDisplay(iY + 0, iX + OffsetX) = Mid$(sValue, 1, 1)
        arrDisplay(iY + 1, iX + OffsetX) = Mid$(sValue, 2, 1)
        arrDisplay(iY + 2, iX + OffsetX) = Mid$(sValue, 3, 1)
    Next iX
   
    'if _TRUE=_FALSE then
    ' COPY OVER SHAPES (SHIFTED DOWN+RIGHT 3, TO SEE COORDINATE NUMBERS)
    For iY = LBound(arrScreen, 2) To UBound(arrScreen, 2) - OffsetY
        For iX = LBound(arrScreen, 1) To UBound(arrScreen, 1) - OffsetX
            ToY = iY + OffsetY
            ToX = iX + OffsetX
            if ToY >= lbound(arrDisplay, 1) _
                _ANDALSO ToY <= ubound(arrDisplay, 1) _
                _ANDALSO ToX >= lbound(arrDisplay, 2) _
                _ANDALSO ToX <= ubound(arrDisplay, 2) _
            Then
                arrDisplay(ToY, ToX) = arrScreen(iY, iX)
            End If
        Next iX
    Next iY
    'end if
   
    ' PRINT SHAPES
    ' 32-bit color names  = Black Blue Green Cyan Red Magenta Brown White Gray LightBlue LightGreen LightCyan LightRed LightMagenta Yellow BrightWhite
    Cls , Black
    For iY = LBound(arrDisplay, 1) To UBound(arrDisplay, 1)
        For iX = LBound(arrDisplay, 2) To UBound(arrDisplay, 2)
           
            ' Alternate bg color for rows/columns
            If IsEven%(iY) _AndAlso IsEven%(iX) Then
                bg = _RGB32(0, 0, 96)
            ElseIf IsOdd%(iY) _AndAlso IsEven%(iX) Then
                bg = _RGB32(0, 96, 0)
            ElseIf IsEven%(iY) _AndAlso IsOdd%(iX) Then
                bg = _RGB32(0, 0, 160)
            Else
                bg = _RGB32(0, 160, 0)
            End If
           
            ' Override bg color if it is along one of the guide lines
            If iY = GuideY1 Then
                bg = _RGB32(192, 192, 0)
            ElseIf iY = GuideY2 Then
                bg = _RGB32(192, 0, 192)
            End If
            If iX = GuideX1 Then
                bg = _RGB32(192, 192, 0)
            ElseIf iX = GuideX2 Then
                bg = _RGB32(192, 0, 192)
            End If
           
            ' Set color for plotted points, text
            sNext = arrDisplay(iY, iX)
            Select Case sNext
                Case "#":
                    ' Color for next plotted point
                    fg = _RGB32(0, 0, 0)
                   
                    ' Set bg color to inverse of current bg color
                    r = _Red32(bg): g = _Green32(bg): b = _Blue32(bg)
                    bg = _RGB32(255 - r, 255 - g, 255 - b)
                Case Else
                    ' Assume all else = text
                    fg = _RGB32(255, 255, 255)
            End Select
           
            ' Plot next character / point
            Color fg, bg
            _PrintString (iX * _FontWidth, iY * _FontHeight), arrDisplay(iY, iX)
        Next iX
    Next iY
   
End Sub ' PlotShapesPrintScreen
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END PLOT SHAPES DEMO
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN 2D SHAPE PLOTTING FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' /////////////////////////////////////////////////////////////////////////////
' More on plotting circles:
'     Fast circle drawing in pure Atari BASIC#
'     https://atariwiki.org/wiki/Wiki.jsp?page=Super%20fast%20circle%20routine
'
'     Drawing a circle in BASIC - fast
'     https://www.cpcwiki.eu/forum/programming/drawing-a-circle-in-basic-fast/
' XC,YC   = center point of circle
' R       = radius
' S       = char to draw
' MyArray = 2D string array to plot circle in
Sub PlotCircle (XC As Integer, YC As Integer, R As Integer, S As String, MyArray() As String * 1)
    Dim RoutineName As String:: RoutineName = "PlotCircle": LastRoutine$ = RoutineName
    Print "PlotCircle XC=" + _ToStr$(XC) + ", YC=" + _ToStr$(YC) + ", R=" + _ToStr$(R) + ", S=" + Chr$(34) + S + Chr$(34) + ", MyArray()"
    Dim A As Integer
    Dim B As Integer
    Dim C As Integer
    Dim S2 As String
    On Error GoTo ErrorHandler
    If Len(S) = 1 Then
        S2 = S
    Else
        If Len(S) = 0 Then
            S2 = " "
        Else
            S2 = Left$(S, 1)
        End If
    End If
    ' Handle R=1 explicitly to ensure visibility
    If R = 1 Then
        PlotPoint XC, YC, S, MyArray()
        PlotPoint XC + 1, YC, S, MyArray()
        PlotPoint XC - 1, YC, S, MyArray()
        PlotPoint XC, YC + 1, S, MyArray()
        PlotPoint XC, YC - 1, S, MyArray()
        Exit Sub
    End If
   
    If R > 0 Then
        B = R
        C = 0
        A = R - 1
        Do
            PlotPoint YC + B, XC + C, S2, MyArray()
            PlotPoint YC - B, XC + C, S2, MyArray()
            PlotPoint YC - B, XC - C, S2, MyArray()
            PlotPoint YC + B, XC - C, S2, MyArray()
            PlotPoint YC + C, XC + B, S2, MyArray()
            PlotPoint YC - C, XC + B, S2, MyArray()
            PlotPoint YC - C, XC - B, S2, MyArray()
            PlotPoint YC + C, XC - B, S2, MyArray()
           
            LastCode$ = "C = C + 1, etc."
            C = C + 1
            A = A + 1 - C - C
            If A < 0 Then
                B = B - 1
                A = A + B + B
            End If
            If B < C Then Exit Do
        Loop
    End If
   
    LastCode$ = ""
End Sub ' PlotCircle
' /////////////////////////////////////////////////////////////////////////////
' Circle plotting wrapper (Top-Left corner input)
Sub PlotCircleTopLeft (X As Integer, Y As Integer, R As Integer, S As String, MyArray() As String * 1)
    PlotCircle X + R, Y + R, R, S, MyArray()
End Sub ' PlotCircleTopLeft
' /////////////////////////////////////////////////////////////////////////////
' Re: Is this fast enough as general circle fill?
' https://forum.qb64.org/index.php?topic=298.msg1913#msg1913
' From: SMcNeill
' Date: « Reply #30 on: June 26, 2018, 03:34:18 pm »
'
' Sometimes, computers do things that are completely counter-intuitive to us, and
' we find ourselves having to step back as programmers and simply say, "WOW!!"
' Here's a perfect example of that:
' Here we look at two different circle fill routines -- one, which I'd assume to
' be faster, which precalculates the offset needed to find the endpoints for each
' line which composes a circle, and another, which is the same old CircleFill
' program which I've shared countless times over the years with people on various
' QB64 forums.
'
' When all is said and done though, CircleFill is STILL even faster than
' CircleFillFast, which pregenerates those end-points for us!
' XC,YC     = center point of circle
' R         = radius
' S         = char to draw
' MyArray = 2D string array to plot circle in
Sub PlotCircleFill (XC As Integer, YC As Integer, R1 As Integer, S As String, MyArray() As String * 1)
    Dim RoutineName As String:: RoutineName = "PlotCircleFill": LastRoutine$ = RoutineName
   
    Print "PlotCircleFill XC=" + _ToStr$(XC) + ", YC=" + _ToStr$(YC) + ", R1=" + _ToStr$(R1) + ", S=" + Chr$(34) + S + Chr$(34) + ", MyArray()"
    Dim R As Integer
    Dim RadiusError As Integer
    Dim X As Integer
    Dim Y As Integer
    Dim iLoopX As Integer
    Dim iLoopY As Integer
   
    On Error GoTo ErrorHandler
   
    R = Abs(R1)
    RadiusError = -R
    X = R
    Y = 0
   
    If R = 0 Then
        'PSET (XC, YC), C
        Exit Sub
    ElseIf R = 1 Then
        ' Plot Center
        PlotPoint XC, YC, S, MyArray()
        ' Plot 4 Axial Points
        PlotPoint XC + 1, YC, S, MyArray()
        PlotPoint XC - 1, YC, S, MyArray()
        PlotPoint XC, YC + 1, S, MyArray()
        PlotPoint XC, YC - 1, S, MyArray()
        Exit Sub
    End If
   
    ' Draw the middle span here so we don't draw it twice in the main loop,
    ' which would be a problem with blending turned on.
    'LINE (XC - X, YC)-(XC + X, YC), C, BF
    For iLoopX = XC - X To XC + X
        PlotPoint YC, iLoopX, S, MyArray()
    Next iLoopX
   
    While X > Y
        RadiusError = RadiusError + Y * 2 + 1
        If RadiusError >= 0 Then
            If X <> Y + 1 Then
                'LINE (XC - Y, YC - X)-(XC + Y, YC - X), C, BF
                iLoopY = YC - X
                For iLoopX = XC - Y To XC + Y
                    PlotPoint iLoopY, iLoopX, S, MyArray()
                Next iLoopX
               
                'LINE (XC - Y, YC + X)-(XC + Y, YC + X), C, BF
                iLoopY = YC + X
                For iLoopX = XC - Y To XC + Y
                    PlotPoint iLoopY, iLoopX, S, MyArray()
                Next iLoopX
            End If
            X = X - 1
            RadiusError = RadiusError - X * 2
        End If
       
        Y = Y + 1
        'LINE (XC - X, YC - Y)-(XC + X, YC - Y), C, BF
        iLoopY = YC - Y
        For iLoopX = XC - X To XC + X
            PlotPoint iLoopY, iLoopX, S, MyArray()
        Next iLoopX
       
        'LINE (XC - X, YC + Y)-(XC + X, YC + Y), C, BF
        iLoopY = YC + Y
        For iLoopX = XC - X To XC + X
            PlotPoint iLoopY, iLoopX, S, MyArray()
        Next iLoopX
    Wend
End Sub ' PlotCircleFill
' /////////////////////////////////////////////////////////////////////////////
' Filled Circle plotting wrapper (Top-Left corner input)
Sub PlotCircleFillTopLeft (X As Integer, Y As Integer, R As Integer, S As String, MyArray() As String * 1)
    PlotCircleFill X + R, Y + R, R, S, MyArray()
End Sub ' PlotCircleFillTopLeft
' /////////////////////////////////////////////////////////////////////////////
' Based on CircleFill and PlotCircleTopLeft.
' XC,YC     = top left point of circle
' R         = radius
' S         = char to draw
' MyArray = 2D string array to plot circle in
Sub PlotCircleFillTopLeft_v1 (XC As Integer, YC As Integer, R As Integer, S As String, MyArray() As String * 1)
    Dim RoutineName As String:: RoutineName = "PlotCircleFillTopLeft": LastRoutine$ = RoutineName
   
    Print "PlotCircleFillTopLeft XC=" + _ToStr$(XC) + ", YC=" + _ToStr$(YC) + ", R=" + _ToStr$(R) + ", S=" + Chr$(34) + S + Chr$(34) + ", MyArray()"
   
    Dim Radius As Integer
    Dim RadiusError As Integer
    Dim X As Integer
    Dim Y As Integer
    Dim iLoopX As Integer
    Dim iLoopY As Integer
    ReDim arrTemp(0, 0) As String * 1
    Dim DY As Integer
    Dim DX As Integer
    Dim W As Integer
    Dim TX As Integer
    Dim TY As Integer
    Dim MinY As Integer
    Dim MaxY As Integer
    Dim MinX As Integer
    Dim MaxX As Integer
   
    On Error GoTo ErrorHandler
   
    Radius = Abs(R)
    RadiusError = -Radius
    X = Radius
    Y = 0
   
    If Radius = 0 Then
        'PSET (XC, YC), C
        Exit Sub
    End If
    ' Get total width
    W = (Radius * 2) + 1
    ' Define a temp array
    ReDim arrTemp(0 To W, 0 To W) As String * 1
    ' Get minimum X, Y of target array
    MinY = LBound(MyArray, 1)
    MaxY = UBound(MyArray, 1)
    MinX = LBound(MyArray, 2)
    MaxX = UBound(MyArray, 2)
    ' Draw the middle span here so we don't draw it twice in the main loop,
    ' which would be a problem with blending turned on.
    'LINE (XC - X, YC)-(XC + X, YC), C, BF
    For iLoopX = R - X To R + X
        PlotPoint R, iLoopX, S, arrTemp()
    Next iLoopX
    While X > Y
        RadiusError = RadiusError + Y * 2 + 1
        If RadiusError >= 0 Then
            If X <> Y + 1 Then
                'LINE (XC - Y, YC - X)-(XC + Y, YC - X), C, BF
                iLoopY = R - X
                For iLoopX = R - Y To R + Y
                    PlotPoint iLoopY, iLoopX, S, arrTemp()
                Next iLoopX
               
                'LINE (XC - Y, YC + X)-(XC + Y, YC + X), C, BF
                iLoopY = R + X
                For iLoopX = R - Y To R + Y
                    PlotPoint iLoopY, iLoopX, S, arrTemp()
                Next iLoopX
            End If
            X = X - 1
            RadiusError = RadiusError - X * 2
        End If
       
        Y = Y + 1
        'LINE (XC - X, YC - Y)-(XC + X, YC - Y), C, BF
        iLoopY = R - Y
        For iLoopX = R - X To R + X
            PlotPoint iLoopY, iLoopX, S, arrTemp()
        Next iLoopX
       
        'LINE (XC - X, YC + Y)-(XC + X, YC + Y), C, BF
        iLoopY = R + Y
        For iLoopX = R - X To R + X
            PlotPoint iLoopY, iLoopX, S, arrTemp()
        Next iLoopX
    Wend
   
    ' Copy circle to destination Y,X
    For DY = LBound(arrTemp, 1) To UBound(arrTemp, 1)
        For DX = LBound(arrTemp, 2) To UBound(arrTemp, 2)
            If Len(arrTemp(DY, DX)) > 0 Then
                TY = DY + YC
                If TY >= MinY Then
                    If TY <= MaxY Then
                        TX = DX + XC
                        If TX >= MinX Then
                            If TX <= MaxX Then
                                PlotPoint TY, TX, arrTemp(DY, DX), MyArray()
                            End If
                        End If
                    End If
                End If
            End If
        Next DX
    Next DY
   
End Sub ' PlotCircleFillTopLeft
' /////////////////////////////////////////////////////////////////////////////
' Re: Is this fast enough as general circle fill?
' https://forum.qb64.org/index.php?topic=298.msg3588#msg3588
' From: bplus
' Date: « Reply #59 on: August 30, 2018, 09:18:34 am »
Sub PlotEllipse (XC As Integer, YC As Integer, xRadius As Integer, yRadius As Integer, S As String, MyArray() As String * 1)
    Dim RoutineName As String:: RoutineName = "PlotEllipse": LastRoutine$ = RoutineName
    Print "PlotEllipse XC=" + _ToStr$(XC) + ", YC=" + _ToStr$(YC) + ", xRadius=" + _ToStr$(xRadius) + ", yRadius=" + _ToStr$(yRadius) + ", S=" + Chr$(34) + S + Chr$(34) + ", MyArray()"
    Dim scale As Single
    Dim xs As Integer
    Dim x As Integer
    Dim y As Integer
    Dim lastx As Integer
    Dim lasty As Integer
    Dim iLoopX As Integer
    Dim iLoopY As Integer
    On Error GoTo ErrorHandler
    scale = yRadius / xRadius
    xs = xRadius * xRadius
    'PSET (XC, YC - yRadius)
    PlotPoint YC - yRadius, XC, S, MyArray()
    'PSET (XC, YC + yRadius)
    PlotPoint YC + yRadius, XC, S, MyArray()
    lastx = 0: lasty = yRadius
    For x = 1 To xRadius
        y = scale * Sqr(xs - x * x)
        'LINE (XC + lastx, YC - lasty)-(XC + x, YC - y)
        PlotLine XC + lastx, YC - lasty, XC + x, YC - y, S, MyArray()
        'LINE (XC + lastx, YC + lasty)-(XC + x, YC + y)
        PlotLine XC + lastx, YC + lasty, XC + x, YC + y, S, MyArray()
        'LINE (XC - lastx, YC - lasty)-(XC - x, YC - y)
        PlotLine XC - lastx, YC - lasty, XC - x, YC - y, S, MyArray()
        'LINE (XC - lastx, YC + lasty)-(XC - x, YC + y)
        PlotLine XC - lastx, YC + lasty, XC - x, YC + y, S, MyArray()
        lastx = x
        lasty = y
    Next x
End Sub ' PlotEllipse
' /////////////////////////////////////////////////////////////////////////////
' Ellipse plotting wrapper (Top-Left corner input)
Sub PlotEllipseTopLeft (X As Integer, Y As Integer, xRadius As Integer, yRadius As Integer, S As String, MyArray() As String * 1)
    PlotEllipse X + xRadius, Y + yRadius, xRadius, yRadius, S, MyArray()
End Sub ' PlotEllipseTopLeft
' /////////////////////////////////////////////////////////////////////////////
' Re: Is this fast enough as general circle fill?
' https://forum.qb64.org/index.php?topic=298.msg3588#msg3588
' From: bplus
' Date: « Reply #59 on: August 30, 2018, 09:18:34 am »
'
' Here is my ellipse and filled ellipse routines, no where near
' Steve's level of performance. The speed is cut in half at
' least because you probably have to do a whole quadrants worth
' of calculations (ellipse not as symmetric as circle).
'
' But I am sure this code can be optimized more than it is:
Sub PlotEllipseFill (XC As Integer, YC As Integer, xRadius As Integer, yRadius As Integer, S As String, MyArray() As String * 1)
    Dim RoutineName As String:: RoutineName = "PlotEllipseFill": LastRoutine$ = RoutineName
   
    Print "PlotEllipseFill XC=" + _ToStr$(XC) + ", YC=" + _ToStr$(YC) + ", xRadius=" + _ToStr$(xRadius) + ", yRadius=" + _ToStr$(yRadius) + ", S=" + Chr$(34) + S + Chr$(34) + ", MyArray()"
    Dim scale As Single
    Dim x As Integer
    Dim y As Integer
    Dim iLoopX As Integer
    Dim iLoopY As Integer
   
    On Error GoTo ErrorHandler
   
    scale = yRadius / xRadius
   
    'LINE (XC, YC - yRadius)-(XC, YC + yRadius), , BF
    For iLoopY = YC - yRadius To YC + yRadius
        PlotPoint iLoopY, XC, S, MyArray()
    Next iLoopY
   
    For x = 1 To xRadius
        y = scale * Sqr(xRadius * xRadius - x * x)
       
        'LINE (XC + x, YC - y)-(XC + x, YC + y), , BF
        iLoopX = XC + x
        For iLoopY = YC - y To YC + y
            PlotPoint iLoopY, iLoopX, S, MyArray()
        Next iLoopY
       
        'LINE (XC - x, YC - y)-(XC - x, YC + y), , BF
        iLoopX = XC - x
        For iLoopY = YC - y To YC + y
            PlotPoint iLoopY, iLoopX, S, MyArray()
        Next iLoopY
    Next x
End Sub ' PlotEllipseFill
' /////////////////////////////////////////////////////////////////////////////
' Filled Ellipse plotting wrapper (Top-Left corner input)
Sub PlotEllipseFillTopLeft (X As Integer, Y As Integer, xRadius As Integer, yRadius As Integer, S As String, MyArray() As String * 1)
    PlotEllipseFill X + xRadius, Y + yRadius, xRadius, yRadius, S, MyArray()
End Sub ' PlotEllipseFillTopLeft
' /////////////////////////////////////////////////////////////////////////////
' Based on "BRESNHAM.BAS" by Kurt Kuzba. (4/16/96)
' From: http://www.thedubber.altervista.org/qbsrc.htm
' PlotLine x1, y1, x2, y2, S, MyArray()
Sub PlotLine (x1 As Integer, y1 As Integer, x2 As Integer, y2 As Integer, S As String, MyArray() As String * 1)
    Dim RoutineName As String:: RoutineName = "PlotLine": LastRoutine$ = RoutineName
   
    Print "PlotLine x1=" + _ToStr$(x1) + ", y1=" + _ToStr$(y1) + ", x2=" + _ToStr$(x2) + ", y2=" + _ToStr$(y2) + ", S=" + Chr$(34) + S + Chr$(34) + ", MyArray()"
   
    Dim iLoop As Integer
    Dim steep As Integer: steep = 0
    Dim ev As Integer: ev = 0
    Dim sx As Integer
    Dim sy As Integer
    Dim dx As Integer
    Dim dy As Integer
   
    On Error GoTo ErrorHandler
   
    If (x2 - x1) > 0 Then
        sx = 1
    Else
        sx = -1
    End If
    dx = Abs(x2 - x1)
    If (y2 - y1) > 0 Then
        sy = 1
    Else
        sy = -1
    End If
    dy = Abs(y2 - y1)
    If (dy > dx) Then
        steep = 1
        Swap x1, y1
        Swap dx, dy
        Swap sx, sy
    End If
    ev = 2 * dy - dx
    For iLoop = 0 To dx - 1
        If steep = 1 Then
            ' SPECIAL CASE: x/y are reversed
            ''PSET (y1, x1), c:
            'LOCATE y1, x1 : PRINT S;
            PlotPoint x1, y1, S, MyArray()
        Else
            ''PSET (x1, y1), c
            'LOCATE x1, y1: PRINT S;
            PlotPoint y1, x1, S, MyArray()
        End If
        While ev >= 0
            y1 = y1 + sy
            ev = ev - 2 * dx
        Wend
        x1 = x1 + sx
        ev = ev + 2 * dy
    Next iLoop
   
    ' Ensure the final endpoint is always plotted
    ''PSET (x2, y2), c
    'LOCATE x2, y2: PRINT S;
    PlotPoint y2, x2, S, MyArray()
End Sub ' PlotLine
' /////////////////////////////////////////////////////////////////////////////
Sub PlotPoint (Y As Integer, X As Integer, S As String, MyArray() As String * 1)
    if Y >= LBound(MyArray, 1) _
        _ANDALSO Y <= UBound(MyArray, 1) _
        _ANDALSO X >= LBound(MyArray, 2) _
        _ANDALSO X <= UBound(MyArray, 2) _
    then
        MyArray(Y, X) = S
    End If
End Sub ' PlotPoint
' /////////////////////////////////////////////////////////////////////////////
' Based on PlotCircle.
' XC,YC   = center point of circle
' R       = radius
' Q       = which quarter of the circle to return
'           where 1=top right, 2=bottom right, 3=bottom left, 4=top left
' S       = char to draw
' MyArray = 2D string array to plot circle in
Sub PlotSemiCircle (XC As Integer, YC As Integer, R As Integer, Q As Integer, S As String, MyArray() As String * 1)
    Dim RoutineName As String:: RoutineName = "PlotSemiCircle": LastRoutine$ = RoutineName
    Print "PlotSemiCircle XC=" + _ToStr$(XC) + ", YC=" + _ToStr$(YC) + ", R=" + _ToStr$(R) + ", Q=" + _ToStr$(Q) + ", S=" + Chr$(34) + S + Chr$(34) + ", MyArray()"
    Dim A As Integer
    Dim B As Integer
    Dim C As Integer
    Dim S2 As String
    On Error GoTo ErrorHandler
    If Len(S) = 1 Then
        S2 = S
    Else
        If Len(S) = 0 Then
            S2 = " "
        Else
            S2 = Left$(S, 1)
        End If
    End If
    If R = 1 Then
        Select Case Q
            Case 1: ' Top Right
                PlotPoint XC + 1, YC, S, MyArray()
                PlotPoint XC, YC - 1, S, MyArray()
            Case 2: ' Bottom Right
                PlotPoint XC + 1, YC, S, MyArray()
                PlotPoint XC, YC + 1, S, MyArray()
            Case 3: ' Bottom Left
                PlotPoint XC - 1, YC, S, MyArray()
                PlotPoint XC, YC + 1, S, MyArray()
            Case 4: ' Top Left
                PlotPoint XC - 1, YC, S, MyArray()
                PlotPoint XC, YC - 1, S, MyArray()
        End Select
        Exit Sub
    ElseIf R > 0 Then
        B = R
        C = 0
        A = R - 1
        Do
            ' Select quadrant
            Select Case Q
                Case 1 ' Top-Right
                    PlotPoint YC - B, XC + C, S2, MyArray()
                    PlotPoint YC - C, XC + B, S2, MyArray()
                Case 2 ' Bottom-Right
                    PlotPoint YC + B, XC + C, S2, MyArray()
                    PlotPoint YC + C, XC + B, S2, MyArray()
                Case 3 ' Bottom-Left
                    PlotPoint YC + B, XC - C, S2, MyArray()
                    PlotPoint YC + C, XC - B, S2, MyArray()
                Case 4 ' Top-Left
                    PlotPoint YC - B, XC - C, S2, MyArray()
                    PlotPoint YC - C, XC - B, S2, MyArray()
            End Select
           
            LastCode$ = "C = C + 1, etc."
            C = C + 1
            A = A + 1 - C - C
            If A < 0 Then ' IF A>=0 THEN 190
                B = B - 1
                A = A + B + B
            End If
            If B < C Then Exit Do ' 190 IF B>=C THEN 60
        Loop
    End If
   
    LastCode$ = ""
End Sub ' PlotSemiCircle
' /////////////////////////////////////////////////////////////////////////////
' Semi-Circle plotting wrapper (Top-Left corner input)
' X,Y     = top left point of circle
' R       = radius
' Q       = which quarter of the circle to return
'           where 1=top right, 2=bottom right, 3=bottom left, 4=top left
'           like this:
'           .......4444111.......
'           .....44.......11.....
'           ....4...........1....
'           ...4.............1...
'           ..4...............1..
'           .4.................1.
'           .4.................1.
'           4...................1
'           4...................1
'           4...................1
'           3...................1
'           3...................2
'           3...................2
'           3...................2
'           .3.................2.
'           .3.................2.
'           ..3...............2..
'           ...3.............2...
'           ....3...........2....
'           .....33.......22.....
'           .......3333222.......
' S       = char to draw
' MyArray = 2D string array to plot circle in
Sub PlotSemicircleTopLeft (X As Integer, Y As Integer, R As Integer, Q As Integer, S As String, MyArray() As String * 1)
    PlotSemiCircle X + R, Y + R, R, Q, S, MyArray()
End Sub ' PlotSemicircleTopLeft
' /////////////////////////////////////////////////////////////////////////////
' Based on CircleFill and PlotSemiCircle
' XC,YC   = top left point of circle
' R       = radius
' Q       = which quarter of the circle to return semicircle from
'           where 1=top right, 2=bottom right, 3=bottom left, 4=top left
'           like this:
'           .......4444111.......
'           .....44444411111.....
'           ....4444444111111....
'           ...444444441111111...
'           ..44444444411111111..
'           .4444444444111111111.
'           .4444444444111111111.
'           444444444441111111111
'           444444444441111111111
'           444444444441111111111
'           333333333331111111111
'           333333333332222222222
'           333333333332222222222
'           333333333332222222222
'           .3333333333222222222.
'           .3333333333222222222.
'           ..33333333322222222..
'           ...333333332222222...
'           ....3333333222222....
'           .....33333322222.....
'           .......3333222.......
' S       = char to draw
' MyArray = 2D string array to plot semicircle in
Sub PlotSemiCircleFill (XC As Integer, YC As Integer, R As Integer, Q As Integer, S As String, MyArray() As String * 1)
    Dim RoutineName As String:: RoutineName = "PlotSemiCircleFill": LastRoutine$ = RoutineName
   
    Print "PlotSemiCircleFill XC=" + _ToStr$(XC) + ", YC=" + _ToStr$(YC) + ", R=" + _ToStr$(R) + ", Q=" + _ToStr$(Q) + ", S=" + Chr$(34) + S + Chr$(34) + ", MyArray()"
    Dim Radius As Integer
    Dim RadiusError As Integer
    Dim X As Integer
    Dim Y As Integer
    Dim iLoopX As Integer
    Dim iLoopY As Integer
    ReDim arrTemp(0, 0) As String * 1
    Dim DY As Integer
    Dim DX As Integer
    Dim W As Integer
    Dim TX As Integer
    Dim TY As Integer
    Dim MinY As Integer
    Dim MaxY As Integer
    Dim MinX As Integer
    Dim MaxX As Integer
   
    On Error GoTo ErrorHandler
   
    Radius = Abs(R)
    RadiusError = -Radius
    X = Radius
    Y = 0
   
    If Radius = 0 Then
        'PSET (XC, YC), C
        Exit Sub
    End If
   
    ' Get total width
    W = (Radius * 2) + 1
   
    ' Define a temp array
    ReDim arrTemp(0 To W, 0 To W) As String * 1
   
    ' Get minimum X, Y of target array
    MinY = LBound(MyArray, 1)
    MaxY = UBound(MyArray, 1)
    MinX = LBound(MyArray, 2)
    MaxX = UBound(MyArray, 2)
   
    ' Draw the middle span here so we don't draw it twice in the main loop,
    ' which would be a problem with blending turned on.
    'LINE (XC - X, YC)-(XC + X, YC), C, BF
    For iLoopX = R - X To R + X
        PlotPoint R, iLoopX, S, arrTemp()
    Next iLoopX
   
    While X > Y
        RadiusError = RadiusError + Y * 2 + 1
        If RadiusError >= 0 Then
            If X <> Y + 1 Then
                'LINE (XC - Y, YC - X)-(XC + Y, YC - X), C, BF
                iLoopY = R - X
                For iLoopX = R - Y To R + Y
                    PlotPoint iLoopY, iLoopX, S, arrTemp()
                Next iLoopX
               
                'LINE (XC - Y, YC + X)-(XC + Y, YC + X), C, BF
                iLoopY = R + X
                For iLoopX = R - Y To R + Y
                    PlotPoint iLoopY, iLoopX, S, arrTemp()
                Next iLoopX
            End If
            X = X - 1
            RadiusError = RadiusError - X * 2
        End If
       
        Y = Y + 1
        'LINE (XC - X, YC - Y)-(XC + X, YC - Y), C, BF
        iLoopY = R - Y
        For iLoopX = R - X To R + X
            PlotPoint iLoopY, iLoopX, S, arrTemp()
        Next iLoopX
       
        'LINE (XC - X, YC + Y)-(XC + X, YC + Y), C, BF
        iLoopY = R + Y
        For iLoopX = R - X To R + X
            PlotPoint iLoopY, iLoopX, S, arrTemp()
        Next iLoopX
    Wend
   
    ' Copy semicircle to destination Y,X
    ' JUST COPY SELECTED QUADRANT:
    Select Case Q
        Case 1:
            ' quadrant #1 (Top-Right)
            For DY = 0 To Radius
                For DX = Radius To W
                    If Len(arrTemp(DY, DX)) > 0 Then
                        TY = YC + (DY - Radius)
                        TX = XC + (DX - Radius)
                        If TY >= MinY And TY <= MaxY And TX >= MinX And TX <= MaxX Then
                            PlotPoint TY, TX, arrTemp(DY, DX), MyArray()
                        End If
                    End If
                Next DX
            Next DY
        Case 2:
            ' quadrant #2 (Bottom-Right)
            For DY = Radius To W
                For DX = Radius To W
                    If Len(arrTemp(DY, DX)) > 0 Then
                        TY = YC + (DY - Radius)
                        TX = XC + (DX - Radius)
                        If TY >= MinY And TY <= MaxY And TX >= MinX And TX <= MaxX Then
                            PlotPoint TY, TX, arrTemp(DY, DX), MyArray()
                        End If
                    End If
                Next DX
            Next DY
        Case 3:
            ' quadrant #3 (Bottom-Left)
            For DY = Radius To W
                For DX = 0 To Radius
                    If Len(arrTemp(DY, DX)) > 0 Then
                        TY = YC + (DY - Radius)
                        TX = XC + (DX - Radius)
                        If TY >= MinY And TY <= MaxY And TX >= MinX And TX <= MaxX Then
                            PlotPoint TY, TX, arrTemp(DY, DX), MyArray()
                        End If
                    End If
                Next DX
            Next DY
        Case 4:
            ' quadrant #4 (Top-Left)
            For DY = 0 To Radius
                For DX = 0 To Radius
                    If Len(arrTemp(DY, DX)) > 0 Then
                        TY = YC + (DY - Radius)
                        TX = XC + (DX - Radius)
                        If TY >= MinY And TY <= MaxY And TX >= MinX And TX <= MaxX Then
                            PlotPoint TY, TX, arrTemp(DY, DX), MyArray()
                        End If
                    End If
                Next DX
            Next DY
        Case Else:
            ' (DO NOTHING)
    End Select
End Sub ' PlotSemiCircleFill
' /////////////////////////////////////////////////////////////////////////////
' Filled Semi-Circle plotting wrapper (Top-Left corner input)
Sub PlotSemiCircleFillTopLeft (X As Integer, Y As Integer, R As Integer, Q As Integer, S As String, MyArray() As String * 1)
    PlotSemiCircleFill X + R, Y + R, R, Q, S, MyArray()
End Sub ' PlotSemiCircleFillTopLeft
' /////////////////////////////////////////////////////////////////////////////
Sub PlotSquare (X1 As Integer, Y1 As Integer, L As Integer, S As String, MyArray() As String * 1)
    Dim RoutineName As String:: RoutineName = "PlotSquare": LastRoutine$ = RoutineName
    Print "PlotSquare X1=" + _ToStr$(X1) + ", Y1=" + _ToStr$(Y1) + ", L=" + _ToStr$(L) + ", S=" + Chr$(34) + S + Chr$(34) + ", MyArray()"
    Dim X As Integer
    Dim X2 As Integer
    Dim Y As Integer
    Dim Y2 As Integer
    Dim S2 As String
    On Error GoTo ErrorHandler
    If Len(S) = 1 Then
        S2 = S
    Else
        If Len(S) = 0 Then
            S2 = " "
        Else
            S2 = Left$(S, 1)
        End If
    End If
    X2 = (X1 + L) - 1
    Y2 = (Y1 + L) - 1
    For X = X1 To X2
        For Y = Y1 To Y2
            PlotPoint Y, X, S2, MyArray()
        Next Y
    Next X
End Sub ' PlotSquare
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END 2D SHAPE PLOTTING FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN GENERAL PURPOSE UTILITY ROUTINES #GEN
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' /////////////////////////////////////////////////////////////////////////////
' Returns _TRUE if number n is even
' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
' see also: IsOdd%
Function IsEven% (n)
    If n Mod 2 = 0 Then
        IsEven% = _TRUE
    Else
        IsEven% = _FALSE
    End If
End Function ' IsEven%
' /////////////////////////////////////////////////////////////////////////////
' Returns _TRUE if number n is odd
' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
' see also: IsEven%
Function IsOdd% (n)
    If n Mod 2 = 1 Then
        IsOdd% = _TRUE
    Else
        IsOdd% = _FALSE
    End If
End Function ' IsOdd%
' /////////////////////////////////////////////////////////////////////////////
Function PadLeft$ (sValue As String, iWidth As Integer)
    PadLeft$ = Right$(String$(iWidth, " ") + sValue, iWidth)
End Function ' PadLeft$
' /////////////////////////////////////////////////////////////////////////////
Function PadRight$ (sValue As String, iWidth As Integer)
    PadRight$ = Left$(sValue + String$(iWidth, " "), iWidth)
End Function ' PadRight$
' /////////////////////////////////////////////////////////////////////////////
Function RandomLong& (Min1&, Max1&)
    Dim NumSpread As _Unsigned Long
    Dim Min2&, Max2&
    'THIS DOESN'T WORK:
    'NumSpread = (Max1& - Min&) + 1
    'BUT THIS DOES:
    If Min1& > Max1& Then
        Min2& = Max1&
        Max2& = Min1&
    Else
        Min2& = Min1&
        Max2& = Max1&
    End If
   
    If Min2& < 0 And Max2& > 0 Then
        NumSpread = (Max2& + Abs(Min2&)) + 1
    ElseIf Min2& < 0 And Max2& < 0 Then
        NumSpread = Max2& + Abs(Min2&) + 1
    ElseIf Min2& > 0 And Max2& > 0 Then
        NumSpread = (Max2& - Min2&) + 1
    ElseIf Min2& = 0 And Max2& > 0 Then
        NumSpread = Max2&
    ElseIf Min2& = 0 And Max2& = 0 Then
        NumSpread = 0
    End If
    ' GET RANDOM # BETWEEN Min2& AND Max2&
    RandomLong& = Int(Rnd * NumSpread) + Min2&
End Function ' RandomLong&
' /////////////////////////////////////////////////////////////////////////////
' Generate random value between Min and Max inclusive.
Function RandomNumber% (Min%, Max%)
    Dim NumSpread%
    ' SET RANDOM SEED
    Randomize Timer
    NumSpread% = (Max% - Min%) + 1
    RandomNumber% = Int(Rnd * NumSpread%) + Min% ' GET RANDOM # BETWEEN Max% AND Min%
End Function ' RandomNumber%
' /////////////////////////////////////////////////////////////////////////////
' FROM: String Manipulation
' found at abandoned, outdated and now likely malicious qb64 dot net website
' http://www.qb64.[net]/forum/index_topic_5964-0/
'
'SUMMARY:
'   Purpose:  A library of custom functions that transform strings.
'   Author:   Dustinian Camburides (dustinian@gmail.com)
'   Platform: QB64 (www.qb64.org)
'   Revision: 1.6
'   Updated:  5/28/2012
'SUMMARY:
'[Replace$] replaces all instances of the [Find] sub-string with the [Add] sub-string within the [Text] string.
'INPUT:
'Text: The input string; the text that's being manipulated.
'Find: The specified sub-string; the string sought within the [Text] string.
'Add: The sub-string that's being added to the [Text] string.
Function Replace$ (Text1 As String, Find1 As String, Add1 As String)
    ' VARIABLES:
    Dim Text2 As String
    Dim Find2 As String
    Dim Add2 As String
    Dim lngLocation As Long ' The address of the [Find] substring within the [Text] string.
    Dim strBefore As String ' The characters before the string to be replaced.
    Dim strAfter As String ' The characters after the string to be replaced.
    ' INITIALIZE:
    ' MAKE COPIESSO THE ORIGINAL IS NOT MODIFIED (LIKE ByVal IN VBA)
    Text2 = Text1
    Find2 = Find1
    Add2 = Add1
    lngLocation = InStr(1, Text2, Find2)
    ' PROCESSING:
    ' While [Find2] appears in [Text2]...
    While lngLocation
        ' Extract all Text2 before the [Find2] substring:
        strBefore = Left$(Text2, lngLocation - 1)
        ' Extract all text after the [Find2] substring:
        strAfter = Right$(Text2, ((Len(Text2) - (lngLocation + Len(Find2) - 1))))
        ' Return the substring:
        Text2 = strBefore + Add2 + strAfter
        ' Locate the next instance of [Find2]:
        lngLocation = InStr(1, Text2, Find2)
        ' Next instance of [Find2]...
    Wend
    ' OUTPUT:
    Replace$ = Text2
End Function ' Replace$
' /////////////////////////////////////////////////////////////////////////////
Function TrueFalse$ (MyValue%)
    TrueFalse$ = _IIf(MyValue% = _TRUE, "_TRUE", "_FALSE")
End Function ' TrueFalse$
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END GENERAL PURPOSE UTILITY ROUTINES @GEN
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


Attached Files
.bas   ShapePlot12Test.bas (Size: 68.91 KB / Downloads: 17)
Reply
#2
Isn't your coordinates reversed?


Sub PlotPoint (Y As Integer, X As Integer, S As String, MyArray() As String * 1)
 
Sub PlotSemiCircle (XC As Integer, YC As Integer, R As Integer, Q As Integer, S As String, MyArray() As String * 1)

One is X/Y, then the other is Y/X, and somewhere along the brain my mind is bugging out.  LOL
Reply
#3
And can I ask about these statements -- this is just making my OCD twitch, and I didn't even know I *had* OCD:

If Err >= 1 And Err <= 1 Then

The only number that can be >= 1 and also be <= 1... IS 1.

Why isn't this just a very simple:
IF Err = 1 Then...

Or even better:

SELECT CASE Err
CASE 1:

My brain is hurting. This code is twitching my eyebrows. LOL!!
Reply
#4
OMG error handling galore! 

I learned early on there is NO WAY to anticipate all the fool errors that could happen and attempting to code for even a likely majority was a boring nightmare.

The solution is simple, make no errors and inform users as best you can what info you are looking to get and how it will be used and allow for some intelligence from your user.
  724  855  599  923  575  468  400  206  147  564  878  823  652  556 bxor cross forever
Reply
#5
I assume the error is in the wrong use of data types. Are you really using the INTEGER data type for decimal numbers?


Reply
#6
First, thanks everyone for your replies!

(10-21-2025, 02:53 PM)SMcNeill Wrote: Isn't your coordinates reversed?
Sub PlotPoint (Y As Integer, X As Integer, S As String, MyArray() As String * 1)
Sub PlotSemiCircle (XC As Integer, YC As Integer, R As Integer, Q As Integer, S As String, MyArray() As String * 1)
One is X/Y, then the other is Y/X, and somewhere along the brain my mind is bugging out.  LOL

Are they?? I'll check that in a minute.

(10-21-2025, 03:02 PM)SMcNeill Wrote: And can I ask about these statements -- this is just making my OCD twitch, and I didn't even know I *had* OCD:
If Err >= 1 And Err <= 1 Then
...
My brain is hurting.  This code is twitching my eyebrows.  LOL!!

Ha! Sorry to hurt your brain! I was trying to debug something that was blowing up, and wanted a quick & dirty way to see the error message without having to look up the codes. Some of the errors had a range (e.g., 502 to 518 = Out of memory) and I was feeling lazy, so I generated that code by copying the tables from the QB64PE error codes page into Excel, then using a SUBSTITUTE formula to fill in the values, and the fastest path was to simply do a "one size fits all" template, even where there was only one value.
[Image: qb64pe-lazy-error-message-code-generator.png]

(10-21-2025, 05:46 PM)bplus Wrote: OMG error handling galore! 
I learned early on there is NO WAY to anticipate all the fool errors that could happen and attempting to code for even a likely majority was a boring nightmare.
The solution is simple, make no errors and inform users as best you can what info you are looking to get and how it will be used and allow for some intelligence from your user.

I agree. This wasn't for a user, this was me grasping for straws trying to debug some puzzling errors. At this point I don't remember what it was, but it eventually got fixed.

(10-21-2025, 08:58 PM)Petr Wrote: I assume the error is in the wrong use of data types. Are you really using the INTEGER data type for decimal numbers?

I think that is probably likely... Where is this happening? I basically copied this code from all over the place and it seemed to work in the past... You know that saying, if it ain't broke? I don't think that covers the case where it wasn't broke but then you broke it!

Anyway, I'll check the data types and the parameter order. Thanks again y'all...
Reply
#7
I still think there's a fundamental issue in this:

  MaxRow = _Height / _FontHeight
    MaxCol = _Width / _FontWidth
    ' Define map boundaries
    ReDim arrScreen(0 To MaxRow, 0 To MaxCol) As String * 1

That's basically saying your screen array is set up for Y, X coordinates.

Sub PlotPoint (Y As Integer, X As Integer, S As String, MyArray() As String * 1)
Sub PlotSemiCircle (XC As Integer, YC As Integer, R As Integer, Q As Integer, S As String, MyArray() As String * 1)

And if you look at some of these other routines, they were created to be ran with X, Y coordinates.

The array is Y, X.
The PlotPoint is Y, X.
The PlotSemiCircle is X, Y.

At some point in there, those need to do a swap to pass the values in the proper order.    I think what you're seeing is something like:

66, 21  is being processed at various points as 21, 66 and at other points as 66, 21, and that's why the glitch pops up intermittently.  At least, it's the type of glitch that makes sense to me after testing it and watching the behavior.  We're just a week away from Halloween though and I couldn't be busier, so I only delved into this for all of about five minutes and it's the area of concern that popped up the most for me, and which in my mind seems to explain the behavior we're seeing.

I just haven't had time to dig deeper and see at which points those might need to swap the values back and forth.  First thing I'd probably do?  Get rid of coordinate error checking... If it wants to draw/print off screen, or access an array point that is out of bounds, let it try it and toss you an error so you can identify the line and the problem.

After that, I'd just choose one routine to debug at a time.  Don't random flip through a dozen of them.  Find one of those draw routines, and dissect it line by line.  Make certain the X, and Y are always passed properly and aren't getting reverse handled.  Get one routine sorted, it might sort them all.  If not, then you know one is working... just pick another one and debug it until it does as well.

Some seem to work.  Some don't.  And tossing them all in together all random makes it hard to focus on any one of them and sort out where the glitch might be in it.  Micro-focus down to getting one to work 100% and without glitching.  Then move on to another.

A simple test might be a routine of:

FOR y = 0 to MaxRow
  FOR x = 0 to MaxCol
      CLS
      'draw background coordinate system
      Chosen_Test_Routine x, y, other_params
      SLEEP
NEXT x, y

See if they all draw at places where it doesn't matter if the coordinates swap.  Can you draw at 10,10?  20,20?  Does it work at 21,66 but not at 66,21?  Watch it results with the different values and see when/where the bug bugs out.  Take the random out of it and make it a pattern based diagnostic check. 



At least, that's the method I think I'd resort to, to sort out this madness.  Divide and conquer and get one going at a time.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  why isn't _FULLSCREEN working? madscijr 5 509 09-20-2025, 01:47 AM
Last Post: SMcNeill
  I'm working on an old MS-DOS thingy... KlamPs 2 503 08-25-2025, 09:43 AM
Last Post: hsiangch_ong
  blue circle isn't drawing and print isn't working? madscijr 12 2,301 09-21-2024, 06:13 PM
Last Post: madscijr
  Updating Clock at a different rate to program loop-example not working as expected? dowster 1 591 08-15-2024, 12:06 PM
Last Post: luke
  Spanish accented chars not working Ikerkaz 2 752 03-14-2024, 02:41 PM
Last Post: Ikerkaz

Forum Jump:


Users browsing this thread: