Обновить
65

Пользователь

2,8
Рейтинг
48
Подписчики
Отправить сообщение

Я просто не знаю языков и синтаксисов (AHK не считается). Представляю только логику :)

Вообще да, можно :)

Я последний план писал три дня и убил в него весь недельный лимит Fable. Зато теперь по нему можно пускать даже самые тупые модели - любая по этому плану код напишет хорошо (это было частью ТЗ).

Не может: вы пишете строчку, оно вам ее переписывает в 10+ строчек плана. Вам только проверять остается.

Человек просто с ног на голову все перевернул и не видит проблемы. Если в условиях использования процессоров Интел появится клуяза о том, что все пользователи добровольно становятся рабами компании, он тоже будет говорить, что именно за эту кляузу процессоры Интел и выбирают.

Логики в этом нет.

Вы меня здесь за простыню упрекаете, вы???

Да что вы, какие упреки? Это сравнение.

Вот так и сделаете. А заодно можете навайбкодить себе другой банк, у которого будут другие, маленькие и быстрые программы, с ограниченынм функционалом.

А, вы из "сделайте свое"? У меня ответ всегда на это один:

Скрытый текст

Мне нравится, что вы в такой панике пытаетесь дистанцироваться от своего говнокода, что предлагаете от него бежать аж делать новый банк :)

Это весьма показательно. Человек буквально поднимает руки и говорит: "нет! наш говнокод трогать нельзя! лучше сделать новый банк!" Я вас услышал.

Если у меня трещина по несущей стене дома пойдет, я не пойду задавать вопросы тем, кто его обслуживает - я просто пойду и построю свой, что я, лох что ли, покажу им как надо!

Тогда вы исчезающее меньшинство, подтверждающее правило.

Ой ляяяяяяяя...

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

Покажите мне потребителя, который просил в приложении Сбера рекламу Самоката, Okko, "След Чикатилло 2026", Мегамаркет и Афишу. Покажите мне потребителя, который просил там же "Чем занять ребенка" и "7 мест для лета". А вы знали, что ваша простыня короче раздела "для жизни" в приложении банка? Я проверил, короче.

Вопрос, а почему сейчас только, почему не 5 или 10 лет назад. Зайди на любой фриланс, найди кожаного, до которого "можно достучаться", заплати ему, чтобы сделал прогармму

Простите, как вы предполагаете будет выглядеть навайбкоженный или написанный фрилансером альтернативный клиент на Сбер? :)

Можете не сомневаться: когда у приложения есть альтернативный APK (например, на Instagram) - я первый в очереди на установку облегченной версии без того (в основном рекламы), что не потребители посчитали необходимым добавить в приложения для шаринга фоточек и видосиков.

...и как, уже навайбкодил программы такой сложности?

Сперва добейся? На моем Хабре? Постыдно. Не нужно быть поваром, чтобы видеть, что тебя кормят говном.

Идёт не в условный мастодон, где сайты маленькие и "кожанные" ближе

И ведь я таки пошел в условный BlueSky, кроме Твиттера. И что же вы думаете? Да нет там никого :) Но я все еще делаю туда посты, не иначе чем сегодня!

Это потребитель требует, чтобы программа появилась на рынке без тестирования, не программист.

Чавой? Я вам гарантирую, что если следующая версия Сбера не будет выходить два года, этого НИКТО НЕ ЗАМЕТИТ. Ни один потребитель. 0.

Хоть оттестируйтесь, хоть вообще каждый байт перепишите - никто вам не мешает.

Ась? Что? Еще три блока рекламы надо добавить? Берем под козырек и делаем. 0 потребителей попросило, попросил кто-то другой - но мы роняя кал бежим и делаем, мы подневольные, нас заставили!

Нет, я специально использовал только ваш промпт. Потому что - без наездов и без претензий - если вы неправильно по своему коду сформулировали ТЗ, то по нему будет неправильный (отличающийся) результат.

Идея была именно в том, чтобы скопировать ваше задание и посмотреть что получится вообще без моего вмешательства.

Что касается ТЗ, то я выше (изначально) уже писал:

И лучший результат достигается, если сначала через plan mode описать, что у тебя есть, и что хочешь получить. Потом ручками подредактировать план, где не согласен, прогнать "ask me questions" и уже после всего этого, по вылизанному плану поставить прогон "вайбкодинга". Тогда да, что-то может и получится.

Правильно поставленная и вылизанная задача - бОльшая часть работы. Поэтому я третий день пишу план вместо кода для своего проекта :)

А в нормальной системе он именно что сначала задает кучу уточняющих вопросов, чтобы лучше "понять" задачу.

Я уже третий день план пишу с Fable... Уже 60% 200-долларовой недельки убил только на вопросах и обсуждениях, без написания кода.

Если ты монополист - наверное да. А что по тестам? Если у тебя приложение прогружается в 2-4-10 раз дольше "нормы", это сколько убитых часов?

Не за что извиняться :)

