#include <owl\owlpch.h>
#include <owl\applicat.h>
#include <owl\framewin.h>
#include <owl\dc.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include "oracle.h"
#include "cell.h"
#include "hexmaze.h"
#include "sqrmaze.h"
#include "plot3d.h"
#include "maze3d.rh"

#ifndef TRUE
#define TRUE -1
#endif
#ifndef FALSE
#define FALSE 0
#endif

static int    hex_external_to_plot(double,double);
static double hex_f(double,double);
static int    hex_red(double,double);
static int    sqr_external_to_plot(double,double);
static double sqr_f(double,double);
static int    sqr_red(double,double);

// maze constants
#define PIXELS_PER_HEXAGONAL_ROOM 60               
#define PIXELS_PER_SQUARE_ROOM    40                           
#define RESOLUTION                 4  // larger values takes more time (and
                                      // virtual memory) but produce a better 
                                      // image.

hexmaze *hexmaze_ptr; // pointer to generator for maze with hexagonal rooms
sqrmaze *sqrmaze_ptr; // pointer to generator for maze with square rooms

class MazeWindow : public TFrameWindow
  {
    public:

      MazeWindow(TWindow* parent,const char far* title);

      void CleanupWindow();

      BOOL IdleAction(long IdleCount);
        // So that the program remains responsive, the plotting is done here.

      void Paint(TDC &dc,BOOL erase,TRect &dirty);
        // This method is invoked when part of the display has been made
        // "dirty" (for example, when another window has been moved from
        // atop the display).

    protected:

      void CeActionClear(TCommandEnabler &ce);
        // Determines whether the action "Clear" may be selected.

      void CeActionSolve(TCommandEnabler &ce);
        // Determines whether the action "Solve" may be selected.

      void CeStyleSquare(TCommandEnabler &ce);
        // Determines whether a check mark should appear to the left of the 
        // style "Square rooms".

      void CeStyleHexagon(TCommandEnabler &ce);
        // Determines whether a check mark should appear to the left of the
        // style "Hexagonal rooms".

      void CmActionNew();
        // Processes a request for a new maze.

      void CmActionSolve();
        // Processes a request that a maze be solved.

      void CmActionClear();
        // Processes a request that the solution be cleared from a maze.

      void CmHelpAbout();
        // Processes a request for information about the author.

      void CmHelpUsage();
        // Processes a request for information about using this program.

      void CmStyleSquare();
        // Processes a request for square rooms.

      void CmStyleHexagon();
        // Processes a request for hexagonal rooms.

      void EvHScroll(UINT code,UINT pos,HWND wnd);
        // Processes a change in the horizontal scroll bar -- a request for
        // a new angle of rotation.

      void EvSize(UINT sizeType,TSize &size);
        // Processes resizing of the window -- a request for a different size
        // maze.

      void EvVScroll(UINT code,UINT pos,HWND wnd);
        // Processes a change in the vertical scroll bar -- a request for a
        // new angle of tilt.

    private:
  
      void   DisplayMessage(const string& msg);
        // Pops up a message to the user.

      double light_x;
      double light_y;
      double light_z;
        // Vector to the major source of light.

      int    num_columns;
        // Number of columns in the current maze.

      int    num_rows;
        // Number of rows in the current maze.

      int    only_plot_solution;
        // If TRUE, only plot the outline to the solution of the maze.

      plot3d *plot3d_ptr;
        // Pointer to an instance of the 3D plotting class.

      TRect  region_to_paint;
        // The part of the maze to be plotted.

      int    rotation;
        // The number of degrees the maze is rotated about a line
        // perpendicular to its base.

      char   seed [9];
        // Random number seed (derived from the system clock) used to
        // generate the maze.

      int    solve;
        // TRUE if the maze is to be solved.

      int    solved;
        // TRUE if the solution is currently displayed.

      char   state;
        // State of the plotting; one of the following:
        //     'B' -- beginning
        //     'M' -- maze being generated
        //     'S' -- preparing plot
        //     'P' -- plotting
        //     'F' -- failure
        //     'D' -- done

      char   style;
        // 'H' for hexagonal rooms; 'S' for square rooms.

      int    tilt;
        // The number of degrees the maze is tilted towards the viewer.
  
      DECLARE_RESPONSE_TABLE(MazeWindow);
       // Associates user commands with methods in this program.
  };

