Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 01:00 10 Jul 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : AI research project for this month

     Page 4 of 4    
Author Message
stef123
Regular Member

Joined: 25/09/2024
Location: United Kingdom
Posts: 89
Posted: 09:57am 27 May 2025
Copy link to clipboard 
Print this post

Thats another and huge Problem with LLMs. If there isn't a large code base with which to train an LLM, it can't respond to that code.

The best thing to do, in principle, would be to invent a specific LLM code, which would then be run locally through an interpreter or cross-compiler - instead of putting the cart before the horse.

Recently i also ran into a problem which my LLMs couldn´t solve. I understand C++ and so by that Arduino Code - up to a certain point, but i don't like to write it because of the finicky upper/lowercase Syntax and other weird constructions. Props to the People who write it with joy, i would go crazy. So i am somehow a noob in this field -  no problem for me , on the other hand i can write for example ARM-Assembly which in turn some others can't.


So in Arduino i was trying to put together a string including decimals and floats from uint8_t and float variables, by using snprintf , which eventually exits an STM32 on one of its serial ports. It sucessfully printed out the chars and also decimals, but no floats, LLMs were thinking here and there, coming up with crazy solutions, but nothing usable. I was already at the point where i was about to give up, because it didn't make any sense anymore.

The final Solution was simple: The Problem was the Library i've used, newlib-nano, which doesn't fully include handling of floats in order to keep the code small (if 4K counts on a 128K Micro).

So the LLMs - which i previously told on which Micro i am and which Platform i was using - could -in theory- easily figure out that this could be related to a wrong library. but didn´t get it. If i could ask an LLM -directly- if a wrong library could be the issue, then they would deliver the correct answer: Float is disabled by default - or use dtostrf.

Thats a key problem: In theory they "know" the answer, but don´t get the link, because nobody told them to create a Link between A and B, neither by hand, or by training data.
Edited 2025-05-30 14:47 by stef123
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3357
Posted: 10:57pm 04 Jun 2025
Copy link to clipboard 
Print this post

"AI-generated code could expand the pool from 30 million to a billion developers, unlocking personalised software everywhere."

Exponential View
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3357
Posted: 07:28pm 28 Jun 2025
Copy link to clipboard 
Print this post

English as a programming language

I've written maybe 3 very simple Python programs in my life, and haven't touched it in years. But apparently python is the programming language of AI.

In Google Gemini, I made this request:

Please produce python code for a raspberry pi which will read a file containing lines like the following one and produce a line chart graph with 6 lines labeled "Upper", "Middle", "South", "Lower", "Side", and "East": 

250628144138  14.8  223 15.1 9.8  207 21.2 10.5  238 22.7 8.8  136 15.4 10.2  334 32.8 9.7  184 18.9

Data items are separated by one or more spaces. The 7th and 8th characters in the first data item are the hour of the day ("00" - "23") and the 9th and 10th are the time in minutes. These make up the horizontal axis of the graph. Note that the horizontal spacing must account for 60 minutes to the hour, not 100.

The numbers to be plotted for each time slot are the 3rd, 6th, 9th, 12th, 15th, and 18th data items.

The file to be read will be named "/home/nn/panels.txt". The output file will be named "/home/nn/panels.html".


I have 6 mini solar panels placed variously on the front of my barn, nominal 18V max, less than 2-3 watts. I want to chart production over the course of a day so that I can understand shading over time. It has been almost totally overcast today, with a short period of very weak sun.

Here is the code which Gemini produced:

import plotly.graph_objects as go

# --- Configuration ---
# Input file containing the data
input_file_path = "/home/nn/panels.txt"

# Output HTML file for the graph
output_file_path = "/home/nn/panels.html"

# --- Data Processing ---

# Lists to store the parsed data from the file
# The x_axis will store time in a format Plotly understands (HH:MM)
x_axis_times = []

# Dictionaries to hold the data for each of the 6 lines
plot_data = {
   "Upper": [],
   "Middle": [],
   "South": [],
   "Lower": [],
   "Side": [],
   "East": []
}

print(f"Attempting to read data from: {input_file_path}")

try:
   with open(input_file_path, 'r') as f:
       for line_num, line in enumerate(f, 1):
           # Skips empty lines
           if not line.strip():
               continue

           # Split the line into parts. Handles one or more spaces.
           parts = line.split()

           # A valid line must have at least 18 data items
           if len(parts) < 18:
               print(f"Warning: Skipping malformed line #{line_num}. Not enough data items.")
               continue

           try:
               # --- 1. Extract Time for the X-axis ---
               timestamp_str = parts[0]
               if len(timestamp_str) < 10:
                   print(f"Warning: Skipping malformed line #{line_num}. Timestamp is too short.")
                   continue
               
               # Extract hour (characters 7-8) and minute (characters 9-10)
               hour = int(timestamp_str[6:8])
               minute = int(timestamp_str[8:10])
               
               # Format as "HH:MM". This ensures the chart handles time correctly
               # (e.g., it knows 60 minutes are in an hour).
               x_axis_times.append(f"{hour:02d}:{minute:02d}")

               # --- 2. Extract Data for the Y-axis ---
               # The values to be plotted are the 3rd, 6th, 9th, 12th, 15th, and 18th items.
               # Python list indices are 0-based, so we access parts[2], parts[5], etc.
               plot_data["Upper"].append(float(parts[2]))
               plot_data["Middle"].append(float(parts[5]))
               plot_data["South"].append(float(parts[8]))
               plot_data["Lower"].append(float(parts[11]))
               plot_data["Side"].append(float(parts[14]))
               plot_data["East"].append(float(parts[17]))

           except (ValueError, IndexError) as e:
               print(f"Warning: Skipping malformed line #{line_num}. Error processing data: {e}")
               continue

except FileNotFoundError:
   print(f"Error: The input file was not found at {input_file_path}")
   print("Please make sure the file exists and the path is correct.")
   exit()

# --- Graph Creation ---

if not x_axis_times:
   print("Error: No valid data was read from the file. Cannot generate a graph.")
   exit()
   
print(f"Successfully processed {len(x_axis_times)} data points.")
print("Generating the line chart...")

# Create a new figure
fig = go.Figure()

# Add each of the 6 lines (traces) to the figure
fig.add_trace(go.Scatter(x=x_axis_times, y=plot_data["Upper"], mode='lines', name='Upper'))
fig.add_trace(go.Scatter(x=x_axis_times, y=plot_data["Middle"], mode='lines', name='Middle'))
fig.add_trace(go.Scatter(x=x_axis_times, y=plot_data["South"], mode='lines', name='South'))
fig.add_trace(go.Scatter(x=x_axis_times, y=plot_data["Lower"], mode='lines', name='Lower'))
fig.add_trace(go.Scatter(x=x_axis_times, y=plot_data["Side"], mode='lines', name='Side'))
fig.add_trace(go.Scatter(x=x_axis_times, y=plot_data["East"], mode='lines', name='East'))

# --- Final Touches ---

# Update the layout with titles and axis labels
fig.update_layout(
   title='Panel Data Readings Over Time',
   xaxis_title='Time of Day (HH:MM)',
   yaxis_title='Data Value',
   legend_title='Panel Location',
   font=dict(
       family="Courier New, monospace",
       size=14,
       color="RebeccaPurple"
   )
)

# By providing time as "HH:MM" strings, Plotly automatically sets the
# x-axis type to 'category' or 'date', correctly spacing the time values
# and solving the "60 minutes per hour" requirement.

# --- Output ---

# Write the figure to an HTML file
try:
   fig.write_html(output_file_path)
   print(f"Success! Graph has been saved to: {output_file_path}")
except Exception as e:
   print(f"Error: Could not write the output file. {e}")


I changed only the paths of the input and output files to fit my Pi.

Here is my data for the 2+ hours I had the program working (6 INA226 current monitors calculating current through 12V-24V LED modules being read by an ESP32-C3Supermini):

