dev optozorax
4.18K subscribers
345 photos
53 videos
10 files
275 links
По деловым предложениям: optozorax.work@gmail.com.

Связь с админом через личку канала (кнопка в канале слева снизу).

Ютуб: https://www.youtube.com/@optozorax

Сайт: optozorax.github.io
Download Telegram
А вот как-то так выглядит использование этой программки.
Ну и конечно, все задачи я решаю на расте, ведь я очень упоротый максималист! Хоть это иногда и доставляет мне проблем, но я стараюсь писать более-менее идиоматичный код. Зато на этих олимпиадках как никогда понимаешь насколько же Растовские итераторы офигенны.

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

Ещё в процессе я нахожу чего не хватает стандартной библиотеке, например вот понял что метод scan какой-то неправильный, и в процессе олимпиадок мне пригодились бы описанные там scan_before и scan_after.

Так же я придумал ещё один метод над Option: any_or_both_with, при помощи которого можно считать минимум или максимум засунутых в Option величин (надо бы в далёком и прекрасном будущем создать на это MR как сделал вафель >_<).

Так же мне нравится политика codeforces в том, что я могу использовать заранее написанный код, поэтому я собираю коллекцию полезных штук для олимпиадок, отлаживаю их и покрываю тестами: olymp/templates.

⬇️
Вот я вернулся, и тупая телега расположила посты в неправильном порядке -_- Сорян.
В свободное время я продолжаю развивать olytest - прогу для быстрого тестирования программ во время олимпиадного программирования.

Последние фичи:
1. Возможность тестировать конкретный экзешник - a, b, e1. Раньше тестирование запускалось только из main.rs файла, и прошлый код приходилось стирать.
2. Появились CLI команды для генерации и удаления кода экзешников.

Следующие фичи будут обозначаться отдельно, потому что я хочу их прокомментировать.

Фича #3: Автоматический парсинг страницы на codeforces, извлечение имён всех задач и тестов с входными и выхоными данными.

Я парсю html через соответствующие библиотеки, и обращаюсь к результату через селекторы, например все входные данные описываются так: "div.input pre". Что удивительно, для растишки все такие библиотеки есть, и подключаются в два клика.

Фича #4: Возможность указывать в тесте чекер (который ты напишешь как обычный экзешник), который будет интерактивно общаться с программой, и проверять её результат.

А вот это уже интересно. Чтобы понимать что такое интерактивное общение, можете прочитать условия этой задачи: https://codeforces.com/contest/1451/problem/E2. Очевидно, что такую задачу тестировать довольно нетривиально. Нужно написать две программы: одна решает саму задачу, другая осуществляет интерактивное общение для заданного массива.

То есть, у нас есть программы А и Б. А решает задачу, а Б общается с А, предоставляя ей информацию на вход. Что есть тест? Например, у нас есть массив 0 0 2 3. Как нам протестировать что программа А способна получить этот массив? Можно подать его на вход Б, Б выведет нужную информацию и далее будет общаться с А.

Значит, изначально, тест мы записываем в stdin Б, затем stdout от Б мы направляем на stdin А, а stdout от A направляем на stdin Б. А как можно после этого узнать правильный ли выдала ответ программа А или нет? Б может записывать вердикт в свой stderr.

И существует два вида тестов:
* Обычный тест: вход теста подаётся на stdin программы, а выход теста сравнивается с stdout программы.
* Тест с чекером: вход теста подаётся чекеру на вход, а выход теста сравнивается с stderr чекера.

Что интерено, такой схемой можно описать любой из вариантов тестирования олимпиадной задачи:
* Когда ответов существует множество, и ответ нужно проверять какой-то программой.
* Когда нужно сгенерировать большой тест для тестирования программы на скорость.
* Ну и конечно, интерактивное общение как в той задаче.

Например, если у нас задача подразумевает простые тесты, то встаёт вопрос, а как быть когда у нас выход теста сравнивается от чекера, а не от программы? Можно просто написать в чекере, чтобы он весь stdout программы транслировал в свой stderr.

А теперь самое интересно, как это запрограммировать? Окей, создаём два процесса через std::process::Command, берём их входы и выходы, и пытаемся читать и писать через read-write. И сталкиваемся с проблемой, что ввод в расте по умолчанию блокирующий. Это означает, что если прямщас байтов нету, то вызов read будет ждать пока программа не выведет данные.

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