DEFINE_RESPONSE_TABLE1(MazeWindow,TFrameWindow)
  EV_COMMAND(CM_ACTION_NEW,CmActionNew),
  EV_COMMAND(CM_ACTION_SOLVE,CmActionSolve),
  EV_COMMAND(CM_ACTION_CLEAR,CmActionClear),
  EV_COMMAND(CM_HELP_ABOUT,CmHelpAbout),
  EV_COMMAND(CM_HELP_USAGE,CmHelpUsage),
  EV_COMMAND(CM_STYLE_SQUARE,CmStyleSquare),
  EV_COMMAND(CM_STYLE_HEXAGON,CmStyleHexagon),
  EV_COMMAND_ENABLE(CM_ACTION_SOLVE,CeActionSolve),
  EV_COMMAND_ENABLE(CM_ACTION_CLEAR,CeActionClear),
  EV_COMMAND_ENABLE(CM_STYLE_SQUARE,CeStyleSquare),
  EV_COMMAND_ENABLE(CM_STYLE_HEXAGON,CeStyleHexagon),
  EV_WM_HSCROLL,
  EV_WM_VSCROLL,
  EV_WM_SIZE,
END_RESPONSE_TABLE;

MazeWindow::MazeWindow(
  TWindow        *parent,
  const char far *title) : TFrameWindow(parent, title)
    {
      Attr.Style |= WS_VSCROLL | WS_HSCROLL;
        // Scroll bars are used to specify tilt and rotation.
      AssignMenu("MAZE_MENU");
      state='B';             // beginning plot
      style='S';             // square rooms
      rotation=0;            // (degrees)
      tilt=30;               // (degrees)
      light_x=(double) 1.5;  // vector to light source
      light_y=(double) -1.0;
      light_z=(double) 2.6;
      solve=FALSE;           // initially, don't show the solution
      plot3d_ptr=new plot3d((TFrameWindow *) this); // 3D plotter
    }

void MazeWindow::CleanupWindow()
  {
    delete plot3d_ptr; // destroy 3D plotter
    TFrameWindow::CleanupWindow();
  }

void MazeWindow::DisplayMessage(const string &msg)
// Pops up a message to the user.
  {
    MessageBox(msg.c_str(),GetApplication()->GetName(),
     MB_OK | MB_ICONEXCLAMATION);
    return;
  }