250628134452  14.9   230 15.4 9.8   212 21.6 10.5   249 23.6 8.8   134 15.2 10.2   336 32.9 9.8   188 19.2
250628134752  14.5   205 14.2 9.7   194 19.9 10.4   220 21.1 8.8   125 14.2 10.1   293 29.1 9.7   172 17.7
250628135254  14.6  212 14.5 9.8  199 20.4 10.4  223 21.3 8.8  126 14.3 10.1  287 28.5 9.7  177 18.2
250628135554  14.5  206 14.2 9.7  193 19.8 10.4  219 21.0 8.8  125 14.2 10.1  293 29.1 9.7  172 17.7
250628135854  14.2  190 13.3 9.7  180 18.5 10.4  204 19.7 8.8  120 13.6 10.0  282 28.1 9.7  160 16.5
250628140154  13.7  161 11.7 9.6  156 16.1 10.3  177 17.2 8.7  105 12.1 10.0  261 26.2 9.6  139 14.5
250628140454  14.0  175 12.5 9.7  166 17.2 10.4  193 18.6 8.7  108 12.3 10.0  279 27.8 9.6  148 15.3
250628140754  14.2  187 13.2 9.7  176 18.2 10.4  205 19.7 8.8  118 13.4 10.1  301 29.8 9.7  157 16.2
250628141054  14.0  176 12.5 9.7  168 17.3 10.4  193 18.7 8.8  110 12.6 10.0  276 27.5 9.6  149 15.4
250628141354  14.4  201 13.9 9.7  190 19.4 10.4  216 20.7 8.8  118 13.5 10.1  289 28.7 9.7  167 17.3
250628141654  14.8  226 15.2 9.8  211 21.5 10.5  237 22.6 8.8  132 14.9 10.1  310 30.6 9.8  186 19.1
250628141954  14.6  211 14.5 9.8  198 20.3 10.5  224 21.4 8.8  127 14.4 10.1  308 30.5 9.7  177 18.1
250628142254  15.1  243 16.1 9.8  226 22.9 10.6  255 24.2 8.8  140 15.8 10.2  344 33.7 9.8  201 20.5
250628142724  16.0  307 19.2 10.0  288 28.7 10.7  321 29.9 8.9  178 19.9 10.4  424 40.8 10.0  257 25.8
250628143024  16.1  312 19.4 10.0  293 29.3 10.8  327 30.4 8.9  178 19.9 10.4  414 39.9 10.0  262 26.3
250628143324  16.0  308 19.2 10.0  291 29.0 10.8  330 30.6 8.9  182 20.3 10.4  420 40.4 10.0  259 26.0
250628143624  15.3  259 16.9 9.9  242 24.5 10.6  276 26.0 8.9  156 17.6 10.3  378 36.8 9.8  216 21.9
250628144438  14.2  187 13.2 9.7  178 18.3 10.4  203 19.6 8.8  119 13.5 10.1  293 29.1 9.7  158 16.3
250628144738  14.0  177 12.6 9.7  170 17.5 10.3  192 18.5 8.8  112 12.8 10.0  276 27.5 9.6  150 15.6
250628145038  13.6  154 11.3 9.6  150 15.7 10.3  170 16.5 8.7  101 11.5 9.9  242 24.3 9.6  134 14.0
250628145338  13.8  164 11.9 9.6  159 16.5 10.3  178 17.3 8.7  104 11.9 9.9  245 24.6 9.6  141 14.7
250628145638  14.0  176 12.6 9.7  169 17.5 10.3  188 18.2 8.8  112 12.7 10.0  253 25.3 9.6  150 15.6
250628145938  13.6  153 11.3 9.6  150 15.6 10.3  167 16.3 8.7  102 11.7 9.9  227 22.9 9.6  134 14.0
250628150238  13.3  138 10.4 9.6  137 14.3 10.2  152 14.9 8.7   94 10.7 9.8  208 21.1 9.5  122 12.7
250628150538  12.9  122 9.4 9.5  123 12.9 10.1  136 13.4 8.7   85 9.8 9.8  190 19.4 9.5  109 11.5
250628150838  12.8  113 8.9 9.5  115 12.1 10.1  126 12.5 8.7   79 9.1 9.7  172 17.7 9.5  103 10.9
250628151138  12.8  116 9.0 9.5  118 12.4 10.1  128 12.7 8.7   79 9.1 9.7  165 17.0 9.5  105 11.1
250628151438  13.3  139 10.4 9.6  138 14.4 10.2  152 14.8 8.7   89 10.3 9.8  193 19.7 9.6  123 12.8
250628151738  13.7  159 11.6 9.6  155 16.1 10.3  173 16.8 8.7  100 11.5 9.9  225 22.8 9.6  137 14.3
250628152038  13.9  171 12.3 9.7  164 17.0 10.3  186 18.0 8.8  108 12.4 10.0  254 25.5 9.6  146 15.2
250628152338  13.9  172 12.3 9.7  166 17.2 10.3  186 18.0 8.8  109 12.5 10.0  251 25.2 9.6  148 15.3
250628152638  14.1  184 13.0 9.7  176 18.1 10.4  197 19.0 8.8  115 13.1 10.0  264 26.4 9.7  156 16.2
250628152938  14.2  187 13.2 9.7  179 18.4 10.4  197 19.0 8.8  116 13.3 10.0  260 26.1 9.7  159 16.4
250628153238  14.0  177 12.7 9.7  171 17.6 10.3  189 18.3 8.8  112 12.8 10.0  251 25.2 9.7  152 15.8
250628153538  13.5  148 11.0 9.6  146 15.2 10.2  161 15.8 8.7   99 11.3 9.9  219 22.2 9.6  130 13.6
250628153838  13.0  124 9.5 9.5  125 13.1 10.1  137 13.5 8.7   85 9.8 9.8  184 18.9 9.5  111 11.7
250628154138  12.9  120 9.3 9.5  122 12.8 10.1  132 13.0 8.7   82 9.4 9.7  174 17.9 9.5  108 11.4
250628154438  13.1  128 9.8 9.5  128 13.4 10.2  141 13.9 8.7   87 10.0 9.8  193 19.7 9.5  114 12.0
250628154738  12.7  109 8.6 9.5  112 11.8 10.1  124 12.2 8.6   77 8.9 9.7  175 17.9 9.5  100 10.5
250628155038  12.4   96 7.8 9.4  100 10.6 10.0  111 11.0 8.6   70 8.1 9.7  154 16.0 9.4   89 9.4


It ran with no changes. I copied the output html file to /var/www/html, and it immediately displayed when I entered the URL:



I am very impressed. It no doubt would have taken me many hours to produce this chart using MMBasic DOS or MMB4L or lua or php. All I did was provide a sufficiently complete specification and some data. I like that it was able to pick out the data from my saying use the 3rd, 6th, 9th, 12th, 15th, and 18th words in each line.

(Now if I can just teach it to code using MMB4L.)
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3357
Posted: 01:01pm 05 Jul 2025
Copy link to clipboard 
Print this post

AI writes MMBasic code

After getting Google Gemini 2.5 Pro to write python code to chart my mini-solar panels current on an ILI9341 over the course of a day, I asked it to do the same for an ILI9488. 3+ hours later and 4 different ili9488.py drivers, it had still not drawn a line or written text to the LCD, and it gave up.

It said that the fourth driver had derived from MMBasic source code (because I had shown that MMBasic could write the ILI9488 screen on the same hardware). (I doubt that it had looked at the MMBasic source, because it later said that it could not look at external sources).

So I asked it to write MMBasic code for the ILI9488, and it said it could. I gave it an 8-line program which illustrated all the graphical elements.

cls
line 48,0,48,272 ' draw vertical axis line
line 48,272,mm.hres,272 ' draw horizontal axis line
Text MM.HRes/2,0,"Panel Output July 4, 2025",c,2,,rgb(yellow) ' print heading
text 60,278,"  9",V,1 ' print first time vertically
text 8,36,"1400",,1 ' print first (highest) milliwatt reading
dim integer  mv(16)=(270,250,200,180,185,150,125,200,110,85,70,180,170,200,240,270,270) ' points to plot
line plot mv(),,50,20,,,rgb(yellow) ' plot the points


Not to laugh but it was 20+ painful versions before it was actually plotting, and Version 26 gave a good plot. Version 33 got some labelling tweaks finalized (279 lines of code):



Although I gave it a link to the MMBasic PicoMite User Manual, it said it was not able to use it to check syntax. Here's the code. I haven't gone through it in detail, but it seems not too bad. (Code at end of post.)

When done, I asked if it would remember what it had learned about MMBasic. It said that in a new "Conversation", it would not. I asked it to produce a "Do Not Use" cheat sheet which I could feed it in a future "Conversation" so the same errors would not be repeated. It said that was a good idea, and this is what it produced:

## Updated MMBasic "Do Not Use" List
Declarations and Scope
CONST [data_type]

Invalid: CONST INTEGER FOO = 10 or CONST STRING FOO = "bar"

Correct Approach: CONST does not take a data type. Use CONST FOO = 10.

LONGINT

Invalid: DIM LONGINT MyVar

Correct Approach: MMBasic does not have a LONGINT type. Use INTEGER for 32-bit integers.

DIM array(0)

Invalid: DIM MyArray(0)

Correct Approach: Array dimensions must be 1 or greater. Use DIM MyArray(1) for a placeholder that a command like a custom Split can work with.

DIM Parts$(...) inside multiple subroutines

Risky: Using the same array name with DIM inside different subroutines can cause "already declared" errors due to MMBasic's variable scope rules.

Correct Approach: Use unique names for local arrays in each subroutine (e.g., FParts$, LParts$).

Passing arrays to subroutines: SUB MySub MyArray()

Risky: Can cause "Incompatible type" errors, especially if the array is also declared globally or locally in the calling code block.

Correct Approach: A more robust method is to make the array a true global variable (declared at the top level) and have the subroutines access it directly without passing it as a parameter.

Control Flow
WHILE...WEND

Invalid: WHILE condition ... WEND

Correct Approach: Use the DO WHILE...LOOP structure.

IF condition: statement

Invalid: Using a colon : after an IF condition without THEN.

Correct Approach: IF statements require the THEN keyword. Use IF condition THEN statement for a single line, or a multi-line IF...ENDIF block.

Built-in Functions (or Lack Thereof)
SPLIT, TRIM$, REPLACE$, MAP, CEIL, FLOOR

