#include <owl\owlpch.h>
#include <owl\applicat.h>
#include <owl\framewin.h>
#include <owl\dc.h>
#include <stdlib.h>
#include "oracle.h"
#include "cell.h"
#include "hexmaze.h"
 
#ifndef TRUE
#define TRUE -1
#endif
#ifndef FALSE
#define FALSE 0
#endif
 
typedef cell *cell_ptr;
typedef char *char_ptr;

hexmaze::hexmaze(int row_count,int column_count,int thickness_of_wall,
  char *seed,TFrameWindow *win_ptr)
//      Contruct a maze having "row_count" rows and "column_count" columns of
// rooms.  The walls should be "thickness_of_wall" (bricks) thick.  A different
// (8 character of less) "seed" generally yields a different maze.
  {
    struct
      {
         int row_num;
         int column_num;
      }  delta [2] [6];
    int  mud_filled_room_found;
    struct
      {
         int row_num;
         int column_num;
      }  next;
    char wall [720] [6];
    char wall_to_check;
    char wall_num;
    char way_out;
    int  x1;
    int  x2;
    int  y1;
    int  y2;

unlink("HEXMAZE.LOG");
    window_ptr=win_ptr; 
    wall_thickness=thickness_of_wall;
    num_rows=row_count;
    num_y_dots=wall_thickness*(4*num_rows+1);
    y_dot_max=num_y_dots-1;
    num_columns=column_count;
    max_x=8*(num_columns/2)+6;
    num_x_dots=wall_thickness*(max_x+1);
    x_dot_max=num_x_dots-1;
    // Allocate a two dimensional array of rooms.
    if (memory_allocated=((room=new cell_ptr[num_rows]) != NULL))
      {
              int row_num=0;
        while (memory_allocated && (row_num < num_rows))
          if (memory_allocated=((room[row_num]=new cell [num_columns]) != NULL))
            row_num++;
        if (! memory_allocated)
          {
            while (row_num)
              delete [] room[--row_num];
            delete [] room;
            window_ptr->MessageBox("Cannot allocate maze!",
             window_ptr->GetApplication()->GetName(),
             MB_OK | MB_ICONEXCLAMATION);
          }
      }
    if (memory_allocated)
      {
         // Allocate a two dimensional array for plotting the maze in
         // terms of "bricks" where a wall is "wall_thickness" bricks
         // thick.
         if (memory_allocated=((page=new char_ptr [num_y_dots]) != NULL))
           {
             int y_dot_num=0;
             while (memory_allocated && (y_dot_num < num_y_dots))
               if (memory_allocated=((page[y_dot_num]=new char [num_x_dots])
                != NULL))
                 y_dot_num++;
             if (! memory_allocated)
               {
                  while (y_dot_num)
                    delete [] page[--y_dot_num];
                  delete [] page;
                  for (int row_num=num_rows-1; row_num >= 0; row_num--)
                    delete [] room[row_num];
                  delete [] room;
                  window_ptr->MessageBox("Cannot allocate maze!",
                   window_ptr->GetApplication()->GetName(),
                   MB_OK | MB_ICONEXCLAMATION);
               }
           }
         else
           {
              for (int row_num=num_rows-1; row_num >= 0; row_num--)
                delete [] room[row_num];
              delete [] room;
              window_ptr->MessageBox("Cannot allocate maze!",
               window_ptr->GetApplication()->GetName(),
               MB_OK | MB_ICONEXCLAMATION);
           }
      }
    if (memory_allocated)
      {
         // Set up the directions by which a room can be exited.
         // Directions for even columns.
         delta[0][0].row_num=-1;    // north
         delta[0][0].column_num=0;
         delta[0][1].row_num=-1;    // northwest
         delta[0][1].column_num=-1;
         delta[0][2].row_num=0;     // southwest
         delta[0][2].column_num=-1;
         delta[0][3].row_num=1;     // south
         delta[0][3].column_num=0;
         delta[0][4].row_num=0;     // southeast
         delta[0][4].column_num=1;
         delta[0][5].row_num=-1;    // northeast
         delta[0][5].column_num=1;
         // Directions for odd columns.
         delta[1][0].row_num=-1;    // north
         delta[1][0].column_num=0;
         delta[1][1].row_num=0;     // northwest
         delta[1][1].column_num=-1;
         delta[1][2].row_num=1;     // southwest
         delta[1][2].column_num=-1;
         delta[1][3].row_num=1;     // south
         delta[1][3].column_num=0;
         delta[1][4].row_num=1;     // southeast
         delta[1][4].column_num=1;
         delta[1][5].row_num=0;     // northeast
         delta[1][5].column_num=1;
         // Set up the 6! orders in which the wall of a room can be accessed.
         int order_num=0;
         for (int wall_num_1=0; wall_num_1 < 6; wall_num_1++)
           for (int wall_num_2=0; wall_num_2 < 6; wall_num_2++)
             if (wall_num_2 != wall_num_1)
               for (int wall_num_3=0; wall_num_3 < 6; wall_num_3++)
                 if ((wall_num_3 != wall_num_2)
                 &&  (wall_num_3 != wall_num_1))
                   for (int wall_num_4=0; wall_num_4 < 6; wall_num_4++)
                     if ((wall_num_4 != wall_num_3)
                     &&  (wall_num_4 != wall_num_2)
                     &&  (wall_num_4 != wall_num_1))
                       for (int wall_num_5=0; wall_num_5 < 6; wall_num_5++)
                         if ((wall_num_5 != wall_num_4)
                         &&  (wall_num_5 != wall_num_3)
                         &&  (wall_num_5 != wall_num_2)
                         &&  (wall_num_5 != wall_num_1))
                           for (int wall_num_6=0; wall_num_6 < 6; wall_num_6++)
                             if ((wall_num_6 != wall_num_5)
                             &&  (wall_num_6 != wall_num_4)
                             &&  (wall_num_6 != wall_num_3)
                             &&  (wall_num_6 != wall_num_2)
                             &&  (wall_num_6 != wall_num_1))
                               {
                                 wall[order_num][wall_num_6]='\0';
                                 wall[order_num][wall_num_5]='\1';
                                 wall[order_num][wall_num_4]='\2';
                                 wall[order_num][wall_num_3]='\3';
                                 wall[order_num][wall_num_2]='\4';
                                 wall[order_num][wall_num_1]='\5';
                                 order_num++;
                               }
         order_selector=new oracle(&seed[0],order_num);
         row_selector=new oracle(&seed[0],num_rows);
         column_selector=new oracle(&seed[0],num_columns);
         int finished=FALSE;
         // Generate mazes until you have one that is hard to solve.
         do
           {
              // Pick a starting room.
              first.column_num=column_selector->random_number();
              if ((first.column_num)%2)
                do
                  {
                    first.row_num=row_selector->random_number();
                  }
                while (first.row_num == (num_rows-1));
              else
                first.row_num=row_selector->random_number();
              current.row_num=first.row_num;
              current.column_num=first.column_num;
              // Excavate the starting room.
              room[current.row_num][current.column_num].mark_floor(' ');
              // Pick the order in which the walls of the starting room will be
              // considered.
              room[current.row_num][current.column_num].set_order(
               order_selector->random_number());
              // Excavate rooms until there are no more to excavate.
              do
                {
                   mud_filled_room_found=FALSE;
                   // Find an adjacent room (not yet considered) that needs
                   // excavating.
                   do
                     {
                        wall_num=room[current.row_num][
                         current.column_num].next_wall_num();
                        if (wall_num < '\6')
                          {
                             wall_to_check=wall[room[current.row_num][
                              current.column_num].order_to_check()][wall_num];
                             if (room[current.row_num][
                              current.column_num].wall_up(wall_to_check))
                               {
                                  next.column_num=current.column_num
                                   +delta[(current.column_num)%2]
                                   [wall_to_check].column_num;
                                  if ((next.column_num >= 0)
                                  &&  (next.column_num < num_columns))
                                    {
                                      next.row_num=current.row_num
                                       +delta[(current.column_num)%2]
                                       [wall_to_check].row_num;
                                      if ((next.row_num >= 0)
                                      &&  ((((next.column_num)%2 == 1)
                                         && (next.row_num < (num_rows-1)))
                                       ||  (((next.column_num)%2 == 0)
                                         && (next.row_num < num_rows))))
                                        {
                                           if (room[next.row_num][
                                            next.column_num].mark()
                                            == 'M')
                                             mud_filled_room_found=TRUE;
                                        }
                                    }
                               }
                          }
                     }
                   while ((wall_num < '\6')
                   &&     (! mud_filled_room_found));
                   if (mud_filled_room_found)
                   // an adjacent room needs excavating
                     {
                        // Exit the current room, knocking down a wall.
                        room[current.row_num][
                         current.column_num].knock_down_wall(wall_to_check);
                        way_out=char(((int) wall_to_check+3)%6);
                        // Enter the adjacent room, knocking down a wall.
                        room[next.row_num][next.column_num].knock_down_wall(
                         way_out);
                        // Record how to return to the previous room.
                        room[next.row_num][next.column_num].set_way_out(
                         way_out);
                        current.row_num=next.row_num;
                        current.column_num=next.column_num;
                        // Excavate the room.
                        room[current.row_num][current.column_num].mark_floor(
                         ' ');
                        // Select the order in which the walls of the room will
                        // be considered.
                        room[current.row_num][current.column_num].set_order(
                         order_selector->random_number());
                     }
                   else
                   // no adjacent room needs excavating
                     {
                        if ((first.row_num != current.row_num)
                        ||  (first.column_num != current.column_num))
                          {
                             // Go back to the room from which you entered
                             // the current room.
                             next.row_num=current.row_num+delta[
                              (current.column_num)%2]
                              [room[current.row_num]
                              [current.column_num].way_back()].row_num;
                             next.column_num=current.column_num+delta[
                              (current.column_num)%2]
                              [room[current.row_num]
                              [current.column_num].way_back()].column_num;
                             current.row_num=next.row_num;
                             current.column_num=next.column_num;
                          }
                     }
                }
              while ((first.row_num != current.row_num)
              ||     (first.column_num != current.column_num)
              ||     (wall_num < '\6'));
              if (maze_okay()) // Maze is hard to solve.
                finished=TRUE;
              else             // Prepare to try another maze.
                for (int row_num=0; row_num < num_rows; row_num++)
                  for (int column_num=0; column_num < num_columns; column_num++)
                    room[row_num][column_num].reinitialize();
           }
         while (! finished);
         // Knock down walls blocking the entrance and exit to the maze.
         room[0][0].knock_down_wall(0);
         room[num_rows-1][num_columns-1].knock_down_wall(3);

         delete column_selector;
         delete row_selector;
         delete order_selector;

         // Generate a 2D plot of the maze.  Each element of "page" corresponds
         // to a possible position of a brick composing the maze.  An element
         // has value 'W' if a brick is present and value ' ' otherwise.  Each
         // wall is "wall_thickness" bricks thick.
         for (y1=0; y1 < num_y_dots; y1++)
           for (x1=0; x1 < num_x_dots; x1++)
             page[y1][x1]=' ';
         for (int row_num=0; row_num < num_rows; row_num++)
           {
             int half_column_num=0;
             for (int column_num=0; column_num < num_columns; column_num+=2)
               {
                 if (room[row_num][column_num].wall_up('\0'))
                   {
                      x1=8*half_column_num+2;
                      y1=4*row_num;
                      x2=x1+2;
                      y2=y1;
                      draw_line_on_page(wall_thickness*x1,wall_thickness*y1,
                       wall_thickness*x2,wall_thickness*y2);
                      //    ***
                      //   O   O
                      //  O     OOO
                      //   O   O
                      //    OOO
                   }
                 half_column_num++;
               }
             half_column_num=0;
             for (column_num=0; column_num < num_columns; column_num+=2)
               {
                 if (room[row_num][column_num].wall_up('\1'))
                   {
                      x1=8*half_column_num;
                      y1=4*row_num+2;
                      x2=x1+2;
                      y2=y1-2;
                      draw_line_on_page(wall_thickness*x1,wall_thickness*y1,
                       wall_thickness*x2,wall_thickness*y2);
                      //    *OO
                      //   *   O
                      //  *     OOO
                      //   O   O
                      //    OOO
                   }
                 if (room[row_num][column_num].wall_up('\5'))
                   {
                      x1=8*half_column_num+4;
                      y1=4*row_num;
                      x2=x1+2;
                      y2=y1+2;
                      draw_line_on_page(wall_thickness*x1,wall_thickness*y1,
                       wall_thickness*x2,wall_thickness*y2);
                      //    OO*
                      //   O   *
                      //  O     *OO
                      //   O   O
                      //    OOO
                   }
                 half_column_num++;
               }
             half_column_num=0;
             for (column_num=0; column_num < (num_columns-1); column_num+=2)
               {
                  if (row_num != (num_rows-1))
                    {
                      if (room[row_num][column_num+1].wall_up('\0'))
                        {
                           x1=8*half_column_num+6;
                           y1=4*row_num+2;
                           x2=x1+2;
                           y2=y1;
                           draw_line_on_page(wall_thickness*x1,
                            wall_thickness*y1,wall_thickness*x2,
                            wall_thickness*y2);
                           //    OOO
                           //   O   O
                           //  O     ***
                           //   O   O
                           //    OOO
                        }
                    }
                 half_column_num++;
               }
             half_column_num=0;
             for (column_num=0; column_num < num_columns; column_num+=2)
               {
                 if (room[row_num][column_num].wall_up('\2'))
                   {
                      x1=8*half_column_num;
                      y1=4*row_num+2;
                      x2=x1+2;
                      y2=y1+2;
                      draw_line_on_page(wall_thickness*x1,wall_thickness*y1,
                       wall_thickness*x2,wall_thickness*y2);
                      //    OOO
                      //   O   O
                      //  *     OOO
                      //   *   O
                      //    *OO
                   }
                 if (room[row_num][column_num].wall_up('\4'))
                   {
                      x1=8*half_column_num+4;
                      y1=4*row_num+4;
                      x2=x1+2;
                      y2=y1-2;
                      draw_line_on_page(wall_thickness*x1,wall_thickness*y1,
                       wall_thickness*x2,wall_thickness*y2);
                      //    OOO
                      //   O   O
                      //  O     *OO
                      //   O   *
                      //    OO*
                   }
                 half_column_num++;
               }
           }
         int half_column_num=0;
         for (int column_num=0; column_num < num_columns; column_num+=2)
           {
              if (room[num_rows-1][column_num].wall_up('\3'))
                {
                   x1=8*half_column_num+2;
                   y1=4*(num_rows-1)+4;
                   x2=x1+2;
                   y2=y1;
                   draw_line_on_page(wall_thickness*x1,wall_thickness*y1,
                    wall_thickness*x2,wall_thickness*y2);
                   //    OOO
                   //   O   O
                   //  O     OOO
                   //   O   O
                   //    ***
                }
              if (column_num+1 < num_columns)
                {
                   if (room[num_rows-2][column_num+1].wall_up('\3'))
                     {
                        x1=8*half_column_num+6;
                        y1=4*(num_rows-1)+2;
                        x2=x1+2;
                        y2=y1;
                        draw_line_on_page(wall_thickness*x1,wall_thickness*y1,
                         wall_thickness*x2,wall_thickness*y2);
                        //    OOO
                        //   O   O
                        //  O     ***
                        //   O   O
                        //    OOO
                     }
                }
             half_column_num++;
           }
      }
  }
 