BOOL MazeWindow::IdleAction(long IdleCount)
// So that the program remains responsive, the plotting is done here.
  {
    switch (state)
      // State of the plotting; one of the following:
      //     'B' -- beginning
      //     'R' -- restarting
      //     'M' -- maze being generated
      //     'S' -- preparing plot
      //     'P' -- plotting
      //     'F' -- failure
      //     'D' -- done
      {
        case 'B': // begin
          {
            solved=FALSE;
              // The solution is not (or soon won't be) completely displayed.
            GetClientRect(region_to_paint);
              // The whole maze is being plotted.
            SetScrollRange(SB_VERT,0,90);   
              // The maze may be tilted between 0 and 90 degrees.
            SetScrollRange(SB_HORZ,0,360);
              // The maze may be rotated between 0 and 360 degrees.
            SetScrollPos(SB_VERT,90-tilt);
              // Display the current tilt on the vertical scroll bar.
            SetScrollPos(SB_HORZ,rotation);
              // Display the current rotation on the horizontal scroll bar.
            only_plot_solution=FALSE;
              // Plot the base, walls, etc.

            // Pick a maze at random. 
            time_t quotient;
            time_t remainder;
            time_t start_time;
            time(&start_time);
            for (int i=0; i < 8; i++)
              {
                quotient=start_time/10;
                remainder=start_time-10*quotient;
                seed[i]=char('0'+remainder);
                start_time=quotient;
              }

            // Since the width of a room (in millimeters) is constant,
            // the number of rows and columns in a maze is determined by
            // the current size of the (client) window.
            TClientDC *dc=new TClientDC(*this);
            double aspect_ratio
             =(double(dc->GetDeviceCaps(VERTSIZE))
             /double(dc->GetDeviceCaps(HORZSIZE)))
             /(double(dc->GetDeviceCaps(VERTRES))
             /double(dc->GetDeviceCaps(HORZRES)));
            if (style == 'S') // square rooms
              {
                num_columns=(GetClientRect().Width())/PIXELS_PER_SQUARE_ROOM;
                num_rows=(int) ((2.0/sqrt(3.0))*aspect_ratio
                 *double(GetClientRect().Height())
                 /double(PIXELS_PER_SQUARE_ROOM));
              }
            else              // hexagonal rooms
              {
                num_columns=(2*GetClientRect().Width())
                 /(3*PIXELS_PER_HEXAGONAL_ROOM)-1;
                num_columns=2*num_columns+1;
                num_rows=(int) ((2.0/sqrt(3.0))*aspect_ratio
                 *double(GetClientRect().Height())
                 /double(PIXELS_PER_HEXAGONAL_ROOM));
              }
            delete dc;
          }

          if ((num_columns >= 4) && (num_rows >= 4))
            // The maze generator requires at least 4 rows and 4 columns.
            {
              state='M';
              TClientDC *dc=new TClientDC(*this);
              dc->PatBlt(this->GetClientRect(),WHITENESS);
                // Clear the (client) window.
              dc->TextOut(0,0,"Generating...");
                // Let the user know the maze is being generated.
              delete dc;
            }
          else
            // If the window is too small for a maze with 4 rows or 4 columns,
            // let the user know.
            {
              state='F';
              if (! IsIconic())
                {
                  TClientDC *dc=new TClientDC(*this);
                  dc->PatBlt(this->GetClientRect(),WHITENESS);
                  delete dc;
                  DisplayMessage("You need a larger window for a maze!");
                }
            }
          break; 

        case 'M': // Generate maze.
          {
            HCURSOR oldCursor=::SetCursor(::LoadCursor(0,IDC_WAIT));
            if (style == 'S')  // square rooms
              sqrmaze_ptr
               =new sqrmaze(num_rows,num_columns,RESOLUTION,&seed[0],this);
            else               // hexagonal rooms
              hexmaze_ptr
               =new hexmaze(num_rows,num_columns,RESOLUTION,&seed[0],this);
            ::SetCursor(oldCursor);
          }
          if (style == 'S') // square rooms
            if (sqrmaze_ptr->constructed())
              state='S';    // proceed to prepare plot
            else
              {
                state='F';  // failure (already announced in pop up)
                TClientDC *dc=new TClientDC(*this);
                dc->PatBlt(this->GetClientRect(),WHITENESS);
                delete dc;
              }
          else              // hexagonal rooms
            if (hexmaze_ptr->constructed())
              state='S';    // proceed to prepare plot
            else
              {
                state='F';  // failure (already announced in pop up)
                TClientDC *dc=new TClientDC(*this);
                dc->PatBlt(this->GetClientRect(),WHITENESS);
                delete dc;
              }
          break;

        case 'R': // Restart.
          solved=FALSE;
            // The solution is not (or soon won't be) completely displayed.
          GetClientRect(region_to_paint);
            // The whole maze is being plotted.
          SetScrollRange(SB_VERT,0,90);   
            // The maze may be tilted between 0 and 90 degrees.
          SetScrollRange(SB_HORZ,0,360);
            // The maze may be rotated between 0 and 360 degrees.
          SetScrollPos(SB_VERT,90-tilt);
            // Display the current tilt on the vertical scroll bar.
          SetScrollPos(SB_HORZ,rotation);
            // Display the current rotation on the horizontal scroll bar.
          only_plot_solution=FALSE;
            // Plot the base, walls, etc.
          if (style == 'S') // square rooms
            if (sqrmaze_ptr->constructed())
              state='S';    // proceed to prepare plot
            else
              {
                state='F';  // failure (already announced in pop up)
                TClientDC *dc=new TClientDC(*this);
                dc->PatBlt(this->GetClientRect(),WHITENESS);
                delete dc;
              }
          else              // hexagonal rooms
            if (hexmaze_ptr->constructed())
              state='S';    // proceed to prepare plot
            else
              {
                state='F';  // failure (already announced in pop up)
                TClientDC *dc=new TClientDC(*this);
                dc->PatBlt(this->GetClientRect(),WHITENESS);
                delete dc;
              }
          break;

        case 'S': // prepare plot
          if (style == 'S') // square rooms
            switch (plot3d_ptr->prepare_plot(
             sqr_f,sqrmaze_ptr->x_min(),sqrmaze_ptr->x_max(),
             sqrmaze_ptr->y_min(),sqrmaze_ptr->y_max(),sqr_external_to_plot,
             sqr_red,sqrmaze_ptr->num_x_divisions(),
             sqrmaze_ptr->num_y_divisions(),double(rotation),double(tilt),
             light_x,light_y,light_z))
              {
                case 'S': // success; plot prepared
                  state='P'; // proceed to plot maze
                  break;
                case 'F': // failure (already announced in pop up)
                  {
                    state='F';
                    TClientDC *dc=new TClientDC(*this);
                    dc->PatBlt(this->GetClientRect(),WHITENESS);
                    delete dc;
                  }
                  break;
                default:  // continue preparing plot
                  break;
              }
          else              // hexagonal rooms
            switch (plot3d_ptr->prepare_plot(
             hex_f,hexmaze_ptr->x_min(),hexmaze_ptr->x_max(),
             hexmaze_ptr->y_min(),hexmaze_ptr->y_max(),hex_external_to_plot,
             hex_red,hexmaze_ptr->num_x_divisions(),
             hexmaze_ptr->num_y_divisions(),double(rotation),double(tilt),
             light_x,light_y,light_z))
              {
                case 'S': // success; plot prepared
                  state='P'; // proceed to plot maze
                  break;
                case 'F': // failure (already announced in pop up)
                  {
                    state='F';
                    TClientDC *dc=new TClientDC(*this);
                    dc->PatBlt(this->GetClientRect(),WHITENESS);
                    delete dc;
                  }
                  break;
                default:  // continue preparing plot
                  break;
              }
          break;

        case 'P': // plotting
          switch (plot3d_ptr->plot(
           region_to_paint,
           solve,                     // highlight solution
           only_plot_solution))       // only plot solution      
            {
              case 'S': // success; plot complete       
                solved=solve;
                state='D'; // proceed to wait for user input
                break;
              case 'F': // failure (already announced in pop up)
                solved=FALSE;
                {
                  state='F';
                  TClientDC *dc=new TClientDC(*this);
                  delete dc;
                }
                break;
              default:  // continue
                break;
            }
          break;

        case 'F': // failed; wait for user input
          break;

        default:  // done; wait for user input
          break;
      }
    TFrameWindow::IdleAction(IdleCount);
    return TRUE;
  }