Invalid: These common functions do not exist in MMBasic.

Correct Approach: They must be implemented as custom FUNCTION or SUB routines using primitive commands.

UBOUND(array)

Invalid as a general tool. While it works on locally-defined arrays, it can fail with an "Array dimensions" error when used on an array passed as a parameter to a subroutine.

Correct Approach: The size of an array must be known from its DIM statement or tracked with a separate variable. When needed inside a subroutine, pass the size as an additional parameter.

FREEFILE

Invalid: This function does not exist.

Correct Approach: Use a literal, fixed number for the file handle (e.g., OPEN file AS #1).

DATE$(string$) to parse

Invalid: Using DATE$ with a string argument does not parse it.

Correct Approach: DATE$ only returns the current system date. To parse a date from a string, you must use LEFT$, MID$, and VAL() to extract the components manually.


I asked it if it could use MMB4L on a linux device or MMB4W on Windows to check syntax. It said it couldn't (although it can and does produce and run python code when you ask it to do some research and produce an Excel chart). I think it can check syntax on C code as well.

So it was a painful session, but I learned a lot and had a good outcome. The steps were not too different from my own coding process--use F10 AUTOSAVE to throw code into the PicoMite, then fix syntax errors, then fix logic errors.

Thoughts for future use

I wonder if feeding it one of the recent MMBasic "help" files would enable it to avoid incorrect syntax. It's not hard to conceive that a near-future coding AI could have access to run MMB4L or MMB4W code in a sandbox to fix syntax errors before presenting code to the user.

Conclusion

Anyway, it was an interesting and fun effort. So now I have a somewhat capable and somewhat imbecilic junior programmer assistant for $.70 a day. More than what I had hoped for when I started this tread, but also in some ways less. Everything is happening fast.

' MMBasic Solar Panel Plotter (Version 33)

OPTION EXPLICIT

' --- Configuration ---
CONST PLOT_MARGIN = 48
CONST DATA_FILE = "panels.txt"

' --- Global Variables ---
DIM STRING DateStr, Title
DIM FLOAT MinVal, MaxVal, StartMins, EndMins
DIM INTEGER PointCount
DIM INTEGER OrderMap(5)

' --- Define the 6 plot series properties ---
DIM INTEGER Colors(5) = (RGB(YELLOW), RGB(RED), RGB(GREEN), RGB(BLUE), RGB(CYAN), RGB(MAGENTA))
DIM STRING Labels$(5) = ("LowerLt", "UpperRt", "LowerRt", "South", "Roof", "UpperLt")

' --- Array for month names ---
DIM STRING Months$(11) = ("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December")

' --- Main Program ---
AnalyseData
IF PointCount > 1 THEN
   FindOrder
   DIM FLOAT s1(PointCount), s2(PointCount), s3(PointCount), s4(PointCount), s5(PointCount), s6(PointCount)
   LoadData s1(), s2(), s3(), s4(), s5(), s6()
   DrawScreen s1(), s2(), s3(), s4(), s5(), s6()
ENDIF
END

' =================================================================
' SUBROUTINES AND FUNCTIONS
' =================================================================

' --- Custom String Functions ---
FUNCTION LTrim$ (in$)
 LOCAL INTEGER i
 FOR i = 1 TO LEN(in$)
   IF MID$(in$, i, 1) <> " " THEN EXIT FOR
 NEXT i
 LTrim$ = RIGHT$(in$, LEN(in$) - i + 1)
END FUNCTION

FUNCTION RTrim$ (in$)
 LOCAL INTEGER i
 FOR i = LEN(in$) TO 1 STEP -1
   IF MID$(in$, i, 1) <> " " THEN EXIT FOR
 NEXT i
 RTrim$ = LEFT$(in$, i)
END FUNCTION

FUNCTION Trim$ (in$)
 Trim$ = RTrim$(LTrim$(in$))
END FUNCTION

FUNCTION Replace$(Source$, Find$, ReplaceWith$)
   LOCAL INTEGER P
   P = INSTR(Source$, Find$)
   DO WHILE P > 0
       Source$ = LEFT$(Source$, P - 1) + ReplaceWith$ + MID$(Source$, P + LEN(Find$))
       P = INSTR(Source$, Find$)
   LOOP
   Replace$ = Source$
END FUNCTION

FUNCTION Split(Text$, Delimiter$, ResultArray$(), MaxParts)
   LOCAL INTEGER P, I
   LOCAL STRING Temp$, Work$
   Work$ = Trim$(Text$)
   DO WHILE INSTR(Work$, "  ") > 0
       Work$ = Replace$(Work$, "  ", " ")
   LOOP
   I = 0
   DO
       P = INSTR(Work$, Delimiter$)
       I = I + 1
       IF I > MaxParts THEN EXIT DO
       IF P > 0 THEN
           ResultArray$(I) = LEFT$(Work$, P - 1)
           Work$ = RIGHT$(Work$, LEN(Work$) - P)
       ELSE
           ResultArray$(I) = Work$
           EXIT DO
       ENDIF
   LOOP
   Split = I
END FUNCTION

FUNCTION Map(val, in_min, in_max, out_min, out_max)
   IF in_max - in_min = 0 THEN
       Map = out_min
   ELSE
       Map = (val - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
   ENDIF
END FUNCTION


' --- Pass 1: Read the file to get metadata ---
SUB AnalyseData
   LOCAL INTEGER I, HH, MM, DD, YY, NumParts, P, DataIdx(5) = (3, 6, 9, 12, 15, 18)
   LOCAL FLOAT Val
   LOCAL STRING T$, Line$
   DIM STRING Parts$(30)

   OPEN DATA_FILE FOR INPUT AS #1
   MinVal = 99999: MaxVal = -99999: PointCount = 0: StartMins = 0

   DO WHILE NOT EOF(1)
       LINE INPUT #1, Line$
       IF Trim$(Line$) <> "" THEN
           PointCount = PointCount + 1
           NumParts = Split(Line$, " ", Parts$(), 30)
           IF NumParts > 17 THEN
               IF DateStr = "" THEN
                   T$ = Parts$(1)
                   YY = VAL(LEFT$(T$, 2))
                   MM = VAL(MID$(T$, 3, 2))
                   DD = VAL(MID$(T$, 5, 2))
                   DateStr = Months$(MM - 1) + " " + STR$(DD) + ", 20" + STR$(YY)
               ENDIF
               
               T$ = Parts$(1)
               HH = VAL(MID$(T$,7,2)): MM = VAL(MID$(T$,9,2))
               IF StartMins = 0 THEN StartMins = HH * 60 + MM
               EndMins = HH * 60 + MM

               FOR I = 0 TO 5
                   Val = VAL(Parts$(DataIdx(I)))
                   IF Val < MinVal THEN MinVal = Val
                   IF Val > MaxVal THEN MaxVal = Val
               NEXT I
           ENDIF
       ENDIF
   LOOP
   CLOSE #1
   PRINT "Found "; PointCount; " data points. Range: "; MinVal; " to "; MaxVal
END SUB

' --- Read file to determine the plot order ---
SUB FindOrder
   LOCAL INTEGER i, j, c, NumParts, P, temp, DataIdx(5) = (3, 6, 9, 12, 15, 18)
   LOCAL FLOAT val
   LOCAL STRING Line$, T$
   ' CORRECTED: Renamed Parts$ to FParts$ to avoid conflict
   DIM STRING FParts$(30)
   DIM INTEGER CrossingIndex(5)

   FOR i = 0 TO 5
       OrderMap(i) = i
       CrossingIndex(i) = 99999
   NEXT i

   OPEN DATA_FILE FOR INPUT AS #1
   c = 0
   DO WHILE NOT EOF(1)
       LINE INPUT #1, Line$
       c = c + 1
       IF Trim$(Line$) <> "" THEN
           NumParts = Split(Line$, " ", FParts$(), 30)
           IF NumParts > 17 THEN
               FOR i = 0 TO 5
                   IF CrossingIndex(i) = 99999 THEN
                       val = VAL(FParts$(DataIdx(i)))
                       IF val > 200 THEN CrossingIndex(i) = c
                   ENDIF
               NEXT i
           ENDIF
       ENDIF
   LOOP
   CLOSE #1

   ' Sort the OrderMap array based on the crossing points (Bubble Sort)
   FOR i = 0 TO 4
       FOR j = 0 TO 4
           IF CrossingIndex(OrderMap(j)) > CrossingIndex(OrderMap(j+1)) THEN
               temp = OrderMap(j)
               OrderMap(j) = OrderMap(j+1)
               OrderMap(j+1) = temp
           ENDIF
       NEXT j
   NEXT i
END SUB


' --- Pass 2: Re-read file to load data into arrays in sorted order ---
SUB LoadData s1(), s2(), s3(), s4(), s5(), s6()
   LOCAL INTEGER C, NumParts, P, I, DataIdx(5) = (3, 6, 9, 12, 15, 18)
   LOCAL STRING Line$, T$
   DIM STRING LParts$(30)
   DIM FLOAT TempData(5)

   OPEN DATA_FILE FOR INPUT AS #1
   C = 0
   DO WHILE NOT EOF(1)
       LINE INPUT #1, Line$
       IF Trim$(Line$) <> "" THEN
           C = C + 1
           NumParts = Split(Line$, " ", LParts$(), 30)
           IF NumParts > 17 AND C <= PointCount THEN
               FOR i = 0 to 5
                   TempData(i) = VAL(LParts$(DataIdx(i)))
               NEXT i
               s1(C) = TempData(OrderMap(0))
               s2(C) = TempData(OrderMap(1))
               s3(C) = TempData(OrderMap(2))
               s4(C) = TempData(OrderMap(3))
               s5(C) = TempData(OrderMap(4))
               s6(C) = TempData(OrderMap(5))
           ENDIF
       ENDIF
   LOOP
   CLOSE #1
END SUB


' --- Draw the complete screen with axes, labels, and plots ---
SUB DrawScreen s1(), s2(), s3(), s4(), s5(), s6()
   LOCAL FLOAT y_range_max, y_range_min, x_inc, val
   LOCAL INTEGER PlotHeight, PlotWidth, y_pos, x_pos, hh, LastLabelX, i, idx
   LOCAL STRING TimeStr
   DIM INTEGER p1(PointCount), p2(PointCount), p3(PointCount), p4(PointCount), p5(PointCount), p6(PointCount)

   y_range_max = INT(MaxVal / 200) * 200: IF y_range_max < MaxVal THEN y_range_max = y_range_max + 200
   y_range_min = INT(MinVal / 200) * 200: IF y_range_min > MinVal AND y_range_min > 0 THEN y_range_min = y_range_min - 200

   PlotHeight = MM.VRes - (2 * PLOT_MARGIN): PlotWidth = MM.HRes - (2 * PLOT_MARGIN)

   CLS
   
   LINE PLOT_MARGIN, PLOT_MARGIN, PLOT_MARGIN, MM.VRes - PLOT_MARGIN
   LINE PLOT_MARGIN, MM.VRes - PLOT_MARGIN, MM.HRes - PLOT_MARGIN, MM.VRes - PLOT_MARGIN
   Title = "Panel Output " + DateStr + " -- mWatts"
   TEXT MM.HRes/2, 5, Title, C, 1, , RGB(WHITE)
   
   FOR val = y_range_min TO y_range_max STEP 200
     y_pos = Map(val, y_range_min, y_range_max, MM.VRes - PLOT_MARGIN, PLOT_MARGIN)
     IF y_pos >= PLOT_MARGIN THEN TEXT 0, y_pos - 4, STR$(val)
     LINE PLOT_MARGIN - 4, y_pos, PLOT_MARGIN, y_pos
   NEXT val

   LastLabelX = -100
   FOR hh = (StartMins / 60) TO (EndMins / 60)
       x_pos = Map(hh * 60, StartMins, EndMins, PLOT_MARGIN, MM.HRes - PLOT_MARGIN)
       IF x_pos > LastLabelX + 20 THEN
           TimeStr = STR$(hh)
           TEXT x_pos, MM.VRes - PLOT_MARGIN + 8, TimeStr, C
           LINE x_pos, MM.VRes - PLOT_MARGIN, x_pos, MM.VRes - PLOT_MARGIN + 4
           LastLabelX = x_pos
       ENDIF
   NEXT hh
   
   ' --- Draw Legend using the sorted OrderMap ---
   FOR i = 0 to 5
       idx = OrderMap(i)
       y_pos = i * (MM.FontHeight + 4)
       TEXT MM.HRes - 1, y_pos, Labels$(idx), R, , , Colors(idx)
   NEXT i
   
   ' --- Manually scale data into new pixel-coordinate arrays ---
   FOR i = 1 TO PointCount
       p1(i) = Map(s1(i), y_range_min, y_range_max, MM.VRes - PLOT_MARGIN, PLOT_MARGIN)
       p2(i) = Map(s2(i), y_range_min, y_range_max, MM.VRes - PLOT_MARGIN, PLOT_MARGIN)
       p3(i) = Map(s3(i), y_range_min, y_range_max, MM.VRes - PLOT_MARGIN, PLOT_MARGIN)
       p4(i) = Map(s4(i), y_range_min, y_range_max, MM.VRes - PLOT_MARGIN, PLOT_MARGIN)
       p5(i) = Map(s5(i), y_range_min, y_range_max, MM.VRes - PLOT_MARGIN, PLOT_MARGIN)
       p6(i) = Map(s6(i), y_range_min, y_range_max, MM.VRes - PLOT_MARGIN, PLOT_MARGIN)
   NEXT i
   
   x_inc = (MM.HRes - 2 * PLOT_MARGIN) / (PointCount - 1)
   
   LINE PLOT p1(), PointCount, PLOT_MARGIN, x_inc, 1, 1, Colors(OrderMap(0))
   LINE PLOT p2(), PointCount, PLOT_MARGIN, x_inc, 1, 1, Colors(OrderMap(1))
   LINE PLOT p3(), PointCount, PLOT_MARGIN, x_inc, 1, 1, Colors(OrderMap(2))
   LINE PLOT p4(), PointCount, PLOT_MARGIN, x_inc, 1, 1, Colors(OrderMap(3))
   LINE PLOT p5(), PointCount, PLOT_MARGIN, x_inc, 1, 1, Colors(OrderMap(4))
   LINE PLOT p6(), PointCount, PLOT_MARGIN, x_inc, 1, 1, Colors(OrderMap(5))
END SUB


~
Edited 2025-07-05 23:07 by lizby
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3357
Posted: 05:46pm 06 Jul 2025
Copy link to clipboard 
Print this post

With a Pico 2 flashed with MMBasic, I issued "LIST commands" and scraped the TeraTerm screen and saved "commands.txt" and then "LIST functions" and saved that as "functions.txt". I downloaded electricat's help.txt file from here: https://www.thebackshed.com/forum/ViewTopic.php?TID=17777&PID=237581#237581#237581

I had to edit lightly. I removed the OPTION entries, and because AUTOSAVE choked on /hex, I edited or deleted the entries which had that (and something else involving "/").

I uploaded those three files to Gemini and told it to use only the commands and functions in those files, and to look into help.txt to find clues for syntax (and said that for many commands it might need further help with syntax and meaning of parameters). It said it understood and would use the proper commands and functions.

I then fed it this specification:

The flags of Germany, France, Russia, Italy, The Netherlands, Belgium, Sweden, Norway, and Ukraine can all be drawn using the line command (with width specified) and the defined colors. For fun, please produce an MMBasic program filling the ILI9488 screen with those 9 flags with 3 rows of 3 flags and 4 pixels between each flag and each row.

Three versions later (less than 15 minutes), after one syntax error and one misalignment of the flags, this is what it produced:



Pretty impressive, I think. It actually used the BOX command, not the LINE command (it said its misunderstanding of the LINE command with LW parameter had caused the misalignment of Version 2). I did not tell it what colors to use for the flags--it figured that out on its own.

Here's the code (120 lines):
' MMBasic Flag Drawing Program (Version 3)

OPTION EXPLICIT

' --- Configuration ---
CONST Gap = 4
CONST FlagW = 157
CONST FlagH = 104

' --- Color Definitions ---
CONST Black = RGB(0,0,0)
CONST White = RGB(WHITE)
CONST Yellow = RGB(YELLOW)
CONST Red = RGB(RED)
CONST Green = RGB(GREEN)
CONST Blue = RGB(BLUE)
CONST Cyan = RGB(CYAN)
CONST Magenta = RGB(MAGENTA)

' --- Global Variables ---
DIM INTEGER Row, Col, FlagNumber, x, y

' --- Main Program ---
CLS

' --- Nested loops to position the 3x3 grid of flags ---
FlagNumber = 1
FOR Row = 0 TO 2
   FOR Col = 0 TO 2
       ' Calculate the top-left corner for the current flag
       x = Col * (FlagW + Gap)
       y = Row * (FlagH + Gap)

       ' Call the appropriate drawing subroutine for each flag
       SELECT CASE FlagNumber
           CASE 1: DrawGermany x, y
           CASE 2: DrawFrance x, y
           CASE 3: DrawRussia x, y
           CASE 4: DrawItaly x, y
           CASE 5: DrawNetherlands x, y
           CASE 6: DrawBelgium x, y
           CASE 7: DrawSweden x, y
           CASE 8: DrawNorway x, y
           CASE 9: DrawUkraine x, y
       END SELECT
       
       FlagNumber = FlagNumber + 1
   NEXT Col
NEXT Row

END

' =================================================================
' SUBROUTINES FOR DRAWING FLAGS (Rewritten with BOX for accuracy)
' =================================================================

SUB DrawGermany(x, y)
   LOCAL INTEGER StripeH1 = 35, StripeH2 = 34
   BOX x, y, FlagW, StripeH1, 0, Black, Black
   BOX x, y + StripeH1, FlagW, StripeH2, 0, Red, Red
   BOX x, y + StripeH1 + StripeH2, FlagW, StripeH1, 0, Yellow, Yellow
END SUB

SUB DrawFrance(x, y)
   LOCAL INTEGER StripeW1 = 52, StripeW2 = 53
   BOX x, y, StripeW1, FlagH, 0, Blue, Blue
   BOX x + StripeW1, y, StripeW2, FlagH, 0, White, White
   BOX x + StripeW1 + StripeW2, y, StripeW1, FlagH, 0, Red, Red
END SUB

SUB DrawRussia(x, y)
   LOCAL INTEGER StripeH1 = 35, StripeH2 = 34
   BOX x, y, FlagW, StripeH1, 0, White, White
   BOX x, y + StripeH1, FlagW, StripeH2, 0, Blue, Blue
   BOX x, y + StripeH1 + StripeH2, FlagW, StripeH1, 0, Red, Red
END SUB

SUB DrawItaly(x, y)
   LOCAL INTEGER StripeW1 = 52, StripeW2 = 53
   BOX x, y, StripeW1, FlagH, 0, Green, Green
   BOX x + StripeW1, y, StripeW2, FlagH, 0, White, White
   BOX x + StripeW1 + StripeW2, y, StripeW1, FlagH, 0, Red, Red
END SUB

SUB DrawNetherlands(x, y)
   LOCAL INTEGER StripeH1 = 35, StripeH2 = 34
   BOX x, y, FlagW, StripeH1, 0, Red, Red
   BOX x, y + StripeH1, FlagW, StripeH2, 0, White, White
   BOX x, y + StripeH1 + StripeH2, FlagW, StripeH1, 0, Blue, Blue
END SUB

SUB DrawBelgium(x, y)
   LOCAL INTEGER StripeW1 = 52, StripeW2 = 53
   BOX x, y, StripeW1, FlagH, 0, Black, Black
   BOX x + StripeW1, y, StripeW2, FlagH, 0, Yellow, Yellow
   BOX x + StripeW1 + StripeW2, y, StripeW1, FlagH, 0, Red, Red
END SUB

SUB DrawSweden(x, y)
   LOCAL INTEGER CrossW = 20, CrossHOff = 42
   BOX x, y, FlagW, FlagH, 0, Blue, Blue ' Background
   BOX x, y + CrossHOff, FlagW, CrossW, 0, Yellow, Yellow ' Horizontal bar
   BOX x + 50, y, CrossW, FlagH, 0, Yellow, Yellow ' Vertical bar
END SUB

SUB DrawNorway(x, y)
   LOCAL INTEGER CrossW = 24, CrossHOff = 40, InnerCrossW = 12, InnerHOff = 46
   BOX x, y, FlagW, FlagH, 0, Red, Red ' Red background
   BOX x, y + CrossHOff, FlagW, CrossW, 0, White, White ' White horizontal
   BOX x + 44, y, CrossW, FlagH, 0, White, White ' White vertical
   BOX x, y + InnerHOff, FlagW, InnerCrossW, 0, Blue, Blue ' Blue horizontal
   BOX x + 50, y, InnerCrossW, FlagH, 0, Blue, Blue ' Blue vertical
END SUB

SUB DrawUkraine(x, y)
   LOCAL INTEGER StripeH = 52
   BOX x, y, FlagW, StripeH, 0, Blue, Blue
   BOX x, y + StripeH, FlagW, StripeH, 0, Yellow, Yellow
END SUB

PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3357
Posted: 12:10pm 07 Jul 2025
Copy link to clipboard 
Print this post

I decided to ask Gemini to do a little independent research as part of its next effort. I gave it this task.

Can you read the list of countries by population here: https://en.wikipedia.org/wiki/List_of_countries_and_dependencies_by_population and determine which 9 with the highest population have flags which can be drawn with the BOX command (no angled or curved lines)?

So here it had to look at a Wikipedia page listing nations by population, look up their flags, and determine whether the flags could be drawn with just the BOX command. It gave me a list of the top 9.

I then gave the specification:
Great. Please produce an MMBasic program to draw those maps in the 3x3 configuration, and print in the middle of each map the name of the country and the population. If the text might go through a white area, use black as the color (rgb(black)), if through a black area, use white. Use the BOX command. With the TEXT command, an "alignment" parameter of C will center the top of the text at the x,y point.

It produced the 9 flags.
Great flags, but you did not include the name of the country and its population centered in each flag.

Two glitches later including a mistake on my part (black text on black background), it produced this:


Exactly right. Now go back to the wikipedia page and pick out the 16 countries with the highest population and a flag which can be drawn with the box command, and produce an MMBasic program to draw those on the ILI9488 with 4 rows of 4 flags.




So this is, at the least, something approaching independent (if guided) research. Gemini is somewhat prone to flattery: I was told that I was expert and patient.

' MMBasic Flag Drawing Program (Version 2)
' Draws the 16 most populous countries with BOX-compatible flags in a 4x4 grid.

OPTION EXPLICIT

' --- Configuration for a 4x4 grid on a 480x320 display ---
CONST Gap = 4
CONST FlagW = 117 ' (480 - 3*Gap) / 4
CONST FlagH = 77  ' (320 - 3*Gap) / 4

' --- Color Definitions ---
CONST Black = RGB(0,0,0)
CONST White = RGB(WHITE)
CONST Yellow = RGB(YELLOW)
CONST Red = RGB(RED)
CONST Green = RGB(GREEN)
CONST Blue = RGB(BLUE)
CONST Ivory = RGB(255, 255, 240) ' A slightly off-white for contrast

' --- Data for Flags (16 countries) ---
DIM STRING Names$(15) = ("Indonesia", "Nigeria", "Russia", "Germany", "Thailand", "France", "Italy", "Colombia", "Ukraine", "Poland", "Yemen", "Madagascar", "Ivory Coast", "Mali", "Netherlands", "Chad")
DIM STRING Pops$(15) = ("279M", "224M", "144M", "84M", "71M", "65M", "59M", "52M", "43M", "41M", "35M", "30M", "28M", "23M", "18M", "18M")

' --- Global Variables ---
DIM INTEGER Row, Col, FlagNumber, x, y, idx

' --- Main Program ---
CLS

' --- Nested loops to position the 4x4 grid of flags ---
FlagNumber = 1
FOR Row = 0 TO 3
   FOR Col = 0 TO 3
       x = Col * (FlagW + Gap)
       y = Row * (FlagH + Gap)
       
       idx = FlagNumber - 1
       
       SELECT CASE FlagNumber
           CASE 1: DrawIndonesia x, y
           CASE 2: DrawNigeria x, y
           CASE 3: DrawRussia x, y
           CASE 4: DrawGermany x, y
           CASE 5: DrawThailand x, y
           CASE 6: DrawFrance x, y
           CASE 7: DrawItaly x, y
           CASE 8: DrawColombia x, y
           CASE 9: DrawUkraine x, y
           CASE 10: DrawPoland x, y
           CASE 11: DrawYemen x, y
           CASE 12: DrawMadagascar x, y
           CASE 13: DrawIvoryCoast x, y
           CASE 14: DrawMali x, y
           CASE 15: DrawNetherlands x, y
           CASE 16: DrawChad x, y
       END SELECT
       
       DrawLabel x, y, Names$(idx), Pops$(idx)
       
       FlagNumber = FlagNumber + 1
   NEXT Col
NEXT Row

END

' =================================================================
' SUBROUTINES
' =================================================================

SUB DrawLabel(x, y, Name$, Pop$)
   LOCAL INTEGER CenterX, CenterY
   LOCAL STRING LabelText$
   CenterX = x + FlagW \ 2
   CenterY = y + FlagH \ 2
   LabelText$ = Name$ + " " + Pop$
   TEXT CenterX, CenterY - (MM.FontHeight \ 2), LabelText$, C, , , White, Black
END SUB

' --- Flag Drawing Subroutines ---
SUB DrawIndonesia(x, y)
   LOCAL INTEGER StripeH = FlagH \ 2
   BOX x, y, FlagW, StripeH, 0, Red, Red
   BOX x, y + StripeH, FlagW, FlagH - StripeH, 0, White, White
END SUB

SUB DrawNigeria(x, y)
   LOCAL INTEGER StripeW = FlagW \ 3
   BOX x, y, StripeW, FlagH, 0, Green, Green
   BOX x + StripeW, y, StripeW, FlagH, 0, White, White
   BOX x + 2 * StripeW, y, FlagW - 2 * StripeW, FlagH, 0, Green, Green
END SUB

SUB DrawRussia(x, y)
   LOCAL INTEGER StripeH = FlagH \ 3
   BOX x, y, FlagW, StripeH, 0, White, White
   BOX x, y + StripeH, FlagW, StripeH, 0, Blue, Blue
   BOX x, y + 2 * StripeH, FlagW, FlagH - 2 * StripeH, 0, Red, Red
END SUB

SUB DrawGermany(x, y)
   LOCAL INTEGER StripeH = FlagH \ 3
   BOX x, y, FlagW, StripeH, 0, Black, Black
   BOX x, y + StripeH, FlagW, StripeH, 0, Red, Red
   BOX x, y + 2 * StripeH, FlagW, FlagH - 2 * StripeH, 0, Yellow, Yellow
END SUB

SUB DrawThailand(x, y)
   LOCAL INTEGER h_outer = FlagH * 1/6, h_inner = FlagH * 1/6, h_center = FlagH * 2/6
   BOX x, y, FlagW, h_outer, 0, Red, Red
   BOX x, y + h_outer, FlagW, h_inner, 0, White, White
   BOX x, y + h_outer + h_inner, FlagW, h_center, 0, Blue, Blue
   BOX x, y + h_outer + h_inner + h_center, FlagW, h_inner, 0, White, White
   BOX x, y + h_outer + h_inner + h_center + h_inner, FlagW, h_outer, 0, Red, Red
END SUB

SUB DrawFrance(x, y)
   LOCAL INTEGER StripeW = FlagW \ 3
   BOX x, y, StripeW, FlagH, 0, Blue, Blue
   BOX x + StripeW, y, StripeW, FlagH, 0, White, White
   BOX x + 2 * StripeW, y, FlagW - 2 * StripeW, FlagH, 0, Red, Red
END SUB

SUB DrawItaly(x, y)
   LOCAL INTEGER StripeW = FlagW \ 3
   BOX x, y, StripeW, FlagH, 0, Green, Green
   BOX x + StripeW, y, StripeW, FlagH, 0, White, White
   BOX x + 2 * StripeW, y, FlagW - 2 * StripeW, FlagH, 0, Red, Red
END SUB

SUB DrawColombia(x, y)
   LOCAL INTEGER h_top = FlagH \ 2, h_bottom = FlagH \ 4
   BOX x, y, FlagW, h_top, 0, Yellow, Yellow
   BOX x, y + h_top, FlagW, h_bottom, 0, Blue, Blue
   BOX x, y + h_top + h_bottom, FlagW, FlagH - (h_top + h_bottom), 0, Red, Red
END SUB

SUB DrawUkraine(x, y)
   LOCAL INTEGER StripeH = FlagH \ 2
   BOX x, y, FlagW, StripeH, 0, Blue, Blue
   BOX x, y + StripeH, FlagW, FlagH - StripeH, 0, Yellow, Yellow
END SUB

SUB DrawPoland(x, y)
   LOCAL INTEGER StripeH = FlagH \ 2
   BOX x, y, FlagW, StripeH, 0, White, White
   BOX x, y + StripeH, FlagW, FlagH - StripeH, 0, Red, Red
END SUB

SUB DrawYemen(x, y)
   LOCAL INTEGER StripeH = FlagH \ 3
   BOX x, y, FlagW, StripeH, 0, Red, Red
   BOX x, y + StripeH, FlagW, StripeH, 0, White, White
   BOX x, y + 2 * StripeH, FlagW, FlagH - 2 * StripeH, 0, Black, Black
END SUB

SUB DrawMadagascar(x, y)
   LOCAL INTEGER v_stripe_w = FlagW \ 3
   LOCAL INTEGER h_stripe_h = FlagH \ 2
   BOX x, y, v_stripe_w, FlagH, 0, White, White
   BOX x + v_stripe_w, y, FlagW - v_stripe_w, h_stripe_h, 0, Red, Red
   BOX x + v_stripe_w, y + h_stripe_h, FlagW - v_stripe_w, FlagH - h_stripe_h, 0, Green, Green
END SUB

SUB DrawIvoryCoast(x, y)
   LOCAL INTEGER StripeW = FlagW \ 3
   BOX x, y, StripeW, FlagH, 0, RGB(247,127,0), RGB(247,127,0) ' Orange
   BOX x + StripeW, y, StripeW, FlagH, 0, White, White
   BOX x + 2 * StripeW, y, FlagW - 2 * StripeW, FlagH, 0, Green, Green
END SUB

SUB DrawMali(x, y)
   LOCAL INTEGER StripeW = FlagW \ 3
   BOX x, y, StripeW, FlagH, 0, Green, Green
   BOX x + StripeW, y, StripeW, FlagH, 0, Yellow, Yellow
   BOX x + 2 * StripeW, y, FlagW - 2 * StripeW, FlagH, 0, Red, Red
END SUB

SUB DrawNetherlands(x, y)
   LOCAL INTEGER StripeH = FlagH \ 3
   BOX x, y, FlagW, StripeH, 0, Red, Red
   BOX x, y + StripeH, FlagW, StripeH, 0, White, White
   BOX x, y + 2 * StripeH, FlagW, FlagH - 2 * StripeH, 0, Blue, Blue
END SUB

SUB DrawChad(x, y)
   LOCAL INTEGER StripeW = FlagW \ 3
   BOX x, y, StripeW, FlagH, 0, Blue, Blue
   BOX x + StripeW, y, StripeW, FlagH, 0, Yellow, Yellow
   BOX x + 2 * StripeW, y, FlagW - 2 * StripeW, FlagH, 0, Red, Red
END SUB


~
Edited 2025-07-07 22:19 by lizby
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
dddns
Guru

Joined: 20/09/2024
Location: Germany
Posts: 488
Posted: 01:37pm 07 Jul 2025
Copy link to clipboard 
Print this post

It reminds me of the classic text adventure games.
But why so polite, bet it will work with grammatical imperative and minimum phrasing as well :))