hexmaze::~hexmaze()
  {
    if (memory_allocated)
      {
        // Free dynamically allocated memory.
        for (int y_dot_num=num_y_dots-1; y_dot_num >= 0; y_dot_num--)
          delete [] page[y_dot_num];
        delete [] page;
        for (int row_num=num_rows-1; row_num >= 0; row_num--)
          delete [] room[row_num];
        delete [] room;
      }
  }
 
void hexmaze::draw_line_on_page(
  int  x1,
  int  y1,
  int  x2,
  int  y2)
//      Draw wall (of bricks) on "page".
    {
      int error;
      int error_prime_x;
      int error_prime_y;
      int permissible_delta_x;
      int permissible_delta_y;
      int x;
      int x_diff;
      int y;
      int y_diff;
 
      error=0;
      if (x2 >= x1)
        permissible_delta_x=1;
      else
        permissible_delta_x=-1;
      if (y2 >= y1)
        permissible_delta_y=1;
      else
        permissible_delta_y=-1;
      x=x1;
      y=y1;
      x_diff=x2-x1;
      y_diff=y2-y1;
      set_point_on_page(x,y);
      while ((x != x2) || (y != y2))
        {
          error_prime_x=error+permissible_delta_x*y_diff;
          error_prime_y=error-permissible_delta_y*x_diff;
          if (abs(error_prime_x) <= abs(error_prime_y))
            {
              x+=permissible_delta_x;
              error=error_prime_x;
            }
          else
            {
              y+=permissible_delta_y;
              error=error_prime_y;
            }
          set_point_on_page(x,y);
        }
      return;
    }
 
