Как этот код генерирует карту Индии?

Этот код печатает карту Индии. Как это работает?

#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;
}

Ответ 1

Длинная строка - это просто двоичная последовательность, преобразованная в 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 через строку.

Ответ 2

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

Закодированная строка

Первые 31 символ этой строки игнорируются. Остальные содержат инструкции для рисования изображения. Отдельные символы определяют, сколько пробелов или восклицательных знаков нужно рисовать последовательно.

Внешнее для цикла

Этот цикл перебирает символы в строке. Каждая итерация увеличивает значение b на единицу и присваивает следующий символ в строке a.

Внутренний цикл

Этот цикл рисует отдельные символы и новую строку всякий раз, когда он достигает конца строки. Количество рисунков a - 64. Значение c изменяется от 10 до 90 и сбрасывается до 10 при достижении конца строки.

putchar

Это можно переписать как:

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

Он рисует соответствующий символ, в зависимости от того, является ли b четным или нечетным, или новой линией, когда это необходимо.

Ответ 3

Я преобразовал один и тот же код в С#. Просто запустите это в консольном приложении.

        Console.OutputEncoding = System.Text.Encoding.UTF8;
        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!".ToCharArray();
        a = bits[b];
        while (a != 0)
        {
            try
            {
                a = bits[b];
                b++;
                while (a > 64)
                {
                    a--;
                    if (++c == 'Z')
                    {
                        c /= 9;
                        Console.Write(Strings.ChrW(c));
                    }
                    else
                    {
                        Console.Write(Strings.ChrW(33 ^ (b & 0x01)));
                    }
                }
            }
            catch (Exception ex)
            {

            }
        }
        Console.ReadKey();
    }