Point it to the source on github and let it crawl and there shouldn't be anymore spoon feeding work left..


and please ask it, what all of this leads to ;)
Edited 2025-07-07 23:38 by dddns
 
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 5050
Posted: 01:37pm 07 Jul 2025
Copy link to clipboard 
Print this post

Thank you for this update.
I am impressed, especially about the list of "things to avoid" that it created on it's own, and your idea to use that at a next session as a starting point.

Volhout
PicomiteVGA PETSCII ROBOTS
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3357
Posted: 02:34pm 07 Jul 2025
Copy link to clipboard 
Print this post

  dddns said  But why so polite, bet it will work with grammatical imperative and minimum phrasing as well :))


I'm sure that's true, but I don't want to get out of the habit, in case I forget around humans. My wife recently returned from visiting relatives, and remarked that it was nice to be back where someone was polite.

  Quote  Point it to the source on github and let it crawl and there shouldn't be anymore spoon feeding work left..


It doesn't appear to be that far along at present. Lots of spoon feeding. Lots of apparently unnecessary regressions. Still faster, for some things, than I would be. And not for some others.

  Quote  and please ask it, what all of this leads to ;)


Do you mean like "Abundance for All" or "Extinction for Humans"? It doesn't have a crystal ball, and I think the path is uncertain.

  Volhout said  I am impressed, especially about the list of "things to avoid"


