Высокоэнтропийный вайбкодинг

от автора

В настоящее время существует много мануалов как правильно делать запросы, в основном они касаются привычного всем языка, причём, неважно какой он, модель преобразует его в вектор который одинаков для большинства людей. Нюансы вроде системы времён, падежей, фиксированной или гибкой последовательности слов мало влияют на структурированный вывод программ, в основном они нужны лишь для художественной генерации или передачи смысла текста от человека к человеку.

Задача довольно простая — как с использованием минимально возможного набора слов без приставок, суффиксов, окончаний или с их минимумом, а также союзов и других вспомогательных речевых конструкций получить на выходе годный код с 0% ошибок и 90% функционала согласно такому промпт-ТЗ.

Итак, приступим. Будем использовать VS Code/блокнот с пустой папкой.

Для начала необходимо развернуть виртуальное окружение. Для этого пишем следующий промпт. >Замечание — пора на Хабре добавить в язык программирования «Промптинг»<

Развёртывание виртуального окружения

Хотеть бэш скрипт проверь .venv если нет создать, обновить pip последняя версия найти requirements.txt установить библиотеки файл этот. Опция аргумент имя файла.py скрипт проверь наличие окружения .вэнв если нет установи рекварементс.txt. Если .вэнв уже есть запускай питон 3 скрипт проверь что запуск внутри вэнв. Хотеть список зависимостей флаг —g сохранить в файл requirements-текущая дата-время.txt изменить версия == на >=. выйди из вэнв по завершению питона.

Данный промпт генерирует следующий код

#!/bin/bash# Имя виртуального окруженияVENV_DIR=".venv"# Имя файла скрипта из аргументаPY_SCRIPT=$1# 1. Если передан флаг --g, сохраняем зависимости и выходимif [[ "$1" == "--g" ]]; then    if [ -d "$VENV_DIR" ]; then        source "$VENV_DIR/bin/activate"        FILENAME="requirements-$(date +'%Y%m%d-%H%M%S').txt"        # Сохраняем, меняя == на >=        pip freeze | sed 's/==/>=/g' > "$FILENAME"        echo "Зависимости сохранены в $FILENAME"        deactivate    else        echo "Ошибка: .venv не найден. Нечего сохранять."    fi    exit 0fi# 2. Проверка и создание .venvif [ ! -d "$VENV_DIR" ]; then    echo "Создаю виртуальное окружение..."    python3 -m venv "$VENV_DIR"    source "$VENV_DIR/bin/activate"        echo "Обновляю pip..."    pip install --upgrade pip        if [ -f "requirements.txt" ]; then        echo "Устанавливаю библиотеки из requirements.txt..."        pip install -r requirements.txt    fielse    source "$VENV_DIR/bin/activate"fi# 3. Запуск Python скрипта (если передан аргумент)if [ -n "$PY_SCRIPT" ]; then    if [ -f "$PY_SCRIPT" ]; then        echo "Запуск $PY_SCRIPT внутри $(which python)..."        python3 "$PY_SCRIPT"    else        echo "Ошибка: Файл $PY_SCRIPT не найден."    fielse    echo "Окружение готово. Имя скрипта для запуска не указано."fi# 4. Выход из venvdeactivate

запуская командой ./generate_requirements.sh my.py можно получить запуск скрипта с автоматической установкой виртуального окружения на основе файла requirements.txt когда виртуальное окружение уже создано и имеется повторный запуск применяется уже к установленному venv. Пример файла requirements.txt
pygame
PyOpenGL
PyOpenGL_accelerate
numpy

matplotlib
Если необходимо сканировать пакеты которые установлены, запускается скрипт с флагом —g, создаётся файл с таймстемпом requirements-20260427-213724.txt
содержащий
contourpy>=1.3.3
cycler>=0.12.1
fonttools>=4.62.1
kiwisolver>=1.5.0
matplotlib>=3.10.9
numpy>=2.4.4

подправленные версии с точки зрения последующей установкой новых

