I was tinkering with a way to print the rooms from this problem. I was using box drawing characters from extended ASCII to test this so I recognize that limits the scope that my code will compile on.
A quick explanation of the problem if you don't want to read over there:
A room is defined as a 4-bit integer such that
- The most-significant bit represents whether the room has a West wall
- The next-to-most-significant bit whether the room has a North wall
- The next-to-least-significant bit whether the room has an East wall
- The least-significant bit represents whether the room has a South wall
As an example a room represented by 0b1101 would have a West, North, and South wall:
┌─
│
└─
There are additional constraints:
- The exterior walls of rooms will always have a wall
- Interior walls will always be expressed in both rooms (the example 0b1101 has a wall to the South, so the room below it must have the next-to-most-significant bit set indicating a North wall)
- There will never be more than
numeric_limits<int>::max()
rooms
My problem is selection of an intersection character. My brute force algorithm must access each room twice (except for rooms in the first row/column.) Is there a way to find intersections with only one memory access per room?
If you'd like to see my code for reference; it takes in:
- A
vector<char>
of the room information - A
size_t
giving the row width - A
vector<int>
with the labels for each room (this could be set tovector(size(testValues), -17)
to just print the room structure without labels
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';
}
}
If you're interested in a simple test for this you could do:
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;