That keeps growing. Since it used, without my telling it to, OPTION EXPLICIT, I've now told it not to use a variable unless it is in a DIM or LOCAL statement (or SUB or FUNCTION parameter). If it follows that directive, it may eliminate a quarter of the errors it has produced.
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
dddns
Guru

Joined: 20/09/2024
Location: Germany
Posts: 488
Posted: 03:51pm 07 Jul 2025
Copy link to clipboard 
Print this post

  lizby said  
  Quote  Point it to the source on github and let it crawl and there shouldn't be anymore spoon feeding work left..


It doesn't appear to be that far along at present. Lots of spoon feeding. Lots of apparently unnecessary regressions. Still faster, for some things, than I would be. And not for some others.

and please ask it, what all of this leads to ;)

Do you mean like "Abundance for All" or "Extinction for Humans"? It doesn't have a crystal ball, and I think the path is uncertain.



I mean, that it already takes now all my illusions and dreams.
If you ask it to make a "jig saw" game out of your flags example, it would for sure do. So why should I even think of doing it by myself if there is is a much more faster and convenient way? From my point of view this point will come faster than the internet itself, which only took 25 years..like 2,5 years from now on??

And yes, if there is no more sense for life it'll be done.
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3357
Posted: 04:24pm 07 Jul 2025
Copy link to clipboard 
Print this post

  dddns said  I mean, that it already takes now all my illusions and dreams.