my.py — любой hello world, но лучше использовать промпт
пример Питон numpy вектор вывод умножение число

import numpy as np# Создание вектораvector = np.array([1, 2, 3])# Умножение на числоresult = vector * 5print(result)# Вывод: [ 5 10 15]

Обратить внимание на характер фраз и введение «промпт» переменных такой как вэнв и скрипт.
Следующий пример — создаём цифровой фильтр с БИХ характеристикой на языке С и проверяем его с генерацией выходного csv файла с отсчётами и значениями коэффициентов.

Цифровой фильтр — ядро

хотеть цифровой фильтр чистый С файл калькюляйт си функция калькуляйт цикл по n отсчётам вход n, массив выходов размер n, массив отсчётов х, и коэффициентов сх одинаковые размер, число коэффициентов эникс, массив отсчётов у, и коэффициентов су одинаковые размер, число коэффициентов энигрек, отсчёты и коэффициенты флоат остальное инт размер. внутри аккумулятор акк ноль, вход х нулевой константа задать 1 затем цикл умножение с накоплением сх и с цикл умножение с накоплением су и у в аккумулятор. сдвигать элементы массивы х и у прямой порядок отсчётов на один только инкремент индекса плюс плюс, начать индекс ноль использовать временная переменная t1 t2 обмен сохранить аккумулятор массив выходов

По данному промпту генерируется следующий код, причём, +- одинаковый для любых моделей.

