2009年12月10日 星期四

老鼠走迷宮

 
步驟:
[1] 往上下左右拜訪鄰接點。
[2] 若鄰點可通行,便遞迴至 [1]。

內有暴力 rand() ...
#include <windows.h>
#include <ctime>
#include <iostream>
using namespace std;

const int W = 23, H = 32;           //迷宮長寬
wchar_t   m[W+1][H+1] = {};         //迷宮本體
int  X, dX[] = {0,-2,0,2}, d;       //方位角
int  Y, dY[] = {2,0,-2,0};
bool bEnd = false;                  //是否已走到終點

void make (int x, int y) 
{
    m[x][y] = L' ';
    for (int n = 16; n--; ) { 
        d = rand() % 4;
        X = x + dX[d];
        Y = y + dY[d];
        if (0<X && X<W && 0<Y && Y<H && 
            m[X][Y] == L'■')
            m[x+dX[d]/2][y+dY[d]/2] = L' ',
            make (X,Y);
   }
}
void show_step (int x, int y, wchar_t ch)  
{
    COORD c = {y*2, x};             //顯示過程
    SetConsoleCursorPosition (
        GetStdHandle (STD_OUTPUT_HANDLE), c);  
    wcout << (m[x][y] = ch);
    Sleep (50);        
}
void visit (int x, int y)               //尋路
{
    if (x==X && y==Y) bEnd = true;      //已抵達終點
    else if (m[x][y] == L' ' && !bEnd) {
        show_step (x, y, L'˙');
        for (int i=0; i<4; ++i) 
            visit (x+dX[i]/2, y+dY[i]/2);
        if (!bEnd) show_step (x, y, L' ');        
    }
}
int main (/* daviddr 091211 */)
{
    srand (time(0));
    wcout.imbue (locale ("cht"));
    for (d=W; d--;) wmemset (m[d], L'■', H)[H] = L'\n';
    make (1,1);

    X = W-2;                        //記錄終點座標
    Y = H-1;
    m[1][0] = m[X][Y] = L'◎';
    wcout << *m;
    visit (1,1);
    getchar();
}
執行結果:
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ◎˙˙˙˙˙■˙˙˙˙˙■      ˙˙˙˙˙˙˙■         ■ ■■■■■˙■˙■■■˙■ ■■■■■˙■■■■■˙■ ■■■■■■■ ■ ■˙˙˙˙˙■˙˙˙■˙■     ■˙■   ■˙■ ■ ■˙˙˙˙˙■ ■˙■■■■■ ■˙■˙■■■■■■■˙■■■ ■˙■ ■ ■˙■■■˙■ ■˙˙˙■   ■˙■˙■˙˙˙˙˙■˙■   ■˙■   ■˙■ ■˙■ ■■■˙■ ■■■˙■˙■˙■■■˙■˙■ ■■■˙■■■ ■˙■ ■˙■ ■˙˙˙■   ■˙■˙˙˙■ ■˙■˙■ ■˙˙˙■   ■˙■ ■˙■ ■˙■■■■■■■˙■■■■■ ■˙■˙■ ■˙■■■■■■■˙■ ■˙■ ■˙˙˙˙˙˙˙˙˙■     ■˙˙˙■˙˙˙■  ˙˙˙˙˙■˙˙˙■ ■■■■■■■■■■■■■ ■ ■■■■■˙■■■■■˙■■■■■˙■■■ ■       ■     ■     ■˙˙˙˙˙˙˙■˙˙˙˙˙■ ■ ■ ■■■■■ ■ ■■■■■■■■■ ■■■■■■■■■˙■■■■■ ■ ■     ■   ■˙˙˙■       ■˙˙˙  ■˙■     ■ ■ ■■■ ■■■ ■˙■˙■■■■■■■ ■˙■˙■ ■˙■■■■■ ■ ■ ■ ■   ■ ■˙■˙˙˙˙˙˙˙■ ■˙■˙■ ■˙˙˙˙˙■ ■ ■ ■ ■■■ ■■■˙■■■■■■■˙■■■˙■˙■■■■■■■˙■ ■ ■   ■ ■   ■˙˙˙˙˙■ ■˙˙˙˙˙■˙˙˙˙˙˙˙˙˙■ ■ ■■■ ■ ■■■ ■■■■■˙■ ■■■■■■■■■■■■■■■■■ ■ ■ ■ ■   ■   ■˙˙˙■    ˙˙˙■  ˙˙˙■˙˙˙˙˙■ ■ ■ ■ ■ ■■■ ■˙■■■■■■■˙■˙■■■˙■˙■˙■■■˙■ ■     ■   ■  ˙˙˙˙˙˙˙˙˙■˙˙˙˙˙■˙˙˙■  ˙◎ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

使用 shuffle 可以隨機拜訪鄰接點,
而 make 中的 for 只要施行 4 次 (轉折點也會變多...(吧?))。

隨機拜訪鄰點,或許能稍微縮短抵達終點的平均時間
(但也可能更久,需視迷宮結構而定)。
#include <algorithm>

void visit (int x, int y)           //尋路
{
    if (x==X && y==Y) {             //已抵達終點
        bEnd = true;
        return;
    }
    if (m[x][y] == L' ' && !bEnd) {
        show_step (x, y, L'˙');
        int i, D[] = {0,1,2,3};     //鄰點序列
        random_shuffle (D, D+3);    //隨機拜訪鄰點  
        for (i=0; i<4; ++i)            
            visit (x+dX[D[i]]/2, y+dY[D[i]]/2);
        if (!bEnd) 
            show_step (x, y, L' ');        
    }
}


OEM懷舊顯示 :-)
#include <windows.h>

void setCodePage (int n...)
{
    va_list p;
    va_start (p, n);
    while (!SetConsoleOutputCP(n)) 
        n = va_arg (p, int);
}

void main ()
{
    int W=20, i;
    char *p, const*const a =     
        "XXXXXXXXXXXXXXXXXXXX"
        "X     X            X"
        "X XXX X X XXX XX X X"
        "X X X X X   X      X"
        "X       X X X X  X X"
        "X X X X XXX X      X"
        "X     X X X   X  X X"
        "X X X   X XXX X  X X"
        "X     X            X"
        "X XXXXXXXXXXXXXXXXXX";      
   
    setCodePage (437, 855, 10000);

    for (p=a, i=0; *p; i++) {
        if (i>=W) { puts(""); i=0; }        
        printf ("%c", *p++=='X'?219:' ');
    }
}

沒有留言:

張貼留言