I can't speak for your illusions, but maybe your dreams would need to expand. ;-) I would be happy to have a black box which can write programs as I specify them. I tend to wake up every few days with something else I want to do, and my to-do list becomes ever longer--for programming as well as for real-life projects.

I want to say: here is the MMB4L source and here is the source and user manual for the PicoMite's pin IO, and here is the specification for the API for libgpiod: now write code which allows MMB4L to handle a Raspberry Pi's pins the way a PicoMite's are handled.

I want to have a self-driving (electric) car available, but don't necessarily want to own one.

I want gummint not to get in the way of clean energy. Three examples in Canada: solar panels tariffed at 165%; mini-split heat pump installers must have a 40-months' apprenticeship, whereas in Maine it's 6 months; Alberta community decides solar farm on "second class" farmland not appropriate for the community.

What I don't want: for AI to decide (to be able to decide) that to further its goals, all the earth must be turned into gray goo (or any other more differentiated state which excludes humans and has humans not in control).

I do think that the threat of human extinction is greater from AI than from climate change (since humans are very adaptable, but might not be able to escape a hyperintelligence which was focused on getting rid of them).

Well, that's far afield from tomorrow's task: getting Gemini to be a little better at writing MMBasic code.
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3357
Posted: 12:17am 08 Jul 2025
Copy link to clipboard 
Print this post

Today's task for Gemini was to get more realistic colors for the 16 flags. I had originally told it to use the named colors: rgb(red), rgb(green), etc. I asked if it could search out flag images on the web and determine the right colors. It said it could, so I set the specification:

