Печатайте комнаты, но доступ только один раз

Я пытался распечатать комнаты из этой проблемы. Я использовал символы рисования прямоугольников из расширенного ASCII, чтобы проверить это, поэтому я понимаю, что это ограничивает область, которую мой код будет компилироваться.

Краткое объяснение проблемы, если вы не хотите читать там:

Комната определяется как 4-битное целое число, такое что

  • Самый старший бит показывает, есть ли в комнате западная стена.
  • Второй по значимости бит, имеет ли комната северную стену.
  • Наименее значимый бит, имеет ли комната восточную стену.
  • Младший бит показывает, есть ли в комнате южная стена.

Например, комната, представленная 0b1101, будет иметь западную, северную и южную стены:

┌─
│
└─

Есть дополнительные ограничения:

  1. Наружные стены комнат всегда будут иметь стену
  2. Внутренние стены всегда будут отображаться в обеих комнатах (в примере 0b1101 стена обращена к югу, поэтому для комнаты под ней должен быть установлен следующий за старшим значащим бит, указывающий на северную стену).
  3. Никогда не будет больше numeric_limits<int>::max() комнат

Моя проблема заключается в выборе символа пересечения. Мой алгоритм грубой силы должен обращаться к каждой комнате дважды (за исключением комнат в первой строке/столбце). Есть ли способ найти пересечения только с одним доступом к памяти для каждой комнаты?


Если вы хотите увидеть мой код для справки; он принимает:

  1. vector<char> информации о номере
  2. size_t, задающий ширину строки
  3. vector<int> с метками для каждой комнаты (можно установить vector(size(testValues), -17), чтобы просто распечатать структуру комнаты без меток).
string printArray(const vector<char>& testValues, const size_t width, const vector<int>& indexes) {
    if (empty(testValues)) {
        return string();
    } else {
        string result;
        auto prevLine = "\xC9\xCD"s;

        prevLine.reserve(2U * (1U + width));

        for (auto i = 0U; i + 1 < width; ++i) {
            if ((testValues[i] & 0b10) != 0) {
                prevLine += "\xD1\xCD"s;
            } else {
                prevLine += "\xCD\xCD"s;
            }
        }
        prevLine += "\xBB\n"s;

        result.reserve(size(prevLine) * (1U + 2U * size(testValues) / width));

        for (auto i = 0U; i < size(testValues) - width; ++i) {
            const auto x = i % width;

            const auto isBottomSet = (testValues[i] & 0b1) != 0;

            if (x == 0) {
                result += (prevLine + '\xBA') + static_cast<char>('0' + indexes[i]);
                prevLine = isBottomSet ? "\xC7\xC4"s : "\xBA "s;
            }

            if (x + 1U == width) {
                result += "\xBA\n"s;
                prevLine += isBottomSet ? "\xB6\n"s : "\xBA\n"s;
            } else {
                const auto isRightSet = (testValues[i] & 0b10) != 0;
                const size_t index = static_cast<int>(isRightSet) << 3 | testValues[i + width + 1] & 0b100 | (testValues[i + width + 1] & 0b1000) >> 2 | static_cast<int>(isBottomSet);
                // MSB: isAboveIntersectionSet
                //      isRightOfIntersectionSet
                //      isBelowIntersectionSet
                // LSB: isLeftOfIntersectionSet
                constexpr const char* getIntersection[] = { "  ", // 0b0
                                                            "  ", // 0b1
                                                            "  ", // 0b10
                                                            "\xBF ", // 0b11
                                                            " \xC4", // 0b100
                                                            "\xC4\xC4", // 0b101
                                                            "\xDA\xC4", // 0b110
                                                            "\xC2\xC4", // 0b111
                                                            "  ", // 0b1000:
                                                            "\xD9 ", // 0b1001
                                                            "\xB3 ", // 0b1010
                                                            "\xB4 ", // 0b1011
                                                            "\xC0\xC4", // 0b1100
                                                            "\xC1\xC4", // 0b1101
                                                            "\xC3\xC4", // 0b1110
                                                            "\xC5\xC4" }; // 0b1111

                result += { isRightSet ? '\xB3' : ' ', static_cast<char>('0' + indexes[i + 1]) };
                prevLine += getIntersection[index];
            }
        }

        result += (prevLine + '\xBA') + static_cast<char>('0' + indexes[size(testValues) - width]);
        prevLine = "\xC8\xCD"s;

        for (auto i = size(testValues) - width; i + 1 < size(testValues); ++i) {
            if ((testValues[i] & 0b10) != 0) {
                result += { '\xB3', static_cast<char>('0' + indexes[i + 1]) };
                prevLine += "\xCF\xCD"s;
            } else {
                result += { ' ', static_cast<char>('0' + indexes[i + 1]) };
                prevLine += "\xCD\xCD"s;
            }
        }
        return result + "\xBA\n"s + prevLine + '\xBC';
    }
}

Если вас интересует простой тест для этого, вы можете сделать:

const vector<char> rooms = { 0b1101,    0b110,  0b1101, 0b110,  0b1100, 0b101,  0b110,
                             0b1110,    0b1001, 0b110,  0b1011, 0b1010, 0b1111, 0b1010,
                             0b1000,    0b101,  0b11,   0b1110, 0b1011, 0b1110, 0b1010,
                             0b1011,    0b1101, 0b101,  0b1,    0b101,  0b11,   0b1011 };
const vector<int> indexes = { 1,    1,  2,  2,  3,  3,  3,
                              1,    1,  1,  2,  3,  5,  3,
                              1,    1,  1,  6,  3,  6,  3,
                              1,    6,  6,  6,  6,  6,  3 };

cout << printArray(rooms, width, indexes) << endl;

Живой пример


person Jonathan Mee    schedule 21.06.2016    source источник
comment
Можете ли вы объяснить, какой точный набор символов вы используете (особенно для пересечений)?   -  person Davis Herring    schedule 07.08.2019
comment
@DavisHerring Да, извините, они плохо переводятся на сайт rextester.com. Я использую расширенный код ASCII: msdn.microsoft. com/en-us/library/9hxt0028(v=vs.71).aspx, а именно символы от 179 до 217 для рисования линий.   -  person Jonathan Mee    schedule 07.08.2019
comment
Я знаком с CP437, но какие из этих 39 символов вы пытаетесь использовать и сколько на комнату/стену? Излишне сложно реконструировать это из кода (и его шестнадцатеричных экранов).   -  person Davis Herring    schedule 07.08.2019