输入:由任意大小的bool矩阵表示的迷宫。 (超出范围计为0)
00100
00100
01110
11111
01110
00100
输出:漂亮的迷宫表示(邻域被映射到wchar_t
):
┌─┐
│1│
┌┘1└┐
┌┘111└┐
|11111|
└┐111┌┘
└┐1┌┘
└─┘
编辑:基本上每个0都会映射到一个代表墙布局的4位值。
我的方法和想法:
我认为一次看每个细胞最简单。然后看看它的邻居来确定放在那里的价值。结果我有8个布尔输入(所有邻居),这产生2 ^ 8 = 256个不同的场景。我不觉得他们都很难编码。
是否有更优雅的方式正确映射值?
答案 0 :(得分:2)
我在2004年IOCCC的my winning entry中实现了这一点。我相信你会发现代码记录良好且易于理解。
如果您只是想要答案,我记得,我采用的方法是计算每个单元格周围的被占用单元格的位图,并将其用作墙角色数组(或等效的字形)的索引。如果像我的解决方案那样,你不允许对角线移动,那么位图是4位长,因此阵列有2 ^ 4 = 16个元素。如果允许对角行程,则需要8位位图和256个条目。
答案 1 :(得分:1)
你可以通过在其他人之前看一些细胞来降低它,但老实说,256并不是那么多。编写一个生成它们的程序,或者手工完成并使用查找表,额外的256个字节(你可以将查找映射到另一个索引来获取实际字符)足够小,不用担心。
答案 2 :(得分:1)
不是扫描每一行1并绘制每个单元格,而是可以“走”墙。
虽然不在你的bool数组的末尾:
定义一个名为“Draw”的函数,它将:
- 返回,恢复扫描直到下一个1或输入结束。
也许不是最有效的,但你说优雅。递归永远优雅! (直到你得到一个stackoverflow)。
以下是一些被黑客入侵的代码(不要像我一样使用魔法数字:))来帮助你:
int inputIdxToOutputIdx(int idx)
{
return (idx + 1);
}
int draw(int x, int y, int arr[6][6], char outBuff[8][8])
{
for (int deltaX = -1; deltaX < 2; ++deltaX)
{
for (int deltaY = -1; deltaY < 2; ++deltaY)
{
int currX = (x + deltaX);
int currY = (y + deltaY);
int drawX = inputIdxToOutputIdx(x) + deltaX;
int drawY = inputIdxToOutputIdx(y) + deltaY;
// if any adjacent to 1 are 0 or off the map,
// draw a border
arr[x][y] = 3;
if (currX > 5 || currY > 5 || currX < 0 || currY < 0 || arr[currX][currY] == 0)
{
printf("Drawing at %i, %i (%i,%i)\n", currX, currY,drawX,drawY);
outBuff[drawX][drawY] = '*';
}
else if (arr[x][y] == 1)
{
draw(currX, currY, arr, outBuff);
}
}
}
}
// make the output buffer size of input + 2
int printMaze(int arr[6][6], char outBuff[8][8])
{
for (int x = 0; x < 6; ++x)
{
for (int y = 0; y < 6; ++y)
{
// this might be able to be made more efficient.
if (arr[x][y] == 1)
{
draw(x, y, arr, outBuff);
}
}
}
}
在上面的解决方案中,我只是画'*'。但是,如果你想为特定情况绘制一个特定的部分,我会在他的评论中使用像 walkytalky 这样的查找表。将给定的一组相邻的1和0映射到给定的一块。 IE:
向上看:
0 1 0
0 1 1
0 1 0
会给中心墙块一个“T”的结果。务必将“离地图”视为等于0。
当完成所有操作时,只需使用基于相邻部分的查找表进行直接扫描(无递归)可能是您最好的选择,除非您能够使上述解决方案更加智能,不重新扫描已扫描的内容。
答案 3 :(得分:1)
受Doug T.解决方案的启发,我自己写了以下内容。
基本上我经历了两次矩阵(性能不佳:/)。我第一次在矩阵中的每个1
周围画墙,我用比特掩码来做。我第二次清理所有“向内指向”的墙。
示例设置:
// Add padding to output-matrix
int owidth = width+2;
int oheight = height+2;
// 4-bit value: 0bWSEN
static char N = 0x1; // The dash that goes from the center to the north
static char E = 0x2; // The dash that goes from the center to the east
static char S = 0x4; // ...
static char W = 0x8;
// This is what I will draw around every tile
char box[] =
{S|E, E|W, W|S,
N|S, 0 , N|S,
N|E, E|W, W|N };
围墙循环:
for(unsigned int y = 0; y < height; y++)
for(unsigned int x = 0; x < width; x++)
{
// We ignore walls
if (! isOne(x, y)) // isOne takes care of out-of-bounds
continue;
// Go through neighbourhood
for(int dy = -1; dy <= 1; dy++)
for(int dx = -1; dx <= 1; dx++)
{
if (dy == 0 && dx == 0) // Ignore self
continue;
if (! isOne(x+dx, y+dy))
{
// Draw part of box
int ox = x+1, oy = y+1; // output-x and y
out[(oy+dy)*owidth+(ox+dx)] |= box[(dy+1)*3 + (dx+1)];
}
}
}
清理循环:
// Clean up "pointing edges"
for(unsigned int y = 0; y < height; y++)
for(unsigned int x = 0; x < width; x++)
{
// We ignore zero's since we're only cleaning walls.
if (isOne(x, y))
continue;
int ox = x+1, oy = y+1; // output-x and y
// Remove edges that points to 'zero'-cells.
if (! isOne(x , y-1)) out[y*width+x] &= ~N;
if (! isOne(x , y+1)) out[y*width+x] &= ~S;
if (! isOne(x-1, y )) out[y*width+x] &= ~W;
if (! isOne(x+1, y )) out[y*width+x] &= ~E;
}
然后我会有一个16个大小(每个符号一个)查找列表,每个字符有一个条目。
map<unsigned int, wchar_t> p;
p[0] = ' ';
p[N] = '.';
// ...
p[N|S] = L'\u2502'; // │
p[E|W] = L'\u2500'; // ─
// ...
p[N|E|S|W] = L'\u253C'; // ┼
这个算法无论如何都没有效率,O(2 * width * height)不好...可以通过生成其他人建议的256大小的循环表来改进它,这会给我们O( 1)执行时。
答案 4 :(得分:1)
首先遍历矩阵,添加以下内核矩阵,将核心0
置于每个1
上,并将数字添加到相邻的正方形(即,将所有数据的二进制表示邻居)。
1 2 4
8 16 32
46 128 256
然后只需编写规则列表,每个形状的一个规则,而不是每个可能的总和的规则。例如,
s = s_ij # the sum at the location of interest
if not s & 16: # never write a symbol over a 1
if s & 8 and not (s & 128 or s & 2):
c = "|"
elif s ==128:
c = “┌─┐”
# etc
或任何你想要的东西。
答案 5 :(得分:0)
如果您首先找到哪些图块是墙,则为您拥有的每种墙类型编写一个特殊情况,例如,如果左侧和/或右侧有一个墙,则为垂直,但顶部或底部没有。< / p>
我希望,这应该缩小一点。 :)垂直,水平和四个不同的边缘。一旦你检测到哪些是边缘,那就是6例。
至少少于256。 :)
答案 6 :(得分:0)
快速入侵。使用3x3数组和一些模运算可能会减少很多内存访问次数,但它可能看起来很难看。警告我没有通过编译器运行它,因此它可能包含拼写错误。
wchar_t maze_wall(int** input,int rows, int cols){
wchar_t** output;
int i,j;
int N,E,S,W,NE,SE,NW,SW;
output = (wchar_t**) malloc(sizeof(wchar_t*)*rows);
for(i=0;i<cols;i++)
output[i]= (wchar_t*) malloc(sizeof(wchar_t)*cols);
for(i=0;i<rows;i++){
for(j=0;j<cols;j++){
if(input[i][j] ==1)
{output[i][j] = '1'; continue;}
N=E=S=W=NE=SE=NW=SW=0;
if(i != 0) /*We are not at the top*/
N = input[i-1][j];
if(i != rows-1) /* We are not at the bottom*/
S = input[i+1][j];
if(j != rows-1) /* We are not at the right side*/
E = input[i][j+1];
if(j != 0) /* We are not at the left side*/
W = input[i][j-1];
/*Expand this for the corners*/
if(N+E+S+W+NE+SE+SW+NE+NW == 0)
{output[i][j] = ' '; continue;}
/*Fill it in for the other six cases {'└', '┐', '┌', '┘', '-', '|'} */
}
}
return output;
}