Please use your understanding of RGB to get a closer match to the actual color as you find flag examples online in the RGB format (e.g., RGB(130,148,5) for dark yellow). Produce a program for that in the 4x4 format last used. So each flag may have a different version of what we might generally call "green".


I thought that if it could find appropriate RGB settings, which it quickly did, this would be result in a quick solution. Unfortunately, for reasons which were mostly silly, it took until Version 13. Among the inexplicable regressions were returning to 9 flags in the 3x3 format, omitting the text, and most contradictory to the specification, returning to the named colors after it had successfully drawn using better colors.

But here's the final result--first with the named colors on the left, then with more accurate colors:



The reds, greens, yellows, and blues are notably darker. You can see the difference between adjacent blues with Thailand and France and Netherlands and Chad, and greens between Ivory Coast and Mali.

Although it was frustrating for it to take so many iterations when it had immediately solved the color problem, the process is pretty straightforward. Usually within a minute of my presenting an error (or a specification), it has new code, which I copy and paste into TeraTerm after F10 AUTOSAVE. Ctrl-Z, run, and there's a new result.

The program--now Version 17 (219 lines) because I noticed a problem with the rendering of the Thai flag (the only one with more than 3 boxes to be drawn).

' MMBasic Flag Drawing Program (Version 17)
' Final check and correction of all variable declarations.

OPTION EXPLICIT

' --- Configuration ---
CONST Gap = 4
CONST FlagW = 117
CONST FlagH = 77

' --- Accurate Color Definitions ---
CONST Black = RGB(0,0,0)
CONST White = RGB(WHITE)
' CORRECTED: All required colors are now explicitly defined
CONST IndoRed = RGB(206, 17, 38)
CONST NgrGreen = RGB(0, 135, 81)
CONST RusBlue = RGB(0, 57, 166)
CONST RusRed = RGB(213, 43, 30)
CONST GerRed = RGB(221, 0, 0)
CONST GerYellow = RGB(255, 206, 0)
CONST ThaiRed = RGB(165, 25, 49)
CONST ThaiBlue = RGB(45, 42, 114)
CONST ItaGreen = RGB(0, 146, 70)
CONST ItaRed = RGB(206, 43, 55)
CONST ColYellow = RGB(252, 209, 22)
CONST ColBlue = RGB(0, 56, 147)
CONST ColRed = RGB(206, 17, 38)
CONST UkrBlue = RGB(0, 91, 187)
CONST UkrYellow = RGB(255, 213, 0)
CONST PolRed = RGB(220, 20, 60)
CONST YemRed = RGB(206, 17, 38)
CONST MadRed = RGB(252, 63, 62)
CONST MadGreen = RGB(0, 129, 60)
CONST IvcOrange = RGB(247, 127, 0)
CONST IvcGreen = RGB(0, 158, 96)
CONST MaliGreen = RGB(20, 170, 52)
CONST MaliYellow = RGB(252, 209, 22)
CONST MaliRed = RGB(206, 17, 38)
CONST NldBlue = RGB(33, 70, 139)
CONST ChadBlue = RGB(0, 32, 91)
CONST ChadYellow = RGB(252, 209, 22)
CONST ChadRed = RGB(206, 17, 38)

' --- Global Variables ---
DIM INTEGER Row, Col, FlagNumber, x, y, idx

' --- Data for Flags ---
DIM STRING Names$(15) = ("Indonesia", "Nigeria", "Russia", "Germany", "Thailand", "France", "Italy", "Colombia", "Ukraine", "Poland", "Yemen", "Madagascar", "Ivory Coast", "Mali", "Netherlands", "Chad")
DIM STRING Pops$(15) = ("279M", "224M", "144M", "84M", "71M", "65M", "59M", "52M", "43M", "41M", "35M", "30M", "28M", "23M", "18M", "18M")

' --- Main Program ---
CLS

' --- Nested loops to position the 4x4 grid of flags ---
FlagNumber = 1
FOR Row = 0 TO 3
   FOR Col = 0 TO 3
       x = Col * (FlagW + Gap)
       y = Row * (FlagH + Gap)
       
       idx = FlagNumber - 1
       
       SELECT CASE FlagNumber
           CASE 1: DrawIndonesia x, y
           CASE 2: DrawNigeria x, y
           CASE 3: DrawRussia x, y
           CASE 4: DrawGermany x, y
           CASE 5: DrawThailand x, y
           CASE 6: DrawFrance x, y
           CASE 7: DrawItaly x, y
           CASE 8: DrawColombia x, y
           CASE 9: DrawUkraine x, y
           CASE 10: DrawPoland x, y
           CASE 11: DrawYemen x, y
           CASE 12: DrawMadagascar x, y
           CASE 13: DrawIvoryCoast x, y
           CASE 14: DrawMali x, y
           CASE 15: DrawNetherlands x, y
           CASE 16: DrawChad x, y
       END SELECT
       
       DrawLabel x, y, Names$(idx), Pops$(idx)
       
       FlagNumber = FlagNumber + 1
   NEXT Col
NEXT Row

END

' =================================================================
' SUBROUTINES
' =================================================================

SUB DrawLabel(x, y, Name$, Pop$)
   LOCAL INTEGER CenterX, CenterY, LabelTextLen
   LOCAL STRING LabelText$
   CenterX = x + FlagW \ 2
   CenterY = y + FlagH \ 2
   LabelText$ = Name$ + " " + Pop$
   LabelTextLen = LEN(LabelText$)
   TEXT CenterX - (LabelTextLen * MM.FontWidth / 2) , CenterY - (MM.FontHeight \ 2), LabelText$, , , , White, Black
END SUB

' --- Flag Drawing Subroutines using the BOX command ---
SUB DrawIndonesia(x, y)
   LOCAL INTEGER StripeH = FlagH \ 2
   BOX x, y, FlagW, StripeH, 0, IndoRed, IndoRed
   BOX x, y + StripeH, FlagW, FlagH - StripeH, 0, White, White
END SUB

SUB DrawNigeria(x, y)
   LOCAL INTEGER StripeW = FlagW \ 3
   BOX x, y, StripeW, FlagH, 0, NgrGreen, NgrGreen
   BOX x + StripeW, y, StripeW, FlagH, 0, White, White
   BOX x + 2 * StripeW, y, FlagW - 2 * StripeW, FlagH, 0, NgrGreen, NgrGreen
END SUB

SUB DrawRussia(x, y)
   LOCAL INTEGER StripeH = FlagH \ 3
   BOX x, y, FlagW, StripeH, 0, White, White
   BOX x, y + StripeH, FlagW, StripeH, 0, RusBlue, RusBlue
   BOX x, y + 2 * StripeH, FlagW, FlagH - 2 * StripeH, 0, RusRed, RusRed
END SUB

SUB DrawGermany(x, y)
   LOCAL INTEGER StripeH = FlagH \ 3
   BOX x, y, FlagW, StripeH, 0, Black, Black
   BOX x, y + StripeH, FlagW, StripeH, 0, GerRed, GerRed
   BOX x, y + 2 * StripeH, FlagW, FlagH - 2 * StripeH, 0, GerYellow, GerYellow
END SUB

SUB DrawThailand(x, y)
   LOCAL INTEGER h_outer, h_center, h_inner
   h_outer = 13
   h_inner = 13
   h_center = 25
   
   BOX x, y, FlagW, h_outer, 0, ThaiRed, ThaiRed
   BOX x, y + h_outer, FlagW, h_inner, 0, White, White
   BOX x, y + h_outer + h_inner, FlagW, h_center, 0, ThaiBlue, ThaiBlue
   BOX x, y + h_outer + h_inner + h_center, FlagW, h_inner, 0, White, White
   BOX x, y + h_outer + h_inner + h_center + h_inner, FlagW, 13, 0, ThaiRed, ThaiRed
END SUB

SUB DrawFrance(x, y)
   LOCAL INTEGER StripeW = FlagW \ 3
   BOX x, y, StripeW, FlagH, 0, RusBlue, RusBlue
   BOX x + StripeW, y, StripeW, FlagH, 0, White, White
   BOX x + 2 * StripeW, y, FlagW - 2 * StripeW, FlagH, 0, RusRed, RusRed
END SUB

SUB DrawItaly(x, y)
   LOCAL INTEGER StripeW = FlagW \ 3
   BOX x, y, StripeW, FlagH, 0, ItaGreen, ItaGreen
   BOX x + StripeW, y, StripeW, FlagH, 0, White, White
   BOX x + 2 * StripeW, y, FlagW - 2 * StripeW, FlagH, 0, ItaRed, ItaRed
END SUB

SUB DrawColombia(x, y)
   LOCAL INTEGER h_top = FlagH \ 2, h_bottom = FlagH \ 4
   BOX x, y, FlagW, h_top, 0, ColYellow, ColYellow
   BOX x, y + h_top, FlagW, h_bottom, 0, ColBlue, ColBlue
   BOX x, y + h_top + h_bottom, FlagW, FlagH - (h_top + h_bottom), 0, ColRed, ColRed
END SUB