Это приводит к тому, что нужно использовать неблокирующий ввод-вывод. А как я понял, официально, и кросс-платформенно он существует только в виде машинерии async/await, и, например, в tokio.

⬇️
Я про async/await не знал абсолютно ничего, и очень тяжело было прийти к первому рабочему прототипу. Я всё же хотел сделать всё очень императивно, найти такой метод, который мне мог бы чётко сказать: ПРЯМ_ЩАС_БАЙТОВ_НЕТУ. Такой метод правда есть, и он называется poll_read, но он какой-то очень сложный, ему нужен какой-то контекст, какой-то waker, а я не знаю откуда всё это взять. Поэтому пришлось извращаться как есть, и несложными измышлениями, и поверхностным чтением документации я пришёл к тому, что нужно использовать макрос select!{}, который из нескольких футур выбирает ту, которая завершится первой.

У нас может быть две главные футуры:
* Чтение stdout чекера
* Чтение stdout программы

После того как мы прочитали хоть сколько-нибудь информации из каждого источника, мы можем сразу записывать в stdin другого. Так что макрос select!{} вполне подходит, но он мне как-то не нравится, ибо с ним надо было иметь для каждого читателя по отдельному буферу, и я хотел прийти всё же к ПРЯМ_ЩАС_БАЙТОВ_НЕТУ.

Затем благодаря помощи Вафеля обнаружился метод futures::poll_fn, который позволяет вызывать сложнющий poll_read без ручного создания всяких контекстов итд. Я как увидел этот метод, сразу понял, что мне нужен был именно он, и недоумевал, почему такой прекрасный метод не суют во все туториалы и вводные по async/await'у в расте.

В итоге я пришёл к такому коду: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=163960a0f7031364984e2099c0a4de66 .

Он вроде работал, и всё было хорошо, но затем я заметил, что когда один из процессов начинает паниковать и выводить кучу инфы в stderr, которая не умещается в буфер, у меня переставало работать считывание. Тупо зависало. Когда я пытался локализовать в каком месте оно зависало, и писал макрос dbg!(), ОНО НЕ ЗАВИСАЛО. Когда я пытался сделать работу помедленней, и ставил sleep(100ms), ОНО НЕ ЗАВИСАЛО. Я погрешил на async/await, что из-за своей сложности они создают какие-то квантовые эффекты, измерение которых приводит к их исчезновению.

Но затем мне всё же удалось найти место, куда можно поставить dbg!() без исчезновения квантовых эффектов, но это ничего не дало. Затем я нарушил своё отстранение от телеги и зашёл в async-чатик и задал там свой вопрос (и сейчас понял что там в коде неправильная ссылка): https://xn--r1a.website/rust_async/29266 (можно не читать). Мне никто не отвечал, поэтому я продолжил решать проблему самостоятельно. И как это обычно у меня бывает, благодаря тому что для чатика я очень хорошо сформулировал вопрос, я начал понимать свою проблему лучше, и потом размышлениями пришёл к такому:

В моём методе poll_read вызывается внутри цикла постоянно и через очень короткие промежутки времени. Когда я ставил задержку или dbg!(), эти промежутки времени увеличивались. А у async/await есть такая штука как waker, и по идее poll_методы нужно вызывать только после того как твоего waker'а ткнут носом что всё закончилось. А я их вызывал в цикле. И видимо, на внутреннюю машинерию асинхронного кода и регистрацию этих waker'ов тратилось время больше, чем мои промежутки времени в цикле, поэтому у меня "неблокирующее" чтение никак не могло выдать результат, который бы отличался от Pending.

В общем я осознал свою ошибку и вернулся на select!{}. И как я потом замерил, select!{} использует минимальное число обращений к чтению, потому что блокируется на всех футурах, если они все не дают результат прямщас. А это значит, что он и эффективней.

⬇️
Фича #5: Модифицировал синтаксис тестов. Теперь он хранится в одном файле, поддерживает экранирование, поддерживает задание чекера, и состоит всего из трёх символов.

