• Help by chatbot

    From Stefan Ram@21:1/5 to All on Sat Sep 7 16:55:41 2024
    Hey everyone! Today, I threw together a C++ program for Windows
    with a little help from a chatbot. It's still got some hiccups
    and bugs, but hey, it's showing some basic vibes!

    I've got a bit of a clue about C++, but the last time I dabbled
    a bit in Windows programming was ages ago. Honestly, I wouldn't
    have been able to make this happen without some guidance!

    The chatbot kicked things off for me with a starter program, and
    now I can tweak it to get closer to what I really want to create.

    (I basically told the chatbot that I wanted a C++ program for
    Windows where a black circle moves towards a red one. Then I went
    over some details about how I wanted it coded, and together with
    the chatbot, I squashed the bugs until it was running.)

    The end condition for the loop still ain't working.
    The black circle should stop moving when it hits the red circle.
    Instead, the program's stuck in an endless loop (it'll freeze!).
    But that's chill. I can handle it later.

    I just added the "Sleep(60);" to slow things down so that it does
    not run too fast, but it's actually intended without this line.

    Manual: Hit Alt-R or just click "Run." You should see two
    circles pop up in random spots, with the black one moving
    towards the red one. Then, the program will freeze up,
    and you'll need to force quit it from outside. (Closing the
    console seems to work.)

    Some compiler options used (the chatbot explained that to me, too!):

    . . . main.cpp -static -mwindows -lquadmath -luser32 -lgdi32

    . main.cpp

    #include <windows.h>
    #include <cstdlib>
    #include <ctime>
    #include <iostream>

    const int WIDTH = 800; // Width of the window
    const int HEIGHT = 600; // Height of the window

    HBITMAP hBitmap;
    HDC hdcMem, hdcWindow;
    int redCircleX, redCircleY, blackCircleX, blackCircleY;
    bool isRunning = false; // Flag to indicate if the simulation is running
    HWND hwnd; // Declare hwnd as a global variable

    // Define a custom message for the simulation
    #define WM_SIMULATE (WM_USER + 1)

    // Timing variables
    DWORD lastUpdateTime = 0; // Last time the window was updated
    const DWORD updateInterval = 50; // Update interval in milliseconds (20 updates per second)

    void CreateConsole() {
    AllocConsole(); // Allocate a new console for the application
    FILE* fp;
    freopen_s(&fp, "CONOUT$", "w", stdout); // Redirect stdout to the console
    freopen_s(&fp, "CONOUT$", "w", stderr); // Redirect stderr to the console
    }

    void StartSimulation() {
    std::srand(std::time(0));
    redCircleX = std::rand() % WIDTH;
    redCircleY = std::rand() % HEIGHT;
    blackCircleX = std::rand() % WIDTH;
    blackCircleY = std::rand() % HEIGHT;

    std::cout << "Red Circle Position: (" << redCircleX << ", " << redCircleY << ")" << std::endl;
    std::cout << "Black Circle Position: (" << blackCircleX << ", " << blackCircleY << ")" << std::endl;

    // Fill bitmap with white
    HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255));
    RECT rect = {0, 0, WIDTH, HEIGHT}; // Define RECT here
    FillRect(hdcMem, &rect, whiteBrush);
    DeleteObject(whiteBrush);

    // Draw red circle
    HBRUSH redBrush = CreateSolidBrush(RGB(255, 0, 0));
    SelectObject(hdcMem, redBrush);
    Ellipse(hdcMem, redCircleX - 10, redCircleY - 10, redCircleX + 10, redCircleY + 10);
    DeleteObject(redBrush);

    // Draw black circle
    HBRUSH blackBrush = CreateSolidBrush(RGB(0, 0, 0));
    SelectObject(hdcMem, blackBrush);
    Ellipse(hdcMem, blackCircleX - 10, blackCircleY - 10, blackCircleX + 10, blackCircleY + 10);
    DeleteObject(blackBrush);

    isRunning = true; // Set the flag to indicate that the simulation is running
    lastUpdateTime = GetTickCount(); // Initialize the last update time
    }

    void SimulateStep() {
    // Check neighboring pixels
    if ((blackCircleX > 0 && blackCircleY > 0 && GetPixel(hdcMem, blackCircleX - 1, blackCircleY) == RGB(255, 0, 0)) ||
    (blackCircleX < WIDTH - 1 && blackCircleY > 0 && GetPixel(hdcMem, blackCircleX + 1, blackCircleY) == RGB(255, 0, 0)) ||
    (blackCircleX > 0 && blackCircleY < HEIGHT - 1 && GetPixel(hdcMem, blackCircleX, blackCircleY - 1) == RGB(255, 0, 0)) ||
    (blackCircleX < WIDTH - 1 && blackCircleY < HEIGHT - 1 && GetPixel(hdcMem, blackCircleX, blackCircleY + 1) == RGB(255, 0, 0))) {
    std::cout << "Black circle is now adjacent to red circle." << std::endl;
    isRunning = false; // Stop the simulation
    return; // Exit the step
    }

    // Move black circle towards red circle
    if (blackCircleX < redCircleX) blackCircleX++;
    else if (blackCircleX > redCircleX) blackCircleX--;

    if (blackCircleY < redCircleY) blackCircleY++;
    else if (blackCircleY > redCircleY) blackCircleY--;

    // Clear and redraw
    HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255));
    RECT rect = {0, 0, WIDTH, HEIGHT}; // Define RECT here
    FillRect(hdcMem, &rect, whiteBrush); // Use the defined RECT
    DeleteObject(whiteBrush);

    // Draw red circle
    HBRUSH redBrush = CreateSolidBrush(RGB(255, 0, 0));
    SelectObject(hdcMem, redBrush);
    Ellipse(hdcMem, redCircleX - 10, redCircleY - 10, redCircleX + 10, redCircleY + 10);
    DeleteObject(redBrush);

    // Draw black circle
    HBRUSH blackBrush = CreateSolidBrush(RGB(0, 0, 0));
    SelectObject(hdcMem, blackBrush);
    Ellipse(hdcMem, blackCircleX - 10, blackCircleY - 10, blackCircleX + 10, blackCircleY + 10);
    DeleteObject(blackBrush);

    // Check if it's time to update the window
    DWORD currentTime = GetTickCount();
    if (currentTime - lastUpdateTime >= updateInterval) {
    InvalidateRect(hwnd, NULL, TRUE); // Use TRUE to force a full redraw
    UpdateWindow(hwnd); // Force the window to repaint immediately
    lastUpdateTime = currentTime; // Update the last update time
    }

    // Debug output for the current positions
    std::cout << "Current Black Circle Position: (" << blackCircleX << ", " << blackCircleY << ")" << std::endl;
    Sleep(60);
    }

    LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_PAINT: {
    PAINTSTRUCT ps;
    BeginPaint(hwnd, &ps);
    BitBlt(ps.hdc, 0, 0, WIDTH, HEIGHT, hdcMem, 0, 0, SRCCOPY);
    EndPaint(hwnd, &ps);
    break;
    }
    case WM_DESTROY: {
    DeleteObject(hBitmap);
    DeleteDC(hdcMem);
    PostQuitMessage(0);
    break;
    }
    case WM_COMMAND: {
    if (LOWORD(wParam) == 1) { // "Run" menu item
    std::cout << "Run command triggered." << std::endl;
    StartSimulation(); // Start the simulation
    PostMessage(hwnd, WM_SIMULATE, 0, 0); // Post a custom message to start the simulation loop
    }
    break;
    }
    case WM_SIMULATE: {
    if (isRunning) {
    SimulateStep(); // Perform one step of the simulation
    PostMessage(hwnd, WM_SIMULATE, 0, 0); // Post the message again for the next iteration
    }
    break;
    }
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
    }

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {
    CreateConsole(); // Create console for debug output

    // Create memory device context
    hdcMem = CreateCompatibleDC(NULL);
    hBitmap = CreateCompatibleBitmap(GetDC(NULL), WIDTH, HEIGHT);
    SelectObject(hdcMem, hBitmap);

    // Register window class
    const char CLASS_NAME[] = "Sample Window Class";
    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;
    RegisterClass(&wc);

    // Create the menu
    HMENU hMenu = CreateMenu();
    AppendMenu(hMenu, MF_STRING, 1, "Run"); // Add "Run" menu item

    // Create window
    hwnd = CreateWindowEx(0, CLASS_NAME, "Circle Simulation", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
    CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT, NULL, hMenu, hInstance, NULL);
    ShowWindow(hwnd, nCmdShow);

    // Message loop
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }

    return 0;
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Stefan Ram on Sat Sep 7 17:40:30 2024
    ram@zedat.fu-berlin.de (Stefan Ram) wrote or quoted:
    // Message loop
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }

    We seem to have leveled up our game with handling Windows
    messages - now the window can actually be closed!

    while (true) {
    // Check for messages
    while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    if (msg.message == WM_QUIT) {
    return msg.wParam; // Exit the application
    }
    }

    // Process simulation step if running
    if (isRunning) {
    SimulateStep(); // Perform one step of the simulation
    }
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Mon Sep 9 16:14:08 2024
    Stefan,

    DispatchMessage(&msg);
    if (msg.message == WM_QUIT) {
    return msg.wParam; // Exit the application

    https://learn.microsoft.com/en-us/windows/win32/learnwin32/window-messages

    See WM_DESTROY and PostQuitMessage

    (the page is one-of-several, combining into a small tutorial)

    Some other stuff is off too: creating a memory DC before entering the message-loop, but destroying it somewhere inside of it (instead of after the message-loop exits)

    Bottom line: your "chatbot" created something that (with some of your help) runs, but what I would call "hacked together" (IOW, not something you would want to show your boss/teacher).

    I do hope you enjoyed talking with it to/and creating the program though.

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to R.Wieser on Mon Sep 9 14:34:33 2024
    "R.Wieser" <address@is.invalid> wrote or quoted:
    Some other stuff is off too: creating a memory DC before entering the >message-loop, but destroying it somewhere inside of it (instead of after the >message-loop exits)

    Thanks for the heads up! I'll try to keep those pointers in mind
    next time I'm tweaking the source code.

    I do hope you enjoyed talking with it to/and creating the program though.

    Yeah, it was pretty sweet to see some progress on my little
    pet project. I went with Python 'cause it's got those built-in
    graphics libraries (turtle and tkinter) that C++ doesn't, but
    Python's going to be way too slow for what I'm cooking up. At least
    now I've got something to start from without breaking a sweat.

    (The endgame is to simulate these robots whose brains level up
    through some evolution-type deal. Kinda like "Framsticks", but
    way more chill since I'm just doing this as a side hustle when
    I'm not crushing it at work or hitting the beach.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)