Я думаю, что по большей части проблема в формулировке ТЗ. Оно действительно открыто к интерпретации, посмотрите анализ (третий спойлер). Я лично не увидел особых расхождений со скопированным ТЗ, я думаю тут вопрос кто как понял.

Вот это кстати промпт, по которому adverserial агент пытался оспорить написанное:

Обратите внимание на "The author's INTERPRETATION (which you should also scrutinise, not just accept):"

You are an ADVERSARIAL code reviewer. Your job is to BREAK and DISPROVE, not to praise. Assume the code is subtly wrong until proven otherwise. Be skeptical and concrete.

The file to review is D:\habr\demo.py — a graphics demo written in pure Python standard library (tkinter Canvas). You may READ it and you may RUN Python to test it (Windows, python 3.12, tkinter 8.6 available). To test without popping a window, create the Tk root and call root.withdraw(), then drive the drawing methods directly and call root.update_idletasks() — do NOT call root.mainloop() (it blocks). There is an existing headless harness at C:\Users\mistd\AppData\Local\Temp\claude\D--habr\141d40eb-0ceb-4b0a-a95d-d449fbf8ab07\scratchpad\smoke.py you can read/adapt.

THE ORIGINAL SPEC (Russian, must be satisfied faithfully): “Окно 640*480, синий фон. Вращаются два желтых кольца справа налево и сверху вниз, синхронно. Это один режим. Переключение на второй - клавишей Enter. Второй режим. Черный фон окна и из центра растут круги стандартных цветов: красный, желтый, зеленый, голубой, синий и фиолетовый. Потом снова красный и т.д. Этот режим имеет два варианта (переключение клавишей Space): Один - новые круги рисуются поверх старых, яркость кругов уменьшается от центра к периферии. Второй - в ходе вывода кругов все изображение темнеет вплоть до черного, поэтому каждый цвет рисуется как бы на черном фоне.”

The author’s INTERPRETATION (which you should also scrutinise, not just accept):

  • Two yellow rings = two concentric ellipses sharing one angle theta; ring1 varies horizontal semi-axis (spins about vertical axis => “right-to-left”), ring2 varies vertical semi-axis (spins about horizontal axis => “top-to-bottom”). “Synchronous” = same theta/phase.

  • Mode 2 colors cycle: red, yellow, green, cyan, blue, magenta, repeat.

  • Variant A: nested filled ovals recolored per-frame; brightness = 1 - r/R_MAX (bright center, dark edge); inner drawn on top of outer.

  • Variant B: expanding ring outlines spawned from center, each fading toward black over time via subtractive dimming; whole picture would go black if spawning stopped.

ADVERSARIAL CHECKLIST — investigate each and try to find a real defect:

  1. CRASHES / EXCEPTIONS: any input (long runtime, integer overflow of self.g/self.frame after millions of frames, division, empty lists, tkinter color-string format like negative or >255 channel values, coords with x1<x0) that throws. Actually reproduce by running many iterations.

  2. RESOURCE LEAK: in variant B, do canvas items accumulate without being deleted over a long run? Prove with a count over thousands of frames. Also: switching modes repeatedly — are old items deleted (canvas.delete(‘all’))? Any orphaned after timers stacking up if you toggle modes fast?

  3. SPEC CONFORMANCE:

    • Mode 1 background actually blue? rings actually yellow and actually reading as “rotating”? Do BOTH directions (right-to-left AND top-to-bottom) actually appear, or do both rings collapse identically (same phase) making it a pulsing plus-sign rather than two distinct rotations? Is that a faithful reading of “справа налево и сверху вниз”? Argue it.

    • Mode 2 background black? Colors exactly the 6 named standard colors and in the right cycle order?

    • Variant A: is brightness truly decreasing from center to periphery at all times? Any radius where it inverts or bands read wrong because of the (g - r)//BAND_W sign when g is small (g starts at 0, so g - r is negative early — does int(negative)//positive behave as intended, and does modulo give the right color)? Check the very first frames.

    • Variant B: does it truly “darken to black”? With SPAWN_EVERY spawning and FADE = SPEED_B/R_MAX, do rings actually reach black before deletion, or get deleted by radius first while still bright (leaving a visible bright ring popping out of existence at the edge)? Compute the numbers.

    • Are A and B VISUALLY DISTINCT enough to be recognisably “two variants”?

  4. KEY HANDLING: Enter (Return AND KP_Enter) toggles mode; Space toggles variant only in mode 2; Esc quits. Any dead keys, or Space doing something wrong in mode 1?

  5. Off-by-one / color math in dim_hex: does it ever produce an invalid Tk color (e.g. ‘#100’ or channel 256)? Feed extreme k.

  6. Anything that would look visibly wrong or janky that a user would immediately complain about.

Deliverables: Return a concise, ranked list of CONFIRMED defects (state how you reproduced each — command/observation), plus PLAUSIBLE concerns you couldn’t fully confirm. If something is fine, say so briefly. Do NOT fix anything — only report. Be specific with file line numbers where possible. Prefer running code to prove claims over speculation.

А еще возможно проблема банально в русском языке и трудностях перевода - как видите агенты между собой общаются на английском, пытаются переводить ваше ТЗ блоками.

Ага, а сейчас просят на камеру показать перед лицом 3 или 4 пальца, чтобы дипфейки не справились :)

