//See TextBase Layer.

#define ATTR (BLACK << 12 + WHITE << 8)

U32 text[TEXT_ROWS][TEXT_COLS];

U0 DrawIt(CTask *task, CDC *)
{ //gr.text_base gets clear 60fps, so we must use our own permanent text array.
        MemCopy(gr.text_base + TEXT_COLS, text, (TEXT_ROWS - 1) * TEXT_COLS * sizeof(U32));

        // You can copy it this way, if you like:
        //      I64 i, j;
        //      for (j = 0; j < TEXT_ROWS; j++)
        //              for (i = 0; i < TEXT_COLS; i++)
        //               TextChar(task,, i, j, text[j][i]);

        TextPrint(task, 0, 0, ATTR >> 8, "Draw a maze with left bttn.");
        TextPrint(task, 0, 1, ATTR >> 8, "Solve maze starting at right click.");
}

#define STACK_SIZE 2048
//We would put these as local vars
//in SolveMaze() but the system stack size
//is limited, so it's a bad habit.  The heap
//is the normal ZealOS technique, but
//it's a pain in this case.
I64 stack_ptr,  stack_x  [STACK_SIZE], 
                                stack_y  [STACK_SIZE], 
                                stack_dir[STACK_SIZE];

//Four directions:
//      0=Up, 1=right,2=down,3=left
I64 dir_x[4] = { 0, +1,  0, -1},   // Could use gr_x_offsets2,gr_y_offsets2
        dir_y[4] = {+1,  0, -1,  0};

U0 SolveMaze(I64 x, I64 y)
{
        I64 dir = 0;

        stack_ptr = 0;
        stack_x[stack_ptr] = x;
        stack_y[stack_ptr] = y;
        stack_dir[stack_ptr++] = dir;
        while (TRUE)
        {
                if (!(0 <= x < MinI64(Fs->win_width,  TEXT_COLS)) ||
                        !(0 <= y < MinI64(Fs->win_height, TEXT_ROWS)) )
                {
                        Beep;
                        Beep;
                        break;
                }
                if (!text[y][x].u8[0])
                        text[y][x] = '.' + ATTR;
                x += dir_x[dir];
                y += dir_y[dir];
//u8.[0] is the ASCII
                if (text[y][x].u8[0])
                {
                        x -= dir_x[dir];
                        y -= dir_y[dir];
                        if (++dir == 4)
                        {
                                if (--stack_ptr < 0)
                                        return;
                                x = stack_x[stack_ptr];
                                y = stack_y[stack_ptr];
                                dir = stack_dir[stack_ptr];
                        }
                }
                else
                {
                        dir = 0;
                        stack_x[stack_ptr] = x;
                        stack_y[stack_ptr] = y;
                        stack_dir[stack_ptr++] = dir;
                        if (stack_ptr == STACK_SIZE)
                                return;
                        Sleep(100);
                        if (CharScan)
                                throw;
                }
        }
}

U0 Maze()
{
        I64 ch, x, y;

        SettingsPush; //See SettingsPush
        AutoComplete;
        WinBorder;
        WinMax;
        DocCursor;
        DocClear;
        Fs->draw_it             = &DrawIt;
        Fs->win_inhibit = WIG_TASK_DEFAULT - WIF_SELF_FOCUS - WIF_SELF_BORDER;

        try
                do
                {
                        MemSet(text, 0, sizeof(text));
                        while (!(ch = CharScan))
                        {
                                x = mouse.pos_text.x - Fs->win_left - Fs->scroll_x / FONT_WIDTH;
                                y = mouse.pos_text.y - Fs->win_top  - Fs->scroll_y / FONT_HEIGHT;
                                if (mouse.lb && !winmgr.grab_scroll)
                                        text[y][x] = CH_SPACE + ATTRF_INVERT + ATTR;
                                if (mouse.rb && !winmgr.grab_scroll)
                                {
                                        text[y][x] = '*'+ATTR;
                                        SolveMaze(x, y);
                                        ch = CharGet;
                                        break;
                                }
                                Refresh;
                        }
                }
                while (ch != CH_SHIFT_ESC && ch != CH_ESC);

        catch
                PutExcept;
        SettingsPop;
}

Maze;