void MazeWindow::Paint(TDC &dc,BOOL erase,TRect &dirty)
// This method is invoked when part of the display has been made "dirty"
// (for example, when another window has been moved from atop the display).
  {
     only_plot_solution=FALSE;
      // the walls, etc. around the solution are probably dirty too
     switch (state)
       {
         case 'B': // beginning
             // Nothing is displayed yet; nothing need be restored.
           break;
         case 'M': // generating maze
           dc.PatBlt(this->GetClientRect(),WHITENESS);
           dc.TextOut(0,0,"Generating...");
             // Redisplay the message.
           break;
         case 'S': // preparing plot
           dc.PatBlt(this->GetClientRect(),WHITENESS);
           dc.TextOut(0,0,"Preparing plot...");
             // The internal state of the 3D plotter is not available here,
             // so display this message.
           break;
         case 'P': // still plotting
           GetClientRect(region_to_paint);
           state='P';
           plot3d_ptr->restart_plot();
             // Proceed to restore the entire display.  Because the painter's
             // algorithm is used, areas outside the "dirty" region may still
             // need plotting.
           break;
         case 'F': // failed
             // Nothing is being displayed; nothing need be restored.
           break;
         default:  // done
           state='P';
           region_to_paint=dirty;
           plot3d_ptr->restart_plot();
             // Redo the "dirty" region.
           break;
       }
  }

void MazeWindow::EvHScroll(UINT code,UINT pos,HWND wnd)
// Processes a change in the horizontal scroll bar -- a request for a new angle
// of rotation.
  {
    TFrameWindow::EvHScroll(code,pos,wnd);
    int change=FALSE;
    switch (code) 
      {
        case SB_LINELEFT:
          rotation--;
          if (rotation < 0)
            rotation=0;
          change=TRUE;
          break;
        case SB_LINERIGHT:
          rotation++;
          if (rotation > 360)
            rotation=360;
          change=TRUE;
          break;
        case SB_PAGELEFT:
          rotation-=10;
          if (rotation < 0)
            rotation=0;
          change=TRUE;
          break;
        case SB_PAGERIGHT:
          rotation+=10;
          if (rotation > 360)
            rotation=360;
          change=TRUE;
          break;
        case SB_THUMBPOSITION:
          rotation=pos;
          change=TRUE;
          break;
        case SB_THUMBTRACK:
          break;
        default:
          break;
      }
    if (change)
      {
        delete plot3d_ptr;
        state='R'; // proceed to completely redo plot
        plot3d_ptr=new plot3d((TFrameWindow *) this);
      }
    return;
  }