Я несколько в шоке. :) Если честно, такой объем текста читать в виде комментария не совсем удобно.

Понимаю. Могу куда-нибудь закинуть.

Но вообще - это какая нейросеть?

Это Claude Opus 4.8 на xhigh effort с ultracode (которым она не воспользовалась).

Потому что такое впечатление, что куски ее диалога - это куски моей беседы с ЖПТ, хотя по идее где она могла их взять?

Я копипастил ТЗ как его увидел из статьи. Потом еще две правки внес, когда прочитал развитие истории (с HTML на Python поменял, потом отказался от pygame).

Вот код, что получился:
# -*- coding: utf-8 -*-
"""
Графическая демка на чистой стандартной библиотеке Python (tkinter).

Окно 640x480.

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

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

Управление:
    Enter  — переключение между режимом 1 и режимом 2
    Space  — в режиме 2 переключение варианта A / B
    Esc    — выход
"""

import math
import tkinter as tk

# --------------------------------------------------------------------------- #
#  Константы
# --------------------------------------------------------------------------- #
W, H = 640, 480                 # размер окна
CX, CY = W // 2, H // 2         # центр
FRAME_MS = 20                   # ~50 кадров в секунду

BG_BLUE = "#0000a0"             # синий фон режима 1
BG_BLACK = "#000000"           # чёрный фон режима 2
YELLOW = "#ffff00"

# Режим 1 — кольца
RING_R = 150                    # радиус колец
RING_WIDTH = 5                  # толщина линии кольца
SPIN = 0.045                    # прирост угла за кадр (скорость вращения)

# Стандартные цвета (по кругу цветового спектра)
STD_COLORS = [
    (255, 0, 0),     # красный
    (255, 255, 0),   # жёлтый
    (0, 255, 0),     # зелёный
    (0, 255, 255),   # голубой
    (0, 0, 255),     # синий
    (255, 0, 255),   # фиолетовый
]
NCOL = len(STD_COLORS)

# Режим 2 — общие
R_MAX = 430                     # радиус, покрывающий углы окна (диагональ/2 ~ 400)

# Вариант A (яркость по радиусу)
BAND_STEP = 5                   # шаг вложенных окружностей (px)
BAND_W = 44                     # ширина одной цветовой полосы (px)
SPEED_A = 1.3                   # скорость "выползания" полос из центра

# Вариант B (затухание в чёрный)
SPEED_B = 3.0                   # скорость роста радиуса кольца (px/кадр)
RING_W_B = 4                    # толщина растущего кольца
SPAWN_EVERY = 3                 # каждые N кадров рождается новое кольцо
FADE = SPEED_B / R_MAX          # за сколько кадров кольцо гаснет до чёрного


def dim_hex(rgb, k):
    """Цвет rgb, приглушённый коэффициентом k (0..1), в виде #rrggbb."""
    if k < 0:
        k = 0.0
    elif k > 1:
        k = 1.0
    r, g, b = rgb
    return "#%02x%02x%02x" % (int(r * k), int(g * k), int(b * k))