int hexmaze::maze_okay()
  {
    int  adjacency;
    struct
      {
         int row_num;
         int column_num;
      }  delta [2] [6];
    struct
      {
         int row_num;
         int column_num;
      }  next;
    int  num_rooms_in_maze;
    int  num_rooms_in_solution;
    int  passage_found;
    struct
      {
         int row_num;
         int column_num;
      }  previous;
    int  result;
    struct
      {
         int row_num;
         int column_num;
      }  saved;
    char wall_to_check;
    char way_out;
 
    // Set up the directions by which a room can be exited.
    // Even columns.
    delta[0][0].row_num=-1;    // north
    delta[0][0].column_num=0;
    delta[0][1].row_num=-1;    // northwest
    delta[0][1].column_num=-1;
    delta[0][2].row_num=0;     // southwest
    delta[0][2].column_num=-1;
    delta[0][3].row_num=1;     // south
    delta[0][3].column_num=0;
    delta[0][4].row_num=0;     // southeast
    delta[0][4].column_num=1;
    delta[0][5].row_num=-1;    // northeast
    delta[0][5].column_num=1;
    // Odd columns.
    delta[1][0].row_num=-1;    // north
    delta[1][0].column_num=0;
    delta[1][1].row_num=0;     // northwest
    delta[1][1].column_num=-1;
    delta[1][2].row_num=1;     // southwest
    delta[1][2].column_num=-1;
    delta[1][3].row_num=1;     // south
    delta[1][3].column_num=0;
    delta[1][4].row_num=1;     // southeast
    delta[1][4].column_num=1;
    delta[1][5].row_num=0;     // northeast
    delta[1][5].column_num=1;
    // Solve the maze.

    // Start at the entrance.
    current.row_num=0;
    current.column_num=0;
    // Mark the room as part of the solution.
    room[current.row_num][current.column_num].mark_floor('S');
    num_rooms_in_solution=1;
    // Prepare to consider all the walls of the room.
    room[current.row_num][current.column_num].zero_wall_to_check();
    // Try rooms until you get to the exit.
    do
      {
        // Find a passage (not yet considered) out of the current room leading
        // to a room not part of the proposed solution.
        passage_found=FALSE;
        do
          {
            wall_to_check
             =room[current.row_num][current.column_num].next_wall_num();
            if (wall_to_check < '\6')
              {
                 if (! (room[current.row_num][
                  current.column_num].wall_up(wall_to_check)))
                   {
                      next.column_num=current.column_num
                       +delta[(current.column_num)%2]
                       [wall_to_check].column_num;
                      if ((next.column_num >= 0)
                      &&  (next.column_num < num_columns))
                        {
                          next.row_num=current.row_num
                           +delta[(current.column_num)%2]
                           [wall_to_check].row_num;
                          if ((next.row_num >= 0)
                          &&  ((((next.column_num)%2 == 1)
                             && (next.row_num < (num_rows-1)))
                           ||  (((next.column_num)%2 == 0)
                             && (next.row_num < num_rows))))
                            {
                               if (room[next.row_num][
                                next.column_num].mark()
                                == ' ')
                                 passage_found=TRUE;
                            }
                        }
                   }
              }
          }
        while ((! passage_found) && (wall_to_check < '\6'));
        if (passage_found)
        // passage to room not currently part of proposed solution found
          {
            // Enter the room.
            current.row_num=next.row_num;
            current.column_num=next.column_num;
            // Record the way back to the previous room.
            way_out=char(((int) wall_to_check+3)%6);
            room[current.row_num][current.column_num].set_way_out(way_out);
            // Mark the room as part of the proposed solution.
            room[current.row_num][current.column_num].mark_floor('S');
            num_rooms_in_solution++;
            // Prepare to consider all the walls of the room.
            room[current.row_num][current.column_num].zero_wall_to_check();
          }
        else
        // dead end
          {
            // Mark current room as not part of proposed solution.
            room[current.row_num][current.column_num].mark_floor(' ');
            num_rooms_in_solution--;
            // Go back to the room from which this room was entered.
            next.row_num=current.row_num+delta[(current.column_num)%2][
             room[current.row_num][current.column_num].way_back()].row_num;
            next.column_num=current.column_num+delta[(current.column_num)%2][
             room[current.row_num][current.column_num].way_back()].column_num;
            current.row_num=next.row_num;
            current.column_num=next.column_num;
          }
      }
    while((current.row_num != num_rows-1)
    ||    (current.column_num != num_columns-1));

    // Now that the maze is solved, calculate the number of rooms in the
    // solution (or outside the maze) that are adjacent to the rooms in
    // the solution.
    adjacency=0;
    previous.row_num=-1;
    previous.column_num=0;
    current.row_num=0;
    current.column_num=0;
    do
      {
        for (wall_to_check='\0'; wall_to_check < '\6'; wall_to_check++)
          if (room[current.row_num][current.column_num].wall_up(wall_to_check))
            {
               next.column_num=current.column_num
                +delta[(current.column_num)%2]
                [wall_to_check].column_num;
               if ((next.column_num >= 0)
               &&  (next.column_num < num_columns))
                 {
                   next.row_num=current.row_num
                    +delta[(current.column_num)%2]
                    [wall_to_check].row_num;
                   if ((next.row_num >= 0)
                   &&  ((((next.column_num)%2 == 1)
                      && (next.row_num < (num_rows-1)))
                    ||  (((next.column_num)%2 == 0)
                      && (next.row_num < num_rows))))
                     {
                        if (room[next.row_num][next.column_num].mark() == 'S')
                          adjacency++;
                     }
                   else
                     adjacency++;
                 }
               else
                 adjacency++;
            }
          else
            {
               next.column_num=current.column_num
                +delta[(current.column_num)%2]
                [wall_to_check].column_num;
               if ((next.column_num >= 0)
               &&  (next.column_num < num_columns))
                 {
                   next.row_num=current.row_num
                    +delta[(current.column_num)%2]
                    [wall_to_check].row_num;
                   if ((next.row_num >= 0)
                   &&  ((((next.column_num)%2 == 1)
                      && (next.row_num < (num_rows-1)))
                    ||  (((next.column_num)%2 == 0)
                      && (next.row_num < num_rows))))
                     {
                        if ((room[next.row_num][next.column_num].mark() == 'S')
                        &&  ((previous.row_num != next.row_num)
                          || (previous.column_num != next.column_num)))
                          {
                            saved.row_num=next.row_num;
                            saved.column_num=next.column_num;
                          }
                     }
                 }
            }
        previous.row_num=current.row_num;
        previous.column_num=current.column_num;
        current.row_num=saved.row_num;
        current.column_num=saved.column_num;
      }
    while((current.row_num != num_rows-1)
    ||    (current.column_num != num_columns-1));
    for (wall_to_check='\0'; wall_to_check < '\6'; wall_to_check++)
      if (room[current.row_num][current.column_num].wall_up(wall_to_check))
        {
           next.column_num=current.column_num
            +delta[(current.column_num)%2]
            [wall_to_check].column_num;
           if ((next.column_num >= 0)
           &&  (next.column_num < num_columns))
             {
                next.row_num=current.row_num
                 +delta[(current.column_num)%2]
                 [wall_to_check].row_num;
                if ((next.row_num >= 0)
                &&  ((((next.column_num)%2 == 1)
                   && (next.row_num < (num_rows-1)))
                 ||  (((next.column_num)%2 == 0)
                   && (next.row_num < num_rows))))
                  {
                     if (room[next.row_num][next.column_num].mark() == 'S')
                       adjacency++;
                  }
                else
                  adjacency++;
             }
           else
             adjacency++;
        }
    num_rooms_in_maze=num_rows*num_columns-(num_columns/2);

    // The maze is hard to solve (from the outside) if more than a third of its
    // rooms are part of its solution and rooms not part of its solution tend to
    // be next to rooms in its solution.
    if ((3*num_rooms_in_solution >= num_rooms_in_maze)
    &&  (5*adjacency <= 11*num_rooms_in_solution))
      result=TRUE;
    else
      result=FALSE;
    return result;
  }
 
