Як цей код генерує карту Індії?


169

Цей код друкує карту Індії. Як це працює?

#include <stdio.h>
main()
{
    int a,b,c;
    int count = 1;
    for (b=c=10;a="- FIGURE?, UMKC,XYZHello Folks,\
    TFy!QJu ROo TNn(ROo)SLq SLq ULo+\
    UHs UJq TNn*RPn/QPbEWS_JSWQAIJO^\
    NBELPeHBFHT}TnALVlBLOFAkHFOuFETp\
    HCStHAUFAgcEAelclcn^r^r\\tZvYxXy\
    T|S~Pn SPm SOn TNn ULo0ULo#ULo-W\
    Hq!WFs XDt!" [b+++21]; )
    for(; a-- > 64 ; )
    putchar ( ++c=='Z' ? c = c/ 9:33^b&1);
    return 0;
}

63
Це просто затуманене C ... є цілі товариства, присвячені такому безумству.
Марк


2
#include "Stdio.h": Це працює на всіх компіляторах? Я здивований, побачивши, що ви можете отримати робочий код з помилками. Можливо, це в Windows (нечутливий до регістру FS)
альтернатива

2
Більше цікавого коду, як це, див. [Міжнародний конкурс з прихованим кодом C] [ ioccc.org/] .
DarkDust

12
Тільки майте на увазі, що навмисно важко зрозуміти код , і не дуже багато можна отримати від його з'ясування, що стосується вивчення C з початкового рівня.
Тайлер Макенрі

Відповіді:


154

Довга рядок - це просто двійкова послідовність, перетворена в ASCII. Перше forтвердження bпочинається з 10, а [b+++21]після рядка виходить 31. Поводження з рядком як масив, зміщення 31 - це початок "реальних" даних у рядку (другий рядок у наданому вами зразку коду). Решта коду просто перебирається через бітову послідовність, перетворюючи 1 та 0 у! І пробіли та друкуючи по одному символу за один раз.

Менш заплутана версія:

#include "stdio.h"
int main (void) {
    int a=10, b=0, c=10;
    char* bits ="TFy!QJu ROo TNn(ROo)SLq SLq ULo+UHs UJq TNn*RPn/QPbEWS_JSWQAIJO^NBELPeHBFHT}TnALVlBLOFAkHFOuFETpHCStHAUFAgcEAelclcn^r^r\\tZvYxXyT|S~Pn SPm SOn TNn ULo0ULo#ULo-WHq!WFs XDt!";
    a = bits[b];
    while (a != 0) {
        a = bits[b];
        b++;
        while (a > 64) {
            a--;
            if (++c == 'Z') {
                c /= 9;
                putchar(c);
            } else {
                putchar(33 ^ (b & 0x01));
            }
        }
    }
    return 0;
}

Дивно розумна частина в putcharзвітності. Візьміть перше putchar. ASCII 'Z'дорівнює 90 у десятковій частині, тому 90/9 = 10 - це символ нового рядка. У другій десятковій 33 є ASCII для '!'. Якщо переключити біт низького порядку 33, ви отримаєте 32, що є ASCII для простору. Це призводить !до друку, якщо bце непарно, і порожнє місце для друку, якщо bпарне. Решта коду просто там, щоб пройти по вказівнику aпо рядку.


22
Рядок не є бітною послідовністю (зауважте, що в коді немає операцій з зсувом бітів). Це кодування зображення довжиною пробігу.
interjay

89

В основному, рядок - це кодування зображення довжиною пробігу : чергування символів у рядку кажуть, скільки разів намалювати пробіл і скільки разів намалювати знак оклику послідовно. Ось аналіз різних елементів цієї програми:

Зашифрований рядок

Перші 31 символ цього рядка ігноруються. Решта містять інструкції щодо малювання зображення. Окремі символи визначають, скільки пробілів або знаків оклику слід малювати послідовно.

Зовнішня для петлі

Цей цикл переходить через символи в рядку. Кожна ітерація збільшує значення bодиниці і присвоює наступний символ у рядку a.

Внутрішня для петлі

Цей цикл малює окремі символи та новий рядок, коли він доходить до кінця рядка. Кількість намальованих символів - a - 64. Значення go cпереходить від 10 до 90, а скидає до 10, коли буде досягнутий кінець рядка.

The putchar

Це можна переписати як:

++c;
if (c==90) {       //'Z' == 90
    c = 10;        //Note: 10 == '\n'
    putchar('\n');
}
else {
    if (b % 2 == 0)
        putchar('!');
    else
        putchar(' ');
}

Він малює відповідний символ, залежно від того b, парне чи непарне чи новий рядок, коли це потрібно.


1
Чому перші 31 символ ігноруються?
Pankaj Mahato

3
@PankajMahato тому, що bпочинається з 10, а індекс є (b++)+21, який починається в 31.
interjay
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.