Я зарабатываю на жизнь инфраструктурой. Распределённые системы, CI/CD pipelines, Terraform — работа, где одно неверное состояние в одном месте тихо ломает всё, что идёт следом. И вот однажды вечером, без всякой причины, я решил написать шахматы на React — и правило en passant вместе с логикой мата оказались самой сложной задачей на управление состоянием за последние годы. Меня никто не просил. Ни клиента, ни тикета, ни дедлайна. Просто хотелось понять, могу ли я смоделировать что-то по-настоящему сложное на TypeScript и не сойти при этом с ума.

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

Отрисовать легко. Правила — вот где боль.

Вот чего вам не говорят, когда вы садитесь писать шахматы на React: визуал — это тривиальные 10%. Остальные 90% — свод правил, который человечество писало комитетом пятьсот лет, и у каждого правила есть краевой случай, готовый вас унизить.

React взял на себя доску и отрисовку фигур. Всю тяжёлую работу по игровой логике вытянул TypeScript, и без него я вряд ли дошёл бы до конца. Когда ты валидируешь шахматные ходы, runtime-ошибка — это не просто баг, это нелегальный ход, который никто не заметит, пока доска уже не сломана. Типобезопасная генерация ходов ловила целые классы ошибок ещё до того, как они попадали на экран.

А потом пошли правила, которые просто не помещаются в голове:

  • Проверка на шах после каждого хода. Причём не только твоего — нужно доказать, что твой собственный король не остаётся под шахом после того, как ход отыграл. То есть симулируешь ход, сканируешь зону атаки каждой вражеской фигуры и откатываешь назад.
  • У рокировки четыре условия, и все должны выполняться одновременно. Король не ходил. Ладья не ходила. Между ними пусто. И король не под шахом, не проходит через битое поле и не встаёт под шах. Я перечитал регламент FIDE дважды, чтобы сделать это правильно.
  • Превращение пешки — звучит просто, пока не нужно свести вместе UI и переход состояния.

En passant вынес мне мозг

En passant — самое запутанное правило в шахматах, и оно становится ещё запутаннее в тот момент, когда до тебя доходит: твой код должен помнить, что было на прошлом ходу, чтобы валидировать текущий. Пешка бьёт поле, которое перескочила пешка соперника, — но только сразу, только на один ход. И вдруг твой валидатор ходов перестаёт быть чистой функцией от текущей доски. Ему нужна история. Одно это правило заставило меня полностью переосмыслить, как я вообще храню состояние партии.

А потом — мат. По-русски «пат» и «мат» отличаются одной буквой. В TypeScript это совершенно разные деревья логики. Мат: король под шахом и не имеет ни одного легального хода, чтобы уйти. Пат: король не под шахом, но легальных ходов нет вообще — и это ничья, а не поражение. Перепутаешь — и код не выбросит ошибку. Он просто молча объявит не того победителя.

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

Чему шахматы научили меня в инфраструктуре

Вот что меня удивило. Этот дурацкий шахматный проект научил меня управлению состоянием больше, чем любой туториал по Redux, что я проходил.

Когда одно неверное состояние ломает всё, что идёт следом, и пользователь видит это мгновенно на доске — начинаешь совсем иначе думать про иммутабельность и валидацию. Перестаёшь верить, что «вроде работает». Начинаешь симулировать ход, проверять инварианты и только потом фиксировать изменение. Ровно так я сегодня думаю про распределённую инфраструктуру: смоделируй систему, определи, что значит «валидно», и не пропускай плохое состояние через ворота.

Моделирование связанных правил, где одно неверное значение ломает всё дальше по цепочке, напрямую переносится на логику CI/CD, на Terraform-планы — на всё, где корректность действительно важна. Шахматная доска просто сделала сбои видимыми так, как сломанный pipeline умеет редко.

Собери то, что тебя пугает

Смысл был не в том, чтобы написать новый Chess.com. Смысл был в том, чтобы взять что-то сложное и довести до конца.

Если все твои пет-проекты лёгкие — ты остаёшься в зоне комфорта. Возьми тот, от которого немного не по себе. Правило en passant, логика мата, четыре условия рокировки — ничего из этого не было в описании вакансии. И всё это сделало меня лучше как инженера. Собери то, что тебя чуть-чуть пугает. Так и растёшь.

Какой пет-проект научил тебя тому, чему не научил ни один курс?