SUB DrawUkraine(x, y)
   LOCAL INTEGER StripeH = FlagH \ 2
   BOX x, y, FlagW, StripeH, 0, UkrBlue, UkrBlue
   BOX x, y + StripeH, FlagW, FlagH - StripeH, 0, UkrYellow, UkrYellow
END SUB

SUB DrawPoland(x, y)
   LOCAL INTEGER StripeH = FlagH \ 2
   BOX x, y, FlagW, StripeH, 0, White, White
   BOX x, y + StripeH, FlagW, FlagH - StripeH, 0, IndoRed, IndoRed
END SUB

SUB DrawYemen(x, y)
   LOCAL INTEGER StripeH = FlagH \ 3
   BOX x, y, FlagW, StripeH, 0, YemRed, YemRed
   BOX x, y + StripeH, FlagW, StripeH, 0, White, White
   BOX x, y + 2 * StripeH, FlagW, FlagH - 2 * StripeH, 0, Black, Black
END SUB

SUB DrawMadagascar(x, y)
   LOCAL INTEGER v_stripe_w = FlagW \ 3
   LOCAL INTEGER h_stripe_h = FlagH \ 2
   BOX x, y, v_stripe_w, FlagH, 0, White, White
   BOX x + v_stripe_w, y, FlagW - v_stripe_w, h_stripe_h, 0, MadRed, MadRed
   BOX x + v_stripe_w, y + h_stripe_h, FlagW - v_stripe_w, FlagH - h_stripe_h, 0, MadGreen, MadGreen
END SUB

SUB DrawIvoryCoast(x, y)
   LOCAL INTEGER StripeW = FlagW \ 3
   BOX x, y, StripeW, FlagH, 0, IvcOrange, IvcOrange
   BOX x + StripeW, y, StripeW, FlagH, 0, White, White
   BOX x + 2 * StripeW, y, FlagW - 2 * StripeW, FlagH, 0, IvcGreen, IvcGreen
END SUB

SUB DrawMali(x, y)
   LOCAL INTEGER StripeW = FlagW \ 3
   BOX x, y, StripeW, FlagH, 0, MaliGreen, MaliGreen
   BOX x + StripeW, y, StripeW, FlagH, 0, MaliYellow, MaliYellow
   BOX x + 2 * StripeW, y, FlagW - 2 * StripeW, FlagH, 0, MaliRed, MaliRed
END SUB

SUB DrawNetherlands(x, y)
   LOCAL INTEGER StripeH = FlagH \ 3
   BOX x, y, FlagW, StripeH, 0, RusRed, RusRed
   BOX x, y + StripeH, FlagW, StripeH, 0, White, White
   BOX x, y + 2 * StripeH, FlagW, FlagH - 2 * StripeH, 0, NldBlue, NldBlue
END SUB

SUB DrawChad(x, y)
   LOCAL INTEGER StripeW = FlagW \ 3
   BOX x, y, StripeW, FlagH, 0, ChadBlue, ChadBlue
   BOX x + StripeW, y, StripeW, FlagH, 0, ChadYellow, ChadYellow
   BOX x + 2 * StripeW, y, FlagW - 2 * StripeW, FlagH, 0, ChadRed, ChadRed
END SUB


~
Edited 2025-07-08 10:51 by lizby
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3357
Posted: 11:16pm 08 Jul 2025
Copy link to clipboard 
Print this post

Today:
A new task, as a lark, illustrating some independent investigation. This MMBasic program will be Version 1. Specification: determine how many unique colors there are on the 16 flags; sort them by wavelength into a rainbow arrangement; display a box for each color starting at y=0, depth 100 pixels, width=mm.hres/number-of-colors; below each color box print the country name with an "alignment" in the TEXT command of CT, which is to be centered below the box and printed vertically; avoid syntax errors by confirming that any variables used have been declared and that command or functions used are in the commands and functions text files provided earlier, or are supplied by you, and syntax conforms to the "help" file provided earlier.


I thought that if Gemini could sort the rgb colors in the flags in rainbow order, as it quickly showed it could with access to some API which gave it hue, this might be a one-and-done task.

Unfortunately, it was Version 10 before it got this:



Errors included undeclared variable (despite the fact that I have told it multiple times to always check before providing code that all variables are in DIM or LOCAL statements), giving country names of "Cyan" and "Magenta", regressing entirely to a version of the flags program, inventing a new parameter for the TEXT command (compounded by my initially saying the "alignment" parameter should be CT instead of CTV), and not sorting in rainbow order (with white and black first).

I eventually had to feed it the colors it had used in the flag program:
CONST IndoRed = RGB(206, 17, 38)
CONST NgrGreen = RGB(0, 135, 81)
CONST RusBlue = RGB(0, 57, 166)
CONST RusRed = RGB(213, 43, 30)
CONST GerRed = RGB(221, 0, 0)
CONST GerYellow = RGB(255, 206, 0)
CONST ThaiRed = RGB(165, 25, 49)
CONST ThaiBlue = RGB(45, 42, 114)
CONST ItaGreen = RGB(0, 146, 70)
CONST ItaRed = RGB(206, 43, 55)
CONST ColYellow = RGB(252, 209, 22)
CONST ColBlue = RGB(0, 56, 147)
CONST ColRed = RGB(206, 17, 38)
CONST UkrBlue = RGB(0, 91, 187)
CONST UkrYellow = RGB(255, 213, 0)
CONST PolRed = RGB(220, 20, 60)
CONST YemRed = RGB(206, 17, 38)
CONST MadRed = RGB(252, 63, 62)
CONST MadGreen = RGB(0, 129, 60)
CONST IvcOrange = RGB(247, 127, 0)
CONST IvcGreen = RGB(0, 158, 96)
CONST MaliGreen = RGB(20, 170, 52)
CONST MaliYellow = RGB(252, 209, 22)
CONST MaliRed = RGB(206, 17, 38)
CONST NldBlue = RGB(33, 70, 139)
CONST ChadBlue = RGB(0, 32, 91)
CONST ChadYellow = RGB(252, 209, 22)
CONST ChadRed = RGB(206, 17, 38)


The process was more frustrating than it should have been, but still pretty quick. I think its finding and sorting on the hue value was creditable--indicative of an ability to search for external means to solve a problem.

Here's the final code (63 lines):
' MMBasic Flag Color Spectrum (Version 10)
' Uses a manually sorted list of all unique colors for accuracy.

OPTION EXPLICIT

' --- Configuration ---
CONST BarH = 100
CONST LabelY = 110

' --- Manually Sorted Array of Unique Colors from all 16 Flags ---
' Sorted: White, Black, Reds, Oranges, Yellows, Greens, Blues
CONST NumColors = 20
DIM INTEGER Colors(NumColors)
DIM STRING Names$(NumColors)

' --- Global Variables ---
DIM INTEGER i, x, BarW, TxtX, TxtY

' --- Main Program ---
' Read all data from the DATA statements into the arrays
FOR i = 1 TO NumColors
   READ Colors(i), Names$(i)
NEXT i

CLS

BarW = MM.HRes / NumColors

FOR i = 1 TO NumColors
   x = (i - 1) * BarW
   BOX x, 0, BarW, BarH, 0, Colors(i), Colors(i)
   
   TxtX = x + (BarW \ 2)
   TxtY = LabelY
   TEXT TxtX, TxtY, Names$(i), CTV, , , RGB(WHITE)
NEXT i

END

' =================================================================
' DATA Section
' =================================================================
' Data is pre-sorted: White, Black, Reds, Orange, Yellows, Greens, Blues
DATA RGB(WHITE), "Russia"
DATA RGB(0,0,0), "Germany"
DATA RGB(165, 25, 49), "Thailand"
DATA RGB(174, 28, 40), "Netherlands"
DATA RGB(186, 12, 47), "Norway"
DATA RGB(206, 17, 38), "Indonesia"
DATA RGB(213, 43, 30), "Russia"
DATA RGB(220, 20, 60), "Poland"
DATA RGB(221, 0, 0), "Germany"
DATA RGB(239, 65, 53), "France"
DATA RGB(252, 63, 62), "Madagascar"
DATA RGB(247, 127, 0), "Ivory Coast"
DATA RGB(255, 206, 0), "Germany"
DATA RGB(255, 213, 0), "Ukraine"
DATA RGB(252, 209, 22), "Colombia"
DATA RGB(0, 158, 96), "Ivory Coast"
DATA RGB(0, 146, 70), "Italy"
DATA RGB(0, 135, 81), "Nigeria"
DATA RGB(0, 57, 166), "Russia"
DATA RGB(0, 32, 91), "Chad"


I notice that although I gave it 28 rgb colors (that it had generated for the flags program), it only displayed 20. It is possible that its hue routine returned the same value for some. I didn't think to ask it if that was what happened.

The last part of the specification is boiler-plate which I will include with each new specification. I wish I could just say it once and be done, but that doesn't seem to be the case:

avoid syntax errors by confirming that any variables used have been declared and that command or functions used are in the commands and functions text files provided earlier, or are supplied by you, and syntax conforms to the "help" file provided earlier.


~
Edited 2025-07-09 09:29 by lizby
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
     Page 4 of 4    
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025