class Demo:
    def __init__(self, root):
        self.root = root
        self.canvas = tk.Canvas(root, width=W, height=H,
                                highlightthickness=0, bg=BG_BLUE)
        self.canvas.pack()

        # общее состояние
        self.mode = 1            # 1 — кольца, 2 — круги
        self.variant = "A"       # A / B (только для режима 2)
        self.theta = 0.0         # угол вращения колец
        self.g = 0.0             # фаза роста кругов
        self.frame = 0           # счётчик кадров (для рождения колец в B)

        # идентификаторы графических объектов
        self.ring1 = None
        self.ring2 = None
        self.bands = []          # вложенные окружности варианта A
        self.rings = []          # активные растущие кольца варианта B: {id, r, col, bright}

        # горячие клавиши
        root.bind("<Return>", self.toggle_mode)
        root.bind("<KP_Enter>", self.toggle_mode)
        root.bind("<space>", self.toggle_variant)
        root.bind("<Escape>", lambda e: root.destroy())

        self.build()
        self.tick()

    # ------------------------------------------------------------------ #
    #  Переключение режимов
    # ------------------------------------------------------------------ #
    def toggle_mode(self, event=None):
        self.mode = 2 if self.mode == 1 else 1
        self.build()

    def toggle_variant(self, event=None):
        if self.mode == 2:
            self.variant = "B" if self.variant == "A" else "A"
            self.build()

    # ------------------------------------------------------------------ #
    #  Пересборка сцены под текущий режим
    # ------------------------------------------------------------------ #
    def build(self):
        self.canvas.delete("all")
        self.bands = []
        self.rings = []
        self.g = 0.0
        self.frame = 0

        if self.mode == 1:
            self.root.title("Режим 1: два вращающихся кольца   |   Enter — сменить режим,  Esc — выход")
            self.canvas.config(bg=BG_BLUE)
            # два кольца — контур (fill=""), обновляются в кадре
            self.ring1 = self.canvas.create_oval(0, 0, 0, 0, outline=YELLOW,
                                                 width=RING_WIDTH, fill="")
            self.ring2 = self.canvas.create_oval(0, 0, 0, 0, outline=YELLOW,
                                                 width=RING_WIDTH, fill="")
        else:
            title_v = "A: ярче в центре" if self.variant == "A" else "B: затухание в чёрный"
            self.root.title("Режим 2 [%s]   |   Enter — сменить режим,  Space — вариант A/B,  Esc — выход"
                            % title_v)
            self.canvas.config(bg=BG_BLACK)
            if self.variant == "A":
                # набор вложенных закрашенных окружностей: внешние снизу, внутренние сверху
                r = R_MAX
                while r > 0:
                    oid = self.canvas.create_oval(CX - r, CY - r, CX + r, CY + r,
                                                  outline="", fill=BG_BLACK)
                    self.bands.append((oid, r))
                    r -= BAND_STEP
                # сдвигаем фазу так, чтобы в центре цикл стартовал с красного
                if self.bands:
                    self.g = float(self.bands[-1][1])
            # вариант B создаёт кольца динамически в tick()

    # ------------------------------------------------------------------ #
    #  Один кадр анимации
    # ------------------------------------------------------------------ #
    def tick(self):
        if self.mode == 1:
            self.draw_rings()
        elif self.variant == "A":
            self.draw_circles_a()
        else:
            self.draw_circles_b()

        self.root.after(FRAME_MS, self.tick)

    # --- Режим 1: вращающиеся кольца ---------------------------------- #
    def draw_rings(self):
        self.theta += SPIN
        c = abs(math.cos(self.theta))   # фаза кольца 1
        s = abs(math.sin(self.theta))   # фаза кольца 2 — сдвиг на 90°, чтобы оба кольца
                                        # были видны всегда (не сливались в одно) и вращались
                                        # синхронно, каждое в своей плоскости

        # кольцо 1: вращение вокруг вертикальной оси -> меняется ширина (справа налево)
        a = max(1, RING_R * c)
        b = RING_R
        self.canvas.coords(self.ring1, CX - a, CY - b, CX + a, CY + b)

        # кольцо 2: вращение вокруг горизонтальной оси -> меняется высота (сверху вниз)
        a = RING_R
        b = max(1, RING_R * s)
        self.canvas.coords(self.ring2, CX - a, CY - b, CX + a, CY + b)

    # --- Режим 2, вариант A: яркость по радиусу ----------------------- #
    def draw_circles_a(self):
        self.g += SPEED_A
        for oid, r in self.bands:
            idx = int((self.g - r) // BAND_W) % NCOL
            bright = 1.0 - r / R_MAX          # ярко в центре, темно по краям
            self.canvas.itemconfig(oid, fill=dim_hex(STD_COLORS[idx], bright))

    # --- Режим 2, вариант B: затухание в чёрный ----------------------- #
    def draw_circles_b(self):
        self.frame += 1

        # рождение нового кольца из центра (первый круг — красный)
        if self.frame % SPAWN_EVERY == 0:
            idx = (self.frame // SPAWN_EVERY - 1) % NCOL
            oid = self.canvas.create_oval(CX, CY, CX, CY,
                                          outline=YELLOW, width=RING_W_B)
            self.rings.append({"id": oid, "r": 1.0,
                               "col": STD_COLORS[idx], "bright": 1.0})

        # рост + затухание существующих колец
        alive = []
        for ring in self.rings:
            ring["r"] += SPEED_B
            ring["bright"] -= FADE
            r = ring["r"]
            if r > R_MAX or ring["bright"] <= 0:
                self.canvas.delete(ring["id"])
                continue
            self.canvas.coords(ring["id"], CX - r, CY - r, CX + r, CY + r)
            self.canvas.itemconfig(ring["id"],
                                   outline=dim_hex(ring["col"], ring["bright"]))
            alive.append(ring)
        self.rings = alive


def main():
    root = tk.Tk()
    root.resizable(False, False)
    Demo(root)
    root.mainloop()


if __name__ == "__main__":
    main()
Вот история чата:

Окно 640*480, синий фон. Вращаются два желтых кольца справа налево и сверху вниз, синхронно. Это один режим. Переключение на второй - клавишей “Enter”.

Второй режим. Черный фон окна и из центра растут круги стандартных цветов: красный, желтый, зеленый, голубой, синий и фиолетовый. Потом снова красный и т.д. Этот режим имеет два варианта (переключение клавишей “Space”):

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

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

● User answered Claude’s questions: · На какой платформе/языке сделать программу с окном 640×480, обработкой Enter/Space и анимацией? → HTML5 Canvas + JS Interrupted · What should Claude do instead?

Я передумал - хочу на Python

Понял — делаю на Python (pygame). Сначала проверю, что установлено на машине.

Ran 1 shell command Остальное я реализую по спецификации (интерпретацию колец опишу ниже и вы поправите, если что).

Ran 1 shell command

Python 3.12.9 есть, а pygame нет. Ставлю pygame:

Ran 1 shell command Interrupted · What should Claude do instead?

Давай только стандартные библиотеки

Понял — только стандартная библиотека, без pygame. Тогда GUI на tkinter (входит в стандартную поставку Python), рисование на Canvas. Проверю, что tkinter доступен:

Ran 1 shell command

tkinter на месте (Tk 8.6). Пишу программу целиком на стандартной библиотеке — окно на tkinter, рисование на Canvas, анимация через after().

● Write(demo.py) Wrote 227 lines to demo.py -- coding: utf-8 -- “” рафическая демка на чистой стандартной библиотеке Python (tkinter).

Окно 640x480.

Режим 1 (синий фон): Два жёлтых кольца вращаются синхронно — одно “справа налево” (вокруг вертикальной оси), другое “сверху вниз” (вок … +217 lines

Как закончишь, перепроверь ADVERSARIAL агентом

Программа готова. Теперь прогоню собственный «дымовой» тест (без всплывающего окна — withdraw()), чтобы убедиться, что все три состояния рисуются без исключений и жизненный цикл колец в варианте B корректен.

● Write(C:\Users\mistd\AppData\Local\Temp\claude\D–habr\141d40eb-0ceb-4b0a-a95d-d449fbf8ab07\scratchpad\smoke.py) Wrote 74 lines

Ran 1 shell command

Собственный дымовой тест зелёный:

  • Режим 1 — 402 кадра без ошибок, кольца схлопываются в линии на θ=90°.

  • Вариант A — 86 вложенных окружностей, центр яркий (#00fc00), край тёмный (#000000) → градиент «ярко в центре, темно по краям». ✓

  • Вариант B — колец рождается и гаснет стабильно (пик 48, утечки нет), все цвета валидны. ✓

Теперь, как вы просили, запускаю адверсариального агента — пусть целенаправленно ищет расхождения со спецификацией, краши и краевые случаи (с правом запускать код).

● Agent(Adversarial review of demo.py) Done (5 tool uses · 48.0k tokens · 5m 40s)

Allowed by auto mode classifier

Адверсариальный агент отработал: крашей, утечек и невалидных цветов нет (прогнал 200k/100k/5k кадров, фаззинг dim_hex, переключения — всё чисто). Нашёл 3 реальных замечания, которые стоит поправить:

  1. Вариант B начинается с жёлтого, а не красного — off-by-one: спека явно требует «красный, жёлтый, …», а первый круг выходит жёлтым.

  2. Режим 1: кольца при одинаковой фазе дважды за цикл идеально совпадают → второе кольцо «пропадает» (сливается в одно). Читается как пульсация, а не как две разнонаправленные оси.

  3. Вариант A стартует с magenta в центре (та же несогласованность фазы) + мёртвая строка self.g += SPEED_B в B.

Исправляю все три.

● Update(demo.py) Added 5 lines, removed 2 lines # — Режим 1: вращающиеся кольца ---------------------------------- # def draw_rings(self): self.theta += SPIN c = abs(math.cos(self.theta)) c = abs(math.cos(self.theta)) # фаза кольца 1 s = abs(math.sin(self.theta)) # фаза кольцакольца # были видны и вращались # синхронно, каждое в своей плоскости

    # кольцо 1: вращение вокруг вертикальной оси -> меняется ширина (справа налево)    a = max(1, RING_R * c)    # кольцо 2: вращение вокруг горизонтальной оси -> меняется высота (сверху вниз)    a = RING_R    b = max(1, RING_R * c)    b = max(1, RING_R * s)    self.canvas.coords(self.ring2, CX - a, CY - b, CX + a, CY + b)
# --- Режим 2, вариант A: яркость по радиусу ----------------------- #

● Update(demo.py) Added 3 lines outline=“”, fill=BG_BLACK) self.bands.append((oid, r)) r -= BAND_STEP # сдвигаем фазу так, чтобы в центре цикл стартовал с красного if self.bands: self.g = float(self.bands[-1][1]) # вариант B создаёт кольца динамически в tick()

# ------------------------------------------------------------------ #

● Update(demo.py) Added 2 lines, removed 3 lines

# --- Режим 2, вариант B: затухание в чёрный ----------------------- #
def draw_circles_b(self):    self.g += SPEED_B    self.frame += 1    # рождение нового кольца из центра    # рождение нового кольца из центра (первый кр    if self.frame % SPAWN_EVERY == 0:        idx = (self.frame // SPAWN_EVERY) % NCOL        idx = (self.frame // SPAWN_EVERY - 1) % NCOL        oid = self.canvas.create_oval(CX, CY, CX, CY,                                      outline=YELLOW, width=RING_W_B)        self.rings.append({"id": oid, "r": 1.0,

Обновляю тест-харнесс под новую семантику режима 1 и проверяю, что фиксы сработали (B и A стартуют с красного, кольца больше не совпадают, утечек по-прежнему нет).

● Write(C:\Users\mistd\AppData\Local\Temp\claude\D–habr\141d40eb-0ceb-4b0a-a95d-d449fbf8ab07\scratchpad\smoke2.py) Wrote 71 lines

Ran 1 shell command

Ассерт упал из-за бага в тесте, а не в коде: draw_rings инкрементирует theta в начале, поэтому после d.theta=0 фактически рисуется θ=0.045 (кольцо 2 почти схлопнуто, высота 13.5, а не <5). Код корректен. Правлю тест (выставляю θ с поправкой на инкремент):

● Update(C:\Users\mistd\AppData\Local\Temp\claude\D–habr\141d40eb-0ceb-4b0a-a95d-d449fbf8ab07\scratchpad\smoke2.py) Added 6 lines, removed 2 lines

Ran 1 shell command

Опять баг теста, не кода: я мерил суммарную «светимость» цвета, а она зависит ещё и от оттенка (magenta ярче green по сумме каналов). Спека говорит про коэффициент яркости k = 1 − r/R_MAX, который монотонен по постением: каждый band должен равняться dim_hex(цвет, k).

● Update(C:\Users\mistd\AppData\Local\Temp\claude\D–habr\141d40eb-0ceb-4b0a-a95d-d449fbf8ab07\scratchpad\smoke2.py) Added 21 lines, removed 13 lines

Готово

Файл: D:\habr\demo.py — чистая стандартная библиотека (tkinter, math), никаких зависимостей.

Запуск: python D:\habr\demo.py

Управление: Enter — режим 1 ↔ режим 2 · Space — вариант A ↔ B (в режиме 2) · Esc — выход. Текущее состояние дублируется в заголовке окна.

Что делает:

  • Режим 1 — синий фон, два жёлтых кольца вращаются синхронно: одно вокруг вертикальной оси («справа налево»), второе вокруг горизонтальной («сверху вниз»).

  • Режим 2 — чёрный фон, из центра растут круги по цветовому кругу (красный → жёлтый → зелёный → голубой → синий → фиолетовый → снова красный):

    • A — новые поверх старых, яркость падает от центра к краю (сплошной градиент);

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

Что нашёл и исправил адверсариальный агент

Крашей, утечек памяти и невалидных цветов не найдено (прогнал 200k/100k/5k кадров, фаззинг dim_hex, сотни переключений). Три реальных замечания — исправлены:

  1. Вариант B стартовал с жёлтого → теперь с красного, как в спеке.

  2. В режиме 1 при одинаковой фазе кольца дважды за оборот сливторого кольца на 90° (эффект «гироскопа»), оба видны всегда.Остаётся синхронным (одна скорость).

  3. Вариант A стартовал с magenta в центре → теперь с красного; заодно убрал мёртвую строку.

Два места, где я выбрал интерпретацию — скажите, если нужно иначе

  • Кольца (режим 1): сделал сдвиг фазы 90° (гироскоп). Если хотите строго одинаковую фазу (оба схлопываются одновременно в «плюс») — в draw_rings замените s = abs(math.sin(…)) на abs(math.cos(…)).

  • Вариант B: каждое кольцо гаснет индивидуально, центр всегда яркий (полотно ушло бы в чёрный, только если перестать плодить кольца). Это соответствует «каждый цвет на чёрном фоне». Если нужен буквально глобальный fade всего кадра — это другая механика, могу переделать.

Хотите — подправлю скорость/радиус/толщину/цвета или запущу у вас для визуальной проверки.

А это комментарий по статье:

Прочитал. Это оказалась статья «Мой первый вайб‑кодинг» (hauserich): автор сравнивает свой код с кодом ChatGPT на трёх задачах, и Задача 3 — ровно наша (кольца + растущие круги, два варианта по Space). Причём и ChatGPT, и автор, и я независимо сошлись на Python + tkinter, create_oval, предсоздании объектов и правке через coords()/itemconfig(), одинаковом списке из 6 цветов и формуле яркости k = 1 − r/R. Так что выбор платформы подтвердился с трёх сторон.

Дальше — честно, что бы я пересмотрел в своём коде и что думаю про листинги из статьи. Свой код не трогаю, только разбор.

Что бы я пересмотрел у себя

  1. Главное: «растущие круги» — последовательно, а не рейнбоу‑полосами

И у ChatGPT, и у автора круги растут по одному цвету за раз: красный вырастает из центра до края → потом жёлтый из центра → потом зелёный, и по кругу. У ChatGPT это массив длительностей TIMES=[3,3.5,4,4.5,5,5.5] (один цвет = один «прогресс» p), у автора — внешний цикл for J in range(1,7) в SFERA().

У меня же в обоих вариантах на экране одновременно много цветов — концентрический радужный набор полос (idx = (g − r)//BAND_W). Это валидное прочтение слов «растут круги стандартных цветов… потом снова красный», но каноничное (то, что реально имел в виду автор задачи, переводя со своего BASIC) — последовательное: один цвет вырос — сменился следующим. Строка спеки «красный, жёлтый… потом снова красный» читается именно как временна́я последовательность.

Это не «баг», но если цель — соответствовать первоисточнику, я бы переключил режим 2 на «один цвет растёт из центра до края, затем следующий». Моя версия визуально богаче, их — ближе к заданию.

  1. Вариант B: у них темнеет всё изображение, у меня — каждое кольцо по отдельности

Спека варианта «Второй»: «в ходе вывода все изображение темнеет вплоть до черного». Обе версии из статьи делают это буквально: растущий диск одного цвета целиком гаснет до чёрного по мере роста —

  • ChatGPT: k = 1 − p, и itemconfig перекрашивает все текущие овалы в одну яркость;

  • автор (ZAL!=0): for K in range(1,I+1): itemconfig(…) — перекрашивает весь диск 1…I в одну убывающую яркость Q=(128−I)*2.

То есть перед сменой цвета экран реально уходит в чёрный, и новый цвет стартует «на чёрном фоне».

У меня в B центр всегда яркий — гаснут только отдельные кольца по мере ухода на периферию. Это тоже читается как «каждый цвет на чёрном», но глобального затемнения нет (мой же адверсариальный агент это отметил как «plausible concern»). После статьи я склонен признать: буквальному тексту точнее соответствует их механика, и я бы привёл B к ней.

  1. Кольца: одинаковая фаза — это и есть канон, а мой «гироскоп» — отклонение

Тут поучительно. Мой адверсариальный агент счёл, что кольца, идеально совпадающие в одно дважды за оборот, — дефект, и я сдвинул фазу на 90°. Но в статье обе версии используют одну фазу для обоих эллипсов:

  • ChatGPT: один и тот же c=abs(cos(t)) для r1 и r2;

  • автор: одно и то же B=R/I для OVALG и OVALV.

Значит совпадение в круг (при c=1) и «плюс» из двух линий (при c=0) — это задуманный пульсирующий вид, а не баг. Мой сдвиг фазы «чинит» то, что чинить не просили. Хорошо, что я оставил ревёрт в одну строку (sin → cos в draw_rings) — им и восстанавливается каноничный вид.

Мелочь в плюс мне: моя (и ChatGPT‑овская) математика R·|cos| — это физически точная ортопроекция равномерно вращающегося кольца (естественно «залипает» анфас, быстро проскакивает ребром). У автора B=R/I с нелинейным I и переменной задержкой WREM — стилизованный ручной easing, не косинус.

  1. Разная скорость по цветам (по желанию)

У них каждый цвет растёт со своей скоростью (TIMES у ChatGPT; TIM=0.01·KOF^J, KOF=1.333 у автора — каждый следующий цвет быстрее). У меня скорость единая. В моей спеке этого не было, так что это не упущение, но приятная деталь — могу добавить.

Где мой код держится хорошо (или лучше)

  • Событийный цикл. У автора анимация крутится в while‑циклах с busy‑wait WREM() (спинит ядро на 100%, блокирует event loop, требует ручного POLE.update()), а ROTOR/SFERA вызываются прямо из обработчика клавиш — это классический tkinter‑footgun: update() внутри цикла может снова диспатчить KLAW, отсюда риск ре‑энтрантности/RecursionError при частом нажатии. И я, и ChatGPT используем идиоматичный root.after(…) — обе «ИИ‑версии» тут аккуратнее человеческой.

  • Нет утечки объектов. У ChatGPT в circles() при смене цвета делается self.items=[] без удаления овалов с холста — старые объекты копятся на канве бесконечно (≈128–168 овалов за цвет, чистятся только при delete(“all”) на смене режима). Забавно: это ровно «видит локальный момент, но не общую картину» из тезиса статьи. У меня A — фиксированные 86 овалов с перекраской, B — кольца удаляются по гашению (проверено: пик 48, роста нет). У автора тоже без утечки — предвыделенные 384 овала.

  • Старт с красного. Обе версии из статьи стартуют красным (self.color=0 / J=1). У меня в первой редакции был off‑by‑one (B начинался с жёлтого) — тот самый, что я уже поправил.

И честно — одно место, где ChatGPT лучше меня: он считает время по стенным часам (time.perf_counter()), поэтому скорость анимации не зависит от частоты кадров; у меня приращения на кадр, и при просадке ниже 50 fps демка замедлится. Для такой задачи неважно, но подход ChatGPT робастнее.

Комментарий к самим листингам

Версия ChatGPT. Компактно и грамотно: after()‑цикл, perf_counter, аккуратный rgb() с клампом max(0,min(255,…)), для ресайза. Слабости: (1) описанная утечка овалов; (2) одинаковая фаза колец — «второе кольцо исчезает» в круг дважды за оборот; (3) круги заполняют лишь центральный радиус 0.35·min = 168 px, а не всё окно. Крепкий «локальный» код с одной неочевидной «глобальной» дырой — прямо иллюстрация к выводу статьи.

Версия автора. Это фактически эталон задачи, и спеку она реализует полностью и вдумчиво: предсоздание овалов против мерцания; тройной овал (OVAL1/2/3 со сдвигом на 1 px) — хак, чтобы соседние 1‑пиксельные контуры не оставляли щелей; ZAL чисто разводит оба варианта (radial gradient ↔ равномерное затемнение всего диска); радиальный градиент Q=(128−I)·2; переменный easing вращения. Минусы — «бейсиковые» привычки: busy‑wait WREM, управление анимацией из while внутри обработчиков (ре‑энтрантность), from tkinter import *, глобальные переменные повсюду, транслит‑имена (OKNO/POLE/PRIZ/ROTOR/SFERA/KLAW), O(n²) перекраска в ветке ZAL!=0. Работает и точно по заданию, но по структуре — самый «олдскульный» из трёх.

Итог

Ничего в моём коде не «сломано», но статья вскрыла три места, где я разошёлся с первоисточником: (1) я показываю все цвета сразу, а канон — по одному растущему цвету; (2) мой B гасит кольца поштучно, а канон — затемняет весь кадр до чёрного; (3) мой сдвиг фазы колец — красивое, но отклонение от задуманной пульсации. По инженерии (event loop, утечки) моя версия и версия ChatGPT аккуратнее человеческой, но у ChatGPT — утечка овалов, а у меня был off‑by‑one с первым цветом (уже поправлен).

Если захочешь «привести к первоисточнику» — скажи, и я (а) переключу режим 2 на последовательный рост одного цвета, (б) сделаю вариант B глобальным затемнением всего диска, (в) верну кольцам одну фазу. Каждое — маленькая правка, но менять пока ничего не буду, как договорились.

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

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

У меня почти на каждую пачку "фич" идет прогон на баги, дедупликацию и прочий рефакторинг. Причем не конкретно по новой пачке - с этим справляется сам ultracode в claude, а именно по всему коду.

Если вы явно ей не скажете - выдели хэндлер, обобщи функционал в какой-то базовый класс и т.д., она это и не сделает, потому что нейронке пофигу на 3000 тысячи строк в файле

Не согласен. В процессе прогона из примера выше таких примеров много. От них на самом деле иногда устаешь отмахиваться.

Например, вот:
  • helpers.py decomposition — defer on cost is fine, but ⚑ "function-local imports = circular-import tell" is falsehelpers.py top-imports only stdlib + lib.log + config + discord; the function-local lib.models/lib.pause_manager imports are one-directional with no cycle. The decomposition is not gated by an import knot. ⏸️ Reviewed 2026-06-23 and kept deferred — 548 lines / 31 functions across ~7 concerns; pure cosmetic refactor with wide import churn and zero functional value. Do only as an isolated, test-backed commit if helpers.py becomes a maintenance drag.

Я готов поставить деньги, что в ТЗ Сбера не ставят задачу дуть размер АПКшки до 1 гигабайта. Если есть желающие поспорить с пруфами - велком.

Это чисто разгильдяйство на местах. От тех, кто нос воротит от вайбкода (апкшку они дули еще до 2021).

Да нет, ТОПОВЫЕ уже привыкли все скидывать на мифических "заказчиков" и "легаси, которое еще дед на бейсике писал" - в приложении-то для заказа такси. Там уже спасать нечего.

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

Это либо саботаж, либо кривые руки. ТЗ такого не было.

Чисто практически это не менее важно: если промпт по сложности и объему равен программе, то зачем нужен ИИ? :)

А тут лайфхак, промпт для ИИ-агентов пишет ИИ. Вы только пишете чего хотите достичь, а как - это уже не ваша забота в идеале.

Если запустите мой вариант (как эталон), то я как раз буду рад посмотреть, какой промпт Вы используете для Fable или Opus.

Попробую.

В коммерческой компании не погромист решает, что будет в продукте. Хоть он трижды ТОПОВЫЙ. Он или кодит, как скажут, или идет лесом.

Опять хороших программистов заставляют писать говнокод! Заставляют либы по 4 раза включать, заставляют какие-то тормозные циклы вхерачивать на холодный запуск, чтобы оно еле включалось - все явно в ТЗ прописано сеньором, который писал под диктовку от заказчика. Ну и у кого тут клоунада?

Вы предлагаете скормить его в ИИ, чтобы она выплюнула улучшенную версию?

Да, именно так, я чуть выше по ветке кидал пример того, как я бы это сделал. Не скажу за Яндекс, но у Сбера есть бета-программы, в которой я и состою - выкатывайте на меня вайбкоженный клиент на 100 мегабайт вместо 1000, с удовольствием потестирую.

1
23 ...

Информация

В рейтинге
1 855-й
Зарегистрирован
Активность

Специализация

Промпт-инженер