Мне хотелось разобраться с языком C по-человечески: не «сто задач на указатели», а так, чтобы каждая написанная программа была зачем-то нужна. Готового такого курса я не нашёл, по своей же идее и собрал себе сам.

Получилось следующее: 80 серий в десяти сезонах, 74 часа задач, семь сквозных проектов, всё собирается без единой внешней библиотеки и прогоняется в CI на Linux и macOS. Курс бесплатный, лежит на GitHub, и я решил им поделиться — вдруг будет интересно или пригодится ещё кому-то.

Год назад я уже писал о нём здесь, но с тех пор от того курса, не осталось почти ни одного эмодзи, а уроков стало в два-три раза больше.


Что это такое

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

Ты — специалист по кибербезопасности. В 23:47 на канал, которым ты не пользовался два года, приходит сообщение от человека, которого похоронили позапрошлой осенью. Сообщение зашифровано. Чтобы прочитать его, придётся написать программу.

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

Season 1: Foundations              Серия s01e01
Локация: Москва 🇷🇺                 1 октября, 23:52
Концепт: биты, hex, XOR одного байта
Артефакт: `bytecheck.c`            Время: ~25 мин

За курс пишется 80 программ. Ничего не выбрасывается: артефакты серий собираются в сквозной проект сезона, а проекты поздних сезонов линкуются с модулями ранних.

$(CC) -I$(S4) -I$(S6) -I$(S8) -I$(S9) -o moonlight_core \
      $(S4)/ml_hash.c $(S6)/ml_crc.c $(S8)/ml_stats.c $(S9)/ml_kalman.c main.c

Хеш из Season 4 работает индексом тикеров в Season 5 и адресацией устройств в Season 6. Не копипастой — линковкой; тест падает, если скопировал реализацию вместо того, чтобы подключить.

Числа в тексте получены кодом серии, а не подобраны: CRC-16 совпадает с эталоном Modbus, период орбиты 7000 км — 97.1 минуты, перцептрон на исключающем «или» даёт ровно 50 %, потому что иначе не может.


Курс живёт в редакторе, а не на сайте

Это, пожалуй, главное отличие от онлайн-платформ, и оно сделано намеренно.

Курс — это репозиторий, который ты клонируешь и открываешь в Cursor. Дальше у тебя на одном экране три вещи: текст серии или твой код, терминал и чат с ИИ-чатом. Не вкладка браузера, где видео отдельно, песочница отдельно, а настоящий проект — отдельно.

cd season-01-foundations/s01e01-strange-message
cp starter.c artifacts/bytecheck.c
make test            # красный — так и задумано

Тест на старте красный не по недосмотру: в starter.c лежат TODO, а не решение. Тест здесь не судья, а спецификация — его вывод говорит, чего не хватает.

Работает и в VS Code, но тогда придётся заменить встроенного тьютора любым другим ИИ-чатом. Про тьютора — дальше, это отдельный сюжет.


ИИ здесь не пишет за тебя код

Про ИИ в программировании говорят так, будто есть один режим: попросил — получил готовое. Есть как минимум два других, и оба к вайб-кодингу отношения не имеют.

Первый — собрать себе программу обучения. Именно так появился этот курс. Не «ИИ, напиши мне курс на C» (так получится оглавление учебника), а разговор о том, чему я хочу научиться, в каком порядке, на каком материале и что должно получиться на выходе. Результат — программа под конкретного человека, а не усреднённая. Это, по-моему, самое недооценённое применение ИИ вообще: не заменять специалистов, а давать людям возможность учиться так, как им удобно.

Второй — помощь во время прохождения. В сюжете есть ИИ-напарник LUNA. Это не литературный приём: LUNA буквально является чатом Cursor, открытым рядом с кодом. Всё, что она «говорит» в тексте серии, можно спросить у неё по-настоящему.

И вот тут важная деталь, ради которой курс, собственно, и устроен так, как устроен.

Курс проходится в режиме Ask, а не Agent. В Agent ассистент правит файлы сам: серия окажется решённой, тесты зелёными, а ты не напишешь ни строки. Через три серии станет ясно, что предыдущие три ты не проходил. В Ask он только отвечает — объясняет, разбирает ошибку, показывает приём на другой задаче. Код пишешь ты.

Разница между «вредит» и «ускоряет» часто в одном слове запроса:

Забирает у тебя работу

Снимает препятствие

«Напиши bytecheck.c»

«Почему знаковость char не определена стандартом?»

«Почини мою гонку»

«Как воспроизвести гонку, чтобы она падала стабильно?»

«Оптимизируй этот код»

«Как измерить, где именно уходит время?»

«Найди ошибку»

«Как читать вывод санитайзера?»

Поэтому в конце каждой из 80 серий стоят два блока: зелёные запросы — те, что делают сильнее, и красный анти-паттерн — вопрос, который выглядит совершенно разумным и вредит именно здесь, с объяснением почему.

«У меня 50 % на XOR, что не так?» — ничего. Перцептрон иначе не может, и в этом весь смысл серии. Спроси, почему именно 50, а не «почини».

Восемьдесят таких, каждый про ловушку своей серии.

А в Season 8 курс делает то, к чему шёл: ты пишешь LUNA сам. Сквозной проект сезона называется luna_ai и собирается из статистики, регрессии и нейросети, написанных в его сериях. К этому моменту ты знаешь, что внутри у того, с кем разговаривал семь сезонов.


Почему версия 1.0, а не 0.3

Первая версия курса, собранная год назад в Cursor с Sonnet, была полуфабрикатом. Она выглядела как курс — а это, как выяснилось, совсем не то же самое, что быть курсом.

Разбор показал:

Заявлено

Оказалось

«100 % готово»

часть тестов красная

README серии

до 3620 строк — их физически не читают

«~120–160 часов»

назначено на глаз, не измерено

единая версия

три схемы нумерации одновременно в разных файлах

«сквозные проекты»

нарративные, кодом не связаны

Отдельная история — Season 5. Он назывался «Financial Markets» и на треть состоял из пересказа теории рынков: спред, стакан, типы ордеров. Красиво и совершенно бесполезно для курса языка C. Сезон переименован в «Real-World Data», и предметом стало то, обо что программист на C бьётся в реальности: деньги, которые не бывают double; битые выгрузки; часовые пояса; UTF-8, в котором strlen считает байты.

Нынешняя версия — результат сплошного рефакторинга уже в Claude Code. Разница между «сгенерировать» и «довести» и есть тот самый разрыв между полуфабрикатом и продуктом, которым не стыдно поделиться.


Что можно проверить

Мы больше не пишем «100 % готово». Вместо этого — числа, которые пересчитываются командой:

Серий

80 в 10 сезонах

Чистого времени на задачи

74 ч 00 мин — сумма по шапкам серий

Сквозных проектов

7

Внешних библиотек

ни одной, включая -lm

Платформы в CI

Linux и macOS

sqrt, exp и генератор псевдослучайных чисел написаны вручную — чтобы результат побитово воспроизводился на любой машине. Тесты детерминированы: ни таймингов, ни идентификаторов процессов, ни системного времени в сравниваемом выводе.

make check      # ссылки + весь курс
make projects   # сборка сквозных проектов
make progress   # где ты сейчас

Чего у курса нет

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

Так что если возьмётесь за серию и что-то не сойдётся — issue с выводом теста будет самой полезной помощью из возможных.

Репозиторий: github.com/gfazzz/moonlight-course · MIT · берите, форкайте, переделывайте под себя.