int hexmaze::external_to_maze(double x,double y)
//      Return TRUE if and only if a point (x,y) is external to the maze.
  {
    int result;
    int x_out;
    int x_next;
    int y_out;
    int y_next;
 
    result=FALSE;
    y_out=(int) x;
    if (y_out < 0)
      result=TRUE;
    else
      if (y_out > y_dot_max)
        result=TRUE;
      else
        {
          x_out=(int) y;
          if (x_out < 0)
            result=TRUE;
          else
            if (x_out > x_dot_max)
              result=TRUE;
            else
              // A point is external to the maze if you don't have to cross
              // a wall, the entrance, or the exit to move from the point to
              // outside the maze.
              {
                if ((x_out/wall_thickness != 3)
                &&  (x_out/wall_thickness != max_x-3))
                  {
                    x_next=x_out;
                    result=TRUE;
                    while((result) && (x_next >= 0))
                      {
                        if (page[y_out][x_next] == ' ')
                          x_next--;
                        else
                          result=FALSE;
                      }
                    if (! result)
                      {
                        x_next=x_out;
                        result=TRUE;
                        while((result) && (x_next <= x_dot_max))
                          {
                            if (page[y_out][x_next] == ' ')
                              x_next++;
                            else
                              result=FALSE;
                          }
                      }
                    if (! result)
                      {
                        y_next=y_out;
                        result=TRUE;
                        while((result) && (y_next >= 0))
                          {
                            if (page[y_next][x_out] == ' ')
                              y_next--;
                            else
                              result=FALSE;
                          }
                      }
                    if (! result)
                      {
                        y_next=y_out;
                        result=TRUE;
                        while((result) && (y_next <= y_dot_max))
                          {
                            if (page[y_next][x_out] == ' ')
                              y_next++;
                            else
                              result=FALSE;
                          }
                      }
                  }
              }
        }
    return result;
  }
 
