home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / CLIPPER / MISC / BM_STAR.ZIP / SOURCE.ZIP / DFID.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-26  |  26.1 KB  |  840 lines

  1. ///////////////////////////////////////////////////////////////
  2. //         Title:  Dfid.c               25jun91/bm           //
  3. //         by:  Bob McIsaac                                  //
  4. ///////////////////////////////////////////////////////////////
  5. //
  6. #include <bios.h>
  7. #include <conio.h>
  8. //nclude <fcntl.h>
  9. #include <graph.h>
  10. //nclude <io.h>
  11. #include <malloc.h>
  12. #include <memory.h>
  13. #include <process.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. //nclude <sys\types.h>
  18. //nclude <sys\stat.h>
  19. #include <time.h>
  20. #define  HASH_SIZE      161     // primary hash table size
  21. #define  YES            1
  22. #define  NO             0
  23. #define  INVALID        -1
  24. #define  PW             4       // puzzle width
  25. #define  PSIZE          PW * PW // puzzle size 
  26. #define  POLES          4       // North,South,East,West
  27. #define  HOLE           '-'     // place to move into
  28. #define  FORWARD        0
  29. #define  REVERSE1       1
  30. #define  REVERSE2       2
  31. // solution types
  32. #define  StoG           1       // if goal on down search
  33. #define  GtoS           2       // if goal on 1st up search
  34. #define  GtoS_COM       3       // if common node on up search
  35. #define  GtoS_K1        4       // if goal on 2nd up search
  36. #define  GtoS_K1_COM    5       // if common node on 2nd up search
  37.  
  38. #define   SetPos(Row,Col) _asm \
  39. { _asm mov ah,02h  _asm mov bh,00h \
  40.   _asm mov dh,Row  _asm mov dl,Col   _asm int 10h \
  41.  
  42. typedef struct lnode *NPTR;     // node pointer
  43. struct lnode
  44.   { NPTR  Next;                 // pointer to next node
  45.             int Num;            // node number
  46.     char *Dptr;                 // pointer to data store
  47.   } ;                           // : use cast if not char
  48.  
  49. typedef struct
  50. { unsigned int
  51.     Gn,                 // cost from source to n
  52.     Hn,                 // estimated cost to goal
  53.     Dad;                // nodenum of parent node
  54.     char Puz[PSIZE+1];  // string representation of puzzle
  55. } PUZZLE ;
  56. //
  57. // global variables 
  58. PUZZLE Goal;            // the ultimate Target 
  59. PUZZLE Source;          // the input pattern
  60. PUZZLE Choice;          // the best one to reach goal
  61. PUZZLE Tries[POLES];    // temporary expansions
  62. NPTR   FreePuzzles;     // list of spare puzzle nodes
  63. NPTR   Closed;          // list of puzzles already tried
  64. NPTR   Open;            // list of puzzles to be evaluated
  65. NPTR   DownData;        // puzzles saved from kth level S->G
  66. NPTR   CommonNode;      // needed for solution path;
  67. NPTR  Known[HASH_SIZE];  // hashed list of known puzzles
  68. NPTR  D_Dat[HASH_SIZE];  // hashed list of level k S->G
  69. char   *Gp;             // the current goal
  70. time_t Time1, Time2;    // timer variables
  71. unsigned long
  72.        ExpDown,         // count of nodes expanded S to G
  73.        ExpUp,           // count of nodes expanded G go S
  74.        Moves;           // count of expansions attempted
  75. unsigned int
  76.        Depth,           // maximum depth of current search
  77.        Level,           // current position in a Dfs
  78.        DownDepth,       // how far from S->G
  79.        UpDepth,         // how far from G->S
  80.        NodeNum;         // count of linked nodes in use
  81. int    Success;         // set if goal with solution type
  82. int    Direction;       // move from goal to source if != 0
  83. int    Pausing;         // pause and test for quit
  84. int    Listing;         // show open & closed lists
  85. int    Puz_Show;        // show puzzles
  86. int    ResultInFile;    // save closed in file
  87. FILE   *Fp;             // data file pointer
  88. int JmpDistance[] = { -PW,      // offset to North
  89.                       +PW,      // offset to South
  90.                       +1,       // offset to East
  91.                       -1  };    // offset to West
  92. int ValidJmps[] = { 0x6,0xE,0xE,0xA,    // direction masks
  93.                     0x7,0xF,0xF,0xB,    // for move rules
  94.                     0x7,0xF,0xF,0xB,
  95.                     0x5,0xD,0xD,0x9 };
  96. //
  97. // function prototypes
  98. int    BiDfid          ( void );
  99. int    CharPos         ( char *Px, int ch );
  100. void   ClearStates     ( int All );
  101. int    Dfs             ( PUZZLE *Px );
  102. NPTR   DfsOpen         ( PUZZLE *Pz );
  103. int    DrawSym         ( int Row, int Col, char *Pz );
  104. NPTR   DropPuzzles     ( NPTR Head );
  105. void   DropTable       ( NPTR *Table, int Size );
  106. NPTR   FindPuzLink     ( NPTR Pos, char *Px );
  107. int    Generate        ( NPTR Link );
  108. int    IfExistPuz      ( char *Pz );
  109. void   KeyWait         ( void );
  110. void   ListInFile      ( NPTR Head, int Level );
  111. int    MakeKey         ( char *Pz );
  112. NPTR   MakePuzNode     ( PUZZLE *Pz );
  113. void   MakeTextRoom    ( void );
  114. int    MatchBottom     ( void );
  115. void   NoRoom          ( void );
  116. void   ReleasePuzzles  ( void );
  117. void   SaveDownData    ( void );
  118. void   ShowHow         ( void );
  119. void   ShowList        ( NPTR Link );
  120. void   ShowListStep    ( void      );
  121. int    ShowMoves       ( void );
  122. void   ShowTable       ( NPTR *Table, int Size );
  123. void   ShowSuccess     ( int Success );
  124. void   Statistics      ( void );
  125. int    TestKey         ( void );
  126. #include "Linked.c" //
  127. ///////////////////////////////////////////////////////////////
  128. //     *** MAIN ***
  129. // 
  130. void main( int argc, char *argv[] )
  131. {
  132.    char *Sptr, *Lptr;
  133.    int i, bpos, Done, ch;
  134.    NPTR L1, L2;
  135.    PUZZLE *Px, *Py;
  136.    _clearscreen(0);
  137.    if( strlen(argv[1]) != PSIZE )
  138.        ShowHow();       // trap puzzle error
  139.    memcpy( Source.Puz, argv[1], PSIZE );
  140.    Source.Puz[PSIZE]=0;
  141.    strcpy( Source.Puz, strupr( Source.Puz ) );
  142.    strcpy( Goal.Puz, "123456789ABCDEF-" );
  143.    Goal.Gn = Goal.Hn = Source.Gn = Source.Hn = 0;
  144.    NodeNum=0;
  145.    FreePuzzles = FreeHead =  NULL;
  146.    Fp = NULL;   // data file
  147.    DownData = Open = Closed = NULL;
  148.    Time1 = Time2 = 0;
  149.    for( i=0; i<POLES; i++ )
  150.    {
  151.         Tries[i].Gn = Tries[i].Hn = INVALID ;
  152.    }
  153.    for( i=0; i<HASH_SIZE; i++ )
  154.    {
  155.        Known[i] = NULL;         // puzzles on open & closed
  156.        D_Dat[i] = NULL;         // puzzles at depth bound only
  157.    }
  158.     memset( Choice.Puz, HOLE, PSIZE );
  159.    time( &Time1 );    // start timer
  160.    ShowMoves();
  161. // MakeTextRoom();
  162.    printf("\nSource= %s  ** %s **",argv[1],argv[2]);
  163.    printf("\n Solve this puzzle <*/N>");
  164.    if( toupper(getch()) =='N' ) exit(0);
  165. //
  166.    Pausing=NO;
  167.    printf("\n1. Display Puzzles");
  168.    printf("\n2. Display Lists");
  169.    printf("\n3. Save Result in file..BmResult");
  170.    printf("\n0. Display Nothing");
  171.    ch = getch();
  172.    Puz_Show = ( ch=='1');
  173.    Listing  = ( ch=='2');
  174.    ResultInFile = ( ch=='3');
  175.    if( ResultInFile )
  176.    {
  177.       if(( Fp = fopen( "BMresult.tmp","w" )) == NULL )
  178.       {
  179.           printf(" ** file open error ** ");
  180.           KeyWait();
  181.           exit(0);
  182.       }
  183.       else
  184.          printf("\nSolution File BMresult.tmp is open..");
  185.    }
  186.    if( !ResultInFile && Listing||Puz_Show )
  187.    {
  188.       printf("\nPause while displaying 1=yes 0=no");
  189.       Pausing = ( getch()=='1' );
  190.    }
  191.    _clearscreen(0);
  192.    Choice = Source;
  193.     memset( Choice.Puz, HOLE, PSIZE );
  194.    time( &Time1 );    // start timer
  195.    CommonNode=NULL;
  196.    ShowMoves();
  197.    cputs("\n..busy..");
  198.    Success = BiDfid();  // ...search...
  199.    time( &Time2 );    // completion time
  200. //
  201.    ShowMoves();
  202.    MakeTextRoom();
  203.    Statistics();
  204.    ShowSuccess( Success );
  205.    KeyWait();
  206. //
  207.    if( Fp != NULL )
  208.       fprintf(Fp,"\nSource= %s  ** %s **",argv[1],argv[2]);
  209.    i = ( Success == StoG || Success == GtoS || Success == GtoS_K1 );
  210.    if( Fp != NULL && i )
  211.    {
  212.       fprintf(Fp,"\n..Final Closed List..");
  213.       fprintf(Fp,"\n..Trace solution path backwards to source..");
  214.       ShowList( Closed );
  215.    }
  216.    i = ( Success == GtoS_COM || Success == GtoS_K1_COM );
  217.    if( Fp != NULL && i && CommonNode != NULL )
  218.    {
  219.       PUZZLE *Px = (PUZZLE*)CommonNode->Dptr;
  220.       NPTR Link = FindPuzLink( DownData, Px->Puz );
  221.       if( Link != NULL )
  222.       {
  223.          fprintf(Fp,"\n..Final Closed List..");
  224.          fprintf(Fp,"\n..Trace path backwards to source.. %s",Source.Puz);
  225.          fprintf(Fp,"\n..from common node %d %s",Link->Num,Px->Puz );
  226.          ShowList( DownData );
  227.          Link = FindPuzLink( Closed, Px->Puz );
  228.          fprintf(Fp,"\n..Trace path backwards to goal.. %s",Goal.Puz);
  229.          fprintf(Fp,"\n..from common node %d %s",Link->Num,Px->Puz );
  230.          ShowList( Closed );
  231.       }
  232.    }
  233.    ClearStates(1);
  234.    ReleasePuzzles();    // make room for shell to dos
  235.    if( Fp != NULL )
  236.    {  // use external full screen viewer to scan solution
  237.       fclose( Fp );
  238.       system("List BMresult.tmp");
  239.    }
  240.    exit(0);
  241. }//
  242. ///////////////////////////////////////////////////////////////
  243. int  BiDfid( void )
  244. // Bidirectional depth first search with iterative deepening
  245. // return solution type: goal hit or common node w/ direction
  246. // GLOBALS: Known[],Depth,Success
  247. {
  248.  
  249.    int Solution = NO;
  250.    Depth = 1;
  251.    Success=NO;
  252.    ExpDown = ExpUp = 0L;        // no expansions yet
  253.    while( !Success && Depth>0 )
  254.    {
  255.       Direction = FORWARD;
  256.       DownDepth=Depth;
  257.       Gp = Goal.Puz;            // goal = actual goal
  258.       Solution = StoG;          // source to goal ?
  259.       Success = Dfs( &Source );
  260.       if( !Success )
  261.       {
  262.          SaveDownData();        // keep S->G bottom level
  263.          ClearStates(0);        // clear states except boundary
  264.          Gp = Source.Puz;       // goal is actual source
  265.          Direction=REVERSE1;
  266.          UpDepth = Depth;       // span from goal to source
  267.          Solution = GtoS;       // goal to source ?
  268.          Success = Dfs( &Goal );  // search reverse to level k
  269.          if( !Success )
  270.          {
  271.             Solution = GtoS_COM;        // look for common node
  272.             Success = MatchBottom();
  273.             if( !Success )
  274.             {   // search reverse to level k+1
  275.                 ClearStates(0); // clear reverse search
  276.                 Direction = REVERSE2;
  277.                 UpDepth=++Depth;
  278.                 Solution = GtoS_K1;  // try K+1 iterations
  279.                 Success = Dfs( &Goal );
  280.                 if( !Success );
  281.                 {
  282.                    Solution = GtoS_K1_COM;
  283.                    Success = MatchBottom();
  284.                    if( !Success )
  285.                    {
  286.                       Solution=NO;
  287.                       ClearStates(1);   //clear all search info
  288.                    }
  289.                 }
  290.             }
  291.          }
  292.       }
  293.    }
  294.    return(Solution);
  295. }//
  296. ///////////////////////////////////////////////////////////////
  297. int CharPos( char *Sptr, int ch )
  298. // Determine if 'ch' exists within puzzle string at Sptr.
  299. // Return integer offset from start of string to position.
  300. // Else trap system error.
  301. {
  302.  
  303.    static char *Lptr;
  304.    Lptr = strchr( Sptr, ch );
  305.    if ( *Lptr != ch )
  306.    {
  307.       printf("\n** puzzle error ** %s",Sptr);
  308.       exit(0);
  309.    }
  310.    return( Lptr-Sptr );
  311. }
  312. ///////////////////////////////////////////////////////////////
  313. void ClearStates( int All )
  314. // BiDirectional DFID requires clearing of the state space at
  315. // the end of each iteration. That is, except for the nodes of
  316. // the state space at the depth bound. These must be preserved
  317. // before calling this function.
  318. // Note: Single step mode may be exception
  319. {
  320.    Open = DropPuzzles( Open ); 
  321.    Closed = DropPuzzles( Closed );
  322.    DropTable( Known, HASH_SIZE );
  323.    if( All > 0 )
  324.    {
  325.       DownData = DropPuzzles( DownData );
  326.       DropTable( D_Dat, HASH_SIZE );
  327.    }
  328. }
  329. //
  330. ///////////////////////////////////////////////////////////////
  331. int    Dfs( PUZZLE *Pz )
  332. // Depth first search with a depth bound
  333. // return success
  334. // GLOBALS: Choice,Puz_Show,Open,Closed,Gp,Depth,Level
  335. {
  336.    int i, j, Done;
  337.    PUZZLE *Py;
  338.    Level=0;
  339.    DfsOpen( Pz );               // source on open list
  340.    Done = Success = NO;
  341.    while( !Done )
  342.    {
  343.       if(  Listing )
  344.       {
  345.          printf("\n---Open List---"); KeyWait();
  346.          ShowList(Open);
  347.          printf("\n---Closed List---"); KeyWait();
  348.          ShowList(Closed);
  349.       }
  350.       Closed = PushLink( Closed, PopLink( &Open ) );
  351.       Py = (PUZZLE*)(Closed->Dptr);
  352.       Level = Py->Gn;
  353.       Success=( strcmp( Gp, Py->Puz )==0 );     //?goal
  354.       if( !Success )
  355.       {
  356.           if( Level < Depth )   // if expandable
  357.           {
  358.              Level++;
  359.              Generate( Closed ); // process successors
  360.           }
  361.       }
  362.       Done = ( Success || Open==NULL );
  363.    }
  364.    return( Success );
  365. }//
  366. ///////////////////////////////////////////////////////////////
  367. NPTR DfsOpen( PUZZLE *Pz )
  368. // put a puzzle in the LIFO  ordered open list and also in the
  369. // the hashed list of generated puzzle strings
  370. // return puzzle node pointer
  371. // GLOBALS: Open, Known[], Level
  372. {
  373.    NPTR L1, L2;
  374.    int i;
  375.    Pz->Gn = Level;
  376.    L1 = MakePuzNode( Pz );
  377.    Open = PushLink( Open, L1 ); // make open like a stack
  378.    L2 = MakeLink( L1->Dptr, 0 );
  379.    if( L2 == NULL )
  380.       NoRoom();
  381.    i = MakeKey( Pz->Puz );      // hash puzzle string
  382.    Known[i] = PushLink( Known[i], L2 );
  383.    return( L1 );
  384. }
  385. ///////////////////////////////////////////////////////////////
  386. int DrawSym( int Row, int Col, char *Sptr )
  387. // display a puzzle given it's string and a starting position
  388. // 
  389. {
  390.    int i,j;
  391.    for( j=0; j<PW; j++ )
  392.    {
  393.       SetPos( Row, Col );
  394.       for( i=0; i<PW; i++ )
  395.       {
  396.          printf(" %c",*Sptr++ );
  397.       }
  398.       Row+=1;
  399.    }
  400. }//
  401. ///////////////////////////////////////////////////////////////
  402. NPTR   DropPuzzles( NPTR Head )
  403. // Reuse space already allocated for a Linked list of puzzles
  404. // Put these puzzle nodes on a linked list of free puzzles.
  405. // and return NULL to mark empty list;
  406. // See also SaveDownDat()
  407. // GLOBALS: FreePuzzles
  408. {
  409.    NPTR L1;
  410.    while( Head != NULL )
  411.    {
  412.       L1 = Head->Next;
  413.       FreePuzzles = PushLink( FreePuzzles, Head );
  414.       Head = L1;
  415.    }
  416.    return( Head );
  417. }
  418. ///////////////////////////////////////////////////////////////
  419. void   DropTable( NPTR *Table, int Size )
  420. // Free linked lists connected to a table of pointers
  421. {
  422.    int i;
  423.    for( i=0; i<Size; i++ )
  424.    {
  425.       Table[i] = DropLinked( Table[i] );
  426.    }
  427. }
  428. ///////////////////////////////////////////////////////////////
  429. NPTR   FindPuzLink( NPTR Pos, char *Sp )
  430. // Return pointer to node in linked list of puzzles which 
  431. // contains specified puzzle string.
  432. // GLOBALS: 
  433. {
  434.     int Found = NO;
  435.     while( Pos != NULL && !Found )
  436.     {
  437.        PUZZLE *Tmp = (PUZZLE*)Pos->Dptr;
  438.        Found = ( strcmp( Tmp->Puz, Sp )==0 );
  439.        if( !Found )
  440.           Pos = Pos->Next;
  441.     }
  442.     return( Pos );
  443. }//
  444. ///////////////////////////////////////////////////////////////
  445. int Generate( NPTR Link )
  446. // Given a puzzle string, create upto 4 variants as permitted
  447. // by move rules. Note that for DFID, no expansion occurs for
  448. // states whose level is at the current Depth bound.
  449. // return nothing
  450. {
  451.    PUZZLE *Py = (PUZZLE*)Link->Dptr;
  452.    int i, bpos, ch, xd, Mask=1;
  453.    bpos = CharPos( Py->Puz, HOLE );        // find open square
  454.    xd = ValidJmps[bpos];
  455.    for( i=0; i<POLES; i++ )             // upto 4 moves possible
  456.    {  // if move is possible copy puzzle and switch 2 squares
  457.        if( xd & Mask )
  458.        {
  459.             Moves++;    // total # moves considered
  460.             strcpy( Tries[i].Puz, Py->Puz );
  461.             ch = Tries[i].Puz[bpos];    // get the HOLE
  462.             Tries[i].Puz[bpos] = Tries[i].Puz[ bpos+JmpDistance[i] ];
  463.             Tries[i].Puz[ bpos+JmpDistance[i] ] = ch;
  464.             if( !IfExistPuz( Tries[i].Puz ) )
  465.             {  // put new children on open list
  466.                if( Direction != FORWARD )
  467.                     ExpUp++;    // count reverse
  468.                else
  469.                     ExpDown++;  // count forward
  470.                Tries[i].Dad = Link->Num;        // remember path
  471.                DfsOpen( &Tries[i] );
  472.             }
  473.        }
  474.        else
  475.        {
  476.             Tries[i].Gn = INVALID ;
  477.        }
  478.        Mask=Mask<<1;
  479.    }
  480.    if( Puz_Show )       // optionally display moves
  481.    {
  482.       memcpy( &Choice, Py, sizeof(PUZZLE) ); 
  483.       ShowMoves();
  484.    }
  485.    return( 0 );
  486. }//
  487. ///////////////////////////////////////////////////////////////
  488. int IfExistPuz( char *Pz )
  489. // Determine if a given puzzle was already generated. Search
  490. // the hashed puzzle string table for a match
  491. // GLOBALS: Known[]
  492. {
  493.    int Ans = NO;
  494.    NPTR Link = Known[ MakeKey( Pz ) ];
  495.    if( Link != NULL )
  496.    {
  497.       Link = FindPuzLink( Link, Pz );
  498.       Ans=( Link!=NULL );
  499.    }
  500.    return(Ans);
  501. }
  502. ///////////////////////////////////////////////////////////////
  503. void KeyWait( void )
  504. {
  505.    printf(" ..key?" );
  506.    getch();
  507. }//
  508. ///////////////////////////////////////////////////////////////
  509. void ListInFile( NPTR Head, int Level   )
  510. // create test data by writing to a file all the nodes from
  511. // the closed list at a specified level.
  512. // Note: Copy Puzzles.dat to a batch file between runs
  513. {
  514.    FILE *fp;
  515.    PUZZLE *Px;
  516.    char Sp[] = "Puzzles.dat";
  517.    if(( fp = fopen( Sp,"w" )) == NULL )
  518.    {
  519.        printf(" ** file open error ** ");
  520.        KeyWait();
  521.        exit(0);
  522.    }
  523.    printf("Filing %s",Sp); 
  524.    while( Head != NULL )
  525.    {
  526.       Px = (PUZZLE*)Head->Dptr;
  527.       Head = Head->Next;
  528.       if( Px->Gn == Level )
  529.         fprintf( fp, "\ndfid %s Level_%d",Px->Puz,Level );
  530.    }
  531.    fclose( fp );
  532.    KeyWait();
  533. }
  534. ///////////////////////////////////////////////////////////////
  535. int MakeKey( char *Sp )
  536. // Given a 16-char puzzle string, pick every 4th char and
  537. // produce a long integer K by multiplication. Then return a
  538. // 16-bit integer result produced by  K mod Tp where Tp is
  539. // a prime number table size.
  540. // GLOBALS: Tp
  541. {
  542.    ldiv_t Result;
  543.    long K1 ;  
  544.    K1 = 1000L * *(Sp+15) + 100L * *(Sp+11) +
  545.           10L * *(Sp+ 7) + *Sp;
  546.    Result = ldiv( K1, (long)HASH_SIZE );
  547.    return( (int)Result.rem );  // quotient not needed
  548. }//
  549. ///////////////////////////////////////////////////////////////
  550. NPTR   MakePuzNode( PUZZLE *Px )
  551. // Get a puzzle node from the free list or
  552. // allocate space for a puzzle node, copy temporary values 
  553. // to it, then return pointer to allocated space.
  554. // If no memory, abort gracefully
  555. // GLOBALS: FreePuzzles, NodeNum
  556. {
  557.    NPTR Link = PopLink( &FreePuzzles );  // recycle an old puzzle
  558.    if( Link == NULL )
  559.    {
  560.        PUZZLE *Puz = (PUZZLE*)malloc( sizeof(PUZZLE) );
  561.        if( Puz != NULL )
  562.            Link = MakeLink( (char*)Puz, 0 );
  563.        if( Puz == NULL || Link == NULL )
  564.        {
  565.           NoRoom();
  566.        }
  567.    }
  568.    memcpy( (PUZZLE*)Link->Dptr, Px, sizeof(PUZZLE) );
  569.    Link->Num = ++NodeNum;       // count puzzles created
  570.    return( Link );
  571. }//
  572. ///////////////////////////////////////////////////////////////
  573. void MakeTextRoom( void )
  574. // erase expansion area of puzzle screen
  575. {
  576.    int Row, Col;
  577.    for( Row=8; Row<23; Row++ )
  578.    {
  579.       SetPos(Row,0);
  580.       for( Col=0; Col < 78; Col++)
  581.           putch(' ');
  582.    }
  583.    SetPos(8,0);
  584. }
  585. ///////////////////////////////////////////////////////////////
  586. int  MatchBottom( void )
  587. // scan closed list from reverse search selecting those nodes
  588. // where Gn = Depth. Look for match in table saved by forward
  589. // search. Remember common node for solution display
  590. // GLOBALS: CommonNode, Success, Depth, D_Dat[]
  591. {
  592.    NPTR Head = Closed;  // the reverse list
  593.    PUZZLE *Px;
  594.    CommonNode = NULL ;
  595.    Success = NO;
  596.    while( Head != NULL && CommonNode == NULL )
  597.    {
  598.       Px = (PUZZLE*)Head->Dptr;
  599.       if( Px->Gn == Depth )
  600.       {  // hash to the forward list
  601.          CommonNode = D_Dat[ MakeKey( Px->Puz ) ];
  602.          if( CommonNode != NULL )
  603.          {
  604.             CommonNode = FindPuzLink( CommonNode, Px->Puz );
  605.          }
  606.          Success = ( CommonNode != NULL );
  607.       }
  608.       Head = Head->Next;
  609.    }
  610.    return( Success );
  611. }//
  612. ///////////////////////////////////////////////////////////////
  613. void NoRoom( void )
  614. {
  615.    time( &Time2 );      // mark the run time
  616.    MakeTextRoom();
  617.    printf("\n*** no heap space ***\n");
  618.    Statistics();
  619.    ClearStates(1);      // clear the state space
  620.    KeyWait();
  621.    exit(0);
  622. }
  623. ///////////////////////////////////////////////////////////////
  624. void ReleasePuzzles( void )
  625. // Unallocate puzzles kept on spare list
  626. // GLOBALS: FreePuzzles, FreeHead
  627. {
  628.     NPTR Tmp = FreePuzzles;
  629.     PUZZLE *Px;
  630.     while( Tmp != NULL )
  631.     {
  632.         Px = (PUZZLE*)Tmp->Dptr;
  633.         free( Px );
  634.         FreeHead = PushLink( FreeHead, PopLink(  &FreePuzzles ) );
  635.         Tmp = FreePuzzles;
  636.     }
  637.     ReleaseNodes();
  638. }
  639. ///////////////////////////////////////////////////////////////
  640. void SaveDownData( void )
  641. // Upon completion of search from source to goal for some depth
  642. // Kn, if the goal was not found, save puzzles from closed list
  643. // which have Gn = Kn, in hashed table. Do this before clearing
  644. // the state space before reverse search.
  645. // Note: all nodes are saved if ResultInFile is TRUE
  646. // GLOBALS: D_DAT[], Depth, Closed, DownData
  647. {
  648.    PUZZLE *Px;
  649.    int x;
  650.    NPTR  L1, L2;
  651.    while( Closed != NULL )
  652.    {
  653.       L1 = PopLink( &Closed );  // eat the closed list
  654.       Px = (PUZZLE*)L1->Dptr;
  655.       if( ( Px->Gn == Depth )||(ResultInFile) )
  656.       {
  657.          DownData = PushLink( DownData, L1 );
  658.          x = MakeKey( Px->Puz );        // use hashing
  659.          L2 = MakeLink( L1->Dptr, 0 );
  660.          if( L2 == NULL )
  661.             NoRoom();
  662.          D_Dat[x] = PushLink( D_Dat[x], L2 );
  663.       }
  664.       else // recycle if not needed
  665.          FreePuzzles = PushLink( FreePuzzles, L1 );
  666.    }
  667.  //ShowTable( D_Dat, HASH_SIZE );
  668.    return;
  669. }//
  670. ///////////////////////////////////////////////////////////////
  671. void   ShowList( NPTR Link )
  672. // Display a linked list of puzzles, if file is open, also
  673. // output to the text file.
  674. // GLOBALS: FILE *Fp
  675. {
  676.    PUZZLE *Pz;
  677.    unsigned int Row=0;
  678.    if( Link== NULL ) printf("\nNULL list..");
  679.    while( Link != NULL )
  680.    {
  681.        Pz = (PUZZLE*)Link->Dptr;
  682.        if( Fp != NULL )
  683.        {  // if result file open
  684.           fprintf(Fp,"\n NodeNum: %5d  Gn: %4d  Hn: %3d  Dad %5d  %s",
  685.              Link->Num, Pz->Gn, Pz->Hn,Pz->Dad, Pz->Puz );
  686.        }
  687.        else
  688.        {
  689.           printf("\n NodeNum: %5d  Gn: %4d  Hn: %3d  Dad %5d %s",
  690.               Link->Num, Pz->Gn, Pz->Hn,Pz->Dad, Pz->Puz );
  691.        }
  692.        Link = Link->Next;
  693.        if( ++Row % 12 == 0 && Fp==NULL )
  694.        {
  695.           KeyWait();
  696.        }
  697.    }
  698.    if( Fp==NULL) KeyWait();
  699. } //
  700. ///////////////////////////////////////////////////////////////
  701. int ShowMoves( void )
  702. {
  703.    int i;
  704.    time_t Ticks;
  705.    SetPos(0,4);
  706.    printf("-Source-");
  707.    DrawSym( 2,4,Source.Puz );
  708.    SetPos(0,16);
  709.    printf("-Parent-");
  710.    DrawSym( 2,16,Choice.Puz );
  711.    SetPos( 0,28 );
  712.    printf("-Goal---");
  713.    DrawSym( 2,28,Goal.Puz );
  714.    SetPos(0,50);
  715.    if( Direction != FORWARD )
  716.       printf("G-->S: %ld",ExpUp);
  717.    else
  718.       printf("S-->G: %ld",ExpDown);
  719.    SetPos(1,50);
  720.       printf("Tries: %ld",ExpDown+ExpUp);
  721.    SetPos(2,50);
  722.    time( &Ticks );    // current time
  723.    printf("Clock: %f ",difftime( Ticks, Time1 ) );
  724.    SetPos(3,50);
  725.    printf("Depth: %ld",(long)Depth );
  726.    SetPos(4,50);
  727.    printf("Moves: %ld",(long)Moves );
  728.    for( i=0; i < POLES; i++ )
  729.        if( Tries[i].Gn == INVALID )
  730.             memset( Tries[i].Puz, HOLE, PSIZE );
  731.    SetPos( 8, 4); printf("BiDirectional DFID -- Bob McIsaac");
  732.    SetPos(12, 4); printf("%5d",Tries[0].Gn );
  733.    SetPos(12,16); printf("%5d",Tries[1].Gn );
  734.    SetPos(12,28); printf("%5d",Tries[2].Gn );
  735.    SetPos(12,40); printf("%5d",Tries[3].Gn );
  736.    printf("  . . . Gn");
  737.    DrawSym(14, 4,Tries[0].Puz );
  738.    DrawSym(14,16,Tries[1].Puz );
  739.    DrawSym(14,28,Tries[2].Puz );
  740.    DrawSym(14,40,Tries[3].Puz );
  741.    putchar('\n');
  742.    if( TestKey() ) exit(0);
  743.    return(0);
  744. }//
  745. ///////////////////////////////////////////////////////////////
  746. void   ShowTable( NPTR *Table, int Size )
  747. {
  748.    PUZZLE *Pz;
  749.    NPTR Link;
  750.    unsigned int i, Row=0;
  751.    for( i=0; i<Size; i++ )
  752.    {
  753.       Link = Table[i];
  754.       Row=0;
  755.       while( Link != NULL )
  756.       {
  757.          Pz = (PUZZLE*)Link->Dptr;
  758.          printf("\n Table___: key %4d Gn %4d %s",i,Pz->Gn,Pz->Puz );
  759.          Link = Link->Next;
  760.          if( ++Row % 12 == 0 ) KeyWait();
  761.       }
  762.    }
  763. }//
  764. ///////////////////////////////////////////////////////////////
  765. void ShowSuccess( int Success )
  766. {
  767.    printf("\n $$$ success $$$ %d",Success );
  768.    switch( Success )
  769.    {
  770.        case StoG:
  771.           printf("\nGoal found on S->G search (step K)");
  772.           break;
  773.        case GtoS:
  774.           printf("\nSource found on G->S search (step K)");
  775.           break;
  776.        case GtoS_COM:
  777.           printf("\nCommon found on G->S search (step K)");
  778.           break;
  779.        case GtoS_K1:
  780.           printf("\nSource found on G->S search (K+1)");
  781.           break;
  782.        case GtoS_K1_COM:
  783.           printf("\nCommon found on G->S search (K+1)");
  784.           break;
  785.        default: break;
  786.    }
  787. }
  788. // 
  789. ///////////////////////////////////////////////////////////////
  790. // Show correct format for command line.
  791. void ShowHow(void)
  792. {
  793.    int i;
  794.    printf("\nUSAGE: dfid <puzzle string>");
  795.    printf("\nEx:");
  796.    printf("\n   DFID 123456789ABCDEF-");
  797.    printf("\n   or use DfidTest.Bat");
  798.    exit(0);
  799. }  
  800. //
  801. ///////////////////////////////////////////////////////////////
  802. void Statistics( void )
  803. // GLOBALS: all variables
  804. {
  805.    if( Fp == NULL )
  806.    {
  807.       printf("\nClock: %6.2f Seconds",difftime( Time2, Time1 ) );
  808.       printf("\nNodes Expanded: S->G %6ld  Depth %d",
  809.                 ExpDown,DownDepth );
  810.       printf("\nNodes Expanded: G->S %6ld  Depth %d",
  811.                 ExpUp,UpDepth);
  812.       printf("\nMoves Considered:    %6ld", Moves);
  813.       printf("\nPuzzles generated:   %6ld",(long)NodeNum );
  814.    }
  815.    else  // write to BmResult.Tmp
  816.    {
  817.       fprintf(Fp,"\n\nBiDirectional DFID --- by Bob McIsaac" );
  818.       fprintf(Fp,"\nClock: %6.1f Seconds",difftime( Time2, Time1 ) );
  819.       fprintf(Fp,"\nNodes Expanded: S->G %6ld  Depth %d",
  820.                 ExpDown,DownDepth );
  821.       fprintf(Fp,"\nNodes Expanded: G->S %6ld  Depth %d",
  822.                 ExpUp,UpDepth);
  823.       fprintf(Fp,"\nMoves Considered:    %6ld", Moves);
  824.       fprintf(Fp,"\nPuzzles generated:   %6ld",(long)NodeNum );
  825.    }
  826. }
  827. ///////////////////////////////////////////////////////////////
  828. int TestKey()
  829. {
  830.    int Ans = 0;
  831.    if( Pausing )
  832.    {
  833.       printf("\n 1=more  0=quit >>" );
  834.       Ans = ( getch()=='0');
  835.    }
  836.    return( Ans );
  837. }
  838. //
  839.