void MazeWindow::EvSize(UINT sizeType,TSize &size)
// Processes resizing of the window -- a request for a different size maze.
  {
    // get rid of old maze
    if (style == 'S') // square rooms
      {
        delete sqrmaze_ptr;
        sqrmaze_ptr=NULL;
      }
    else              // hexagonal rooms
      {
        delete hexmaze_ptr;
        hexmaze_ptr=NULL;
      }
    delete plot3d_ptr; // get rid of old 3D plotter
    solve=FALSE;       // initially, don't display the solution 
    state='B';         // proceed to do new maze
    plot3d_ptr=new plot3d((TFrameWindow *) this);
    return;
  }

void MazeWindow::EvVScroll(UINT code,UINT pos,HWND wnd)
// Processes a change in the vertical scroll bar -- a request for a new angle of
// tilt.
  {
    TFrameWindow::EvVScroll(code,pos,wnd);
    int change=FALSE;
    switch (code) 
      {
        case SB_LINEUP:
          tilt++;
          if (tilt > 90)
            tilt=90;
          change=TRUE;
          break;
        case SB_LINEDOWN:
          tilt--;
          if (tilt < 0)
            tilt=0;
          change=TRUE;
          break;
        case SB_PAGEUP:
          tilt+=5;
          if (tilt > 90)
            tilt=90;
          change=TRUE;
          break;
        case SB_PAGEDOWN:
          tilt-=5;
          if (tilt < 0)
            tilt=0;
          change=TRUE;
          break;
        case SB_THUMBPOSITION:
          tilt=90-pos;
          change=TRUE;
          break;
        case SB_THUMBTRACK:
          break;
        default:
          break;
      }
    if (change)
      {
        delete plot3d_ptr;
        state='R'; // proceed to completely redo plot
        plot3d_ptr=new plot3d((TFrameWindow *) this);
      }
    return;
  }

void MazeWindow::CmActionNew()
// Processes a request for a new maze.
  {
    // get rid of old maze
    if (style == 'S') // square rooms
      {
        delete sqrmaze_ptr;
        sqrmaze_ptr=NULL;
      }
    else              // hexagonal rooms
      {
        delete hexmaze_ptr;
        hexmaze_ptr=NULL;
      }
    delete plot3d_ptr; // get rid of old 3D plotter
    solve=FALSE;       // initially, don't display the solution 
    state='B';         // proceed to do new maze
    plot3d_ptr=new plot3d((TFrameWindow *) this);
    return;
  }

void MazeWindow::CeActionSolve(TCommandEnabler& ce)
// Determines whether the action "Solve" may be selected.
  {
    ce.Enable((state == 'D') && (! solved));
    // "Solve" may be selected if the plotting is done and the maze has
    // not yet been solved.
  }

void MazeWindow::CmActionSolve()
// Processes a request that a maze be solved.
  {
    if (state == 'D') // plotting done
      {
        if (! solved) // not solved yet
          {
            only_plot_solution=TRUE;        // only the solution need be plotted
            solve=TRUE;
            plot3d_ptr->restart_plot();     // set the 3D plotter to restart
            GetClientRect(region_to_paint); // whole solution will be plotted
            state='P';                      // proceed to plot the solution
          }
      }
    return;
  }

void MazeWindow::CeActionClear(TCommandEnabler& ce)
// Determines whether the action "Clear" may be selected.
  {
    ce.Enable((state == 'D') && (solved));
    // "Clear" may be selected if the plotting is done and the solution is
    // currently displayed.
  }

void MazeWindow::CmActionClear()
// Processes a request that the solution be cleared from a maze.
  {
    if (state == 'D') // plotting done
      {
        if (solved)   // solution displayed
          {
            only_plot_solution=TRUE;        // only the solution need be cleared
            solve=FALSE;
            plot3d_ptr->restart_plot();     // set the 3D plotter to restart
            GetClientRect(region_to_paint); // whole solution will be cleared
            state='P';                      // proceed to clear the solution
          }
      }
    return;
  }

void MazeWindow::CmHelpAbout()
// Processes a request for information about the author.
  {
    MessageBox("\tMAZE3D\n\n"
     "Written on May 2, 1994 by\n"
     "\tJames L. Dean\n"
     "\t406 40th Street\n"
     "\tNew Orleans, LA 70124-1532\n"
     "\tcsvcjld@nomvs.lsumc.edu\n",
     GetApplication()->GetName(),MB_ICONINFORMATION);
    return;
  }

