«Крестики-нолики» и printf
Очень люблю так называемое ненормальное программирование (нормального мне и на работе хватает), когда программируют ради преодоления каких-то препятствий, а не ради практического результата. С удовольствием занимаюсь им сам и очень люблю находить такие примеры у других.
На днях один из читателей очень меня порадовал игрой «Крестики-нолики», написанной на… языке функции printf! Возможно я когда-то и слышал, что язык printf полный по Тьюрингу, но в голове это не отложилось.
Для тех, кто не знает, поясню, язык printf — это значки, которыми описывается в каком именно виде нам хочется вывести на экран информацию о переменных. Используется во многих языках, но особенно часто в Си.
В этом языке много интересных конструкций, есть даже такие, которыми можно даже что-то записывать в другие переменные!
Например, вот небольшой пример, который запишет число «42» (длину строки «Answer to the Ultimate Question of Life is») в переменную c:
#include <stdio.h>
int main() {
int c;
printf("Answer to the Ultimate Question of Life is%n ", &c);
printf("%d", c);
}
Как, используя эти значки, можно что-то запрограммировать? С большим трудом. Автор программы нашёл способ описания логических операций, а потом с их помощью реализовал нужную ему логику.
Если закодировать «ложь» пустой строкой, а «истину» строкой длиной один, то логическую операцию «ИЛИ» можно получить, если померить совокупную длину двух входных значений:
// c = strlen("") + strlen("")
printf("%s%s%n", "", "", &c); // в c будет «0»
// c = strlen("1") + strlen("")
printf("%s%s%n", "1", "", &c); // в c будет «1»
«НЕ» получается сложнее, для этого надо использовать несколько хитростей.
Во-первых, у printf есть возможность задавать отступ для значения.
Во-вторых, у %n есть параметр, который выводит длину по модулю 256.
В-третьих, вместо форматирования входных параметров по порядку, есть способ для указания параметра, который мы хотим вывести, по его номеру.
Всё это позволяет закодировать «НЕ» как (strlen(a)+255)%256 или strlen(a)-1:
printf("%1$255s%1$s%2$hhn", a, &c);
Тут написано следующее: вывести первый параметр как строку, дополнив его до длины в 255 символов пробелами (%1$255s), снова вывести первый параметр как строку (%1$s), записать полученную длину по модулю 256 во второй параметр (%2$hhn).
Отсюда легко понять как сделать операцию «И-НЕ»:
printf("%1$254s%1$s%2$s%3$hhn", a, b, &c);
В принципе, этого хватило, что реализовать всю требуемую логику.
Играют два игрока, последовательно вводя номер ячейки, куда делается ход (от единицы до девяти, считая слева направо, сверху вниз). Программа отрисовывает поле и определяет победу одного из игроков или ничью.
Очень заморочено и очень интересная идея!
«номер ячейки, куда делается ход (от нуля до девяти)»
От 0 до 9 получается 10 ячеек
Ой, спасибо, поправил! )