double hexmaze::f(double x,double y)
//      Return 5.0*wall_thickness if a point (x,y) is on a wall, 0.0 otherwise.
  {
    int    x_out;
    int    y_out;
    double z;
 
    y_out=(int) x;
    if (y_out < 0)
      z=0.0;
    else
      if (y_out > y_dot_max)
        z=0.0;
      else
        {
          x_out=(int) y;
          if (x_out < 0)
            z=0.0;
          else
            if (x_out > x_dot_max)
              z=0.0;
            else
              if (page[y_out][x_out] == 'W')
                z=1.0;
              else
                z=0.0;
        }
    return z*double(5*wall_thickness);
  }
 
int hexmaze::part_of_solution(double x,double y)
//      Return TRUE if and only if a point (x,y) is on a wall outlining the
// solution to the maze.
  {
    int base_x;
    int base_x_mod_8;
    int base_y;
    int base_y_mod_4;
    int half_column_num;
    int result;
    int row_num;
    int x_out;
    int y_out;
 
    y_out=(int) x;
    if (y_out < 0)
      result=FALSE;
    else
      if (y_out > y_dot_max)
        result=FALSE;
      else
        {
          x_out=(int) y;
          if (x_out < 0)
            result=FALSE;
          else
            if (x_out > x_dot_max)
              result=FALSE;
            else
              if (page[y_out][x_out] == 'W')
                {
                  result=FALSE;
                  base_x=x_out/wall_thickness;
                  half_column_num=base_x/8;
                  base_x_mod_8=base_x-8*half_column_num;
                  base_y=y_out/wall_thickness;
                  row_num=base_y/4;
                  base_y_mod_4=base_y-4*row_num;
                  switch (base_y_mod_4)
                  //      000
                  //     1   1
                  //    2     22 
                  //     3   3
                  //      000
                    {
                      case 0:
                        if (base_x_mod_8 < 3)
                        //      *00
                        //     1   1
                        //    2     22
                        //     3   3
                        //      000
                          {
                            if (row_num < num_rows)
                              {
                                if (room[row_num][2*half_column_num].mark()
                                 == 'S')
                                  result=TRUE;
                              }
                            if (! result)
                              {
                                if (row_num > 0)
                                  {
                                    if (room[row_num-1]
                                     [2*half_column_num].mark() == 'S')
                                      result=TRUE;
                                  }
                              }
                            if (! result)
                              {
                                if (row_num > 0)
                                  {
                                    if (half_column_num > 0)
                                      {
                                        if (room[row_num-1]
                                         [2*half_column_num-1].mark() == 'S')
                                          result=TRUE;
                                      }
                                  }
                              }
                          }
                        else
                          if (base_x_mod_8 > 3)
                          //      00*
                          //     1   1
                          //    2     22
                          //     3   3
                          //      000
                            {
                              if (row_num < num_rows)
                                {
                                  if (room[row_num][2*half_column_num].mark()
                                   == 'S')
                                    result=TRUE;
                                }
                              if (! result)
                                {
                                  if (row_num > 0)
                                    {
                                      if (room[row_num-1]
                                       [2*half_column_num].mark() == 'S')
                                        result=TRUE;
                                    }
                                }
                              if (! result)
                                {
                                  if (row_num > 0)
                                    {
                                      if (2*half_column_num+1 < num_columns)
                                        {
                                          if ((row_num-1) < (num_rows-1))
                                            {
                                              if (room[row_num-1]
                                               [2*half_column_num+1].mark()
                                               == 'S')
                                                result=TRUE;
                                            }
                                        }
                                    }
                                }
                            }
                          else
                          //      0*0
                          //     1   1
                          //    2     22
                          //     3   3
                          //      000
                            {
                              if (row_num < num_rows)
                                {
                                  if (room[row_num][2*half_column_num].mark()
                                   == 'S')
                                    result=TRUE;
                                }
                              if (! result)
                                {
                                  if (row_num > 0)
                                    {
                                      if (room[row_num-1]
                                       [2*half_column_num].mark() == 'S')
                                        result=TRUE;
                                    }
                                }
                            }
                        break;
                      case 1:
                        if (base_x_mod_8 < 3)
                        //      000
                        //     *   1
                        //    2     22
                        //     3   3
                        //      000
                          {
                            if (room[row_num][2*half_column_num].mark() == 'S')
                              result=TRUE;
                            if (! result)
                              {
                                if (row_num > 0)
                                  {
                                    if (half_column_num > 0)
                                      {
                                        if (room[row_num-1]
                                         [2*half_column_num-1].mark() == 'S')
                                          result=TRUE;
                                      }
                                  }
                              }
                          }
                        else
                        //      000
                        //     1   *
                        //    2     22
                        //     3   3
                        //      000
                          {
                            if (room[row_num][2*half_column_num].mark() == 'S')
                              result=TRUE;
                            if (! result)
                              {
                                if (row_num > 0)
                                  {
                                    if (2*half_column_num+1 < num_columns)
                                      {
                                        if (room[row_num-1]
                                         [2*half_column_num+1].mark() == 'S')
                                          result=TRUE;
                                      }
                                  }
                              }
                          }
                        break;
                      case 2:
                        if (base_x_mod_8 < 3)
                        //      000
                        //     1   1
                        //    *     22
                        //     3   3
                        //      000
                          {
                            if (room[row_num][2*half_column_num].mark() == 'S')
                              result=TRUE;
                            else
                              {
                                if (half_column_num > 0)
                                  {
                                    if (row_num > 0)
                                      {
                                        if (room[row_num-1]
                                         [2*half_column_num-1].mark() == 'S')
                                          result=TRUE;
                                      }
                                    if (! result)
                                      {
                                        if (row_num < (num_rows-1))
                                          {
                                            if (room[row_num]
                                             [2*half_column_num-1].mark()
                                             == 'S')
                                              result=TRUE;
                                          }
                                      }
                                  }
                              }
                          }
                        else
                          if (base_x_mod_8 < 7) // case 6
                          //      000
                          //     1   1
                          //    2     *2
                          //     3   3
                          //      000
                            {
                              if (room[row_num][2*half_column_num].mark()
                               == 'S')
                                result=TRUE;
                              if (! result)
                                {
                                  if (row_num < num_rows-1)
                                    {
                                      if (2*half_column_num+1 < num_columns)
                                        {
                                          if (room[row_num]
                                           [2*half_column_num+1].mark() == 'S')
                                            result=TRUE;
                                        }
                                    }
                                }
                              if (! result)
                                {
                                  if (row_num > 0)
                                    {
                                      if (2*half_column_num+1 < num_columns)
                                        {
                                          if (room[row_num-1]
                                           [2*half_column_num+1].mark() == 'S')
                                            result=TRUE;
                                        }
                                    }
                                }
                            }
                          else
                          //      000
                          //     1   1
                          //    2     2*
                          //     3   3
                          //      000
                            {
                              if (row_num < (num_rows-1))
                                {
                                  if (room[row_num][2*half_column_num+1].mark()
                                   == 'S')
                                    result=TRUE;
                                }
                              if (! result)
                                {
                                  if (row_num > 0)
                                    {
                                      if (room[row_num-1]
                                       [2*half_column_num+1].mark() == 'S')
                                        result=TRUE;
                                    }
                                }
                            }
                        break;
                      default:
                        if (base_x_mod_8 < 3)
                        //      000
                        //     1   1
                        //    2     22
                        //     *   3
                        //      000
                          {
                            if (room[row_num][2*half_column_num].mark()
                             == 'S')
                              result=TRUE;
                            else
                              {
                                if (half_column_num > 0)
                                  {
                                    if (row_num < (num_rows-1))
                                      {
                                        if (room[row_num]
                                         [2*half_column_num-1].mark() == 'S')
                                          result=TRUE;
                                      }
                                  }
                              }
                          }
                        else
                        //      000
                        //     1   1
                        //    2     22
                        //     3   *
                        //      000
                          {
                            if (room[row_num][2*half_column_num].mark()
                             == 'S')
                              result=TRUE;
                            if (! result)
                              {
                                if (row_num < (num_rows-1))
                                  {
                                    if (2*half_column_num+1 < num_columns)
                                      {
                                        if (room[row_num]
                                         [2*half_column_num+1].mark()
                                         == 'S')
                                          result=TRUE;
                                      }
                                  }
                              }
                          }
                        break;
                    }
                }
              else
                result=FALSE;
        }
    return result;
  }
 
void hexmaze::set_point_on_page(
  int  x,
  int  y)
//      Place a section of wall on "page".  Each section is "wall_thickness"
// bricks long and "wall_thickness" bricks wide.
    {
      int x_offset;
      int x_out;
      int y_offset;
      int y_out;
 
      for (x_offset=0; x_offset < wall_thickness; x_offset++)
        {
          x_out=x+x_offset;
          for (y_offset=0; y_offset < wall_thickness; y_offset++)
            {
              y_out=y+y_offset;
              page[y_out][x_out]='W';
            }
        }
      return;
    }