void MazeWindow::CmHelpUsage()
// Processes a request for information about using this program.
  {
    MessageBox("\t\tMAZE3D\n\n"
     "     The following options are available under \"Action\":\n"
     "\tNew -- generate another maze\n"
     "\tSolve -- outline the solution\n"
     "\tClear -- remove the solution\n\n"
     "     Under \"Style\" you may select square or\n"
     "hexagonal rooms.\n\n"
     "     Use the horizontal scroll bar to vary the\n"
     "rotation form 0 to 360 degrees.\n\n"
     "     Use the vertical scroll bar to vary the tilt from\n"
     "0 to 90 degrees.\n\n"
     "     Resizing the window yields a new maze.  The size\n"
     "of the rooms remains the same.",
     GetApplication()->GetName(),MB_ICONINFORMATION);
    return;
  }

void MazeWindow::CeStyleSquare(TCommandEnabler& ce)
// Determines whether a check mark should appear to the left of the style
// "Square rooms".
  {
    ce.SetCheck(style == 'S');
  }

void MazeWindow::CmStyleSquare()
// Processes a request for square rooms.
  {
    if (style != 'S') // style is currently hexagonal rooms
      {
        delete hexmaze_ptr; // get rid of maze generator for hexagonal rooms
        hexmaze_ptr=NULL;   
        delete plot3d_ptr;  // get rid of the current 3D plotter
        style='S';          // style is now square rooms
        solve=FALSE;        // initially, don't display the solution
        state='B';          // proceed to do new maze
        plot3d_ptr=new plot3d((TFrameWindow *) this);
      }
    return;
  }

void MazeWindow::CeStyleHexagon(TCommandEnabler& ce)
// Determines whether a check mark should appear to the left of the style
// "Hexagonal rooms".
  {
    ce.SetCheck(style == 'H');
  }

void MazeWindow::CmStyleHexagon()
  {
// Processes a request for hexagonal rooms.
    if (style != 'H') // style is currently square rooms
      {
        delete sqrmaze_ptr; // get rid of maze generator for square rooms
        sqrmaze_ptr=NULL;
        delete plot3d_ptr;  // get rid of current 3D plotter
        style='H';          // style is now square rooms
        solve=FALSE;        // initially, don't display the solution
        state='B';          // proceed to do new maze
        plot3d_ptr=new plot3d((TFrameWindow *) this);
      }
    return;
  }

static int hex_external_to_plot(
  double x,
  double y)
// Returns TRUE if and only if a point is external to the maze with hexagonal
// rooms.
    {
       return hexmaze_ptr->external_to_maze(x,y);
    }

static int hex_red(
  double x,
  double y)
// Returns TRUE if and only if a point lies on top of a wall adjacent to the
// solution of the maze with hexagonal rooms.
    {
       return hexmaze_ptr->part_of_solution(x,y);
    }

static double hex_f(
  double x,
  double y)
// Returns a positive value for a point on top of a wall of the maze with
// hexagonal rooms, 0 otherwise.
    {
       return hexmaze_ptr->f(x,y);
    }

static int sqr_external_to_plot(
  double x,
  double y)
// Returns TRUE if and only if a point is external to the maze with square
// rooms.
    {
       return sqrmaze_ptr->external_to_maze(x,y);
    }         

static int sqr_red(
  double x,
  double y)
// Returns TRUE if and only if a point lies on top of a wall adjacent to the
// solution of the maze with square rooms.
    {
       return sqrmaze_ptr->part_of_solution(x,y);
    }

static double sqr_f(
  double x,
  double y)
// Returns a positive value for a point on top of a wall of the maze with
// square rooms, 0 otherwise.
    {
       return sqrmaze_ptr->f(x,y);
    }

class MazeApp : public TApplication
  {
    public:
           MazeApp() : TApplication("3D Mazes") {}
      void InitMainWindow();
  };

void MazeApp::InitMainWindow()
  {
    MainWindow=new MazeWindow(0,"3D Mazes");
    MainWindow->SetIcon(this,"MAZE_ICON");
  }

int OwlMain(int /*argc*/, char* /*argv*/ [])
// Execution of this program starts here.
  {
    hexmaze_ptr=NULL;       // Initialize pointers to the maze generators, one
    sqrmaze_ptr=NULL;       // for hexagonal rooms and one for square rooms.
    int rc=MazeApp().Run(); // Process Windows messages until user is done.
    delete sqrmaze_ptr;     // Get rid of any maze generators.
    delete hexmaze_ptr;
    return rc;
  }