void calculate(int n, float* outputs, float* x, float* cx, int nx, float* y, float* cy, int ny) {    for (int i = 0; i < n; i++) {        float acc = 0.0f;                // Входной отсчет x[0] константа 1 (согласно запросу)        x[0] = 1.0f;        // Цикл умножения с накоплением для входов (сх и х)        for (int j = 0; j < nx; j++) {            acc += cx[j] * x[j];        }        // Цикл умножения с накоплением для выходов (су и у)        // Обычно у[0] не используется в сумме для расчета текущего у[0],         // поэтому начинаем с 1, если су[0] не предусмотрен как обратная связь        for (int j = 1; j < ny; j++) {            acc += cy[j] * y[j];        }        // Сохраняем результат        outputs[i] = acc;        y[0] = acc;        // Сдвиг элементов массивов х и у (прямой порядок, инкремент ++)        // Используем временные переменные t1, t2 для обмена (сдвига)        float t1, t2;        // Сдвиг X        t1 = x[0];        for (int j = 1; j < nx; j++) {            t2 = x[j];            x[j] = t1;            t1 = t2;        }        // Сдвиг Y        t1 = y[0];        for (int j = 1; j < ny; j++) {            t2 = y[j];            y[j] = t1;            t1 = t2;        }    }}

Отличный фильтр! Как и требуется — умножение с накоплением, сдвиг элементов на 1 только с использованием инкремента указателя. На архитектурах DSP процессоров есть команды, которые используют пост-инкремент указателя. Пример кода ассемблера и промпт для этого:

хотеть реализация сдвиг массивов Х и У фрагмент кода ассемблер для Техас Инструменты процессор семейства С2000 используй пост-инкремент

; Предположим:; XAR4 указывает на начало массива (X[0]); XAR5 указывает на X[1]; AL используется как временная переменная (T1); PH используется как счетчик (NX - 1)        MOVZ    AR6, @NX        ; Загружаем NX        SUBB    XAR6, #1        ; Нам нужно NX-1 итераций для сдвига        MOVZ    AR0, @AR6       ; Переносим в AR0 для использования в BANZ        ; Настройка указателей        MOVL    XAR4, #_X       ; Адрес X[0]        MOVL    XAR5, #_X       ; Адрес X[0]        ADDB    XAR5, #1        ; Теперь XAR5 указывает на X[1]SHIFT_LOOP:        MOV     AL, *XAR4       ; T1 = X[i]        MOV     AH, *XAR5       ; Временный буфер для обмена (T2)        MOV     *XAR4++, AH     ; X[i] = X[i+1], инкремент указателя i        MOV     *XAR5++, AL     ; X[i+1] = T1, инкремент указателя i+1                BANZ    SHIFT_LOOP, AR0-- ; Цикл, пока AR0 не станет 0

Довольно неплохо, но требует проверки, которую оставим за кадром. Что касается оптимизации то можно получить классическое решение

хотеть реализация ассемблер код фрагмент фильтр для Техас Инструменты процессор семейства С2000 используй рэп и мак

; На входе:; XAR4 - указатель на массив данных (X); XAR5 - указатель на массив коэффициентов (CX); PH   - количество коэффициентов (NX); ACC  - результат (аккумулятор)        ZAPA                    ; Обнулить ACC и P (регистр произведения)        MOVZ    AR0, @NX        ; Загрузить количество итераций (NX)        SUBB    XAR0, #1        ; RPT выполняет N+1 раз, поэтому вычитаем 1        ; --- Цикл умножения с накоплением (MAC) ---        ; RPT повторяет следующую инструкцию AR0 раз        ; *XAR4++ : берет X[i], пост-инкремент адреса        ; *XAR5++ : берет CX[i], пост-инкремент адреса        RPT     @AR0        MAC     *XAR4++, *XAR5++, ACC                ADDL    ACC, P          ; Добавить последний результат произведения в ACC

Достаточно попросить использовать команды RPT (рэп) — повторение заданного количества раз в регистре и MAC (мак) — умножение с накоплением. Последовательность на ассемблере RPT-MAC означает выполнить эту команду заданное количество раз, очень удобно для повторяющихся операций.
Для оптимизации попросить MACD. Оптимизированная версия

хотеть реализация ассемблер код фрагмент фильтр для Техас Инструменты процессор семейства С2000 используй команду Макдональдс вместо Т1 Т2

; XAR4 — указывает на ПОСЛЕДНИЙ элемент массива данных X (X[NX-1]); XAR5 — указывает на ПОСЛЕДНИЙ элемент массива коэффициентов CX (CX[NX-1]); ACC  — аккумулятор (результат); Обязательно: массивы должны идти "задом наперед" для логики сдвига MACD        SETC    SXM             ; Включить знаковое расширение        ZAPA                    ; Обнулить ACC и P        MOVZ    AR0, @NX        ; Загружаем число коэффициентов        SUBB    XAR0, #1        ; Корректировка для RPT (выполняет N+1 раз)        ; --- Главный цикл фильтрации ---        ; MACD делает: P = *XAR4 * *XAR5, ACC = ACC + P,         ; затем копирует: *(XAR4+1) = *XAR4 (сдвиг!)        ; и делает декремент: XAR4--, XAR5-- (пост-декремент)                RPT     @AR0        MACD    ACC, *XAR4--, *XAR5--        ADDL    ACC, P          ; Добавить финальное произведение в ACC

Получаем полностью оптимизированный вариант. Но это уже другая история, какой командой обнулить аккумулятор.

Создаём заголовочник
хотеть калькюляйт аш с прототипом функции кальк, документ и кислород но будь осторожен с типами и указателями

/** * @file calculate.h * @brief Реализация цифрового фильтра (Прямая форма I). */#ifndef CALCULATE_H#define CALCULATE_H/** * @brief Вычисляет выходные значения цифрового фильтра. *  * Функция проходит циклом по n отсчетам, выполняя умножение с накоплением (MAC) * и обновляя линии задержки x и y. *  * @param n        [in]  Количество итераций (отсчетов). * @param outputs  [out] Массив для записи результатов (размер n). * @param x        [in,out] Массив предыдущих входных отсчетов (размер nx). * @param cx       [in]  Массив коэффициентов для входов (размер nx). * @param nx       [in]  Количество входных коэффициентов. * @param y        [in,out] Массив предыдущих выходных отсчетов (размер ny). * @param cy       [in]  Массив коэффициентов обратной связи (размер ny). * @param ny       [in]  Количество выходных коэффициентов. */void calculate(int n, float* outputs, float* x, float* cx, int nx, float* y, float* cy, int ny);#endif // CALCULATE_H

Любезно позаботился сделав Doxygen формат описания, необходимый как воздух (кислород)

Далее продолжаем с новым контекстным окном. Пробуем сопряжение без запоминания предыдущего, описываем прототип функции промптом вместо кода. Рассчитываем коэффициенты цифрового фильтра — нерекуррентная часть скользящее среднее, рекуррентная — комплексно сопряжённые (колебательные) полюса, расположенные случайным образом на комплексной окружности.

Генерация коэффициентов цифрового фильтра и главная функция

Хотеть проверку чистый С вызови готовая функция калькюляйт прототип аргументы вход N, массив выходов вых размер N, массив отсчётов Х, и коэффициентов СХ одинаковые размер, число коэффициентов ЭнИкс, массив отсчётов У, и коэффициентов СУ одинаковые размер, число коэффициентов ЭнИгрек, отсчёты коэффициенты флоат остальное инт, инклуд калькюляйт аш без заглушек. Сделать формирование коэффициентов СХ и СУ так что СУ индекс ноль всегда ноль. Коэффициенты СХ одинаково единица делённая на ЭнИкс размер. Коэффициенты СУ функция рандом внутри единичной комплексная окружность устойчивость учти, альфа амплитуда количество по размеру ЭнИгрек. Хардкод Пи. Обнули массивы Х и У. Массивы статические макросы ЭнИкс 5 ЭнИгрек 7 Эн 50. Дай вывод CSV файл и на экран сначала коэффициенты СХ СУ потом отсчёты вых Эн с индекс. Внимательно вызов калькюляйт число аргументов типы и массивы последовательность.

Вывод

#include <stdio.h>#include <stdlib.h>#include <math.h>#include <time.h>#include "calculate.h"#define NX 5#define NY 7#define N  50#define PI 3.14159265358979323846int main() {    // Статические массивы    float out[N];    float x[NX] = {0};    float cx[NX];    float y[NY] = {0};    float cy[NY];    srand((unsigned int)time(NULL));    // 1. Формирование CX: 1/NX    for (int i = 0; i < NX; i++) {        cx[i] = 1.0f / NX;    }    // 2. Формирование CY: устойчивые коэффициенты    // CY[0] всегда 0 по условию    cy[0] = 0.0f;    // Генерируем остальные как малые случайные величины для устойчивости    // (Сумма модулей CY < 1 — достаточное условие устойчивости)    for (int i = 1; i < NY; i++) {        float alpha = (float)rand() / RAND_MAX; // амплитуда < 1        float phase = (float)rand() / RAND_MAX * 2.0f * PI;        // Берем проекцию на вещественную ось и нормируем, чтобы система не "разлетелась"        cy[i] = (alpha * cosf(phase)) / NY;     }    // 3. Вызов функции calculate    // Прототип: void calculate(int n, float *out, int nx, float *x, float *cx, int ny, float *y, float *cy);    calculate(N, out, x, cx, NX, y, cy, NY);    // 4. Вывод на экран    printf("Coefficients CX:\n");    for (int i = 0; i < NX; i++) printf("%.4f ", cx[i]);        printf("\n\nCoefficients CY:\n");    for (int i = 0; i < NY; i++) printf("%.4f ", cy[i]);    printf("\n\nResults (Index, Value):\n");    for (int i = 0; i < N; i++) {        printf("%d, %.6f\n", i, out[i]);    }    // 5. Вывод в CSV файл    FILE *f = fopen("output.csv", "w");    if (f) {        fprintf(f, "Type,Index,Value\n");        for (int i = 0; i < NX; i++) fprintf(f, "CX,%d,%.6f\n", i, cx[i]);        for (int i = 0; i < NY; i++) fprintf(f, "CY,%d,%.6f\n", i, cy[i]);        for (int i = 0; i < N; i++)  fprintf(f, "OUT,%d,%.6f\n", i, out[i]);        fclose(f);        printf("\nData saved to output.csv\n");    }    return 0;}

Создаём файл Main.c и сохраняем

После чего конечно же мы не будем долго думать как создать Makefile для gcc

Makefile

Хотеть Makefile для антилопы а также Си не хуже 2011 года, сканировать все файлы с и компилировать в оут исполняемый а также математика либа

# Настройки компилятораCC = gccCFLAGS = -Wall -Wextra -std=c11 -O2LDFLAGS = -lm# Имя выходного файлаTARGET = out# Автоматический поиск всех .c файлов в текущей директорииSRCS = $(wildcard *.c)# Превращение списка .c в список .oOBJS = $(SRCS:.c=.o)# Главная цельall: $(TARGET)# Сборка исполняемого файла$(TARGET): $(OBJS)        $(CC) $(OBJS) -o $(TARGET) $(LDFLAGS)# Правило для объектных файлов%.o: %.c        $(CC) $(CFLAGS) -c $< -o $@# Очисткаclean:        rm -f $(OBJS) $(TARGET).PHONY: all clean

запускаем make, видим
gcc -Wall -Wextra -std=c11 -O2 -c calculate.c -o calculate.o
gcc -Wall -Wextra -std=c11 -O2 -c Main.c -o Main.o
gcc calculate.o Main.o -o out -lm
запускаем исполняемый файл ./out

Вывод программы

Type,Index,Value
CX,0,0.200000
CX,1,0.200000
CX,2,0.200000
CX,3,0.200000
CX,4,0.200000
CY,0,0.000000
CY,1,0.049448
CY,2,-0.008871
CY,3,0.092645
CY,4,0.083334
CY,5,-0.053389
CY,6,-0.077179
OUT,0,0.200000
OUT,1,0.409890
OUT,2,0.618494
OUT,3,0.845476
OUT,4,1.090962
OUT,5,1.127226
OUT,6,1.138613
OUT,7,1.153176
OUT,8,1.149394
OUT,9,1.122531
OUT,10,1.102652
OUT,11,1.099363
OUT,12,1.094917
OUT,13,1.089723
OUT,14,1.089271
OUT,15,1.091743

….

Теперь приступим к визуализации результатов нашего csv. Также очищаем контекст для старта с нуля

Визуализатор Питон

хотеть питон визуализируй комплексная плоскость если коэффициенты отсчётов входа X как CX а выходов Y как СУ поля а на графике от отсчётов размести поле OUT. Читай csv формат тип CX или CY или OUT ,index,value. Индекс коэффициентов максимальный есть порядок фильтра. Пересчитать коэффициенты в нули и полюса для строить график комплексная плоскость и единичная окружность справа половина слева половина график отсчётов ОУТ от индекса. матплотлиб без пандас. открой любой csv папка текущая. данные идут списком в столбец, первый столбец тип, первая строка заголовок

import matplotlib.pyplot as pltimport numpy as npimport glob# 1. Чтение CSV (без pandas)csv_files = glob.glob("*.csv")if not csv_files:    raise FileNotFoundError("CSV файл не найден в текущей директории.")filename = csv_files[0]cx_dict, cy_dict, out_dict = {}, {}, {}with open(filename, 'r') as f:    next(f)  # Пропуск заголовка    for line in f:        parts = line.strip().split(',')        if len(parts) < 3: continue        label, idx, val = parts[0], int(parts[1]), float(parts[2])        if label == 'CX': cx_dict[idx] = val        elif label == 'CY': cy_dict[idx] = val        elif label == 'OUT': out_dict[idx] = val# 2. Подготовка массивовdef to_arr(d):    if not d: return np.array([1.0])    res = np.zeros(max(d.keys()) + 1)    for k, v in d.items(): res[k] = v    return resb = to_arr(cx_dict)  # Числитель (нули)a = to_arr(cy_dict)  # Знаменатель (полюса)# 3. Расчет нулей и полюсовzeros = np.roots(b) if len(b) > 1 else []poles = np.roots(a) if len(a) > 1 else []# 4. Визуализацияfig, (ax_out, ax_z) = plt.subplots(1, 2, figsize=(12, 5))# Слева: График отсчетов OUTindices = sorted(out_dict.keys())values = [out_dict[i] for i in indices]ax_out.stem(indices, values)ax_out.set_title("Отсчеты OUT")ax_out.grid(True)# Справа: Комплексная плоскостьunit_circle = plt.Circle((0,0), 1, color='black', fill=False, linestyle='--', alpha=0.5)ax_z.add_artist(unit_circle)ax_z.scatter(np.real(zeros), np.imag(zeros), s=60, marker='o', edgecolors='blue', facecolors='none', label='Нули (CX)')ax_z.scatter(np.real(poles), np.imag(poles), s=60, marker='x', color='red', label='Полюса (CY)')ax_z.axhline(0, color='black', lw=1)ax_z.axvline(0, color='black', lw=1)ax_z.set_xlim([-1.5, 1.5])ax_z.set_ylim([-1.5, 1.5])ax_z.set_aspect('equal')ax_z.set_title("Комплексная плоскость")ax_z.legend()ax_z.grid(True)plt.tight_layout()plt.show()

Ну что-ж, довольно неплохо вайб-ЦОС позволяет анализировать различные фильтры, хорошо видна КИХ-составляющая вначале пятого порядка (5 отсчётов) и БИХ с затуханием, построена единичная окружность, нанесены нули-полюса.

Далее следуют небольшие примеры для методов с конечными разностями

Столкновение Тейи и Земли. Луна не получилась

Язык Змей Горыныч модель окружность 1 окружность 2 навстречу друг другу диаметры отношение один к четырём окружность есть 64 точки отрезков аппроксимация каждый отрезок масса отрезки связаны в точках использовать сохранение импульса закон Ньютона столкновение без рассеяния отрезки между собой закон Гука пружинят конечные разности расчёт шаг счёта по времени примерно одна окружность в секундe использовать матплотлиб визуализация мышь слайдер быстрее медленнее логарифм

import numpy as npimport matplotlib.pyplot as pltfrom matplotlib.widgets import Sliderfrom matplotlib.animation import FuncAnimation# Параметры системыN = 64              # Количество точек в окружностиK_SPRING = 5000.0   # Жесткость пружинMASS = 0.1          # Масса одной точкиR1, R2 = 1.0, 4.0   # Радиусы (1:4)V_INIT = 2.5        # Начальная скорость сближения# Инициализация координат и скоростейtheta = np.linspace(0, 2 * np.pi, N, endpoint=False)# Окружность 1 (Малая)pos1 = np.stack([R1 * np.cos(theta) - 7.0, R1 * np.sin(theta)], axis=1)vel1 = np.zeros_like(pos1)vel1[:, 0] = V_INIT# Окружность 2 (Большая)pos2 = np.stack([R2 * np.cos(theta) + 7.0, R2 * np.sin(theta)], axis=1)vel2 = np.zeros_like(pos2)vel2[:, 0] = -V_INIT# Длины покоя (отрезки аппроксимации)def get_lengths(p):    diff = np.roll(p, -1, axis=0) - p    return np.sqrt(np.sum(diff**2, axis=1))L1, L2 = get_lengths(pos1), get_lengths(pos2)# Визуализацияfig, ax = plt.subplots(figsize=(10, 6))plt.subplots_adjust(bottom=0.2)line1, = ax.plot([], [], 'r-o', markersize=3, lw=1.5, label='Small (1x)')line2, = ax.plot([], [], 'b-o', markersize=3, lw=1.5, label='Large (4x)')ax.set_xlim(-12, 12)ax.set_ylim(-6, 6)ax.set_aspect('equal')ax.legend()# Слайдер для скорости (логарифмический шаг)ax_speed = plt.axes([0.25, 0.05, 0.5, 0.03])slider = Slider(ax_speed, 'Time Step (log)', -4.0, -1.5, valinit=-3.0)def compute_physics(p, v, L_rest):    # Силы упругости (Закон Гука)    diff = np.roll(p, -1, axis=0) - p    dist = np.sqrt(np.sum(diff**2, axis=1))    f_mag = K_SPRING * (dist - L_rest)    f_vec = (diff / dist[:, None]) * f_mag[:, None]        # Результирующая сила на каждую точку (соседние сегменты)    net_f = f_vec - np.roll(f_vec, 1, axis=0)        # Ускорение (Закон Ньютона)    a = net_f / MASS    return adef update(frame):    global pos1, vel1, pos2, vel2        # Текущий шаг времени из слайдера    dt = 10**slider.val        # Расчет сил и обновление (метод Эйлера-Кромера для стабильности)    for _ in range(5): # Вложенные итерации для точности при больших dt        # Физика связей        vel1 += compute_physics(pos1, vel1, L1) * dt        vel2 += compute_physics(pos2, vel2, L2) * dt                # Обработка столкновения (Сохранение импульса)        # Проверка расстояния между всеми парами точек окружностей        dist_matrix = np.linalg.norm(pos1[:, None, :] - pos2[None, :, :], axis=2)        collisions = np.where(dist_matrix < 0.25)                for i, j in zip(*collisions):            normal = (pos1[i] - pos2[j]) / dist_matrix[i, j]            v_rel = vel1[i] - vel2[j]            v_norm = np.dot(v_rel, normal)            if v_norm < 0:                # Обмен импульсами (массы равны, без рассеяния)                impulse = v_norm * normal                vel1[i] -= impulse                vel2[j] += impulse                pos1 += vel1 * dt        pos2 += vel2 * dt    # Обновление графики (замыкаем кольцо для отрисовки)    p1_plot = np.vstack([pos1, pos1[0]])    p2_plot = np.vstack([pos2, pos2[0]])    line1.set_data(p1_plot[:, 0], p1_plot[:, 1])    line2.set_data(p2_plot[:, 0], p2_plot[:, 1])    return line1, line2ani = FuncAnimation(fig, update, interval=20, blit=True)plt.show()

Как обычно запускаем ранее навайбкоженным ./generate_requirements.sh zmei.py с автоматической подцепкой виртуального окружения

Робот-манипулятор двузвенный. Используется матмодель, которой надо дать инъекцию в виде подсказок про арктангенс двойного аргумента (от 0 до 360) и sqrt — теорему Пифагора, а также что одной точке может соответствовать 2 положения (плюс минус дискриминант), которых тем больше чем больше звеньев.

Автоботы и Десептиконы

Пропитонь двузвенный манипулятор да дай-ка в него PyGame numpy но будь осторожен с дискриминант sqrt а угол atan2 клавиатура меняй знак положение. Мышь точка задания фиксация первого звена центр координаты ортогональные сцены сетка имеется. Ай да обратная кинематика! Ух сольвер тригонометрический.

import pygameimport numpy as npimport math# Константы сценыWIDTH, HEIGHT = 800, 600L1, L2 = 180, 140  # Длины звеньевORIGIN = np.array([WIDTH // 2, HEIGHT // 2])def solve_ik(target, l1, l2, sign):    tx, ty = target    dist_sq = tx**2 + ty**2    dist = math.sqrt(dist_sq)    # Ограничение рабочей зоны    if dist > l1 + l2:        dist_sq = (l1 + l2)**2        dist = l1 + l2        # Закон косинусов для второго угла    cos_a2 = (dist_sq - l1**2 - l2**2) / (2 * l1 * l2)    cos_a2 = np.clip(cos_a2, -1, 1) # Защита от ошибок в sqrt        # Выбор знака локтя через atan2    sin_a2 = math.sqrt(1 - cos_a2**2) * sign    a2 = math.atan2(sin_a2, cos_a2)    # Угол первого звена    a1 = math.atan2(ty, tx) - math.atan2(l2 * sin_a2, l1 + l2 * cos_a2)        return a1, a2def run():    pygame.init()    screen = pygame.display.set_mode((WIDTH, HEIGHT))    clock = pygame.time.Clock()    elbow_sign = 1        while True:        for event in pygame.event.get():            if event.type == pygame.QUIT: return            if event.type == pygame.KEYDOWN:                if event.key == pygame.K_SPACE: elbow_sign *= -1        screen.fill((30, 30, 30))                # Сетка        for i in range(0, WIDTH, 40): pygame.draw.line(screen, (50,50,50), (i,0), (i,HEIGHT))        for i in range(0, HEIGHT, 40): pygame.draw.line(screen, (50,50,50), (0,i), (WIDTH,i))        # Таргет от мышки относительно центра        m_pos = np.array(pygame.mouse.get_pos()) - ORIGIN                # Расчет        a1, a2 = solve_ik(m_pos, L1, L2, elbow_sign)        # Координаты суставов        joint = ORIGIN + np.array([L1 * math.cos(a1), L1 * math.sin(a1)])        end_eff = joint + np.array([L2 * math.cos(a1 + a2), L2 * math.sin(a1 + a2)])        # Отрисовка (Ортогонально из центра)        pygame.draw.line(screen, (0, 255, 0), ORIGIN, joint, 6)   # Плечо        pygame.draw.line(screen, (255, 100, 0), joint, end_eff, 6) # Предплечье        pygame.draw.circle(screen, (255, 255, 255), ORIGIN, 8)        pygame.draw.circle(screen, (200, 0, 0), end_eff.astype(int), 5)        pygame.display.flip()        clock.tick(60)if __name__ == "__main__":    run()

Пробелом можно менять положение локтя, мышью — крутить роботом обеспечивая положение звеньев

Вайб-код-стих. Пропарсим с использованием питона C-файлы сделанные выше и выберем имена функций.

Рифмо-парсер

Питоном я доволен
Файл открыть любой
Там С код стройный
Читай его любой
Используй regexp дорогой
И извлекай Имя функции () как родной
Те что в скобках и
Фигурных расписных
Строй список мне имён
Довольный и на экран выводи
Мой файл пай мне задай
Ищем мы всё в каталоге текущем
Всё что Си имеет текст грядущий
Но ты за ключевым словом следи
Всякие форы и ифы убери!
Устроит меня не имплементация
А только реализация

Результат:

import reimport os# Регулярка: ищет потенциальное имя функции перед скобками,# игнорируя ключевые слова C, и проверяет наличие открывающей фигурной скобкиpattern = r'\b(?!if|while|for|switch|return|void|int|char|float|double|static|struct|else)\w+\s*\([^)]*\)\s*\{'def find_functions():    # Ищем файлы с расширением .c в текущей папке    c_files = [f for f in os.listdir('.') if f.endswith('.c')]    if not c_files:        print("Си-файлов в округе не видать...")        return    for filename in c_files:        print(f"--- Файл: {filename} ---")        try:            with open(filename, 'r', encoding='utf-8') as f:                content = f.read()                # Находим все совпадения                matches = re.findall(pattern, content)                for match in matches:                    # Очищаем имя от скобок и лишних символов                    func_name = match.split('(')[0].strip()                    # На случай, если в match попал тип данных (например, "int main")                    func_name = func_name.split()[-1]                    print(f"Найдена функция: {func_name}")        except Exception as e:            print(f"Ошибка при чтении {filename}: {e}")if __name__ == "__main__":    find_functions()

В созданных выше файлах он прекрасно находит наши функции
— Файл: Main.c —
Найдена функция: main
— Файл: calculate.c —
Найдена функция: calculate

Практически все модели обладают +- одинаковым выводом, так как обучающие выборки наверняка в большинстве своём примерно одни и те же, собраны из исходников, форумов и подготовлены по известным шаблонам датасетов. Промпты рабочие с первого раза за редким исключением.

ссылка на оригинал статьи https://habr.com/ru/articles/1028834/