Более подробно:
* Вход и выход теста теперь находится в одном файле по совету Сергея Совы.
* Разные тесты разделяются символом \.
* Вход и выход разделяются либо символом ~, либо символом %. Первый символ пишется в случае обычного теста, а второй в случае наличия чекера. Если нужно, чтобы тест не сравнивался с чем-то, а его результат просто вывелся на экран, то выход может быть просто набором пробельных символов.
* Так же я сделал токенизацию выхода программы и теста, чтобы лишние пробелы и лишние пустые строки не влияли на результат, и чтобы легко было сравнивать.
* Экранировать один из трёх управляющих символов можно тупо написав его два раза.

Для синтаксиса тестов я старался выбирать символы, которые практически никогда не встречаются в тестах олимпиадных задачек, но иногда всё же могут встретиться, и экранировать их - важно. Я часто замечаю, что экранированию синтаксиса уделяется мало внимания при проектировании языка описания чего-то. Для меня растовские строки с r#"text"# стали откровением в области экранирования, ведь это гениально, сделать хэши, чтобы можно было без проблем писать кавычки. Жаль что эти строки являются raw, и внутри них нельзя писать \n чтобы обознчаить перенос строки. Я бы хотел обычную строку, но с хэшами: #" "hi" - says\nsimon "#.

Далее в olytest у меня осталось три жирных пункта:
* Добавить возможность писать в олимпиадной программе include!(), чтобы вместо этого подставлялся нужный текст, и генерировался в отдельный файл, чтобы вручную не копипастить.
* Добавить поддержку ЯП: C++ и Python/PyPy. Это самые частые языки для олимпиадного программирования.
* Написать доку на английском и русском.

После этих трёх пунктов я отлажу программу на себе, своих знакомых, и затем можно будет её официально представить на codeforces, ибо у людей спрос на что-то такое есть: они на стримах с разборами у neal'а постоянно спрашивают что у него там за скрипты и где их можно взять (кто не помнит, я вдохновился именно его скриптами).

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

⬇️
Тестирование всех экзешников.

⬇️
Тестирование той самой задачи с использованием чекера.

⬇️
Так же происходит замер времени, если указать флаг -t.
С НГ! Желаю в этом году чтобы произошёл качественный переход, после которого от тебя все отстанут и будут меньше трепать нервы и отнимать время
Как известно, я очень упорот по клавиатурам.

И в этой области я развиваюсь уже много лет, поэтому мне есть что сказать. И вот думал что неплохо было бы написать статью о своей раскладке (а она довольно уникальна). Получилась, конечно, статья о раскладке, но случайно я параллельно рассказал про десятипальцевый метод, про неверность стандартных клавиатур и историю своего развития. Получилась огромная статья на 200к символов, которую читать, наверное, 2 часа.

Так что приятного чтения! 🍿

#клавиатуры
👍62🔥1
В моей статье, в секции про Кладенец, было упоминание концепта клавиатуры, которую я однажды придумал. И называется она - Нумкорд.

Данная клавиатура состоит из 5 клавиш, и на ней всё нажимается через аккорды. Пользоваться ей можно используя всего три пальца. Данная клавиатура реализует расширенный нумпад, то есть с помощью неё можно писать цифры, стрелки, арифметические знаки, скобочки, и ещё на ней поместились клавиши для передвижения по ячейкам экселя через Tab, Shift+Tab, Enter, Shift+Enter. И это всё на 5 клавишах!

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

А ещё в реальности она была бы очень маленькой. Выглядит как игрушка, но при этом полноценный нумпад.
ДР Канала! Вчера, 24 января, данному каналу исполнился год. И как раз аккурат к этому событию количество подписчиков перевалило за 4 сотни. За этот год сюда было написано почти 300 сообщений.

Я не в настроении рефлексировать, рассказывать историю или говорить планы на будущее, так что просто скажу спасибо всем кто читает и делится с друзьями!
Forwarded from Кладенец, обучение (илья шепрут)
Я тут вдохновился статьёй про однорукую раскладку OPRI, и решил придумать что-то аккордовое, чтобы можно было одной рукой нажимать любой хоткей.

И получилось такая клавиатура - Hotkeypad. Тут вся основная инфа написана на картинке. Главное отличие от Кладенца - это то, что любой хоткей нажимается одним аккордом, когда как на Кладенце хоткеи одной рукой нажимаются при помощи залипающих модификаторов.